mte/unikernel/duniverse/mirage-crypto/ec/mirage_crypto_ec.mli
2025-11-11 02:07:51 +01:00

224 lines
7.9 KiB
OCaml

(** {1 Elliptic curve cryptography} *)
(** Mirage-crypto-ec implements public key cryptography with named elliptic
curves. Ephemeral key exchanges with {{!Dh}Diffie-Hellman} and
{{!Dsa}digital signatures (ECDSA)} are implemented.
The arithmetic operations uses code generated by
{{:https://github.com/mit-plv/fiat-crypto}fiat-crypto} which is proven to
consume a constant amount of time, independent of the input values.
*)
type error = [
| `Invalid_range
| `Invalid_format
| `Invalid_length
| `Not_on_curve
| `At_infinity
| `Low_order
]
(** The type for errors. *)
val pp_error : Format.formatter -> error -> unit
(** Pretty printer for errors *)
exception Message_too_long
(** Raised if the provided message is too long for the curve. *)
(** Diffie-Hellman key exchange. *)
module type Dh = sig
type secret
(** Type for private keys. *)
val secret_of_octets : ?compress:bool -> string ->
(secret * string, error) result
(** [secret_of_octets ~compress secret] decodes the provided buffer as
{!secret}. If [compress] is provided and [true] (defaults to [false]),
the shared part will be compressed. May result in an error if the buffer
had an invalid length or was not in bounds. *)
val secret_to_octets : secret -> string
(** [secret_to_octets secret] encodes the provided secret into a freshly
allocated buffer. *)
val gen_key : ?compress:bool -> ?g:Mirage_crypto_rng.g -> unit ->
secret * string
(** [gen_key ~compress ~g ()] generates a private and a public key for
Ephemeral Diffie-Hellman. If [compress] is provided and [true] (defaults
to [false]), the shared part will be compressed. The returned key pair
MUST only be used for a single key exchange.
The generated private key is checked to be greater than zero and lower
than the group order meaning the public key cannot be the point at
inifinity. *)
val key_exchange : secret -> string -> (string, error) result
(** [key_exchange secret received_public_key] performs Diffie-Hellman key
exchange using your secret and the data received from the other party.
Returns the shared secret or an error if the received data is wrongly
encoded, doesn't represent a point on the curve or represent the point
at infinity.
The shared secret is returned as is i.e. not stripped from leading 0x00
bytes.
The public key encoding is described
{{:http://www.secg.org/sec1-v2.pdf}in SEC 1} from SECG. *)
end
(** Digital signature algorithm. *)
module type Dsa = sig
type priv
(** The type for private keys. *)
type pub
(** The type for public keys. *)
val byte_length : int
(** [byte_length] is the size of a ECDSA signature in bytes. *)
val bit_length : int
(** [bit_length] is the number of significant bits in a ECDSA signature *)
(** {2 Serialisation} *)
val priv_of_octets : string -> (priv, error) result
(** [priv_of_octets buf] decodes a private key from the buffer [buf]. If the
provided data is invalid, an error is returned. *)
val priv_to_octets : priv -> string
(** [priv_to_octets p] encode the private key [p] to a buffer. *)
val pub_of_octets : string -> (pub, error) result
(** [pub_of_octets buf] decodes a public key from the buffer [buf]. If the
provided data is invalid, an error is returned. *)
val pub_to_octets : ?compress:bool -> pub -> string
(** [pub_to_octets ~compress p] encodes the public key [p] into a buffer.
If [compress] is provided and [true] (default [false]), the compressed
representation is returned. *)
(** {2 Deriving the public key} *)
val pub_of_priv : priv -> pub
(** [pub_of_priv p] extracts the public key from the private key [p]. *)
(** {2 Key generation} *)
val generate : ?g:Mirage_crypto_rng.g -> unit -> priv * pub
(** [generate ~g ()] generates a key pair. *)
(** {2 Cryptographic operations} *)
val sign : key:priv -> ?k:string -> string -> string * string
(** [sign ~key ~k digest] signs the message [digest] using the private
[key]. The [digest] is not processed further - it should be the hash of
the message to sign. If [k] is not provided, it is computed using the
deterministic construction from RFC 6979. The result is a pair of [r]
and [s].
Warning: there {{:https://www.hertzbleed.com/2h2b.pdf}are}
{{:https://www.hertzbleed.com/hertzbleed.pdf}attacks} that recover the
private key from a power and timing analysis of the RFC 6979 computation
of [k] - thus it is advised to provide a good nonce ([k]) explicitly,
which is independent of key and digest.
@raise Invalid_argument if [k] is not suitable or not in range.
@raise Message_too_long if the bit size of [msg] exceeds the curve. *)
val verify : key:pub -> string * string -> string -> bool
(** [verify ~key (r, s) digest] verifies the signature [r, s] on the message
[digest] with the public [key]. The return value is [true] if verification
was successful, [false] otherwise. If the message has more bits than the
group order, the result is false. *)
(** [K_gen] can be instantiated over a hashing module to obtain an RFC6979
compliant [k]-generator for that hash. *)
module K_gen (H : Digestif.S) : sig
val generate : key:priv -> string -> string
(** [generate ~key digest] deterministically takes the given private key
and message digest to a [k] suitable for seeding the signing process. *)
end
(** {2 Misc} *)
(** Operations to precompute useful data meant to be hardcoded in
[mirage-crypto-ec] before compilation *)
module Precompute : sig
val generator_tables : unit -> string array array array
(** Return an array of shape (Fe_length * 2, 15, 3) containing multiples of
the generator point for the curve. Useful only to bootstrap tables
necessary for scalar multiplication. *)
end
end
(** Elliptic curve with Diffie-Hellman and DSA. *)
module type Dh_dsa = sig
(** Diffie-Hellman key exchange. *)
module Dh : Dh
(** Digital signature algorithm. *)
module Dsa : Dsa
end
(** The NIST P-256 curve, also known as SECP256R1. *)
module P256 : Dh_dsa
(** The NIST P-384 curve, also known as SECP384R1. *)
module P384 : Dh_dsa
(** The NIST P-521 curve, also known as SECP521R1. *)
module P521 : Dh_dsa
(** Curve 25519 Diffie-Hellman, also known as X25519. *)
module X25519 : Dh
(** Curve 25519 DSA, also known as Ed25519. *)
module Ed25519 : sig
type priv
(** The type for private keys. *)
type pub
(** The type for public keys. *)
(** {2 Serialisation} *)
val priv_of_octets : string -> (priv, error) result
(** [priv_of_octets buf] decodes a private key from the buffer [buf]. If the
provided data is invalid, an error is returned. *)
val priv_to_octets : priv -> string
(** [priv_to_octets p] encode the private key [p] to a buffer. *)
val pub_of_octets : string -> (pub, error) result
(** [pub_of_octets buf] decodes a public key from the buffer [buf]. If the
provided data is invalid, an error is returned. *)
val pub_to_octets : pub -> string
(** [pub_to_octets p] encodes the public key [p] into a buffer. *)
(** {2 Deriving the public key} *)
val pub_of_priv : priv -> pub
(** [pub_of_priv p] extracts the public key from the private key [p]. *)
(** {2 Key generation} *)
val generate : ?g:Mirage_crypto_rng.g -> unit -> priv * pub
(** [generate ~g ()] generates a key pair. *)
(** {2 Cryptographic operations} *)
val sign : key:priv -> string -> string
(** [sign ~key msg] signs the message [msg] using the private [key]. The
result is the concatenation of [r] and [s], as specified in RFC 8032. *)
val verify : key:pub -> string -> msg:string -> bool
(** [verify ~key signature msg] verifies the [signature] on the message
[msg] with the public [key]. The return value is [true] if verification
was successful, [false] otherwise. *)
end