def multiply(self, p, e): """Multiply a point by an integer.""" e %= self.order() if p == self._infinity or e == 0: return self._infinity pubkey = create_string_buffer(64) public_pair_bytes = b'\4' + to_bytes_32(p[0]) + to_bytes_32(p[1]) r = libsecp256k1.secp256k1_ec_pubkey_parse(libsecp256k1.ctx, pubkey, public_pair_bytes, len(public_pair_bytes)) if not r: return False r = libsecp256k1.secp256k1_ec_pubkey_tweak_mul(libsecp256k1.ctx, pubkey, to_bytes_32(e)) if not r: return self._infinity pubkey_serialized = create_string_buffer(65) pubkey_size = c_size_t(65) libsecp256k1.secp256k1_ec_pubkey_serialize(libsecp256k1.ctx, pubkey_serialized, byref(pubkey_size), pubkey, SECP256K1_EC_UNCOMPRESSED) x = from_bytes_32(pubkey_serialized[1:33]) y = from_bytes_32(pubkey_serialized[33:]) return self.Point(x, y)
def test_sign(self): if libsecp256k1 is None: raise unittest.SkipTest("no libsecp256k1") ctx = libsecp256k1.ctx 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' ) signature = create_string_buffer(64) r = libsecp256k1.secp256k1_ecdsa_sign(ctx, signature, sighash, secret_key, None, None) self.assertEqual(r, 1) compact_signature = create_string_buffer(64) libsecp256k1.secp256k1_ecdsa_signature_serialize_compact(ctx, compact_signature, signature) r = from_bytes_32(compact_signature[:32]) s = from_bytes_32(compact_signature[32:]) signature = (r, s) pubkey_size = c_size_t(65) pubkey_serialized = create_string_buffer(65) libsecp256k1.secp256k1_ec_pubkey_serialize( ctx, pubkey_serialized, byref(pubkey_size), public_key, SECP256K1_EC_UNCOMPRESSED) x = from_bytes_32(pubkey_serialized[1:33]) y = from_bytes_32(pubkey_serialized[33:]) legacy_secp256k1_group.verify((x, y), 1000, signature)
def sign(self, secret_exponent, val, gen_k=None): nonce_function = None if gen_k is not None: k_as_bytes = to_bytes_32(gen_k(self.order(), secret_exponent, val)) def adaptor(nonce32_p, msg32_p, key32_p, algo16_p, data, attempt): nonce32_p.contents[:] = list(iterbytes(k_as_bytes)) return 1 p_b32 = POINTER(c_byte * 32) nonce_function = CFUNCTYPE(c_int, p_b32, p_b32, p_b32, POINTER(c_byte * 16), c_void_p, c_uint)(adaptor) sig = create_string_buffer(64) sig_hash_bytes = to_bytes_32(val) libsecp256k1.secp256k1_ecdsa_sign(libsecp256k1.ctx, sig, sig_hash_bytes, to_bytes_32(secret_exponent), nonce_function, None) compact_signature = create_string_buffer(64) libsecp256k1.secp256k1_ecdsa_signature_serialize_compact( libsecp256k1.ctx, compact_signature, sig) r = from_bytes_32(compact_signature[:32]) s = from_bytes_32(compact_signature[32:]) return (r, s)
def __mul__(self, e): e %= self.order() if e == 0: return self._infinity pubkey = create_string_buffer(65) libsecp256k1.secp256k1_ec_pubkey_create(libsecp256k1.ctx, pubkey, c_char_p(to_bytes_32(e))) pubkey_size = c_size_t(65) pubkey_serialized = create_string_buffer(65) libsecp256k1.secp256k1_ec_pubkey_serialize(libsecp256k1.ctx, pubkey_serialized, byref(pubkey_size), pubkey, SECP256K1_EC_UNCOMPRESSED) x = from_bytes_32(pubkey_serialized[1:33]) y = from_bytes_32(pubkey_serialized[33:]) return self.Point(x, y)
def from_text(class_, text, is_compressed=False): """ This function will accept a BIP0032 wallet string, a WIF, or a bitcoin address. The "is_compressed" parameter is ignored unless a public address is passed in. """ data = a2b_hashed_base58(text) netcode, key_type, length = netcode_and_type_for_data(data) data = data[1:] if key_type in ("pub32", "prv32"): # TODO: fix this... it doesn't belong here from pycoinzpub.key.BIP32Node import BIP32Node return BIP32Node.from_wallet_key(text) if key_type == 'wif': is_compressed = (len(data) > 32) if is_compressed: data = data[:-1] return Key( secret_exponent=from_bytes_32(data), prefer_uncompressed=not is_compressed, netcode=netcode) if key_type == 'address': return Key(hash160=data, is_compressed=is_compressed, netcode=netcode) raise EncodingError("unknown text: %s" % text)
def sign(self, h): """ Return a der-encoded signature for a hash h. Will throw a RuntimeError if this key is not a private key """ if not self.is_private(): raise RuntimeError("Key must be private to be able to sign") val = from_bytes_32(h) r, s = secp256k1_generator.sign(self.secret_exponent(), val) return sigencode_der(r, s)
def initial_key_to_master_key(initial_key): """ initial_key: a hex string of length 32 """ b = initial_key.encode("utf8") orig_input = b for i in range(100000): b = hashlib.sha256(b + orig_input).digest() return from_bytes_32(b)
def verify(self, h, sig): """ Return whether a signature is valid for hash h using this key. """ val = from_bytes_32(h) pubkey = self.public_pair() rs = sigdecode_der(sig) if self.public_pair() is None: # find the pubkey from the signature and see if it matches # our key possible_pubkeys = secp256k1_generator.possible_public_pairs_for_signature(val, rs) hash160 = self.hash160() for candidate in possible_pubkeys: if hash160 == public_pair_to_hash160_sec(candidate, True): pubkey = candidate break if hash160 == public_pair_to_hash160_sec(candidate, False): pubkey = candidate break else: # signature is using a pubkey that's not this key return False return secp256k1_generator.verify(pubkey, val, rs)
def subkey(self, path): """ path: of the form "K" where K is an integer index, or "K/N" where N is usually a 0 (deposit address) or 1 (change address) """ t = path.split("/") if len(t) == 2: n, for_change = t else: n, = t for_change = 0 b = (str(n) + ':' + str(for_change) + ':').encode("utf8") + self.master_public_key() offset = from_bytes_32(double_sha256(b)) if self.master_private_key(): return Key(secret_exponent=((self.master_private_key() + offset) % ORDER), prefer_uncompressed=True) p1 = offset * secp256k1_generator x, y = self.public_pair() p2 = secp256k1_generator.Point(x, y) p = p1 + p2 return Key(public_pair=p, prefer_uncompressed=True)
def __init__(self, initial_key=None, master_private_key=None, master_public_key=None, netcode='BTC'): if [initial_key, master_private_key, master_public_key ].count(None) != 2: raise ValueError( "exactly one of initial_key, master_private_key, master_public_key must be non-None" ) self._initial_key = initial_key self._netcode = netcode if initial_key is not None: master_private_key = initial_key_to_master_key(initial_key) pp = None if master_public_key: pp = tuple( from_bytes_32(master_public_key[idx:idx + 32]) for idx in (0, 32)) super(ElectrumWallet, self).__init__(secret_exponent=master_private_key, public_pair=pp) self._master_public_key = None