def tweak_pubkey_mul(pubkey: bytes, tweak: bytes, compressed: bool = True) -> bytes: ''' Tweaks a pubkey by multiplying by a 32 byte tweak Args: pubkey (bytes): 32 byte pubkey tweak (bytes): 32 byte tweak Returns: (bytes): 32 byte tweaked pubkey ''' ctx = get_verify_context() if len(tweak) != 32: raise ValueError('tweak must be 32 bytes') pubkey_tuple = secpy256k1.ec_pubkey_parse(ctx, pubkey) if pubkey_tuple[0] != 1: raise Exception('unknown exception -- pubkey parse failed') tweaked_tuple = secpy256k1.ec_pubkey_tweak_mul(ctx, pubkey_tuple[1], tweak) if tweaked_tuple[0] != 1: raise Exception('unknown exception -- pubkey tweak mul failed') flag = (secpy256k1.lib.SECP256K1_EC_COMPRESSED if compressed else secpy256k1.lib.SECP256K1_EC_UNCOMPRESSED) pubkey_ser_tuple = secpy256k1.ec_pubkey_serialize(ctx, tweaked_tuple[1], flag) if pubkey_ser_tuple[0] != 1: raise Exception('unknown exception -- pubkey ser failed') return bytes(secpy256k1.ffi.buffer(pubkey_ser_tuple[1]))
def priv_to_pub(privkey: bytes, compressed: bool = True) -> bytes: ''' Returns the pubkey for a given privkey Args: privkey (bytes): the 32 byte secret key compressed (bool): True for compressed (33 byte), False for uncompressed (65 byte) Returns: (bytes): 33 (compressed) or 65 (uncompressed) byte pubkey ''' ctx = get_sign_context() pubkey_tuple = secpy256k1.ec_pubkey_create(ctx, privkey) if pubkey_tuple[0] != 1: raise Exception('unknown exception -- pubkey create failed') flags = (secpy256k1.lib.SECP256K1_EC_COMPRESSED if compressed else secpy256k1.lib.SECP256K1_EC_UNCOMPRESSED) pubkey_ser_tuple = secpy256k1.ec_pubkey_serialize(ctx, pubkey_tuple[1], flags) if pubkey_ser_tuple[0] != 1: raise Exception('unknown exception -- pubkey serialize failed') return bytes(secpy256k1.ffi.buffer(pubkey_ser_tuple[1]))
def test_ec_pubkey_create(self): sign_context = secpy256k1.context_create( secpy256k1.lib.SECP256K1_CONTEXT_SIGN) pubkey_tuple = secpy256k1.ec_pubkey_create(sign_context, self.privkey) pubkey_compressed_ser = secpy256k1.ec_pubkey_serialize( sign_context, pubkey_tuple[1], secpy256k1.lib.SECP256K1_EC_COMPRESSED) pubkey = bytes(secpy256k1.ffi.buffer(pubkey_compressed_ser[1])) self.assertEqual(pubkey_tuple[0], 1) self.assertEqual(pubkey, self.pubkey)
def compress_pubkey(pubkey: bytes) -> bytes: ''' Converts an uncompressed pubkey to a compressed pubkey Args: pubkey (bytes): the 65 byte uncompressed key Returns: (bytes): the compressed (33 byte) pubkey ''' ctx = get_verify_context() pubkey_tuple = secpy256k1.ec_pubkey_parse(ctx, pubkey) if pubkey_tuple[0] != 1: raise Exception('unknown exception -- pubkey parse failed') pubkey_ser_tuple = secpy256k1.ec_pubkey_serialize( ctx, pubkey_tuple[1], secpy256k1.lib.SECP256K1_EC_COMPRESSED) if pubkey_ser_tuple[0] != 1: raise Exception('unknown exception -- pubkey ser failed') return bytes(secpy256k1.ffi.buffer(pubkey_ser_tuple[1]))
def test_ec_pubkey_serialize(self): for flags in self.context_flags: # Create context secp256k1_ctx = secpy256k1.context_create(flags) # Create COMPRESSED secp256k1_pubkey object to serialize secp256k1_pubkey_tuple = secpy256k1.ec_pubkey_parse( secp256k1_ctx, self.pubkey) secp256k1_pubkey = secp256k1_pubkey_tuple[1] # Serialize COMPRESSED pubkey pubkey_ser_tuple = secpy256k1.ec_pubkey_serialize( secp256k1_ctx, secp256k1_pubkey, secpy256k1.lib.SECP256K1_EC_COMPRESSED) pubkey_int = pubkey_ser_tuple[0] pubkey_ser = pubkey_ser_tuple[1] pubkeylen = pubkey_ser_tuple[2] # First tuple entry always returns 1 self.assertEqual(pubkey_int, 1) # Second tuple entry returns type char[] pointer to COMPRESSED # public key byte array self.assertEqual(secpy256k1.ffi.typeof(pubkey_ser), secpy256k1.ffi.typeof('char[]')) self.assertEqual(secpy256k1.ffi.sizeof(pubkey_ser), 33) # Third tuple entry returns type size_t* pointer to public key size self.assertEqual(secpy256k1.ffi.typeof(pubkeylen), secpy256k1.ffi.typeof('size_t*')) # Errors if invalid context flag with self.assertRaises(TypeError) as err: secpy256k1.ec_pubkey_parse(0, self.pubkey) self.assertIn( 'Invalid context. Must be secp256k1_context_struct pointer.', str(err.exception)) # Errors if invalid seralized public key with self.assertRaises(ValueError) as err: secpy256k1.ec_pubkey_parse(secp256k1_ctx, 0) self.assertIn('Invalid pubkey. Must be 33- or 65-bytes.', str(err.exception)) for flags in self.context_flags: # Create context secp256k1_ctx = secpy256k1.context_create(flags) # Create UNCOMPRESSED secp256k1_pubkey object to serialize secp256k1_pubkey_tuple = secpy256k1.ec_pubkey_parse( secp256k1_ctx, self.uncomp_pubkey) secp256k1_pubkey = secp256k1_pubkey_tuple[1] # Serialize UNCOMPRESSED pubkey pubkey_ser_tuple = secpy256k1.ec_pubkey_serialize( secp256k1_ctx, secp256k1_pubkey, secpy256k1.lib.SECP256K1_EC_UNCOMPRESSED) pubkey_int = pubkey_ser_tuple[0] pubkey_ser = pubkey_ser_tuple[1] pubkeylen = pubkey_ser_tuple[2] # First tuple entry always returns 1 self.assertEqual(pubkey_int, 1) # Second tuple entry returns type char[] pointer to UNCOMPRESSED # public key byte array self.assertEqual(secpy256k1.ffi.typeof(pubkey_ser), secpy256k1.ffi.typeof('char[]')) self.assertEqual(secpy256k1.ffi.sizeof(pubkey_ser), 65) # Third tuple entry returns type size_t* pointer to public key size self.assertEqual(secpy256k1.ffi.typeof(pubkeylen), secpy256k1.ffi.typeof('size_t*')) # Errors if invalid context flag with self.assertRaises(TypeError) as err: secpy256k1.ec_pubkey_parse(0, self.pubkey) self.assertIn( 'Invalid context. Must be secp256k1_context_struct pointer.', str(err.exception)) # Errors if invalid seralized public key with self.assertRaises(ValueError) as err: secpy256k1.ec_pubkey_parse(secp256k1_ctx, 0) self.assertIn('Invalid pubkey. Must be 33- or 65-bytes.', str(err.exception))
) # noqa: E501 tweak = b'\x66' * 32 # noqa: E501 msg = bytes.fromhex('deadbeef' * 8) verify_context = secpy256k1.context_create(SECP256K1_CONTEXT_VERIFY) sign_context = secpy256k1.context_create(SECP256K1_CONTEXT_SIGN) # try cloning to make sure it doesn't error secpy256k1.context_clone(verify_context) # parse the pubkey to a secpy pubkey tuple secp256k1_pubkey_tuple = secpy256k1.ec_pubkey_parse(verify_context, pubkey) # serialize the pubkey output_tuple = secpy256k1.ec_pubkey_serialize(verify_context, secp256k1_pubkey_tuple[1], SECP256K1_EC_COMPRESSED) ser_pub = output_tuple[1] pubkey_ser = bytes(secpy256k1.ffi.buffer(ser_pub)) print('\n\npubkey_ser', pubkey_ser.hex()) # check pubkey tweak function tweaked_pubkey_tuple = secpy256k1.ec_pubkey_tweak_add( verify_context, secpy256k1.ec_pubkey_parse(verify_context, pubkey)[1], tweak) tweaked_pubkey = tweaked_pubkey_tuple[1] output_tweak_tuple = secpy256k1.ec_pubkey_serialize( verify_context, secpy256k1.ec_pubkey_parse(verify_context, pubkey)[1], SECP256K1_EC_COMPRESSED)