Ejemplo n.º 1
0
def _cdata_signature_to_der(signature):
    '''Return a DER-serialized signature; bytes of length at most 72.'''
    size = ffi.new('size_t *', MAX_SIG_LENGTH)
    data = ffi.new(f'unsigned char [{MAX_SIG_LENGTH}]')
    result = lib.secp256k1_ecdsa_signature_serialize_der(CONTEXT, data, size, signature)
    # Failure should never happen - MAX_SIG_LENGTH bytes is always enough
    assert result
    return bytes(ffi.buffer(data, size[0]))
Ejemplo n.º 2
0
    def to_bytes(self, *, compressed=None):
        '''Serialize a PublicKey to bytes.'''
        if (self._compressed if compressed is None else compressed):
            length, flag = 33, EC_COMPRESSED
        else:
            length, flag = 65, EC_UNCOMPRESSED
        result = ffi.new(f'unsigned char [{length}]')
        rlength = ffi.new('size_t *', length)

        lib.secp256k1_ec_pubkey_serialize(CONTEXT, result, rlength, self._public_key, flag)
        return bytes(ffi.buffer(result, length))
Ejemplo n.º 3
0
def der_signature_to_compact(der_sig):
    '''Returns 64 bytes representing r and s as concatenated 32-byte big-endian numbers.'''
    cdata_sig = _der_signature_to_cdata(der_sig)
    compact_sig = ffi.new('unsigned char [64]')
    lib.secp256k1_ecdsa_signature_serialize_compact(CONTEXT, compact_sig,
                                                    cdata_sig)
    return bytes(ffi.buffer(compact_sig))
Ejemplo n.º 4
0
def public_key_from_recoverable_signature(recoverable_sig, msg_hash):
    cdata_recsig = _cdata_recsig(recoverable_sig)
    public_key = ffi.new('secp256k1_pubkey *')
    if not lib.secp256k1_ecdsa_recover(CONTEXT, public_key, cdata_recsig,
                                       msg_hash):
        raise InvalidSignatureError('invalid recoverable signature')
    return public_key
Ejemplo n.º 5
0
def compact_signature_to_der(compact_sig):
    if not (isinstance(compact_sig, bytes) and len(compact_sig) == 64):
        raise InvalidSignatureError('compact signature must be 64 bytes')
    cdata_sig = ffi.new('secp256k1_ecdsa_signature *')
    lib.secp256k1_ecdsa_signature_parse_compact(CONTEXT, cdata_sig,
                                                compact_sig)
    return _cdata_signature_to_der(cdata_sig)
Ejemplo n.º 6
0
def verify_recoverable_signature(recoverable_sig, msg_hash, public_key):
    # Convert a 65-byte recoverable sig to a CDATA one
    cdata_sig = ffi.new('secp256k1_ecdsa_signature *')
    cdata_recsig = _cdata_recsig(recoverable_sig)
    # Always succeeds
    lib.secp256k1_ecdsa_recoverable_signature_convert(CONTEXT, cdata_sig, cdata_recsig)
    return bool(lib.secp256k1_ecdsa_verify(CONTEXT, cdata_sig, msg_hash, public_key))
Ejemplo n.º 7
0
 def multiply(self, value):
     '''Return a new PrivateKey instance multiplying value by our secret.'''
     secret = ffi.new('unsigned char [32]', self._secret)
     if not lib.secp256k1_ec_privkey_tweak_mul(CONTEXT, secret,
                                               _to_32_bytes(value)):
         raise ValueError('value or result out of range')
     return PrivateKey(secret, self._compressed, self._coin)
Ejemplo n.º 8
0
    def from_bytes(cls, data):
        '''Construct a PublicKey from its serialized bytes.

        data should be bytes of length 33 or 65.'''
        public_key = ffi.new('secp256k1_pubkey *')
        if not lib.secp256k1_ec_pubkey_parse(CONTEXT, public_key, data, len(data)):
            raise ValueError('invalid public key')
        return cls(public_key, len(data) == 33)
Ejemplo n.º 9
0
    def add(self, value):
        '''Return a new PublicKey instance formed by adding value*G to this one.

        Preserves compressed / uncompressed serialization.'''
        public_key = ffi.new('secp256k1_pubkey *', self._public_key[0])
        if not lib.secp256k1_ec_pubkey_tweak_add(CONTEXT, public_key, _to_32_bytes(value)):
            raise ValueError('value or result out of range')
        return PublicKey(public_key, self._compressed, self._network)
