From 3ebfbd7f27cdd39e70991828b409b1104cd11730 Mon Sep 17 00:00:00 2001 From: Jacques Wagener Date: Wed, 18 Oct 2017 11:46:27 +0200 Subject: [PATCH] Basic ecrecovery example added. --- contracts/ecrecovery.eg.py | 28 ++++++++++++++++ contracts/ecrecovery.v.py | 28 ++++++++++++++++ contracts/erc725.v.py | 68 +++++++++++++++++++++++++++++++++++++- tests/test_ecrecovery.py | 3 ++ 4 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 contracts/ecrecovery.eg.py create mode 100644 contracts/ecrecovery.v.py create mode 100644 tests/test_ecrecovery.py diff --git a/contracts/ecrecovery.eg.py b/contracts/ecrecovery.eg.py new file mode 100644 index 0000000..3e4035a --- /dev/null +++ b/contracts/ecrecovery.eg.py @@ -0,0 +1,28 @@ +import pytest + +from ethereum import utils +from tests.setup_transaction_tests import chain as s, tester as t, ethereum_utils as u, check_gas, \ + get_contract_with_gas_estimation, get_contract + + +def sign(message, key): + _hash = utils.sha3(message) + return _hash, utils.ecsign(_hash, key) + + +_hash, sigdata = sign("test message", t.k0) +v, r, s = sigdata +sig = utils.encode_int32(r) + utils.encode_int32(s) + utils.encode_int(v) + + +code = """ +def extract_v(sig: bytes <= 66) -> num256: + s = slice(sig, start=64, len=1) + return as_num256(bytes_to_num(s)) +""" +code = """ +def extract_v(sig: bytes <= 96) -> bytes <= 96: + return slice(sig, start=64, len=1) +""" +c = get_contract(code) +c.extract_v(sig) diff --git a/contracts/ecrecovery.v.py b/contracts/ecrecovery.v.py new file mode 100644 index 0000000..0f6b0b0 --- /dev/null +++ b/contracts/ecrecovery.v.py @@ -0,0 +1,28 @@ +# Viper verify ecrecovery function. + + +owner: address + + +def __init__(): + self.owner = msg.sender + + +def sigdata_verify(h: bytes32, sigdata: num256[3]) -> bool: + if ecrecover(h, sigdata[0], sigdata[1], sigdata[2]) == self.owner: + return True + else: + return False + + +def sig_verify(h: bytes32, sig: bytes <= 66) -> bool: + + r = extract32(sig, 0, type=num256) + s = extract32(sig, 32, type=num256) + sliced = slice(sig, start=64, len=1) + v = as_num256(bytes_to_num(sliced)) + + if ecrecover(h, r, s, v) == self.owner: + return True + else: + return False diff --git a/contracts/erc725.v.py b/contracts/erc725.v.py index 39efd72..54a6ebe 100644 --- a/contracts/erc725.v.py +++ b/contracts/erc725.v.py @@ -1,7 +1,19 @@ - +# Key management types keys: address[20] key_types: num[20] key_count: num +claim_count: num + +# Claim types +claims: { + claimId: bytes32, + claimType: num, + issuer: address, + signatureType: num, + signature: bytes <= 4096, + data: bytes <= 4096, + uri: bytes <= 4096 +}[num] def __init__(): @@ -100,3 +112,57 @@ def replaceKey(_oldKey: address, _newKey: address) -> bool: return True return False + + + +# The signature format is a compact form of: +# {bytes32 r}{bytes32 s}{uint8 v} +# Compact means, uint8 is not padded to 32 bytes. +@internal +def sig_verify(h: bytes32, signer: address, sig: bytes <= 66) -> bool: + r = extract32(sig, 0, type=num256) + s = extract32(sig, 32, type=num256) + sliced = slice(sig, start=64, len=1) + v = bytes_to_num(sliced) + + # geth uses [0, 1] and some clients have followed. + # Add 27 to make it v compatible. + if v < 27: + v += 27 + assert v == 27 or v == 28 + + if ecrecover(h, r, s, as_num256(v)) == signer: + return True + else: + return False + + +def addClaim(_claimType: num(num256), issuer: address, signatureType: num(num256), + _signature: bytes <= 4096, _data: bytes <= 4096, _uri: bytes <= 4096) -> bytes32: + # For the time being assume singatureType == 1 means use ecrecover to verify. + # Also we only allow EC verify in this contract. + assert signatureType == 1 + + _id = sha3(concat(as_bytes32(_claimType), as_bytes32(issuer), as_bytes32(signatureType), _data, _uri)) + + if self.sig_verify(_id, issuer, slice(_signature, start=0, len=65)): + self.claims[0] = { + claimId: _id, + claimType: _claimType, + issuer: issuer, + signatureType: signatureType, + signature: _signature, + data: _data, + uri: _uri + } + return _id + else: + throw + +# Outstanding: +# function getClaim(bytes32 _claimId) constant returns(uint256 claimType, address issuer, uint256 signatureType, bytes signature, bytes data, string uri); +# function getClaimIdsByType(uint256 _claimType) constant returns(bytes32[] claimIds); +# function removeClaim(bytes32 _claimId) returns (bool success) + +# function addClaim(uint256 _claimType, address issuer, uint256 signatureType, +# bytes _signature, bytes _data, string _uri) returns (bytes32 claimRequestId) diff --git a/tests/test_ecrecovery.py b/tests/test_ecrecovery.py new file mode 100644 index 0000000..e043a3e --- /dev/null +++ b/tests/test_ecrecovery.py @@ -0,0 +1,3 @@ +import pytest +from tests.setup_transaction_tests import chain as s, tester as t, ethereum_utils as u, check_gas, \ + get_contract_with_gas_estimation, get_contract