예제 #1
0
def ec_pubkey_combine(ctx, pubkeys):
    '''Add a number of public keys together.
    Args:
        ctx	(secp256k1_context*):   pointer to a context object
        pubkeys	(list):			list of pubkeys to add together
    Returns:
        (int, secp256k1_pubkey*):   	(1: the sum of the public keys is valid
                                        0: the sum of the public keys is not
                                        valid,
                                        pointer to a public key object for
                                        placing the resulting public key
                                        (cannot be NULL))
    '''
    # Validate context
    utils.validate_context(ctx)

    # Number of public keys to add together
    n = len(pubkeys)

    # Pointer to array of pointers to public keys (cannot be null)
    ins = ffi.new('secp256k1_pubkey[]', n)
    ins = ffi.new('secp256k1_pubkey*[]',
                  [pk.as_cffi_pointer() for pk in pubkeys])

    # Pointer to a public key object for placing the resulting public key
    out = ffi.new('secp256k1_pubkey *')

    return (lib.secp256k1_ec_pubkey_combine(ctx, out, ins, n), out)
예제 #2
0
def ec_pubkey_parse(ctx, ser_pub):
    '''Parse a variable-length public key into the pubkey object.
    This function supports parsing compressed (33 bytes, header byte 0x02 or
    0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes,
    header byte 0x06 or 0x07) format public keys.
    Args:
        ctx     (secp256k1_context*):   secp256k1 context object
        ser_pub   (bytes):                pointer to a serialized public key
    Returns:
        (int, secp256k1_pubkey*):       (1 if the public key was fully
                                        valid. 0 if the public key could
                                        not be parsed or is invalid,
                                        pointer to a secp256k1_pubkey
                                        containing an initialized public
                                        key)
    '''
    # Validate context
    utils.validate_context(ctx)

    # Validate input
    utils.validate_public_key_ser(ser_pub)

    # Length of the array pointed to by input
    inputlen = len(ser_pub)

    # Pointer to a pubkey object. If 1 is returned, it is set to a parsed
    # version of input. If not, its value is undefined.
    pubkey = ffi.new('secp256k1_pubkey *')

    return (lib.secp256k1_ec_pubkey_parse(ctx, pubkey, ser_pub,
                                          inputlen), pubkey)
예제 #3
0
def ec_pubkey_create(ctx, seckey):
    '''Compute the public key for a secret key.
    Args:
        ctx     (secp256k1_context*):   a secp256k1 context object, initialized
                                        for signing (cannot be NULL)
        seckey  (bytes):                pointer to a 32-byte private key
                                        (cannot be NULL)
    Returns:
        (int, secp256k1_pubkey):        (1 if secret was valid, public key
                                        stores, 0 if secret was invalid, try
                                        again,
                                        pointer to the created public key
                                        (cannot be NULL))
    '''
    # Validate context
    utils.validate_context(ctx)

    # Validate secret key
    utils.validate_secret_key_ser(seckey)

    # Pointer to the created public key
    pubkey = ffi.new('secp256k1_pubkey *')

    # Compute the public key for a secret key
    return (lib.secp256k1_ec_pubkey_create(ctx, pubkey, seckey), pubkey)
예제 #4
0
def ecdsa_signature_parse_der(ctx, ser_sig):
    '''Parse a DER ECDSA signature.

    This function will accept any valid DER encoded signature, even if the
    encoded numbers are out of range.

    After the call, sig will always be initialized. If parsing failed or the
    encoded numbers are out of range, signature validation with it is
    guaranteed to fail for every message and public key.

    Args:
        ctx     (secp256k1_context*):       a secp256k1 context object
        ser_sig   (bytes):                    a pointer to the signature to be
                                            parsed
    Returns:
        (int, secp256k1_ecdsa_signature*):  (1 when the signature could be
                                            parsed, 0 otherwise,
                                            a pointer to a signature object)
    '''
    # Validate context
    utils.validate_context(ctx)

    # Validate signature
    utils.validate_signature_ser(ser_sig)

    # Length of the array pointed to be input
    inputlen = len(ser_sig)

    # Pointer to a signature object
    sig = ffi.new('secp256k1_ecdsa_signature *')

    # Parse a DER ECDSA signature
    return (lib.secp256k1_ecdsa_signature_parse_der(ctx, sig, ser_sig,
                                                    inputlen), sig)
