def test_verify_proof(self): claim1_name = 97 # 'a' claim1_txid = 'bd9fa7ffd57d810d4ce14de76beea29d847b8ac34e8e536802534ecb1ca43b68' claim1_outpoint = 0 claim1_height = 10 claim1_node_hash = claims.get_hash_for_outpoint( binascii.unhexlify(claim1_txid)[::-1], claim1_outpoint, claim1_height) claim2_name = 98 # 'b' claim2_txid = 'ad9fa7ffd57d810d4ce14de76beea29d847b8ac34e8e536802534ecb1ca43b68' claim2_outpoint = 1 claim2_height = 5 claim2_node_hash = claims.get_hash_for_outpoint( binascii.unhexlify(claim2_txid)[::-1], claim2_outpoint, claim2_height) to_hash1 = claim1_node_hash hash1 = Hash(to_hash1) to_hash2 = chr(claim1_name) + hash1 + chr( claim2_name) + claim2_node_hash root_hash = Hash(to_hash2) proof = { 'last takeover height': claim1_height, 'txhash': claim1_txid, 'nOut': claim1_outpoint, 'nodes': [ { 'children': [{ 'character': 97 }, { 'character': 98, 'nodeHash': claim2_node_hash[::-1].encode('hex') }] }, { 'children': [] }, ] } out = claims.verify_proof(proof, root_hash[::-1].encode('hex'), 'a') self.assertEqual(out, True)
def update_signatures(self, raw): """Add new signatures to a transaction""" d = deserialize(raw) for i, txin in enumerate(self.inputs()): sigs1 = txin.get('signatures') sigs2 = d['inputs'][i].get('signatures') for sig in sigs2: if sig in sigs1: continue for_sig = Hash(self.tx_for_sig(i).decode('hex')) # der to string order = ecdsa.ecdsa.generator_secp256k1.order() r, s = ecdsa.util.sigdecode_der(sig.decode('hex'), order) sig_string = ecdsa.util.sigencode_string(r, s, order) pubkeys = txin.get('pubkeys') compressed = True for recid in range(4): public_key = MyVerifyingKey.from_signature(sig_string, recid, for_sig, curve=SECP256k1) pubkey = point_to_ser(public_key.pubkey.point, compressed).encode('hex') if pubkey in pubkeys: public_key.verify_digest( sig_string, for_sig, sigdecode=ecdsa.util.sigdecode_string) j = pubkeys.index(pubkey) print_error("adding sig", i, j, pubkey, sig) self._inputs[i]['signatures'][j] = sig self._inputs[i]['x_pubkeys'][j] = pubkey break # redo raw self.raw = self.serialize()
def verify_message(cls, address, sig, message): if len(sig) != 65: raise Exception("Wrong encoding") nV = ord(sig[0]) if nV < 27 or nV >= 35: raise Exception("Bad encoding") if nV >= 31: compressed = True nV -= 4 else: compressed = False recid = nV - 27 h = Hash(msg_magic(message)) public_key = MyVerifyingKey.from_signature(sig[1:], recid, h, curve=SECP256k1) # check public key public_key.verify_digest(sig[1:], h, sigdecode=ecdsa.util.sigdecode_string) pubkey = point_to_ser(public_key.pubkey.point, compressed) # check that we get the original signing address addr = public_key_to_bc_address(pubkey) if address != addr: raise Exception("Bad signature")
def sign(self, keypairs): for i, txin in enumerate(self.inputs()): num = txin['num_sig'] for x_pubkey in txin['x_pubkeys']: signatures = filter(None, txin['signatures']) if len(signatures) == num: # txin is complete break if x_pubkey in keypairs.keys(): print_error("adding signature for", x_pubkey) # add pubkey to txin txin = self._inputs[i] x_pubkeys = txin['x_pubkeys'] ii = x_pubkeys.index(x_pubkey) sec = keypairs[x_pubkey] pubkey = public_key_from_private_key(sec) txin['x_pubkeys'][ii] = pubkey txin['pubkeys'][ii] = pubkey self._inputs[i] = txin # add signature for_sig = Hash(self.tx_for_sig(i).decode('hex')) pkey = regenerate_key(sec) secexp = pkey.secret private_key = MySigningKey.from_secret_exponent(secexp, curve=SECP256k1) public_key = private_key.get_verifying_key() sig = private_key.sign_digest_deterministic(for_sig, hashfunc=hashlib.sha256, sigencode=ecdsa.util.sigencode_der) assert public_key.verify_digest(sig, for_sig, sigdecode=ecdsa.util.sigdecode_der) txin['signatures'][ii] = sig.encode('hex') self._inputs[i] = txin print_error("is_complete", self.is_complete()) self.raw = self.serialize()
def hash_160_to_bc_address(h160, addrtype=0): if addrtype == PUBKEY_ADDRESS[0]: c = chr(PUBKEY_ADDRESS[1]) elif addrtype == SCRIPT_ADDRESS[0]: c = chr(SCRIPT_ADDRESS[1]) vh160 = c + h160 h = Hash(vh160) addr = vh160 + h[0:4] return base_encode(addr, base=58)
def DecodeBase58Check(psz): vchRet = base_decode(psz, None, base=58) key = vchRet[0:-4] csum = vchRet[-4:] hash = Hash(key) cs32 = hash[0:4] if cs32 != csum: return None else: return key
def pw_decode(s, password): if password is not None: secret = Hash(password) try: d = DecodeAES(secret, s).decode("utf8") except Exception: raise InvalidPassword() return d else: return s
def sign_message(self, message, compressed, address): signature = self.sign(Hash(msg_magic(message))) for i in range(4): sig = chr(27 + i + (4 if compressed else 0)) + signature try: self.verify_message(address, sig, message) return sig except Exception: log.exception("error: cannot sign message") continue raise Exception("error: cannot sign message")
def bc_address_to_hash_160(addr): bytes = base_decode(addr, 25, base=58) addr_without_checksum, addr_checksum = bytes[:21], bytes[21:] if Hash(addr_without_checksum)[:4] != addr_checksum: raise Exception("Invalid address checksum") if bytes[0] == chr(PUBKEY_ADDRESS[1]): return PUBKEY_ADDRESS[0], bytes[1:21] elif bytes[0] == chr(SCRIPT_ADDRESS[1]): return SCRIPT_ADDRESS[0], bytes[1:21] else: raise Exception("Invalid address prefix")
def hash_160_to_bc_address(h160, addrtype=0): if addrtype == PUBKEY_ADDRESS[0]: c = chr(PUBKEY_ADDRESS[1]) elif addrtype == SCRIPT_ADDRESS[0]: c = chr(SCRIPT_ADDRESS[1]) else: raise Exception("Invalid address prefix") vh160 = c + h160 h = Hash(vh160) addr = vh160 + h[0:4] return base_encode(addr, base=58)
def tx_response(self, response): params, result = self.parse_response(response) if not params: return tx_hash, tx_height = params assert tx_hash == hash_encode(Hash(result.decode('hex'))) tx = Transaction(result) try: tx.deserialize() except Exception: log.info("cannot deserialize transaction, skipping: %s", tx_hash) return self.wallet.receive_tx_callback(tx_hash, tx, tx_height) self.requested_tx.remove((tx_hash, tx_height)) log.info("received tx %s height: %d bytes: %d", tx_hash, tx_height, len(tx.raw)) # callbacks self.network.trigger_callback('new_transaction', tx) if not self.requested_tx: self.network.trigger_callback('updated')
def pw_encode(s, password): if password: secret = Hash(password) return EncodeAES(secret, s.encode("utf8")) else: return s
def hash(self): return Hash(self.raw.decode('hex'))[::-1].encode('hex')
def verify_proof(proof, rootHash, name): previous_computed_hash = None reverse_computed_name = '' verified_value = False for i, node in enumerate(proof['nodes'][::-1]): found_child_in_chain = False to_hash = '' previous_child_character = None for child in node['children']: if child['character'] < 0 or child['character'] > 255: raise InvalidProofError( "child character not int between 0 and 255") if previous_child_character: if previous_child_character >= child['character']: raise InvalidProofError("children not in increasing order") previous_child_character = child['character'] to_hash += chr(child['character']) if 'nodeHash' in child: if len(child['nodeHash']) != 64: raise InvalidProofError("invalid child nodeHash") to_hash += binascii.unhexlify(child['nodeHash'])[::-1] else: if previous_computed_hash is None: raise InvalidProofError("previous computed hash is None") if found_child_in_chain is True: raise InvalidProofError( "already found the next child in the chain") found_child_in_chain = True reverse_computed_name += chr(child['character']) to_hash += previous_computed_hash if not found_child_in_chain: if i != 0: raise InvalidProofError("did not find the alleged child") if i == 0 and 'txhash' in proof and 'nOut' in proof and 'last takeover height' in proof: if len(proof['txhash']) != 64: raise InvalidProofError("txhash was invalid: {}".format( proof['txhash'])) if not isinstance(proof['nOut'], (long, int)): raise InvalidProofError("nOut was invalid: {}".format( proof['nOut'])) if not isinstance(proof['last takeover height'], (long, int)): raise InvalidProofError( 'last takeover height was invalid: {}'.format( proof['last takeover height'])) to_hash += get_hash_for_outpoint( binascii.unhexlify(proof['txhash'])[::-1], proof['nOut'], proof['last takeover height']) verified_value = True elif 'valueHash' in node: if len(node['valueHash']) != 64: raise InvalidProofError("valueHash was invalid") to_hash += binascii.unhexlify(node['valueHash'])[::-1] previous_computed_hash = Hash(to_hash) if previous_computed_hash != binascii.unhexlify(rootHash)[::-1]: raise InvalidProofError("computed hash does not match roothash") if 'txhash' in proof and 'nOut' in proof: if not verified_value: raise InvalidProofError("mismatch between proof claim and outcome") if 'txhash' in proof and 'nOut' in proof: if name != reverse_computed_name[::-1]: raise InvalidProofError("name did not match proof") if not name.startswith(reverse_computed_name[::-1]): raise InvalidProofError("name fragment does not match proof") return True
def hash_merkle_root(self, merkle_s, target_hash, pos): h = hash_decode(target_hash) for i, item in enumerate(merkle_s): h = Hash(hash_decode(item) + h) if ((pos >> i) & 1) else Hash(h + hash_decode(item)) return hash_encode(h)
def EncodeBase58Check(vchIn): hash = Hash(vchIn) return base_encode(vchIn + hash[0:4], base=58)
def hash_header(self, header): if header is None: return '0' * 64 return hash_encode(Hash(self.serialize_header(header).decode('hex')))
def get_hash_for_outpoint(txhash, nOut, nHeightOfLastTakeover): txhash_hash = Hash(txhash) nOut_hash = Hash(str(nOut)) height_of_last_takeover_hash = Hash(height_to_vch(nHeightOfLastTakeover)) outPointHash = Hash(txhash_hash + nOut_hash + height_of_last_takeover_hash) return outPointHash