Example #1
0
def derive_child_xpublic_key(xpublic_key, i):
    c = xpublic_key[13:45]
    k = xpublic_key[45:]
    fingerprint = hash160(k)[:4]
    depth = xpublic_key[4] + 1
    if depth > 255:
        raise ValueError("path depth should be <= 255")
    if i >= HARDENED_KEY:
        raise ValueError("derivation from extended public key impossible")
    s = hmac_sha512(c, k + pack(">L", i))
    if int.from_bytes(s[:32], byteorder='big') >= ECDSA_SEC256K1_ORDER:
        return None
    pubkey_ptr = ffi.new('secp256k1_pubkey *')
    if not lib.secp256k1_ec_pubkey_parse(ECDSA_CONTEXT_VERIFY, pubkey_ptr, k,
                                         len(k)):
        raise RuntimeError("secp256k1 parse public key operation failed")
    if not lib.secp256k1_ec_pubkey_tweak_add(ECDSA_CONTEXT_ALL, pubkey_ptr,
                                             s[:32]):
        raise RuntimeError("secp256k1 parse tweak addition operation failed")
    pubkey = ffi.new('char [%d]' % 33)
    outlen = ffi.new('size_t *', 33)
    if not lib.secp256k1_ec_pubkey_serialize(
            ECDSA_CONTEXT_VERIFY, pubkey, outlen, pubkey_ptr, EC_COMPRESSED):
        raise RuntimeError("secp256k1 serialize public key operation failed")
    pk = bytes(ffi.buffer(pubkey, 33))
    print(len(pk))
    return b"".join([
        xpublic_key[:4],
        bytes([depth]), fingerprint,
        pack(">L", i), s[32:], pk
    ])
Example #2
0
def sign_message(msg, private_key, hex=False):
    """
    :param msg:  message to sign 
    :param private_key:  private key (bytes, hex encoded string)
    :param hex:  
    :return:  DER encoded sinature  
    """
    if type(msg) != bytes:
        if type(msg) == bytearray:
            msg = bytes(msg)

        elif type(msg) == str:
            msg = unhexlify(msg)
        else:
            raise TypeError("message must be a bytes or hex encoded string")
    if type(private_key) != bytes:
        if type(private_key) == bytearray:
            private_key = bytes(private_key)
        elif type(private_key) == str:
            private_key = WIF2priv(private_key)
        else:
            raise TypeError(
                "private key must be a bytes or hex encoded string")
    raw_sig = ffi.new('secp256k1_ecdsa_signature *')
    signed = secp256k1.secp256k1_ecdsa_sign(ECDSA_CONTEXT_SIGN, raw_sig, msg,
                                            private_key, ffi.NULL, ffi.NULL)
    assert signed == 1
    len_sig = 74
    output = ffi.new('unsigned char[%d]' % len_sig)
    outputlen = ffi.new('size_t *', len_sig)
    res = secp256k1.secp256k1_ecdsa_signature_serialize_der(
        ECDSA_CONTEXT_SIGN, output, outputlen, raw_sig)
    assert res == 1
    signature = bytes(ffi.buffer(output, outputlen[0]))
    return hexlify(signature).decode() if hex else signature
Example #3
0
def public_key_recovery(signature,
                        messsage,
                        rec_id,
                        compressed=True,
                        hex=True):
    if isinstance(signature, str):
        signature = bytes.fromhex(signature)
    if isinstance(messsage, str):
        messsage = bytes.fromhex(messsage)
    raw_sig = ffi.new('secp256k1_ecdsa_signature *')
    r = secp256k1.secp256k1_ecdsa_signature_parse_der(ECDSA_CONTEXT_SIGN,
                                                      raw_sig, signature,
                                                      len(signature))
    if not r:
        raise RuntimeError("secp256k1 error")
    compact_sig = ffi.new('unsigned char[%d]' % 64)
    r = secp256k1.secp256k1_ecdsa_signature_serialize_compact(
        ECDSA_CONTEXT_VERIFY, compact_sig, raw_sig)
    if not r:
        raise RuntimeError("secp256k1 error")

    recover_sig = ffi.new('secp256k1_ecdsa_recoverable_signature *')
    t = secp256k1.secp256k1_ecdsa_recoverable_signature_parse_compact(
        ECDSA_CONTEXT_ALL, recover_sig, compact_sig, rec_id)
    if not r:
        raise RuntimeError("secp256k1 error")

    pubkey_ptr = ffi.new('secp256k1_pubkey *')
    t = secp256k1.secp256k1_ecdsa_recover(ECDSA_CONTEXT_ALL, pubkey_ptr,
                                          recover_sig, messsage)
    len_key = 33 if compressed else 65
    pubkey = ffi.new('char [%d]' % len_key)
    outlen = ffi.new('size_t *', len_key)
    compflag = EC_COMPRESSED if compressed else EC_UNCOMPRESSED
    if bytes(ffi.buffer(pubkey_ptr.data, 64)) == b"\x00" * 64:
        return None
    r = secp256k1.secp256k1_ec_pubkey_serialize(ECDSA_CONTEXT_VERIFY, pubkey,
                                                outlen, pubkey_ptr, compflag)
    if not r:
        raise RuntimeError("secp256k1 error")
    pub = bytes(ffi.buffer(pubkey, len_key))
    return pub.hex() if hex else pub