예제 #5
0
def ecdsa_signature_parse_compact(ctx, input64):
    '''Parse an ECDSA signature in compact (64 bytes) format.

    The signature must consist of a 32-byte big endian R value, followed by a
    32-byte big endian S value. If R or S fall outside of [0..order-1], the
    encoding is invalid. R and S with value 0 are allowed in the encoding.

    After the call, sig will always be initialized. If parsing failed or R or
    S are zero, the resulting sig value is guaranteed to fail validation for
    any message and public key.

    Args:
        ctx     (secp256k1_context*):       a secp256k1 context object
        input64 (bytes):                    a pointer to the 64-byte array to
                                            parse
    Returns:
        (int, secp256k1_ecdsa_signature*):  (1 when the signature could be
                                            parsed, 0 otherwise,
                                            a pointer to a signature object)
    '''
    # Validate context
    utils.validate_context(ctx)

    # Pointer to a signature object
    sig = ffi.new('secp256k1_ecdsa_signature *')

    # Parse an ECDSA signature in compact (64 bytes) format
    return (lib.secp256k1_ecdsa_signature_parse_compact(ctx, sig,
                                                        input64), sig)
예제 #6
0
def ec_pubkey_serialize(ctx, pubkey, flags):
    '''Serialize a pubkey object into a serialized byte sequence.
    Args:
        ctx     (secp256k1_context*):       a secp256k1 context object
        pubkey  (secp256k1_pubkey*):        a pointer to a secp256k1_pubkey
                                            containing an initialized public
                                            key
        flags   (int):                      SECP256K1_EC_COMPRESSED if
                                            serialization should be in
                                            compressed format, otherwise
                                            SECP256K1_EC_UNCOMPRESSED
    Returns:
        (int, ctype 'char[33]', size_t*):   (1,
                                            a pointer to a 65-byte (if
                                            compressed==0) or 33-byte (if
                                            compressed==1) byte array to place
                                            the serialized key in,
                                            Pointer to an integer which is
                                            initially set to the size of the
                                            output, and is overwritten with the
                                            written size)
    '''
    # Validate context
    utils.validate_context(ctx)

    # Validate public key
    utils.validate_public_key(pubkey)

    # Validate flags
    if flags == lib.SECP256K1_EC_COMPRESSED:
        publen = 33
    elif flags == lib.SECP256K1_EC_UNCOMPRESSED:
        publen = 65
    else:
        raise ValueError('Invalid serialized compression format flag.')

    # Pointer to a 33- or 65-byte array to place the serialized key in
    output = ffi.new('char[]', publen)

    # Pointer to an integer which is initially set to the size of the output,
    # and is overwritten with the written size
    outputlen = ffi.new('size_t *', publen)
    output_length = int(ffi.cast('uint32_t', outputlen[0]))

    return (lib.secp256k1_ec_pubkey_serialize(ctx, output, outputlen, pubkey,
                                              flags), output[0:output_length],
            outputlen)
예제 #7
0
def ecdsa_signature_serialize_der(ctx, sig, outputlen=74):
    '''Serialize an ECDSA signature in DER format.
    Args:
        ctx         (secp256k1_context*):           a secp256k1 context object
        sig         (secp256k1_ecdsa_signature*):   a pointer to an initialized
                                                    signature object
        outputlen   (int):                          pointer to a length of
                                                    output
    Returns:
        (int, unsigned char[], size_t*):            (1 if enough space was
                                                    available to serialize, 0
                                                    otherwise, a pointer to an
                                                    array to store the DER
                                                    serialization, a pointer to
                                                    a length of the
                                                    serialization (even if 0
                                                    was returned))
    '''
    # Validate context
    utils.validate_context(ctx)

    # Validate signature
    utils.validate_signature(sig)

    # Pointer to an array to store the DER serialization
    output = ffi.new('unsigned char[]', outputlen)

    # Pointer to a length integer
    outputlen = ffi.new('size_t *', outputlen)

    res = lib.secp256k1_ecdsa_signature_serialize_der(ctx, output, outputlen,
                                                      sig)

    output_length = int(ffi.cast('uint32_t', outputlen[0]))

    # Serialize an ECDSA signature in DER format
    return (res, output[0:output_length], outputlen)
