def test_javascript_signatures(): # The zero address will cause `approve` to default to valid signatures zero_address = "0x0000000000000000000000000000000000000000" accounts = ["0x776ba14735ff84789320718cf0aa43e91f7a8ce1", "0x095ce4e4240fa66ff90282c26847456e3f3b5002"] # The address that will receive the transaction recipient = "0x776ba14735ff84789320718cf0aa43e91f7a8ce1" # These are the matching sigs to the accounts raw_sigs = [ "0x4a89507bf71749fb338ed13fba623a683d9ecab0fb9c389a4298525c043e38281a00ab65628bb18a382eb8c8b4fb4dae95ccc993cf49f617c60d8051180778601c", "0xc84fe5d2a600e033930e0cf73f26e78f4c65b134f9c9992f60f08ce0863abdbe0548a6e8aa2d952659f29c67106b59fdfcd64d67df03c1df620c70c85578ae701b" ] # Turns the raw sigs into sigs sigs = [(utils.big_endian_to_int(x[64:]), utils.big_endian_to_int(x[:32]), utils.big_endian_to_int(x[32:64])) for x in map(lambda z: utils.decode_hex(z[2:]), raw_sigs)] h = utils.sha3(utils.encode_int32(0) + b'\x00' * 12 + utils.decode_hex(recipient[2:]) + utils.encode_int32(25) + b'') h2 = utils.sha3(b"\x19Ethereum Signed Message:\n32" + h) # Check to make sure the signatures are valid assert '0x'+utils.encode_hex(utils.sha3(utils.ecrecover_to_pub(h2, sigs[0][0], sigs[0][1], sigs[0][2]))[12:]) == accounts[0] assert '0x'+utils.encode_hex(utils.sha3(utils.ecrecover_to_pub(h2, sigs[1][0], sigs[1][1], sigs[1][2]))[12:]) == accounts[1] # Set the owners to zero addresses x2 = t.s.contract(open('examples/wallet/wallet.v.py').read(), args=[accounts + [t.a3, zero_address, zero_address], 2], language='viper') t.s.tx(sender=t.k1, to=x2.address, value=10**17) # There's no need to pass in signatures because the owners are 0 addresses causing them to default to valid signatures assert x2.approve(0, recipient, 25, "", sigs + [[0, 0, 0]] * 3, value=25, sender=t.k1) print("Javascript signature tests passed")
def ecrecover(data: List[int]) -> List[int]: """ :param data: :return: """ # TODO: Add type hints try: byte_data = bytearray(data) v = extract32(byte_data, 32) r = extract32(byte_data, 64) s = extract32(byte_data, 96) except TypeError: raise NativeContractException message = b"".join([ALL_BYTES[x] for x in byte_data[0:32]]) if r >= secp256k1n or s >= secp256k1n or v < 27 or v > 28: return [] try: pub = ecrecover_to_pub(message, v, r, s) except Exception as e: log.debug("An error has occured while extracting public key: " + str(e)) return [] o = [0] * 12 + [x for x in sha3(pub)[-20:]] return list(bytearray(o))
def ecrecover(msg, signature, address=None): """ Returns None on failure, returns the recovered address on success. If address is provided: Returns True if the recovered address matches it, otherwise False. """ rawhash = sha3(msg) if isinstance(signature, str): signature = data_decoder(signature) if len(signature) >= 65: v = safe_ord(signature[64]) r = big_endian_to_int(signature[0:32]) s = big_endian_to_int(signature[32:64]) else: if address: return False else: return None if v == 0 or v == 1: v += 27 pub = ecrecover_to_pub(rawhash, v, r, s) recaddr = data_encoder(sha3(pub)[-20:]) if address: if not address.startswith("0x"): recaddr = recaddr[2:] return recaddr == address return recaddr
def proc_ecrecover(ext, msg): # print('ecrecover proc', msg.gas) OP_GAS = opcodes.GECRECOVER gas_cost = OP_GAS if msg.gas < gas_cost: return 0, 0, [] message_hash_bytes = [0] * 32 msg.data.extract_copy(message_hash_bytes, 0, 0, 32) message_hash = b''.join(map(ascii_chr, message_hash_bytes)) # TODO: This conversion isn't really necessary. # TODO: Invesitage if the check below is really needed. v = msg.data.extract32(32) r = msg.data.extract32(64) s = msg.data.extract32(96) if r >= secp256k1n or s >= secp256k1n or v < 27 or v > 28: return 1, msg.gas - opcodes.GECRECOVER, [] try: pub = utils.ecrecover_to_pub(message_hash, v, r, s) except Exception as e: return 1, msg.gas - gas_cost, [] o = [0] * 12 + [safe_ord(x) for x in utils.sha3(pub)[-20:]] return 1, msg.gas - gas_cost, o
def sender(self): if not self._sender: # Determine sender if self.r == 0 and self.s == 0: self._sender = null_address else: if self.v in (27, 28): vee = self.v sighash = utils.sha3(rlp.encode(self, UnsignedTransaction)) elif self.v >= 37: vee = self.v - self.network_id * 2 - 8 assert vee in (27, 28) rlpdata = rlp.encode(rlp.infer_sedes(self).serialize(self)[ :-3] + [self.network_id, '', '']) sighash = utils.sha3(rlpdata) else: raise InvalidTransaction("Invalid V value") if self.r >= secpk1n or self.s >= secpk1n or self.r == 0 or self.s == 0: raise InvalidTransaction("Invalid signature values!") pub = ecrecover_to_pub(sighash, vee, self.r, self.s) if pub == b'\x00' * 64: raise InvalidTransaction( "Invalid signature (zero privkey cannot sign)") self._sender = utils.sha3(pub)[-20:] return self._sender
def sign(self, tx_hash: str) -> Tuple[int, int, int]: msg_bytes = bytes.fromhex(tx_hash) v, r, s = 0, 0, 0 with self.token.open(user_pin=self.user_pin) as session: priv = session.get_key(key_type=pkcs11.KeyType.EC, object_class=pkcs11.ObjectClass.PRIVATE_KEY, label=self.label) signature = priv.sign(msg_bytes, mechanism=pkcs11.Mechanism.ECDSA) r = int.from_bytes(signature[0:32], byteorder='big') s = int.from_bytes(signature[32:], byteorder='big') secpk1n = 115792089237316195423570985008687907852837564279074904382605163141518161494337 s = s if s * 2 < secpk1n else secpk1n - s v = 0 for _v in range(27, 29): pub2 = ecrecover_to_pub(msg_bytes, _v, r, s) if pub2 == self.public_key: v = _v if not v: raise ValueError("Failed to sign") return r, s, v
def get_sender(hash, sig): v = sig[64] if v < 27: v += 27 r = u.bytes_to_int(sig[:32]) s = u.bytes_to_int(sig[32:64]) pub = u.ecrecover_to_pub(hash, v, r, s) return u.sha3(pub)[-20:]
def get_signing_address(hash, v, r, s) -> str: """ :return: checksum encoded address starting by 0x, for example `0x568c93675A8dEb121700A6FAdDdfE7DFAb66Ae4A` :rtype: str """ encoded_64_address = ecrecover_to_pub(hash, v, r, s) address_bytes = sha3(encoded_64_address)[-20:] return checksum_encode(address_bytes)
def get_signing_address(signed_hash: Union[bytes, str], v: int, r: int, s: int) -> str: """ :return: checksummed ethereum address, for example `0x568c93675A8dEb121700A6FAdDdfE7DFAb66Ae4A` :rtype: str """ encoded_64_address = ecrecover_to_pub(HexBytes(signed_hash), v, r, s) address_bytes = sha3(encoded_64_address)[-20:] return checksum_encode(address_bytes)
def get_signing_address(self) -> str: """ :return: checksum encoded address starting by 0x, for example `0x568c93675A8dEb121700A6FAdDdfE7DFAb66Ae4A` :rtype: str """ encoded_64_address = utils.ecrecover_to_pub(self.message_hash, self.v, self.r, self.s) address_bytes = utils.sha3(encoded_64_address)[-20:] return utils.checksum_encode(address_bytes)
def generateInvalidUnlockTx(self, userAddress, contractAddress, maliciousAddress): commit, witness, R, S = generate_submarine_commit._generateRS( normalize_address(rec_hex(userAddress)), normalize_address(rec_hex(contractAddress)), UNLOCK_AMOUNT, b'', OURGASPRICE, OURGASLIMIT) unlockFunctionSelector = b"\xec\x9b\x5b\x3a" submarineData = unlockFunctionSelector + commit # need the unsigned TX hash for ECRecover unlock_tx_unsigned_object = transactions.UnsignedTransaction( 0, # nonce; OURGASPRICE, # gasprice OURGASLIMIT, # startgas normalize_address(maliciousAddress), # to addr UNLOCK_AMOUNT, # value submarineData, # data ) unlock_tx_unsigned_hash = sha3( rlp.encode(unlock_tx_unsigned_object, transactions.UnsignedTransaction)) unlock_tx_object = transactions.Transaction( 0, # nonce; OURGASPRICE, # gasprice OURGASLIMIT, # startgas normalize_address(maliciousAddress), # to addr UNLOCK_AMOUNT, # value submarineData, # data 27, # v R, # r S # s ) try: pub = ecrecover_to_pub(unlock_tx_unsigned_hash, 27, R, S) if pub == b"\x00" * 64: log.info("Address no good, retrying") return self.generateInvalidUnlockTx(userAddress, contractAddress, maliciousAddress) else: commit_addr = sha3(pub)[-20:] log.info("Fake Unlock TX Dict: {}".format( unlock_tx_unsigned_object.as_dict())) log.info("Fake Unlock TX Commit B: {}".format(commit_addr)) return unlock_tx_object, unlock_tx_unsigned_object, commit_addr, commit, witness except (ValueError, InvalidTransaction) as e: if isinstance(e, ValueError) and "VRS" not in str(e): raise log.info("Address no good (%s), retrying" % e) return self.generateInvalidUnlockTx(userAddress, contractAddress, maliciousAddress)
def create_urs_tx(shard_id, gasprice=GASPRICE): bytecode = get_urs_bytecode(shard_id) tx = Transaction(0, gasprice, 2000000, to=b'', value=0, data=bytecode) tx.v = 27 tx.r = 10000 tx.s = shard_id + 1 tx_rawhash = get_tx_rawhash(tx) urs_sender_addr = utils.sha3( utils.ecrecover_to_pub(tx_rawhash, tx.v, tx.r, tx.s))[-20:] urs_addr = utils.mk_contract_address(urs_sender_addr, 0) return tx, urs_addr, urs_sender_addr
def add_signatures(self, signatures): # sort signatures by lower case lexicographical order mapping = {} for signature in signatures: address = ecrecover_to_pub(self.hash, signature['v'], signature['r'], signature['s']) mapping[address.lower()] = signature sorted_signatures = [] for address in sorted(mapping): sorted_signatures.append(mapping[address]) self.signatures = sorted_signatures
def validate(self, *args, **kwargs): signer, signature = self.get_authorization() signer = normalize_address(signer) signature = signature[-130:] r = int(signature[0:64], 16) s = int(signature[64:128], 16) v = int(signature[128:130], 16) if v not in (27, 28): v += 27 message = self._message(signer) prefix = b'\x19Ethereum Signed Message:\n' + str(len(message)).encode() mhash = sha3(prefix + message) pubkey = ecrecover_to_pub(mhash, v, r, s) address = normalize_address(sha3(pubkey)[-20:]) if signer != address: return self.get_authenticate()
def verify_sig(data, sig, trusted_addrs): data_hash = eth.sha3(data) sig_pubkey = eth.ecrecover_to_pub(data_hash, sig[0], sig[1], sig[2]) addr = '0x' + eth.encode_hex(eth.sha3(sig_pubkey)[12:]) cert = tx.get_cert_from_address(addr, trusted_addrs) if cert is None: logging.info('No certificate found on address {0}. Invalid ' 'signature'.format(addr)) else: if cert.status == 'valid': logging.info('The signature is valid.') else: logging.info('The signature is invalid.') logging.info('Certificate status: {}'.format(cert.status)) logging.info('Certificate data: {}'.format(cert.data))
def _sig_valid(self, signature, message_hash, signer): try: r = int(signature[0:66], 16) s = int(add_0x_prefix(signature[66:130]), 16) v = int(add_0x_prefix(signature[130:132]), 16) if v not in (27, 28): v += 27 pubkey = ecrecover_to_pub(decode_hex(message_hash), v, r, s) msg_signer = encode_hex(sha3(pubkey)[-20:]) valid = (msg_signer == signer.lower()) except: print('exception in _sig_valid') valid = False return valid
def valid_metamask_message(address, message, signature): #address = attrs['address'] #message = attrs['msg'] #signature = attrs['signed_msg'] r = int(signature[0:66], 16) s = int(add_0x_prefix(signature[66:130]), 16) v = int(add_0x_prefix(signature[130:132]), 16) if v not in (27, 28): v += 27 message_hash = defunct_hash_message(text=message) pubkey = ecrecover_to_pub(decode_hex(message_hash.hex()), v, r, s) signer_address = encode_hex(sha3(pubkey)[-20:]) if signer_address != address.lower(): raise ValidationError({'result': 'Incorrect signature'}, code=400) return True
def ecrecover(data): try: data = bytearray(data) v = extract32(data, 32) r = extract32(data, 64) s = extract32(data, 96) except TypeError: raise NativeContractException message = b"".join([ALL_BYTES[x] for x in data[0:32]]) if r >= secp256k1n or s >= secp256k1n or v < 27 or v > 28: return [] try: pub = ecrecover_to_pub(message, v, r, s) except Exception as e: logging.info("An error has occured while extracting public key: " + e) return [] o = [0] * 12 + [x for x in sha3(pub)[-20:]] return o
def ecrecover(h, v, r, s): pub = ecrecover_to_pub(h, v, r, s) addr = keccak(pub)[-20:] addr = encode_hex(addr) addr = to_checksum_address(addr) return addr
] recipient = "0x776ba14735ff84789320718cf0aa43e91f7a8ce1" raw_sigs = [ "0x4a89507bf71749fb338ed13fba623a683d9ecab0fb9c389a4298525c043e38281a00ab65628bb18a382eb8c8b4fb4dae95ccc993cf49f617c60d8051180778601c", "0xc84fe5d2a600e033930e0cf73f26e78f4c65b134f9c9992f60f08ce0863abdbe0548a6e8aa2d952659f29c67106b59fdfcd64d67df03c1df620c70c85578ae701b" ] sigs = [(utils.big_endian_to_int(x[64:]), utils.big_endian_to_int(x[:32]), utils.big_endian_to_int(x[32:64])) for x in map(lambda z: utils.decode_hex(z[2:]), raw_sigs)] h = utils.sha3( utils.encode_int32(0) + b'\x00' * 12 + utils.decode_hex(recipient[2:]) + utils.encode_int32(25) + b'') h2 = utils.sha3(b"\x19Ethereum Signed Message:\n32" + h) assert '0x' + utils.encode_hex( utils.sha3(utils.ecrecover_to_pub(h2, sigs[0][0], sigs[0][1], sigs[0][2]))[12:]) == accounts[0] assert '0x' + utils.encode_hex( utils.sha3(utils.ecrecover_to_pub(h2, sigs[1][0], sigs[1][1], sigs[1][2]))[12:]) == accounts[1] x2 = c.contract(open('wallet.v.py').read(), args=[accounts + [t.a3, zero_address, zero_address], 2], language='viper') c.tx(sender=t.k1, to=x2.address, value=10**17) assert x2.approve(0, recipient, 25, "", sigs + [[0, 0, 0]] * 3) print("Javascript signature tests passed")
def extract_sender_from_tx(tx): tx_rawhash = get_tx_rawhash(tx) return utils.sha3(utils.ecrecover_to_pub(tx_rawhash, tx.v, tx.r, tx.s))[-20:]
def recover_to_addr(msg, sig): msghash = hash_personal_message(msg) vrs = sig_to_vrs(sig) return '0x' + sha3.keccak_256(ecrecover_to_pub(msghash, * vrs)).hexdigest()[24:]
from ethereum.utils import sha3, ecrecover_to_pub from eth_utils import decode_hex import sys if len(sys.argv) != 5: print("Wrong number of arguments. Should be ecrecovery.py msghash v r s.") print(sys.argv) sys.exit() prog, hash, vstr, rstr, str = sys.argv msg_hash = decode_hex(hash) v = int(vstr) r = int(rstr) s = int(str) pubkey = ecrecover_to_pub(msg_hash, v, r, s) addr = sha3(pubkey)[-20:].hex() print('0x' + addr)