Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support for ERC 1271 #33

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions contracts/ERC1271Sample.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.5.16;

import "./IERC1271.sol";

// libraries
import "@openzeppelin/contracts/ownership/Ownable.sol";

/**
* @notice ERC-1271: Standard Signature Validation Method for Contracts
*/
contract ERC1271Sample is ERC1271, Ownable {

// bytes4(keccak256("isValidSignature(bytes32,bytes)")
bytes4 constant internal MAGICVALUE = 0x1626ba7e;

// To store the Data Hash => Singature Hash
mapping(bytes32 => bytes32) public signatures;

/**
* @dev Should return whether the signature provided is valid for the provided data
* @param _hash Arbitrary length data signed on the behalf of address(this)
* @param _signature Signature byte array associated with _hash
*
* MUST return the bytes4 magic value 0x1626ba7e when function passes.
* MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
* MUST allow external calls
*/
function isValidSignature(
bytes32 _hash,
bytes memory _signature)
public
view
returns (bytes4 magicValue) {
if(signatures[_hash] == keccak256(_signature))
return MAGICVALUE;
return 0;
}

function addSignature(
bytes32 _hash,
bytes memory _signature)
public
onlyOwner {
signatures[_hash] = keccak256(_signature);
}

function addSignature(
bytes32 _hash,
bytes32 _signatureHash)
public
onlyOwner {
signatures[_hash] = _signatureHash;
}
}
97 changes: 81 additions & 16 deletions contracts/EthereumDIDRegistry.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
pragma solidity ^0.4.4;
pragma solidity ^0.5.16;

import "./IERC1271.sol";

// libraries
import "@openzeppelin/contracts/cryptography/ECDSA.sol";

