def new_commitment_tx(node, current_channel, cost, secret_hash): remote_peer = current_channel.peer # Create input using the output from the funding tx tx_in = TxIn(bytes.fromhex(current_channel.funding_tx.id()), 0) # Create 3 outputs. 1 to nodeA and 1 to nodeB and 1 to an HTLC script script_1 = p2pkh_script(decode_base58(node.address)) tx_out_1 = TxOut(amount=current_channel.local_amt - cost, script_pubkey=script_1) script_2 = p2pkh_script(decode_base58(remote_peer.btc_addr.decode())) tx_out_2 = TxOut(amount=current_channel.remote_amt, script_pubkey=script_2) #script_3 HTLC script_3 = Script([ 99, 168, secret_hash, 136, 118, 169, hash160(remote_peer.public_key.sec()), 103, encode_varint(1000), 177, 117, 118, 169, hash160(node.public_key.sec()), 104, 136, 172 ]) tx_out_3 = TxOut(amount=cost, script_pubkey=script_3) # Construct the commitment tx object commitment_tx = Tx(1, [tx_in], [tx_out_1, tx_out_2, tx_out_3], 0, True) #sign it commitment_tx.tx_ins[0].script_sig = get_script_sig( commitment_tx, node.private_key) return commitment_tx
def child(self, index, hardened=False): if index >= 0x80000000: raise ValueError('child number should always be less than 2^31') sec = self.private_key.point.sec() fingerprint = hash160(sec)[:4] if hardened: index += 0x80000000 pk = self.private_key.secret.to_bytes(32, 'big') data = b'\x00' + pk + index.to_bytes(4, 'big') raw = HMAC(key=self.chain_code, msg=data, digestmod=sha512).digest() else: data = sec + index.to_bytes(4, 'big') raw = HMAC(key=self.chain_code, msg=data, digestmod=sha512).digest() secret = (int.from_bytes(raw[:32], 'big') + self.private_key.secret) % N private_key = PrivateKey(secret=secret, compressed=True) chain_code = raw[32:] depth = self.depth + 1 child_number = index return HDPrivateKey( private_key=private_key, chain_code=chain_code, depth=depth, fingerprint=fingerprint, child_number=child_number, testnet=self.testnet, )
def op_hash160(stack): # if stack is empty, return False if len(stack) < 1: return False element = stack.pop() stack.append(hash160(element)) return True
def verify_input(self, input_index): '''Returns whether the input has a valid signature''' # get the relevant input tx_in = self.tx_ins[input_index] # get the number of signatures required. This is available in tx_in.script_sig.num_sigs_required() sigs_required = tx_in.script_sig.num_sigs_required() # iterate over the sigs required and check each signature for sig_num in range(sigs_required): # get the point from the sec format sec = tx_in.sec_pubkey(index=sig_num) # get the sec_pubkey at current signature index point = S256Point.parse(sec) # get the der sig and hash_type from input # get the der_signature at current signature index der, hash_type = tx_in.der_signature(index=sig_num) # get the signature from der format signature = Signature.parse(der) # get the hash to sign if tx_in.is_segwit(): h160 = hash160(tx_in.script_sig.redeem_script()) if h160 != tx_in.script_pubkey(self.testnet).elements[1]: return False pubkey_h160 = tx_in.script_sig.redeem_script()[-20:] if pubkey_h160 != point.h160(): return False z = self.sig_hash_bip143(input_index, hash_type) else: z = self.sig_hash(input_index, hash_type) # use point.verify on the hash to sign and signature if not point.verify(z, signature): return False return True
def op_hash160(stack): if len(stack) < 1: return False element = stack.pop() h160 = hash160(element) stack.append(h160) return True
def address(self, compressed=True, testnet=False): # get the sec # hash160 the sec # raw is hash 160 prepended w/ b'\x00' for mainnet, b'\x6f' for testnet # checksum is first 4 bytes of double_sha256 of raw # encode_base58 the raw + checksum # return as a string, you can use .decode('ascii') to do this. '''Returns the address string''' # get the sec format sec = self.sec(compressed) # hash160 the result h160 = hash160(sec) # prepend b'\x00' for mainnet b'\x6f' for testnet if testnet: prefix = b'\x6f' else: prefix = b'\x00' raw = prefix + h160 # get the double_sha256 of the prefix + h160, first 4 bytes are the checksum checksum = double_sha256(raw)[:4] # append checksum # encode_base58 the whole thing sum = encode_base58(raw + checksum).decode('ascii') return (sum)
def derive_pub_child(self, i): if i >= HARD_CAP: return ValueError("Chosen i is not in range [0, 2**32-1]") # Not quite sure if this is true # if int.from_bytes(self.child_num, 'big') >= SOFT_CAP: # raise TypeError("Hardened Public Keys cannot derive child keys. Use Extended Private key.") if i >= SOFT_CAP: raise TypeError( "Hardened Keys cannot be be derived from Extended Pub Keys. Use Extended Private key." ) else: ii = hmac.new(self.chaincode, self.key + i.to_bytes(4, 'big'), digestmod=sha512).digest() fingerprint = hash160(self.key)[:4] # edge case: invalid keys key_num = int.from_bytes(ii[:32], 'big') point = key_num * G if key_num >= N or point.x is None: raise ValueError(INVALID_KEY_MSG) child_key = point + S256Point.parse(self.key) child_chaincode = ii[32:] #assemble new xpub child_xpub = self.pfx child_xpub += (self.depth[0] + 1).to_bytes(1, 'big') child_xpub += fingerprint child_xpub += i.to_bytes(4, 'big') child_xpub += child_chaincode child_xpub += child_key.sec() checksum = hash256(child_xpub)[:4] child_xpub += checksum return self.__class__(child_xpub)
def derive_priv_child(self, i): if i >= HARD_CAP: return ValueError("Chosen i is not in range [0, 2**32-1]") if i >= SOFT_CAP: # hardened ii = hmac.new(self.chaincode, self.key + i.to_bytes(4, 'big'), digestmod=sha512).digest() else: #unhardened ii = hmac.new(self.chaincode, self.to_priv_key().point.sec() + i.to_bytes(4, 'big'), digestmod=sha512).digest() key = (int.from_bytes(ii[:32], 'big') + int.from_bytes(self.key, 'big')) % N # from ecc.py fingerprint = hash160(self.to_pub_key().sec())[:4] child_xprv = self.pfx child_xprv += (self.depth[0] + 1).to_bytes(1, 'big') child_xprv += fingerprint child_xprv += i.to_bytes(4, 'big') # add chaincode child_xprv += ii[32:] # add key child_xprv += b"\x00" + key.to_bytes(32, 'big') checksum = hash256(child_xprv)[:4] child_xprv += checksum return self.__class__(child_xprv)
def test_example_9(self): sec = bytes.fromhex('025CBDF0646E5DB4EAA398F365F2EA7A0E3D419B7E0330E39CE92BDDEDCAC4F9BC') h160 = hash160(sec) raw = b"\x00" + h160 raw = raw + hash256(raw)[:4] addr = encode_base58(raw) self.assertEqual(addr, b'19ZewH8Kk1PDbSNdJ97FP4EiCjTRaZMZQA')
def verify(self, z, sig): if isinstance(z, str): # Hash string and convert to int z = int.from_bytes(hash160(z.encode()), 'big') u = z * pow(sig.s, N - 2, N) % N v = sig.r * pow(sig.s, N - 2, N) % N return (u * G + v * self).x.num == sig.r
def test_address_p2wpkh(self): secret = b'[email protected] test1' private_key = PrivateKey(little_endian_to_int(hash256(secret))) point = private_key.point h160 = hash160(point.sec()) script_pubkey = p2wpkh_script(h160) self.assertEqual(script_pubkey.address(testnet=True), 'tb1q3845h8hm5uqgjh7jkq4pkrftlrcgvjf442jh4z')
def op_hash160(stack): # check that there's at least 1 element on the stack # pop off the top element from the stack # push a hash160 of the popped off element to the stack if len(stack) < 1: return False stack.append(hash160(stack.pop())) return True
def test_exercise_1(self): bit_field_size = 10 bit_field = [0] * bit_field_size for item in (b'hello world', b'goodbye'): h = hash160(item) bit = int.from_bytes(h, 'big') % bit_field_size bit_field[bit] = 1 self.assertEqual(bit_field, [1, 1, 0, 0, 0, 0, 0, 0, 0, 0])
def address(self, compressed=True, testnet=False): sec = self.sec(compressed) h160 = hash160(sec) if testnet: prefix = b'\x6f' else: prefix = b'\x00' return encode_base58_checksum(prefix + h160)
def address(self, compressed=True, testnet=False): h160 = hash160(self.sec(compressed=compressed)) if testnet: prefix = b'\x6f' else: prefix = b'\x00' raw = prefix + h160 raw = raw + double_sha256(raw)[:4] return encode_base58(raw).decode('ascii')
def op_hash160(stack: list) -> bool: # check that there's at least 1 element on the stack if len(stack) < 1: return False # pop off the top element from the stack element = stack.pop() # push a hash160 of the popped off element to the stack stack.append(hash160(element)) return True
def test_address_p2sh_p2wpkh(self): secret = b'[email protected] test1' private_key = PrivateKey(little_endian_to_int(hash256(secret))) point = private_key.point real_h160 = hash160(point.sec()) redeem_script = p2wpkh_script(real_h160) h160 = redeem_script.hash160() self.assertEqual( p2sh_script(h160).address(testnet=True), '2N3a8NdfeA7SAurCGsd5k9AEYvbszipz3Jz')
def op_hash160(stack): # check that there's at least 1 element on the stack if len(stack) < 1: return False element = stack.pop() stack.append(hash160(element)) return True # pop off the top element from the stack # push a hash160 of the popped off element to the stack raise NotImplementedError
def op_hash160(stack): # check to see if there's at least 1 element if len(stack) < 1: return False # get the element on the top with stack.pop() element = stack.pop() # add the hash160 of the element to the end of the stack h160 = hash160(element) stack.append(h160) return True
def sign(self, z): if isinstance(z, str): # Hash string and convert to int z = int.from_bytes(hash160(z.encode()), 'big') k = randint(0, 2**256) r = (k * G).x.num s = (z + r * self.secret) * pow(k, N - 2, N) % N if s * 2 > N: s = N - s return Signature(r, s)
def getaddress(self, testnet=False, compressed=True): comp = self.point.sec(compressed) h160 = hash160(comp) prefix = b'\00' if testnet: prefix = b'\x6f' else: prefix = b'\00' raw = prefix + h160 checksum = double_sha256(raw)[:4] total = raw + checksum return encode_base58(total)
def getaddress(x, y, testnet=True, compressed=True): p = S256Point(x, y) comp = p.sec(compressed) h160 = hash160(comp) prefix = b'\00' if testnet: prefix = b'\x6f' else: prefix = b'\00' raw = prefix + h160 checksum = double_sha256(raw)[:4] total = raw + checksum return encode_base58(total)
def address(self, compressed=True, testnet=False): '''Returns the address string''' # get the sec sec = self.sec(compressed) # hash160 the sec h160 = hash160(sec) # prefix is b'\x00' for mainnet, b'\x6f' for testnet if testnet: prefix = b'\x6f' else: prefix = b'\x00' # return the encode_base58_checksum of the prefix and h160 return encode_base58_checksum(prefix + h160)
def check_htlc_and_get_secret_hash(node, commitment_tx, channel): tx_in = commitment_tx.tx_ins[0] tx_out_1 = commitment_tx.tx_outs[1] tx_out_2 = commitment_tx.tx_outs[2] if ( tx_in.prev_tx.hex() == channel.funding_tx.id() ): #checks that it is spending from the correct 2-of-2 multisig tx (the funding tx) if (tx_out_1.script_pubkey.cmds[2] == decode_base58(node.address) and tx_out_1.amount == channel.local_amt): if (tx_out_2.script_pubkey.cmds[6] == hash160( node.public_key.sec())): return tx_out_2.script_pubkey.cmds[2] return None
def address(self, compressed=True, testnet=False): '''Returns the address string''' # get the sec / hash160 the sec h160 = hash160(self.sec(compressed=compressed)) # raw is hash 160 prepended w/ b'\x00' for mainnet, b'\x6f' for testnet if testnet: prefix = b'\x6f' else: prefix = b'\x00' raw = prefix + h160 # checksum is first 4 bytes of double_sha256 of raw checksum = double_sha256(raw)[:4] # encode_base58 the raw + checksum return encode_base58(raw + checksum).decode('ascii')
def KeyToAddr(privkey, prefix): '''Returns the address string''' # get the sec sec = privkey.point.sec(compressed=True) # hash160 the sec h160 = hash160(sec) raw = prefix + h160 # checksum is first 4 bytes of double_sha256 of raw checksum = double_sha256(raw)[:4] # encode_base58 the raw + checksum address = encode_base58(raw + checksum) # return as a string, you can use .decode('ascii') to do this. return address.decode('ascii')
def verify_input(self, input_index): '''Returns whether the input has a valid signature''' # Exercise 1.1: get the relevant input tx_in = self.tx_ins[input_index] # Exercise 6.2: get the number of signatures required. This is available in tx_in.script_sig.num_sigs_required() if tx_in.script_sig.type() == 'blank': if tx_in.script_pubkey().type() == 'p2wpkh': sigs_required = 1 # TODO: refactor # witness program verification if hash160(tx_in.script_witness[1]) != tx_in.script_pubkey().elements[-1]: return False point = S256Point.parse(tx_in.script_witness[1]) der, hash_type = tx_in.der_signature() signature = Signature.parse(der) z = self.sig_hash(input_index, hash_type) if not point.verify(z, signature): return False #elif tx_in.script_pubkey().type() == 'p2wsh': # sigs_required = 1 # point = S256Point.parse(tx_in.script_witness[1]) # der, hash_type = tx_in.der_signature() # signature = Signature.parse(der) # z = self.sig_hash(input_index, hash_type) # if not point.verify(z, signature): # return False else: raise RuntimeError("other witness type not yet supported") else: sigs_required = tx_in.script_sig.num_sigs_required() # Exercise 6.2: iterate over the sigs required and check each signature for sig_num in range(sigs_required): # Exercise 1.1: get the point from the sec format (tx_in.sec_pubkey()) # Exercise 6.2: get the sec_pubkey at current signature index (check sec_pubkey function) point = S256Point.parse(tx_in.sec_pubkey(index=sig_num)) # Exercise 1.1: get the der sig and hash_type from input # Exercise 6.2: get the der_signature at current signature index (check der_signature function) der, hash_type = tx_in.der_signature(index=sig_num) # Exercise 1.1: get the signature from der format signature = Signature.parse(der) # Exercise 1.1: get the hash to sign z = self.sig_hash(input_index, hash_type) # Exercise 1.1: use point.verify on the hash to sign and signature if not point.verify(z, signature): return False return True
def child(self, index): if index >= 0x80000000: raise ValueError('child number should always be less than 2^31') sec = self.point.sec() data = sec + index.to_bytes(4, 'big') raw = HMAC(key=self.chain_code, msg=data, digestmod=sha512).digest() point = PrivateKey(int.from_bytes(raw[:32], 'big')).point + self.point chain_code = raw[32:] depth = self.depth + 1 fingerprint = hash160(sec)[:4] child_number = index return HDPublicKey( point=point, chain_code=chain_code, depth=depth, fingerprint=fingerprint, child_number=child_number, )
def op_hash160(stack: List[Any]) -> bool: """ convert top element into hash160 value Parameters ---------- stack : List[Any] [description] Returns ------- bool [description] """ if len(stack) < 1: return False element = stack.pop() stack.append(hash160(element)) return True
def address(self, testnet=False): '''Returns the address corresponding to the script''' sig_type = self.type() if sig_type == 'p2pkh': # hash160 is the 3rd element h160 = self.elements[2] # convert to p2pkh address using h160_to_p2pkh_address (remember testnet) return h160_to_p2pkh_address(h160, testnet) elif sig_type == 'p2sh': # hash160 is the 2nd element h160 = self.elements[1] # convert to p2sh address using h160_to_p2sh_address (remember testnet) return h160_to_p2sh_address(h160, testnet) elif sig_type == 'p2pk': return h160_to_p2pkh_address(hash160(self.elements[0]), testnet) elif sig_type == 'p2wpkh': import segwit_addr if self.elements[0] == b'': witver = 0 else: assert 0 return segwit_addr.encode("bc", witver, self.elements[1])