def info_for_p2wit(self, hrp, data): decoded = segwit_addr.convertbits(data[1:], 5, 8, False) decoded_data = b''.join(int2byte(d) for d in decoded) ldd = len(decoded_data) version_byte = int2byte(data[0]) script = version_byte + int2byte(ldd) + decoded_data if version_byte == 0: if ldd == 20: return dict( type="address", address_type="p2pkh_wit", hash160=data, create_f=lambda: self._pay_to.script_for_p2pkh_wit(data)) if ldd == 32: return dict( type="address", address_type="p2sh_wit", hash256=data, create_f=lambda: self._pay_to.script_for_p2sh_wit(data)) return dict(type="address", address_type="wit_other", version_byte=version_byte, create_f=lambda: script)
def test_compile_push_data_list(self): def test_bytes(as_bytes): script = ScriptTools.compile_push_data_list([as_bytes]) # this is a pretty horrible hack to test the vm with long scripts. But it works tx_context = TxContext() tx_context.signature_for_hash_type_f = None tx_context.flags = 0 tx_context.traceback_f = None vm = BitcoinVM(script, tx_context, tx_context.signature_for_hash_type_f, flags=0) vm.MAX_SCRIPT_LENGTH = int(1e9) vm.MAX_BLOB_LENGTH = int(1e9) stack = vm.eval_script() assert len(stack) == 1 assert stack[0] == as_bytes def test_val(n): as_bytes = IntStreamer.int_to_script_bytes(n) test_bytes(as_bytes) for i in range(100): test_val(100) for i in range(0xfff0, 0x10004): test_val(i) for i in range(0xfffff0, 0x1000005): test_val(i) for l in (1, 2, 3, 254, 255, 256, 257, 258, 0xfff9, 0xfffe, 0xffff, 0x10000, 0x10001, 0x10005): for v in (1, 2, 3, 4, 15, 16, 17, 18): b = int2byte(v) * l test_bytes(b) b = int2byte(30) * (0x1000000+1) for l in (0x1000000-1, 0x1000000, 0x1000000+1): test_bytes(b[:l])
def test_bin_script(self): def test_bytes(as_bytes): script = bin_script([as_bytes]) stack = [] eval_script(script, None, lock_time=0, stack=stack, disallow_long_scripts=False) assert len(stack) == 1 assert stack[0] == as_bytes def test_val(n): as_bytes = int_to_script_bytes(n) test_bytes(as_bytes) for i in range(100): test_val(100) for i in range(0xfff0, 0x10004): test_val(i) for i in range(0xfffff0, 0x1000005): test_val(i) for l in (1, 2, 3, 254, 255, 256, 257, 258, 0xfff9, 0xfffe, 0xffff, 0x10000, 0x10001, 0x10005): for v in (1, 2, 3, 4, 15, 16, 17, 18): b = int2byte(v) * l test_bytes(b) b = int2byte(30) * (0x1000000 + 1) for l in (0x1000000 - 1, 0x1000000, 0x1000000 + 1): test_bytes(b[:l])
def test_compile_push_data_list(self): def test_bytes(as_bytes): script = network.script.compile_push_data_list([as_bytes]) # this is a pretty horrible hack to test the vm with long scripts. But it works tx_context = TxContext() tx_context.signature_for_hash_type_f = None tx_context.flags = 0 tx_context.traceback_f = None vm = BitcoinVM(script, tx_context, tx_context.signature_for_hash_type_f, flags=0) vm.MAX_SCRIPT_LENGTH = int(1e9) vm.MAX_BLOB_LENGTH = int(1e9) stack = vm.eval_script() assert len(stack) == 1 assert stack[0] == as_bytes def test_val(n): as_bytes = IntStreamer.int_to_script_bytes(n) test_bytes(as_bytes) for i in range(100): test_val(100) for i in range(0xfff0, 0x10004): test_val(i) for i in range(0xfffff0, 0x1000005): test_val(i) for l in (1, 2, 3, 254, 255, 256, 257, 258, 0xfff9, 0xfffe, 0xffff, 0x10000, 0x10001, 0x10005): for v in (1, 2, 3, 4, 15, 16, 17, 18): b = int2byte(v) * l test_bytes(b) b = int2byte(30) * (0x1000000+1) for l in (0x1000000-1, 0x1000000, 0x1000000+1): test_bytes(b[:l])
def encode_length(l): assert l >= 0 if l < 0x80: return int2byte(l) s = "%x" % l if len(s) % 2: s = "0" + s s = binascii.unhexlify(s) llen = len(s) return int2byte(0x80 | llen) + s
def encode_length(l): assert l >= 0 if l < 0x80: return int2byte(l) s = "%x" % l if len(s) % 2: s = "0"+s s = binascii.unhexlify(s) llen = len(s) return int2byte(0x80 | llen) + s
def encode_integer(r): assert r >= 0 # can't support negative numbers yet h = "%x" % r if len(h) % 2: h = "0" + h s = binascii.unhexlify(h.encode("utf8")) if ord(s[:1]) <= 0x7f: return b"\x02" + int2byte(len(s)) + s else: # DER integers are two's complement, so if the first byte is # 0x80-0xff then we need an extra 0x00 byte to prevent it from # looking negative. return b"\x02" + int2byte(len(s)+1) + b"\x00" + s
def encode_integer(r): assert r >= 0 # can't support negative numbers yet h = "%x" % r if len(h) % 2: h = "0" + h s = binascii.unhexlify(h.encode("utf8")) if ord(s[:1]) <= 0x7f: return b"\x02" + int2byte(len(s)) + s else: # DER integers are two's complement, so if the first byte is # 0x80-0xff then we need an extra 0x00 byte to prevent it from # looking negative. return b"\x02" + int2byte(len(s) + 1) + b"\x00" + s
def test_sign_verify_mutual_compatability(self): if libsecp256k1 is None: raise unittest.SkipTest("no libsecp256k1") ctx = libsecp256k1.ctx signature = create_string_buffer(64) sighash = to_bytes_32(1000) secret_key = to_bytes_32(100) public_key = create_string_buffer(64) r = libsecp256k1.secp256k1_ec_pubkey_create(ctx, public_key, secret_key) self.assertEqual(r, 1) self.assertEqual( b2h(public_key), '880f50f7ceb4210289266a40b306e33ef52bb75f834c172e65175e3ce2ac3bed' '6e2835e3d57ae1fcd0954808be17bd97bf871f7a8a5edadcffcc8812576f7ae5') r = libsecp256k1.secp256k1_ecdsa_sign(ctx, signature, sighash, secret_key, None, None) self.assertEqual(r, 1) r = libsecp256k1.secp256k1_ecdsa_verify(ctx, signature, sighash, public_key) self.assertEqual(r, 1) signature1 = signature[:-1] + int2byte(byte2int(signature[-1]) ^ 1) r = libsecp256k1.secp256k1_ecdsa_verify(ctx, signature1, sighash, public_key) self.assertEqual(r, 0)
def _segwit(self, s, blob_len, segwit_attr): script_f = getattr(self._network.contract, segwit_attr, None) if script_f is None: return None pair = parse_bech32(s) if pair is None or pair[0] != self._bech32_hrp or pair[1] is None: return None data = pair[1] version_byte = int2byte(data[0]) decoded = segwit_addr.convertbits(data[1:], 5, 8, False) decoded_data = b''.join(int2byte(d) for d in decoded) if version_byte != b'\0' or len(decoded_data) != blob_len: return None script = script_f(decoded_data) script_info = self._network.contract.info_for_script(script) return Contract(script_info, self._network)
def test_sign_verify_mutual_compatability(self): if libsecp256k1 is None: raise unittest.SkipTest("no libsecp256k1") ctx = libsecp256k1.ctx signature = create_string_buffer(64) sighash = to_bytes_32(1000) secret_key = to_bytes_32(100) public_key = create_string_buffer(64) r = libsecp256k1.secp256k1_ec_pubkey_create(ctx, public_key, secret_key) self.assertEqual(r, 1) self.assertEqual( b2h(public_key), '880f50f7ceb4210289266a40b306e33ef52bb75f834c172e65175e3ce2ac3bed' '6e2835e3d57ae1fcd0954808be17bd97bf871f7a8a5edadcffcc8812576f7ae5' ) r = libsecp256k1.secp256k1_ecdsa_sign(ctx, signature, sighash, secret_key, None, None) self.assertEqual(r, 1) r = libsecp256k1.secp256k1_ecdsa_verify(ctx, signature, sighash, public_key) self.assertEqual(r, 1) signature1 = signature[:-1] + int2byte(byte2int(signature[-1]) ^ 1) r = libsecp256k1.secp256k1_ecdsa_verify(ctx, signature1, sighash, public_key) self.assertEqual(r, 0)
def _segwit(self, s, blob_len, segwit_attr): script_f = getattr(self._network.contract, segwit_attr, None) if script_f is None: return None pair = parse_bech32(s) if pair is None or pair[0] != self._bech32_hrp or pair[1] is None: return None data = pair[1] version_byte = int2byte(data[0]) decoded = segwit_addr.convertbits(data[1:], 5, 8, False) decoded_data = b''.join(int2byte(d) for d in decoded) if version_byte != b'\0' or len(decoded_data) != blob_len: return None script = script_f(decoded_data) script_info = self._network.contract.info_for_script(script) return Contract(script_info, self._network)
def _create_script_signature( self, secret_exponent, signature_for_hash_type_f, signature_type, script): sign_value = signature_for_hash_type_f(signature_type, script) order = secp256k1_generator.order() r, s = secp256k1_generator.sign(secret_exponent, sign_value) if s + s > order: s = order - s return der.sigencode_der(r, s) + int2byte(signature_type)
def f(solved_values, **kwargs): signature_type = kwargs.get("signature_type", DEFAULT_SIGNATURE_TYPE) generator_for_signature_type_f = kwargs[ "generator_for_signature_type_f"] signature_for_hash_type_f = m["signature_for_hash_type_f"] existing_script = kwargs.get("existing_script", b'') existing_signatures, secs_solved = _find_signatures( existing_script, generator_for_signature_type_f, signature_for_hash_type_f, len(m["sig_list"]), m["sec_list"]) sec_keys = m["sec_list"] signature_variables = m["sig_list"] signature_placeholder = kwargs.get("signature_placeholder", DEFAULT_PLACEHOLDER_SIGNATURE) db = kwargs.get("hash160_lookup", {}) # we reverse this enumeration to make the behaviour look like the old signer. BRAIN DAMAGE for signature_order, sec_key in reversed(list(enumerate(sec_keys))): sec_key = solved_values.get(sec_key, sec_key) if sec_key in secs_solved: continue if len(existing_signatures) >= len(signature_variables): break result = db.get(hash160(sec_key)) if result: secret_exponent = result[0] sig_hash = signature_for_hash_type_f(signature_type) generator = result[3] r, s = generator.sign(secret_exponent, sig_hash) else: # try existing signatures generator = generator_for_signature_type_f(signature_type) public_pair = sec_to_public_pair(sec_key, generator=generator) for sig in all_signature_hints(public_pair, signature_for_hash_type_f, **kwargs): sig_hash = signature_for_hash_type_f(indexbytes(sig, -1)) sig_pair = der.sigdecode_der(sig[:-1]) if generator.verify(public_pair, sig_hash, sig_pair): r, s = sig_pair break else: continue order = generator.order() if s + s > order: s = order - s binary_signature = der.sigencode_der(r, s) + int2byte(signature_type) existing_signatures.append((signature_order, binary_signature)) # pad with placeholder signatures if signature_placeholder is not None: while len(existing_signatures) < len(signature_variables): existing_signatures.append((-1, signature_placeholder)) existing_signatures.sort() return dict( zip(signature_variables, (es[-1] for es in existing_signatures)))
def info_for_p2wit(self, hrp, data): decoded = segwit_addr.convertbits(data[1:], 5, 8, False) decoded_data = b''.join(int2byte(d) for d in decoded) ldd = len(decoded_data) version_byte = int2byte(data[0]) script = version_byte + int2byte(ldd) + decoded_data if version_byte == 0: if ldd == 20: return dict(type="address", address_type="p2pkh_wit", hash160=data, create_f=lambda: self._pay_to.script_for_p2pkh_wit(data)) if ldd == 32: return dict(type="address", address_type="p2sh_wit", hash256=data, create_f=lambda: self._pay_to.script_for_p2sh_wit(data)) return dict(type="address", address_type="wit_other", version_byte=version_byte, create_f=lambda: script)
def sigmake(a_key, a_hash_for_sig, a_sig_type): """ Signs a_hash_for_sig with a_key and returns a DER-encoded signature with a_sig_type appended. """ order = secp256k1_generator.order() r, s = secp256k1_generator.sign(a_key.secret_exponent(), a_hash_for_sig) if s + s > order: s = order - s return sigencode_der(r, s) + int2byte(a_sig_type)
def sigmake(a_key, a_hash_for_sig, a_sig_type=SIGHASH_ALL): """ Signs a_hash_for_sig with a_key and returns a DER-encoded signature with a_sig_type appended. """ order = secp256k1_generator.order() r, s = secp256k1_generator.sign(a_key.secret_exponent(), a_hash_for_sig) if s + s > order: s = order - s return sigencode_der(r, s) + int2byte(a_sig_type)
def f(solved_values, **kwargs): signature_type = kwargs.get("signature_type", DEFAULT_SIGNATURE_TYPE) signature_hints = kwargs.get("signature_hints", []) generator_for_signature_type_f = kwargs["generator_for_signature_type_f"] signature_for_hash_type_f = m["signature_for_hash_type_f"] existing_script = kwargs.get("existing_script", b'') existing_signatures, secs_solved = _find_signatures( existing_script, generator_for_signature_type_f, signature_for_hash_type_f, len(m["sig_list"]), m["sec_list"]) sec_keys = m["sec_list"] signature_variables = m["sig_list"] signature_placeholder = kwargs.get("signature_placeholder", DEFAULT_PLACEHOLDER_SIGNATURE) db = kwargs.get("hash160_lookup", {}) # we reverse this enumeration to make the behaviour look like the old signer. BRAIN DAMAGE for signature_order, sec_key in reversed(list(enumerate(sec_keys))): sec_key = solved_values.get(sec_key, sec_key) if sec_key in secs_solved: continue if len(existing_signatures) >= len(signature_variables): break result = db.get(hash160(sec_key)) if result: secret_exponent = result[0] sig_hash = signature_for_hash_type_f(signature_type) generator = result[3] r, s = generator.sign(secret_exponent, sig_hash) else: # try existing signatures for sig in signature_hints: sig_hash = signature_for_hash_type_f(indexbytes(sig, -1)) generator = generator_for_signature_type_f(signature_type) public_pair = sec_to_public_pair(sec_key, generator=generator) sig_pair = der.sigdecode_der(sig[:-1]) if generator.verify(public_pair, sig_hash, sig_pair): r, s = sig_pair break else: continue order = generator.order() if s + s > order: s = order - s binary_signature = der.sigencode_der(r, s) + int2byte(signature_type) existing_signatures.append((signature_order, binary_signature)) # pad with placeholder signatures if signature_placeholder is not None: while len(existing_signatures) < len(signature_variables): existing_signatures.append((-1, signature_placeholder)) existing_signatures.sort() return dict(zip(signature_variables, (es[-1] for es in existing_signatures)))
def signature_for_message_hash(self, secret_exponent, msg_hash, is_compressed): """ Return a signature, encoded in Base64, of msg_hash. """ r, s, recid = self._generator.sign_with_recid(secret_exponent, msg_hash) # See http://bitcoin.stackexchange.com/questions/14263 and key.cpp # for discussion of the proprietary format used for the signature first = 27 + recid + (4 if is_compressed else 0) sig = b2a_base64(int2byte(first) + to_bytes_32(r) + to_bytes_32(s)).strip() sig = sig.decode("utf8") return sig
def signature_for_message_hash(self, secret_exponent, msg_hash, is_compressed): """ Return a signature, encoded in Base64, of msg_hash. """ r, s, recid = self._generator.sign_with_recid(secret_exponent, msg_hash) # See http://bitcoin.stackexchange.com/questions/14263 and key.cpp # for discussion of the proprietary format used for the signature first = 27 + recid + (4 if is_compressed else 0) sig = b2a_base64(int2byte(first) + to_bytes_32(r) + to_bytes_32(s)).strip() sig = sig.decode("utf8") return sig
def generate_default_placeholder_signature(): order = ecdsa.generator_secp256k1.order() r, s = order - 1, order // 2 return der.sigencode_der(r, s) + int2byte(1)
def generate_default_placeholder_signature(): order = secp256k1_generator.order() r, s = order - 1, order // 2 return der.sigencode_der(r, s) + int2byte(1)