Ejemplo n.º 10
0
 def _secp256k1_public_key(self):
     '''Construct a wrapped secp256k1 PublicKey.'''
     public_key = ffi.new('secp256k1_pubkey *')
     created = lib.secp256k1_ec_pubkey_create(CONTEXT, public_key, self._secret)
     # Only possible if client code has mucked with the private key's internals
     if not created:
         raise RuntimeError('invalid private key')
     return public_key
Ejemplo n.º 11
0
def sign_recoverable(msg_hash, secret):
    '''Sign a message hash and return a 65-byte recoverable signature.  This is a 64-byte
    compact signature with a recovery ID byte appended; and from which the public key can
    be immediately recovered.
    '''
    rec_signature = ffi.new('secp256k1_ecdsa_recoverable_signature *')
    if not lib.secp256k1_ecdsa_sign_recoverable(
            CONTEXT, rec_signature, msg_hash, secret, ffi.NULL, ffi.NULL):
        raise ValueError('invalid private key')

    # Serialize its as a 65-byte compact recoverable signature
    output = ffi.new(f'unsigned char [{CDATA_SIG_LENGTH}]')
    recid = ffi.new('int *')

    lib.secp256k1_ecdsa_recoverable_signature_serialize_compact(
        CONTEXT, output, recid, rec_signature)

    # recid is 0, 1, 2 or 3.
    return bytes(ffi.buffer(output, CDATA_SIG_LENGTH)) + bytes([recid[0]])
Ejemplo n.º 12
0
    def multiply(self, value):
        '''Return a new PublicKey instance formed by multiplying this one by value (i.e. adding
        it to itself value times).

        Preserves compressed / uncompressed serialization.
        '''
        public_key = ffi.new('secp256k1_pubkey *', self._public_key[0])
        if not lib.secp256k1_ec_pubkey_tweak_mul(CONTEXT, public_key, _to_32_bytes(value)):
            raise ValueError('value or result out of range')
        return PublicKey(public_key, self._compressed, self._network)
Ejemplo n.º 13
0
def compact_signature_to_der(compact_sig, raise_on_overflow=False):
    '''If R or S are too large (>= the curve order) returns a der signature with both set to
    zero, unless raise_on_overflow is True.
    '''
    if not (isinstance(compact_sig, bytes) and len(compact_sig) == 64):
        raise InvalidSignature('compact signature must be 64 bytes')
    cdata_sig = ffi.new('secp256k1_ecdsa_signature *')
    overflow = not lib.secp256k1_ecdsa_signature_parse_compact(CONTEXT, cdata_sig, compact_sig)
    if overflow and raise_on_overflow:
        raise InvalidSignature('R or S value overflows')
    return _cdata_signature_to_der(cdata_sig)
Ejemplo n.º 14
0
def _cdata_recsig(recoverable_sig):
    if len(recoverable_sig) != 65:
        raise InvalidSignatureError('invalid recoverable signature')
    cdata_recsig = ffi.new('secp256k1_ecdsa_recoverable_signature *')
    recid = recoverable_sig[-1]
    if not 0 <= recid <= 3:
        raise InvalidSignatureError('invalid recoverable signature')
    if not lib.secp256k1_ecdsa_recoverable_signature_parse_compact(
            CONTEXT, cdata_recsig, recoverable_sig, recid):
        raise InvalidSignatureError('invalid recoverable signature')
    return cdata_recsig
Ejemplo n.º 15
0
    def combine_keys(cls, public_keys):
        '''Return a new PublicKey equal to the sum of the given PublicKeys.

        The result takes its default compressed and network attributes from the first public key.
        '''
        lib_keys = [pk._public_key for pk in public_keys]
        if not lib_keys:
            raise ValueError('no public keys to combine')
        public_key = ffi.new('secp256k1_pubkey *')
        if not lib.secp256k1_ec_pubkey_combine(CONTEXT, public_key, lib_keys, len(lib_keys)):
            raise ValueError('the sum of the public keys is invalid')
        return cls(public_key, public_keys[0]._compressed, public_keys[0]._network)
Ejemplo n.º 16
0
def _der_signature_to_cdata(der_sig):
    cdata_sig = ffi.new('secp256k1_ecdsa_signature *')
    if not lib.secp256k1_ecdsa_signature_parse_der(CONTEXT, cdata_sig, der_sig,
                                                   len(der_sig)):
        raise InvalidSignatureError('invalid DER-encoded signature')
    return cdata_sig
Ejemplo n.º 17
0
def sign_der(msg_hash, secret):
    cdata_sig = ffi.new('secp256k1_ecdsa_signature *')
    if not lib.secp256k1_ecdsa_sign(CONTEXT, cdata_sig, msg_hash, secret,
                                    ffi.NULL, ffi.NULL):
        raise ValueError('invalid private key')
    return _cdata_signature_to_der(cdata_sig)