Example #4
0
def pubkey_format(pub):
    assert pub.public_key, "No public key defined"

    len_compressed = 65
    res_compressed = ffi.new('unsigned char [%d]' % len_compressed)

    serialized = lib.secp256k1_ec_pubkey_serialize(
        pub.ctx, res_compressed, ffi.new('size_t *', len_compressed),
        pub.public_key, EC_UNCOMPRESSED)
    assert serialized == 1

    return bytes(ffi.buffer(res_compressed, len_compressed))
Example #5
0
def sign_message(msg, private_key, hex=True):
    """
    Sign message

    :param msg:  message to sign  bytes or HEX encoded string.
    :param private_key:  private key (bytes, hex encoded string or WIF format)
    :param hex:  (optional) If set to True return key in HEX format, by default is True.
    :return:  DER encoded signature in bytes or HEX encoded string.  
    """
    if isinstance(msg, bytearray):
        msg = bytes(msg)
    if isinstance(msg, str):
        try:
            msg = bytes.fromhex(msg)
        except:
            pass
    if not isinstance(msg, bytes):
        raise TypeError("message must be a bytes or hex encoded string")

    if isinstance(private_key, bytearray):
        private_key = bytes(private_key)
    if isinstance(private_key, str):
        try:
            private_key = bytes.fromhex(private_key)
        except:
            if is_wif_valid(private_key):
                private_key = wif_to_private_key(private_key, hex=False)
    if not isinstance(private_key, bytes):
        raise TypeError(
            "private key must be a bytes, hex encoded string or in WIF format")

    raw_sig = ffi.new('secp256k1_ecdsa_signature *')
    signed = secp256k1.secp256k1_ecdsa_sign(ECDSA_CONTEXT_SIGN, raw_sig, msg,
                                            private_key, ffi.NULL, ffi.NULL)
    if not signed:
        raise RuntimeError("secp256k1 error")
    len_sig = 74
    output = ffi.new('unsigned char[%d]' % len_sig)
    outputlen = ffi.new('size_t *', len_sig)
    res = secp256k1.secp256k1_ecdsa_signature_serialize_der(
        ECDSA_CONTEXT_SIGN, output, outputlen, raw_sig)
    if not res:
        raise RuntimeError("secp256k1 error")
    signature = bytes(ffi.buffer(output, outputlen[0]))
    raw_sig = ffi.new('secp256k1_ecdsa_signature *')
    return signature.hex() if hex else signature
Example #6
0
def private_to_public_key(private_key, compressed=True, hex=True):
    """
    Get public key from private key using ECDSA secp256k1

    :param private_key: private key in WIF, HEX or bytes.
    :param compressed: (optional) flag of public key compressed format, by default set to True.
                       In case private_key in WIF format, this flag is set in accordance with 
                       the key format specified in WIF string.
    :param hex:  (optional) if set to True return key in HEX format, by default is True.
    :return: 33/65 bytes public key in HEX or bytes string.
    """
    if not isinstance(private_key, bytes):
        if isinstance(private_key, bytearray):
            private_key = bytes(private_key)
        elif isinstance(private_key, str):
            if not is_wif_valid(private_key):
                private_key = bytes.fromhex(private_key)
            else:
                if private_key[0] in (MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX,
                                      TESTNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX):
                    compressed = False
                private_key = wif_to_private_key(private_key, hex=0)
        else:
            raise TypeError(
                "private key must be a bytes or WIF or hex encoded string")
    pubkey_ptr = ffi.new('secp256k1_pubkey *')
    r = secp256k1.secp256k1_ec_pubkey_create(ECDSA_CONTEXT_ALL, pubkey_ptr,
                                             private_key)
    if not r:
        raise RuntimeError("secp256k1 error")
    len_key = 33 if compressed else 65
    pubkey = ffi.new('char [%d]' % len_key)
    outlen = ffi.new('size_t *', len_key)
    compflag = EC_COMPRESSED if compressed else EC_UNCOMPRESSED
    r = secp256k1.secp256k1_ec_pubkey_serialize(ECDSA_CONTEXT_VERIFY, pubkey,
                                                outlen, pubkey_ptr, compflag)
    pub = bytes(ffi.buffer(pubkey, len_key))
    if not r:
        raise RuntimeError("secp256k1 error")
    return pub.hex() if hex else pub
Example #7
0
def priv2pub(private_key, compressed=True, hex=False):
    if type(private_key) != bytes:
        if type(private_key) == bytearray:
            private_key = bytes(private_key)
        elif type(private_key) == str:
            private_key = unhexlify(private_key)
        else:
            raise TypeError(
                "private key must be a bytes or hex encoded string")
    pubkey_ptr = ffi.new('secp256k1_pubkey *')
    r = secp256k1.secp256k1_ec_pubkey_create(ECDSA_CONTEXT_ALL, pubkey_ptr,
                                             private_key)
    assert r == 1
    len_key = 33 if compressed else 65
    pubkey = ffi.new('char [%d]' % len_key)
    outlen = ffi.new('size_t *', len_key)
    compflag = EC_COMPRESSED if compressed else EC_UNCOMPRESSED
    r = secp256k1.secp256k1_ec_pubkey_serialize(ECDSA_CONTEXT_VERIFY, pubkey,
                                                outlen, pubkey_ptr, compflag)
    assert r == 1
    pub = bytes(ffi.buffer(pubkey, len_key))
    return hexlify(pub).decode() if hex else pub