Copyright | (c) 2024 Jared Tobin |
---|---|
License | MIT |
Maintainer | Jared Tobin <jared@ppad.tech> |
Safe Haskell | None |
Language | Haskell2010 |
Crypto.Curve.Secp256k1
Description
Synopsis
- _CURVE_Q :: Integer
- _CURVE_P :: Integer
- remQ :: Integer -> Integer
- modQ :: Integer -> Integer
- type Pub = Projective
- derive_pub :: Integer -> Pub
- derive_pub' :: Context -> Integer -> Pub
- _CURVE_G :: Projective
- _CURVE_ZERO :: Projective
- parse_int256 :: ByteString -> Integer
- parse_point :: ByteString -> Maybe Projective
- parse_sig :: ByteString -> Maybe ECDSA
- serialize_point :: Projective -> ByteString
- ecdh :: Projective -> Integer -> ByteString
- sign_schnorr :: Integer -> ByteString -> ByteString -> ByteString
- verify_schnorr :: ByteString -> Pub -> ByteString -> Bool
- data ECDSA = ECDSA {}
- sign_ecdsa :: Integer -> ByteString -> ECDSA
- sign_ecdsa_unrestricted :: Integer -> ByteString -> ECDSA
- verify_ecdsa :: ByteString -> Pub -> ECDSA -> Bool
- verify_ecdsa_unrestricted :: ByteString -> Pub -> ECDSA -> Bool
- data Context
- precompute :: Context
- sign_schnorr' :: Context -> Integer -> ByteString -> ByteString -> ByteString
- verify_schnorr' :: Context -> ByteString -> Pub -> ByteString -> Bool
- sign_ecdsa' :: Context -> Integer -> ByteString -> ECDSA
- sign_ecdsa_unrestricted' :: Context -> Integer -> ByteString -> ECDSA
- verify_ecdsa' :: Context -> ByteString -> Pub -> ECDSA -> Bool
- verify_ecdsa_unrestricted' :: Context -> ByteString -> Pub -> ECDSA -> Bool
Field and group parameters
remQ :: Integer -> Integer Source #
Division modulo secp256k1 group order, when argument is nonnegative.
secp256k1 points
type Pub = Projective Source #
A Schnorr and ECDSA-flavoured alias for a secp256k1 point.
derive_pub :: Integer -> Pub Source #
Derive a public key (i.e., a secp256k1 point) from the provided secret.
>>>
import qualified System.Entropy as E
>>>
sk <- fmap parse_int256 (E.getEntropy 32)
>>>
derive_pub sk
"<secp256k1 point>"
derive_pub' :: Context -> Integer -> Pub Source #
The same as derive_pub
, except uses a Context
to optimise
internal calculations.
>>>
import qualified System.Entropy as E
>>>
sk <- fmap parse_int256 (E.getEntropy 32)
>>>
let !tex = precompute
>>>
derive_pub' tex sk
"<secp256k1 point>"
_CURVE_G :: Projective Source #
secp256k1 generator point.
_CURVE_ZERO :: Projective Source #
secp256k1 zero point, point at infinity, or monoidal identity.
Parsing
parse_int256 :: ByteString -> Integer Source #
Parse a positive 256-bit Integer
, e.g. a Schnorr or ECDSA
secret key.
>>>
import qualified Data.ByteString as BS
>>>
parse_int256 (BS.replicate 32 0xFF)
<2^256 - 1>
parse_point :: ByteString -> Maybe Projective Source #
Parse compressed secp256k1 point (33 bytes), uncompressed point (65 bytes), or BIP0340-style point (32 bytes).
>>>
parse_point <33-byte compressed point>
Just <Pub>>>>
parse_point <65-byte uncompressed point>
Just <Pub>>>>
parse_point <32-byte bip0340 public key>
Just <Pub>>>>
parse_point <anything else>
Nothing
parse_sig :: ByteString -> Maybe ECDSA Source #
Parse an ECDSA signature encoded in 64-byte "compact" form.
>>>
parse_sig <64-byte compact signature>
"<ecdsa signature>"
Serializing
serialize_point :: Projective -> ByteString Source #
Serialize a secp256k1 point in 33-byte compressed form.
>>>
serialize_point pub
"<33-byte compressed point>"
ECDH
Arguments
:: Projective | public key |
-> Integer | secret key |
-> ByteString | shared secret |
Compute a shared secret, given a secret key and public secp256k1 point, via Elliptic Curve Diffie-Hellman (ECDH).
The shared secret is the SHA256 hash of the x-coordinate of the point obtained by scalar multiplication.
>>>
let sec_alice = 0x03 -- contrived
>>>
let sec_bob = 2 ^ 128 - 1 -- contrived
>>>
let pub_alice = derive_pub sec_alice
>>>
let pub_bob = derive_pub sec_bob
>>>
let secret_as_computed_by_alice = ecdh pub_bob sec_alice
>>>
let secret_as_computed_by_bob = ecdh pub_alice sec_bob
>>>
secret_as_computed_by_alice == secret_as_computed_by_bob
True
BIP0340 Schnorr signatures
Arguments
:: Integer | secret key |
-> ByteString | message |
-> ByteString | 32 bytes of auxilliary random data |
-> ByteString | 64-byte Schnorr signature |
Create a 64-byte Schnorr signature for the provided message, using the provided secret key.
BIP0340 recommends that 32 bytes of fresh auxiliary entropy be
generated and added at signing time as additional protection
against side-channel attacks (namely, to thwart so-called "fault
injection" attacks). This entropy is supplemental to security,
and the cryptographic security of the signature scheme itself does
not rely on it, so it is not strictly required; 32 zero bytes can
be used in its stead (and can be supplied via mempty
).
>>>
import qualified System.Entropy as E
>>>
aux <- E.getEntropy 32
>>>
sign_schnorr sec msg aux
"<64-byte schnorr signature>"
Arguments
:: ByteString | message |
-> Pub | public key |
-> ByteString | 64-byte Schnorr signature |
-> Bool |
Verify a 64-byte Schnorr signature for the provided message with the supplied public key.
>>>
verify_schnorr msg pub <valid signature>
True>>>
verify_schnorr msg pub <invalid signature>
False
RFC6979 ECDSA
An ECDSA signature.
Instances
Generic ECDSA Source # | |||||
Defined in Crypto.Curve.Secp256k1 Associated Types
| |||||
Show ECDSA Source # | |||||
Eq ECDSA Source # | |||||
type Rep ECDSA Source # | |||||
Defined in Crypto.Curve.Secp256k1 type Rep ECDSA = D1 ('MetaData "ECDSA" "Crypto.Curve.Secp256k1" "ppad-secp256k1-0.3.0-2RiLeGP2i6sFDQENTGajra" 'False) (C1 ('MetaCons "ECDSA" 'PrefixI 'True) (S1 ('MetaSel ('Just "ecdsa_r") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Integer) :*: S1 ('MetaSel ('Just "ecdsa_s") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Integer))) |
Arguments
:: Integer | secret key |
-> ByteString | message |
-> ECDSA |
Produce an ECDSA signature for the provided message, using the provided private key.
sign_ecdsa
produces a "low-s" signature, as is commonly required
in applications using secp256k1. If you need a generic ECDSA
signature, use sign_ecdsa_unrestricted
.
>>>
sign_ecdsa sec msg
"<ecdsa signature>"
sign_ecdsa_unrestricted Source #
Arguments
:: Integer | secret key |
-> ByteString | message |
-> ECDSA |
Produce an ECDSA signature for the provided message, using the provided private key.
sign_ecdsa_unrestricted
produces an unrestricted ECDSA signature,
which is less common in applications using secp256k1 due to the
signature's inherent malleability. If you need a conventional
"low-s" signature, use sign_ecdsa
.
>>>
sign_ecdsa_unrestricted sec msg
"<ecdsa signature>"
Arguments
:: ByteString | message |
-> Pub | public key |
-> ECDSA | signature |
-> Bool |
Verify a "low-s" ECDSA signature for the provided message and public key,
Fails to verify otherwise-valid "high-s" signatures. If you need to
verify generic ECDSA signatures, use verify_ecdsa_unrestricted
.
>>>
verify_ecdsa msg pub valid_sig
True>>>
verify_ecdsa msg pub invalid_sig
False
verify_ecdsa_unrestricted Source #
Arguments
:: ByteString | message |
-> Pub | public key |
-> ECDSA | signature |
-> Bool |
Verify an unrestricted ECDSA signature for the provided message and public key.
>>>
verify_ecdsa_unrestricted msg pub valid_sig
True>>>
verify_ecdsa_unrestricted msg pub invalid_sig
False
Fast variants
Precomputed multiples of the secp256k1 base or generator point.
Instances
Generic Context Source # | |||||
Defined in Crypto.Curve.Secp256k1 Associated Types
| |||||
Show Context Source # | |||||
Eq Context Source # | |||||
type Rep Context Source # | |||||
Defined in Crypto.Curve.Secp256k1 type Rep Context = D1 ('MetaData "Context" "Crypto.Curve.Secp256k1" "ppad-secp256k1-0.3.0-2RiLeGP2i6sFDQENTGajra" 'False) (C1 ('MetaCons "Context" 'PrefixI 'True) (S1 ('MetaSel ('Just "ctxW") 'SourceUnpack 'SourceStrict 'DecidedStrict) (Rec0 Int) :*: S1 ('MetaSel ('Just "ctxArray") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 (Array Projective)))) |
precompute :: Context Source #
Create a secp256k1 context by precomputing multiples of the curve's generator point.
This should be used once to create a Context
to be reused
repeatedly afterwards.
>>>
let !tex = precompute
>>>
sign_ecdsa' tex sec msg
>>>
sign_schnorr' tex sec msg aux
Arguments
:: Context | secp256k1 context |
-> Integer | secret key |
-> ByteString | message |
-> ByteString | 32 bytes of auxilliary random data |
-> ByteString | 64-byte Schnorr signature |
The same as sign_schnorr
, except uses a Context
to optimise
internal calculations.
You can expect about a 2x performance increase when using this
function, compared to sign_schnorr
.
>>>
import qualified System.Entropy as E
>>>
aux <- E.getEntropy 32
>>>
let !tex = precompute
>>>
sign_schnorr' tex sec msg aux
"<64-byte schnorr signature>"
Arguments
:: Context | secp256k1 context |
-> ByteString | message |
-> Pub | public key |
-> ByteString | 64-byte Schnorr signature |
-> Bool |
The same as verify_schnorr
, except uses a Context
to optimise
internal calculations.
You can expect about a 1.5x performance increase when using this
function, compared to verify_schnorr
.
>>>
let !tex = precompute
>>>
verify_schnorr' tex msg pub <valid signature>
True>>>
verify_schnorr' tex msg pub <invalid signature>
False
Arguments
:: Context | secp256k1 context |
-> Integer | secret key |
-> ByteString | message |
-> ECDSA |
The same as sign_ecdsa
, except uses a Context
to optimise internal
calculations.
You can expect about a 10x performance increase when using this
function, compared to sign_ecdsa
.
>>>
let !tex = precompute
>>>
sign_ecdsa' tex sec msg
"<ecdsa signature>"
sign_ecdsa_unrestricted' Source #
Arguments
:: Context | secp256k1 context |
-> Integer | secret key |
-> ByteString | message |
-> ECDSA |
The same as sign_ecdsa_unrestricted
, except uses a Context
to
optimise internal calculations.
You can expect about a 10x performance increase when using this
function, compared to sign_ecdsa_unrestricted
.
>>>
let !tex = precompute
>>>
sign_ecdsa_unrestricted' tex sec msg
"<ecdsa signature>"
Arguments
:: Context | secp256k1 context |
-> ByteString | message |
-> Pub | public key |
-> ECDSA | signature |
-> Bool |
The same as verify_ecdsa
, except uses a Context
to optimise
internal calculations.
You can expect about a 2x performance increase when using this
function, compared to verify_ecdsa
.
>>>
let !tex = precompute
>>>
verify_ecdsa' tex msg pub valid_sig
True>>>
verify_ecdsa' tex msg pub invalid_sig
False
verify_ecdsa_unrestricted' Source #
Arguments
:: Context | secp256k1 context |
-> ByteString | message |
-> Pub | public key |
-> ECDSA | signature |
-> Bool |
The same as verify_ecdsa_unrestricted
, except uses a Context
to
optimise internal calculations.
You can expect about a 2x performance increase when using this
function, compared to verify_ecdsa_unrestricted
.
>>>
let !tex = precompute
>>>
verify_ecdsa_unrestricted' tex msg pub valid_sig
True>>>
verify_ecdsa_unrestricted' tex msg pub invalid_sig
False