contract EthereumDIDRegistry {

bytes4 internal constant _ERC1271_MAGICVALUE = 0x1626ba7e;

mapping(address => address) public owners;
mapping(address => mapping(bytes32 => mapping(address => uint))) public delegates;
Expand Down Expand Up @@ -36,7 +43,7 @@ contract EthereumDIDRegistry {

function identityOwner(address identity) public view returns(address) {
address owner = owners[identity];
if (owner != 0x0) {
if (owner != address(0x0)) {
return owner;
}
return identity;
Expand All @@ -49,8 +56,41 @@ contract EthereumDIDRegistry {
return signer;
}

/**
* @notice Checks if an identity's owner had provided a valid `_signature` for `_hash`.
* If the identity's owner is a smart contract, the 'isValidSignature' will be called accourding to ERC1271 interface.
*
* @param _hash hash of the data signed//Arbitrary length data signed on the behalf of `identity`
* @param _signature identity's signature(s) of the data
*/
function checkSignature(
address identity,
bytes32 _hash,
bytes memory _signature
) internal returns (address) {
address owner = identityOwner(identity);
bool isContract;
// solium-disable-next-line security/no-inline-assembly
assembly {
isContract := gt(extcodesize(owner), 0)
}
if (isContract) {
require(
_ERC1271_MAGICVALUE ==
ERC1271(owner).isValidSignature(_hash, _signature)
);
nonce[owner]++;
return owner;
} else {
address signer = ECDSA.recover(_hash, _signature);
require(signer == identityOwner(identity));
nonce[signer]++;
return signer;
}
}

function validDelegate(address identity, bytes32 delegateType, address delegate) public view returns(bool) {
uint validity = delegates[identity][keccak256(delegateType)][delegate];
uint validity = delegates[identity][keccak256(abi.encodePacked(delegateType))][delegate];
return (validity > now);
}

Expand All @@ -65,12 +105,17 @@ contract EthereumDIDRegistry {
}

function changeOwnerSigned(address identity, uint8 sigV, bytes32 sigR, bytes32 sigS, address newOwner) public {
bytes32 hash = keccak256(byte(0x19), byte(0), this, nonce[identityOwner(identity)], identity, "changeOwner", newOwner);
bytes32 hash = keccak256(abi.encodePacked(byte(0x19), byte(0), this, nonce[identityOwner(identity)], identity, "changeOwner", newOwner));
changeOwner(identity, checkSignature(identity, sigV, sigR, sigS, hash), newOwner);
}

function changeOwnerSigned(address identity, bytes memory signature, address newOwner) public {
bytes32 hash = keccak256(abi.encodePacked(byte(0x19), byte(0), this, nonce[identityOwner(identity)], identity, "changeOwner", newOwner));
changeOwner(identity, checkSignature(identity, hash, signature), newOwner);
}

function addDelegate(address identity, address actor, bytes32 delegateType, address delegate, uint validity) internal onlyOwner(identity, actor) {
delegates[identity][keccak256(delegateType)][delegate] = now + validity;
delegates[identity][keccak256(abi.encodePacked(delegateType))][delegate] = now + validity;
emit DIDDelegateChanged(identity, delegateType, delegate, now + validity, changed[identity]);
changed[identity] = block.number;
}
Expand All @@ -80,12 +125,17 @@ contract EthereumDIDRegistry {
}

function addDelegateSigned(address identity, uint8 sigV, bytes32 sigR, bytes32 sigS, bytes32 delegateType, address delegate, uint validity) public {
bytes32 hash = keccak256(byte(0x19), byte(0), this, nonce[identityOwner(identity)], identity, "addDelegate", delegateType, delegate, validity);
bytes32 hash = keccak256(abi.encodePacked(byte(0x19), byte(0), this, nonce[identityOwner(identity)], identity, "addDelegate", delegateType, delegate, validity));
addDelegate(identity, checkSignature(identity, sigV, sigR, sigS, hash), delegateType, delegate, validity);
}

function addDelegateSigned(address identity, bytes memory signature, bytes32 delegateType, address delegate, uint validity) public {
bytes32 hash = keccak256(abi.encodePacked(byte(0x19), byte(0), this, nonce[identityOwner(identity)], identity, "addDelegate", delegateType, delegate, validity));
addDelegate(identity, checkSignature(identity, hash, signature), delegateType, delegate, validity);
}

function revokeDelegate(address identity, address actor, bytes32 delegateType, address delegate) internal onlyOwner(identity, actor) {
delegates[identity][keccak256(delegateType)][delegate] = now;
delegates[identity][keccak256(abi.encodePacked(delegateType))][delegate] = now;
emit DIDDelegateChanged(identity, delegateType, delegate, now, changed[identity]);
changed[identity] = block.number;
}
Expand All @@ -95,36 +145,51 @@ contract EthereumDIDRegistry {
}

function revokeDelegateSigned(address identity, uint8 sigV, bytes32 sigR, bytes32 sigS, bytes32 delegateType, address delegate) public {
bytes32 hash = keccak256(byte(0x19), byte(0), this, nonce[identityOwner(identity)], identity, "revokeDelegate", delegateType, delegate);
bytes32 hash = keccak256(abi.encodePacked(byte(0x19), byte(0), this, nonce[identityOwner(identity)], identity, "revokeDelegate", delegateType, delegate));
revokeDelegate(identity, checkSignature(identity, sigV, sigR, sigS, hash), delegateType, delegate);
}

function setAttribute(address identity, address actor, bytes32 name, bytes value, uint validity ) internal onlyOwner(identity, actor) {
function revokeDelegateSigned(address identity, bytes memory signature, bytes32 delegateType, address delegate) public {
bytes32 hash = keccak256(abi.encodePacked(byte(0x19), byte(0), this, nonce[identityOwner(identity)], identity, "revokeDelegate", delegateType, delegate));
revokeDelegate(identity, checkSignature(identity, hash, signature), delegateType, delegate);
}

function setAttribute(address identity, address actor, bytes32 name, bytes memory value, uint validity ) internal onlyOwner(identity, actor) {
emit DIDAttributeChanged(identity, name, value, now + validity, changed[identity]);
changed[identity] = block.number;
}

function setAttribute(address identity, bytes32 name, bytes value, uint validity) public {
function setAttribute(address identity, bytes32 name, bytes memory value, uint validity) public {
setAttribute(identity, msg.sender, name, value, validity);
}

function setAttributeSigned(address identity, uint8 sigV, bytes32 sigR, bytes32 sigS, bytes32 name, bytes value, uint validity) public {
bytes32 hash = keccak256(byte(0x19), byte(0), this, nonce[identityOwner(identity)], identity, "setAttribute", name, value, validity);
function setAttributeSigned(address identity, uint8 sigV, bytes32 sigR, bytes32 sigS, bytes32 name, bytes memory value, uint validity) public {
bytes32 hash = keccak256(abi.encodePacked(byte(0x19), byte(0), this, nonce[identityOwner(identity)], identity, "setAttribute", name, value, validity));
setAttribute(identity, checkSignature(identity, sigV, sigR, sigS, hash), name, value, validity);
}

function revokeAttribute(address identity, address actor, bytes32 name, bytes value ) internal onlyOwner(identity, actor) {
function setAttributeSigned(address identity, bytes memory signature, bytes32 name, bytes memory value, uint validity) public {
bytes32 hash = keccak256(abi.encodePacked(byte(0x19), byte(0), this, nonce[identityOwner(identity)], identity, "setAttribute", name, value, validity));
setAttribute(identity, checkSignature(identity, hash, signature), name, value, validity);
}

function revokeAttribute(address identity, address actor, bytes32 name, bytes memory value ) internal onlyOwner(identity, actor) {
emit DIDAttributeChanged(identity, name, value, 0, changed[identity]);
changed[identity] = block.number;
}

function revokeAttribute(address identity, bytes32 name, bytes value) public {
function revokeAttribute(address identity, bytes32 name, bytes memory value) public {
revokeAttribute(identity, msg.sender, name, value);
}

function revokeAttributeSigned(address identity, uint8 sigV, bytes32 sigR, bytes32 sigS, bytes32 name, bytes value) public {
bytes32 hash = keccak256(byte(0x19), byte(0), this, nonce[identityOwner(identity)], identity, "revokeAttribute", name, value);
function revokeAttributeSigned(address identity, uint8 sigV, bytes32 sigR, bytes32 sigS, bytes32 name, bytes memory value) public {
bytes32 hash = keccak256(abi.encodePacked(byte(0x19), byte(0), this, nonce[identityOwner(identity)], identity, "revokeAttribute", name, value));
revokeAttribute(identity, checkSignature(identity, sigV, sigR, sigS, hash), name, value);
}

function revokeAttributeSigned(address identity, bytes memory signature, bytes32 name, bytes memory value) public {
bytes32 hash = keccak256(abi.encodePacked(byte(0x19), byte(0), this, nonce[identityOwner(identity)], identity, "revokeAttribute", name, value));
revokeAttribute(identity, checkSignature(identity, hash, signature), name, value);
}

}
27 changes: 27 additions & 0 deletions contracts/IERC1271.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.5.16;

/**
* @notice ERC-1271: Standard Signature Validation Method for Contracts
*/
contract ERC1271 {

// bytes4(keccak256("isValidSignature(bytes32,bytes)")
bytes4 constant internal MAGICVALUE = 0x1626ba7e;

/**
* @dev Should return whether the signature provided is valid for the provided data
* @param _hash Arbitrary length data signed on the behalf of address(this)
* @param _signature Signature byte array associated with _hash
*
* MUST return the bytes4 magic value 0x1626ba7e when function passes.
* MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
* MUST allow external calls
*/
function isValidSignature(
bytes32 _hash,
bytes memory _signature)
public
view
returns (bytes4 magicValue);
}
4 changes: 2 additions & 2 deletions contracts/Migrations.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity ^0.4.17;
pragma solidity ^0.5.16;

contract Migrations {
address public owner;
Expand All @@ -8,7 +8,7 @@ contract Migrations {
if (msg.sender == owner) _;
}

function Migrations() public {
constructor() public {
owner = msg.sender;
}

Expand Down
6 changes: 6 additions & 0 deletions migrations/2_erc1271_sample.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
var ERC1271Sample = artifacts.require("ERC1271Sample");

module.exports = function(deployer) {
// deployment steps
deployer.deploy(ERC1271Sample);
};
Loading