예제 #8
0
def ecdsa_sign(ctx, msg32, seckey, noncefp=ffi.NULL, ndata=ffi.NULL):
    '''Create an ECDSA signature.
    The created signature is always in lower-S form. See
    secp256k1_ecdsa_signature_normalize for more details.
    Args:
        ctx     (secp256k1_context*):       a secp256k1 context object,
                                            initialized for signing
        msg32   (bytes):                    the 32-byte message hash being
                                            signed (cannot be NULL)
        seckey  (bytes):                    pointer to a 32-byte secret key
                                            (cannot be NULL)
        noncefp (secp256k1_nonce_function): pointer to a nonce generation
                                            function. If NULL,
                                            secp256k1_nonce_function_default
                                            is used
        ndata   (void*):                    pointer to arbitrary data used by
                                            the nonce generation function (can
                                            be NULL)
    Returns:
        (int, secp256k1_ecdsa_signature*):  (1: signature created, 0: the nonce
                                            generation function failed, or the
                                            private key was invalid,
                                            pointer to an array where the
                                            signature will be placed (cannot be
                                            NULL))
    '''
    # Validate context
    utils.validate_context(ctx)

    # Validate msg32
    utils.validate_msg32_ser(msg32)

    # Validate secret key
    utils.validate_secret_key_ser(seckey)

    # Validate noncefp
    utils.validate_noncefp(noncefp)

    # Validate ndata
    utils.validate_ndata(ndata)

    sig = ffi.new('secp256k1_ecdsa_signature *')

    return (lib.secp256k1_ecdsa_sign(ctx, sig, msg32, seckey, noncefp,
                                     ndata), sig)
예제 #9
0
def ecdsa_signature_serialize_compact(ctx, sig):
    '''Serialize an ECDSA signature in compact (64 byte) format.
    See secp256k1_ecdsa_signature_parse_compact for details about the encoding.
    Args:
        ctx (secp256k1_context*):           a secp256k1 context object
        sig (secp256k1_ecdsa_signature*):   a pointer to an initialized
                                            signature object
    Returns:
        (int, unsigned char):               (1,
                                            a pointer to a 64-byte array to
                                            store the compact serialization)
    '''
    # Validate context
    utils.validate_context(ctx)

    # Validate signature
    utils.validate_signature(sig)

    # Pointer to a 64-byte array to store the compact serialization
    output64 = ffi.new('unsigned char[]', 64)

    return (lib.secp256k1_ecdsa_signature_serialize_compact(
        ctx, output64, sig), output64)
예제 #10
0
def ecdsa_signature_normalize(ctx, sigout, sigin):
    '''Convert a signature to a normalized lower-S form.

    With ECDSA a third-party can forge a second distinct signature of the same
    message, given a single initial signature, but without knowing the key.
    This is done by negating the S value modulo the order of the curve,
    'flipping' the sign of the random point R which is not included in the
    signature.

    Forgery of the same message isn't universally problematic, but in systems
    where message malleability or uniqueness of signatures is important this
    can cause issues. This forgery can be blocked by all verifiers forcing
    signers to use a normalized form.

    The lower-S form reduces the size of signatures slightly on average when
    variable length encodings (such as DER) are used and is cheap to verify,
    making it a good choice. Security of always using lower-S is assured
    because anyone can trivially modify a signature after the fact to enforce
    this property anyway.

    The lower S value is always between 0x1 and
    0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,
    inclusive.

    No other forms of ECDSA malleability are known and none seem likely, but
    there is no formal proof that ECDSA, even with this additional restriction,
    is free of other malleability. Commonly used serialization schemes will
    also accept various non-unique encodings, so care should be taken when this
    property is required for an application.

    The secp256k1_ecdsa_sign function will by default create signatures in the
    lower-S form, and secp256k1_ecdsa_verify will not accept others. In case
    signatures come from a system that cannot enforce this property,
    secp256k1_ecdsa_signature_normalize must be called before verification.

    Args:
        ctx     (secp256k1_context*):           a secp256k1 context object
        sigin   (secp256k1_ecdsa_signature*):   a pointer to a signature to
                                                check/normalize (cannot be
                                                NULL, can be identical to
                                                sigout)
    Returns:
        (int, secp256k1_ecdsa_signature*):      (1 if sigin was not normalized,
                                                0 if it already was,
                                                a pointer to a signature to
                                                fill with the normalized form,
                                                or copy if the input was
                                                already normalized. (can be
                                                NULL if you're only interested
                                                in whether the input was
                                                already normalized).
    '''
    # Validate context
    utils.validate_context(ctx)

    # Validate sig
    utils.validate_signature(sigin)

    # Pointer to a signature to fill witht he normalized form, or copy if the
    # input was already normalized
    sigout = ffi.new('secp256k1_ecdsa_signature *')

    return (lib.secp256k1_ecdsa_signature_normalize(ctx, sigout,
                                                    sigin), sigout)