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 test_inverse_mod(self): prime = secp256k1_generator.curve().p() order = secp256k1_generator.order() for v in range(70): n = int(float("1e%d" % v)) i = secp256k1_generator.inverse_mod(n, prime) assert n * i % prime == 1 i = secp256k1_generator.inverse_mod(n, order) assert n * i % order == 1
def test_inverse_mod(self): prime = secp256k1_generator.curve().p() order = secp256k1_generator.order() for v in range(70): n = int(float("1e%d" % v)) i = secp256k1_generator.inverse_mod(n, prime) assert n * i % prime == 1 i = secp256k1_generator.inverse_mod(n, order) assert n * i % order == 1
def __init__(self, secret_exponent=None, public_pair=None, hash160=None, prefer_uncompressed=None, is_compressed=None, is_pay_to_script=False, netcode=None): """ secret_exponent: a long representing the secret exponent public_pair: a tuple of long integers on the ecdsa curve hash160: a hash160 value corresponding to a bitcoin address Include at most one of secret_exponent, public_pair or hash160. prefer_uncompressed: whether or not to produce text outputs as compressed or uncompressed. is_pay_to_script: whether or not this key is for a pay-to-script style transaction netcode: the code for the network (as defined in pycoin.networks) Include at most one of secret_exponent, public_pair or hash160. prefer_uncompressed, is_compressed (booleans) are optional. """ if is_compressed is None: is_compressed = False if hash160 else True if netcode is None: netcode = get_current_netcode() if [secret_exponent, public_pair, hash160].count(None) != 2: raise ValueError("exactly one of secret_exponent, public_pair, hash160 must be passed.") if prefer_uncompressed is None: prefer_uncompressed = not is_compressed self._prefer_uncompressed = prefer_uncompressed self._secret_exponent = secret_exponent self._public_pair = public_pair self._hash160_uncompressed = None self._hash160_compressed = None if hash160: if is_compressed: self._hash160_compressed = hash160 else: self._hash160_uncompressed = hash160 self._netcode = netcode if self._public_pair is None and self._secret_exponent is not None: if self._secret_exponent < 1 \ or self._secret_exponent >= secp256k1_generator.order(): raise InvalidSecretExponentError() public_pair = self._secret_exponent * secp256k1_generator self._public_pair = public_pair if self._public_pair is not None \ and (None in self._public_pair or not secp256k1_generator.contains_point(*self._public_pair)): raise InvalidPublicPairError()
def do_test(secret_exponent, val_list): public_point = secret_exponent * secp256k1_generator for v in val_list: signature = secp256k1_generator.sign(secret_exponent, v) r = secp256k1_generator.verify(public_point, v, signature) assert r is True r = secp256k1_generator.verify(public_point, v, (signature[0], secp256k1_generator.order() - signature[1])) assert r is True signature = signature[0],signature[1]+1 r = secp256k1_generator.verify(public_point, v, signature) assert r is False
def test_multiply(self): g2 = secp256k1_generator * 2 g2p = g2 * 1 self.assertEqual(g2p, g2) g4 = g2 * 2 self.assertEqual(g4, secp256k1_generator * 4) g8 = g2 * 4 self.assertEqual(g8, secp256k1_generator * 8) g24 = g8 * 3 self.assertEqual(g24, secp256k1_generator * 24) g_big = g2 * (71 ** 41) self.assertEqual(g_big, secp256k1_generator * ((2 * 71 ** 41) % secp256k1_generator.order()))
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 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 test_key_limits(self): nc = 'BTC' cc = b'000102030405060708090a0b0c0d0e0f' order = secp256k1_generator.order() for k in -1, 0, order, order + 1: self.assertRaises(InvalidSecretExponentError, Key, secret_exponent=k, generator=secp256k1_generator) self.assertRaises(InvalidSecretExponentError, BIP32Node, secp256k1_generator, nc, cc, secret_exponent=k) for i in range(1, 512): Key(secret_exponent=i, generator=secp256k1_generator) BIP32Node(secp256k1_generator, cc, secret_exponent=i)
def generate_default_placeholder_signature(): order = secp256k1_generator.order() r, s = order - 1, order // 2 return der.sigencode_der(r, s) + int2byte(1)
def parse_as_secret_exponent(s): v = parse_as_number(s) if v and 0 < v < secp256k1_generator.order(): return v
import hashlib import itertools from pycoin.ecdsa.secp256k1 import secp256k1_generator from pycoin.encoding import double_sha256, from_bytes_32, to_bytes_32 from pycoin.key import Key from pycoin.serialize import b2h ORDER = secp256k1_generator.order() 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) class ElectrumWallet(Key): 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:
def __init__(self, secret_exponent=None, public_pair=None, hash160=None, prefer_uncompressed=None, is_compressed=None, is_pay_to_script=False, netcode=None): """ secret_exponent: a long representing the secret exponent public_pair: a tuple of long integers on the ecdsa curve hash160: a hash160 value corresponding to a bitcoin address Include at most one of secret_exponent, public_pair or hash160. prefer_uncompressed: whether or not to produce text outputs as compressed or uncompressed. is_pay_to_script: whether or not this key is for a pay-to-script style transaction netcode: the code for the network (as defined in pycoin.networks) Include at most one of secret_exponent, public_pair or hash160. prefer_uncompressed, is_compressed (booleans) are optional. """ if is_compressed is None: is_compressed = False if hash160 else True if netcode is None: netcode = get_current_netcode() if [secret_exponent, public_pair, hash160].count(None) != 2: raise ValueError( "exactly one of secret_exponent, public_pair, hash160 must be passed." ) if prefer_uncompressed is None: prefer_uncompressed = not is_compressed self._prefer_uncompressed = prefer_uncompressed self._secret_exponent = secret_exponent self._public_pair = public_pair self._hash160_uncompressed = None self._hash160_compressed = None if hash160: if is_compressed: self._hash160_compressed = hash160 else: self._hash160_uncompressed = hash160 self._netcode = netcode if self._public_pair is None and self._secret_exponent is not None: if self._secret_exponent < 1 \ or self._secret_exponent >= secp256k1_generator.order(): raise InvalidSecretExponentError() public_pair = self._secret_exponent * secp256k1_generator self._public_pair = public_pair if self._public_pair is not None \ and (None in self._public_pair or not secp256k1_generator.contains_point(*self._public_pair)): raise InvalidPublicPairError()
return int.from_bytes(hashBytes, byteorder="big") def signECDSAsecp256k1(msg, privKey): msgHash = sha3_256Hash(msg) signature = secp256k1_generator.sign(privKey, msgHash) return signature def verifyECDSAsecp256k1(msg, signature, pubKey): msgHash = sha3_256Hash(msg) valid = secp256k1_generator.verify(pubKey, msgHash, signature) return valid # ECDSA sign message (using the curve secp256k1 + SHA3-256) msg = "Message for ECDSA signing" privKey = secrets.randbelow(secp256k1_generator.order()) signature = signECDSAsecp256k1(msg, privKey) print("Message:", msg) print("Private key:", hex(privKey)) print("Signature: r=" + hex(signature[0]) + ", s=" + hex(signature[1])) # ECDSA verify signature (using the curve secp256k1 + SHA3-256) pubKey = (secp256k1_generator * privKey) #.pair() valid = verifyECDSAsecp256k1(msg, signature, pubKey) print("\nMessage:", msg) print("Public key: (" + hex(pubKey[0]) + ", " + hex(pubKey[1]) + ")") print("Signature valid?", valid) # ECDSA verify tampered signature (using the curve secp256k1 + SHA3-256) msg = "Tampered message" valid = verifyECDSAsecp256k1(msg, signature, pubKey)
def parse_as_secret_exponent(s): v = parse_as_number(s) if v and 0 < v < secp256k1_generator.order(): return v
import hashlib import itertools from pycoin.ecdsa.secp256k1 import secp256k1_generator from pycoin.encoding import double_sha256, from_bytes_32, to_bytes_32 from pycoin.key import Key from pycoin.serialize import b2h ORDER = secp256k1_generator.order() 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) class ElectrumWallet(Key): 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