Skip to content

Commit

Permalink
mirage-crypto-ec: move API to string (instead of cstruct)
Browse files Browse the repository at this point in the history
  • Loading branch information
hannesm committed Feb 29, 2024
1 parent 61721c2 commit db1c855
Show file tree
Hide file tree
Showing 8 changed files with 298 additions and 479 deletions.
67 changes: 35 additions & 32 deletions bench/speed.ml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ let msg =
Cstruct.memset b 0xAA;
b

let msg_str =
Cstruct.to_string msg

let msg_str_32 = String.sub msg_str 0 32
let msg_str_48 = String.sub msg_str 0 48
let msg_str_65 = String.sub msg_str 0 65

module PSS = Mirage_crypto_pk.Rsa.PSS(Mirage_crypto.Hash.SHA256)

let rsa_1024 =
Expand Down Expand Up @@ -181,34 +188,30 @@ let dh_secrets =

let ecdsa_p256 =
Result.get_ok
(Mirage_crypto_ec.P256.Dsa.priv_of_cstruct
(Cstruct.of_hex "089f4ffcccf9ba13fedd0942ef08cf2d909f32e2934ab5c93b6c99be5a9ff527"))
(Mirage_crypto_ec.P256.Dsa.priv_of_octets
(Uncommon.of_hex "089f4ffcccf9ba13fedd0942ef08cf2d909f32e2934ab5c93b6c99be5a9ff527"))

let ecdsa_p256_sig () =
Mirage_crypto_ec.P256.Dsa.sign ~key:ecdsa_p256 (Cstruct.sub msg 0 32)
let ecdsa_p256_sig () = Mirage_crypto_ec.P256.Dsa.sign ~key:ecdsa_p256 msg_str_32

let ecdsa_p384 =
Result.get_ok
(Mirage_crypto_ec.P384.Dsa.priv_of_cstruct
(Cstruct.of_hex "f5c0c9fb95178641af76f3831f41e2d37cfaafffc7e60172cfb089fe604b56a61c7c31a6904b3b5d08207a4b81e25ea5"))
(Mirage_crypto_ec.P384.Dsa.priv_of_octets
(Uncommon.of_hex "f5c0c9fb95178641af76f3831f41e2d37cfaafffc7e60172cfb089fe604b56a61c7c31a6904b3b5d08207a4b81e25ea5"))

let ecdsa_p384_sig () =
Mirage_crypto_ec.P384.Dsa.sign ~key:ecdsa_p384 (Cstruct.sub msg 0 48)
let ecdsa_p384_sig () = Mirage_crypto_ec.P384.Dsa.sign ~key:ecdsa_p384 msg_str_48

let ecdsa_p521 =
Result.get_ok
(Mirage_crypto_ec.P521.Dsa.priv_of_cstruct
(Cstruct.of_hex "00b18f60c0352ad8e3ef982f1ddfcf6eec7fa6caf0e6f368354a8b02b2d8ac1e059e309891e2bfa85791a5e71b40bdecbf902bf243dc3b0080495cf4d91c78728bd5"))
(Mirage_crypto_ec.P521.Dsa.priv_of_octets
(Uncommon.of_hex "00b18f60c0352ad8e3ef982f1ddfcf6eec7fa6caf0e6f368354a8b02b2d8ac1e059e309891e2bfa85791a5e71b40bdecbf902bf243dc3b0080495cf4d91c78728bd5"))

let ecdsa_p521_sig () =
Mirage_crypto_ec.P521.Dsa.sign ~key:ecdsa_p521 (Cstruct.sub msg 0 65)
let ecdsa_p521_sig () = Mirage_crypto_ec.P521.Dsa.sign ~key:ecdsa_p521 msg_str_65

let ed25519 =
Result.get_ok (Mirage_crypto_ec.Ed25519.priv_of_cstruct
(Cstruct.of_hex "3e0ab682171275c569fce9ca8bccd2d2771454a2300c3529f7a4d80b843883bc"))
Result.get_ok (Mirage_crypto_ec.Ed25519.priv_of_octets
(Uncommon.of_hex "3e0ab682171275c569fce9ca8bccd2d2771454a2300c3529f7a4d80b843883bc"))

let ed25519_sig () =
Mirage_crypto_ec.Ed25519.sign ~key:ed25519 msg
let ed25519_sig () = Mirage_crypto_ec.Ed25519.sign ~key:ed25519 msg_str

let ecdsas = [
("P256", `P256 (ecdsa_p256, ecdsa_p256_sig ()));
Expand All @@ -219,14 +222,14 @@ let ecdsas = [

let ecdh_shares =
[
("P256", `P256 (Mirage_crypto_ec.P256.Dh.secret_of_cs (Cstruct.of_hex "470d57706c7706b68a3f423aeaf4ff7fdd02494a10d3e381c3c11f7276802cdc") |> Result.get_ok |> fst,
Cstruct.of_hex "0411b3fc82721c269a19909a3b2fc26d9895826d0cfcbc1f7626e488f01f4ca6b5c5ed76adee7af81bb20b17cf231cbf0c67db0295d68d1d92c2d2a5a80638d78d"));
("P384", `P384 (Mirage_crypto_ec.P384.Dh.secret_of_cs (Cstruct.of_hex "ee55e29b61752d5a3e525656db8bd8fe6f94fab8aacc9e92acff4c4812bf7a6187aba46cc60ab8f08efcf2d574584b74") |> Result.get_ok |> fst,
Cstruct.of_hex "040489cf24bc80bf89fdfe9c05ecc39f6916ad4509d9398597950d3d24e828f6bf56ba4ad6d21ed7863bed68e413364bd4c7b1e9047d36124c6953be7c61209cb3fc56452f7305293783c7c0ed929d6c98c7bc97f60a72ed2269a8eb19bb7ee131"));
("P521", `P521 (Mirage_crypto_ec.P521.Dh.secret_of_cs (Cstruct.of_hex "00aa470ba1cc843ba314821e72de4cd299aec1f26e9d64a0d87db18a3da9f65c45ecfcc5617ff0d73b2e0e1cdff8048e01be5e20149412e7dbfab7feae249b1bfa4d") |> Result.get_ok |> fst,
Cstruct.of_hex "04001d1629eeb1c425f904d755330079d13c77da921e01cf50d717e0d6850a81a3902bb92a03faeacbd6289c1590685a6044b5e94dcfc41deb6a88db62a891b0b893bb00e42a66b2f013bdd0d27d8e07cb35fc3e2c2b22f93ecfd5eab7886197ca073c2c5e6831d65e2d0b8aa408438e49542f05f41c576df70e3caf5bb8227d483094ae58"));
("X25519", `X25519 (Mirage_crypto_ec.X25519.secret_of_cs (Cstruct.of_hex "4c6db7cf935bcf84026178d40c956af09d8e363203490d2c41625acb68b931a4") |> Result.get_ok |> fst,
Cstruct.of_hex "ca19193cf5c0b38c61aa01c172b2e93d16f750d0846277ad322de5e4fb332429"));
("P256", `P256 (Mirage_crypto_ec.P256.Dh.secret_of_octets (Uncommon.of_hex "470d57706c7706b68a3f423aeaf4ff7fdd02494a10d3e381c3c11f7276802cdc") |> Result.get_ok |> fst,
Uncommon.of_hex "0411b3fc82721c269a19909a3b2fc26d9895826d0cfcbc1f7626e488f01f4ca6b5c5ed76adee7af81bb20b17cf231cbf0c67db0295d68d1d92c2d2a5a80638d78d"));
("P384", `P384 (Mirage_crypto_ec.P384.Dh.secret_of_octets (Uncommon.of_hex "ee55e29b61752d5a3e525656db8bd8fe6f94fab8aacc9e92acff4c4812bf7a6187aba46cc60ab8f08efcf2d574584b74") |> Result.get_ok |> fst,
Uncommon.of_hex "040489cf24bc80bf89fdfe9c05ecc39f6916ad4509d9398597950d3d24e828f6bf56ba4ad6d21ed7863bed68e413364bd4c7b1e9047d36124c6953be7c61209cb3fc56452f7305293783c7c0ed929d6c98c7bc97f60a72ed2269a8eb19bb7ee131"));
("P521", `P521 (Mirage_crypto_ec.P521.Dh.secret_of_octets (Uncommon.of_hex "00aa470ba1cc843ba314821e72de4cd299aec1f26e9d64a0d87db18a3da9f65c45ecfcc5617ff0d73b2e0e1cdff8048e01be5e20149412e7dbfab7feae249b1bfa4d") |> Result.get_ok |> fst,
Uncommon.of_hex "04001d1629eeb1c425f904d755330079d13c77da921e01cf50d717e0d6850a81a3902bb92a03faeacbd6289c1590685a6044b5e94dcfc41deb6a88db62a891b0b893bb00e42a66b2f013bdd0d27d8e07cb35fc3e2c2b22f93ecfd5eab7886197ca073c2c5e6831d65e2d0b8aa408438e49542f05f41c576df70e3caf5bb8227d483094ae58"));
("X25519", `X25519 (Mirage_crypto_ec.X25519.secret_of_octets (Uncommon.of_hex "4c6db7cf935bcf84026178d40c956af09d8e363203490d2c41625acb68b931a4") |> Result.get_ok |> fst,
Uncommon.of_hex "ca19193cf5c0b38c61aa01c172b2e93d16f750d0846277ad322de5e4fb332429"));
]

let bm name f = (name, fun () -> f name)
Expand Down Expand Up @@ -309,20 +312,20 @@ let benchmarks = [
bm "ecdsa-sign" (fun name ->
let open Mirage_crypto_ec in
count name (fun (_, x) -> match x with
| `P256 (key, _) -> P256.Dsa.sign ~key (Cstruct.sub msg 0 32)
| `P384 (key, _) -> P384.Dsa.sign ~key (Cstruct.sub msg 0 48)
| `P521 (key, _) -> P521.Dsa.sign ~key (Cstruct.sub msg 0 65)
| `Ed25519 (key, _) -> Ed25519.sign ~key msg, Cstruct.empty
| `P256 (key, _) -> P256.Dsa.sign ~key msg_str_32
| `P384 (key, _) -> P384.Dsa.sign ~key msg_str_48
| `P521 (key, _) -> P521.Dsa.sign ~key msg_str_65
| `Ed25519 (key, _) -> Ed25519.sign ~key msg_str, ""
)
fst ecdsas);

bm "ecdsa-verify" (fun name ->
let open Mirage_crypto_ec in
count name (fun (_, x) -> match x with
| `P256 (key, signature) -> P256.Dsa.(verify ~key:(pub_of_priv key) signature (Cstruct.sub msg 0 32))
| `P384 (key, signature) -> P384.Dsa.(verify ~key:(pub_of_priv key) signature (Cstruct.sub msg 0 48))
| `P521 (key, signature) -> P521.Dsa.(verify ~key:(pub_of_priv key) signature (Cstruct.sub msg 0 65))
| `Ed25519 (key, signature) -> Ed25519.(verify ~key:(pub_of_priv key) signature ~msg)
| `P256 (key, signature) -> P256.Dsa.(verify ~key:(pub_of_priv key) signature msg_str_32)
| `P384 (key, signature) -> P384.Dsa.(verify ~key:(pub_of_priv key) signature msg_str_48)
| `P521 (key, signature) -> P521.Dsa.(verify ~key:(pub_of_priv key) signature msg_str_65)
| `Ed25519 (key, signature) -> Ed25519.(verify ~key:(pub_of_priv key) signature ~msg:msg_str)
) fst ecdsas);

bm "dh-secret" (fun name ->
Expand Down
136 changes: 28 additions & 108 deletions ec/mirage_crypto_ec.ml
Original file line number Diff line number Diff line change
Expand Up @@ -40,27 +40,27 @@ let bit_at buf i =

module type Dh = sig
type secret
val secret_of_cs : ?compress:bool -> Cstruct.t ->
(secret * Cstruct.t, error) result
val secret_of_octets : ?compress:bool -> string ->
(secret * string, error) result
val gen_key : ?compress:bool -> ?g:Mirage_crypto_rng.g -> unit ->
secret * Cstruct.t
val key_exchange : secret -> Cstruct.t -> (Cstruct.t, error) result
secret * string
val key_exchange : secret -> string -> (string, error) result
end

module type Dsa = sig
type priv
type pub
val byte_length : int
val priv_of_cstruct : Cstruct.t -> (priv, error) result
val priv_to_cstruct : priv -> Cstruct.t
val pub_of_cstruct : Cstruct.t -> (pub, error) result
val pub_to_cstruct : ?compress:bool -> pub -> Cstruct.t
val priv_of_octets : string -> (priv, error) result
val priv_to_octets : priv -> string
val pub_of_octets : string -> (pub, error) result
val pub_to_octets : ?compress:bool -> pub -> string
val pub_of_priv : priv -> pub
val generate : ?g:Mirage_crypto_rng.g -> unit -> priv * pub
val sign : key:priv -> ?k:Cstruct.t -> Cstruct.t -> Cstruct.t * Cstruct.t
val verify : key:pub -> Cstruct.t * Cstruct.t -> Cstruct.t -> bool
val sign : key:priv -> ?k:string -> string -> string * string
val verify : key:pub -> string * string -> string -> bool
module K_gen (H : Mirage_crypto.Hash.S) : sig
val generate : key:priv -> Cstruct.t -> Cstruct.t
val generate : key:priv -> string -> string
end
module Precompute : sig
val generator_tables : unit -> string array array array
Expand Down Expand Up @@ -506,33 +506,20 @@ module Make_dh (Param : Parameters) (P : Point) (S : Scalar) : Dh = struct
| Ok p -> Ok (p, share ?compress p)
| Error _ as e -> e

let secret_of_cs ?compress s =
Result.map (fun (p, share) -> p, Cstruct.of_string share)
(secret_of_octets ?compress (Cstruct.to_string s))

let rec generate_private_key ?g () =
let candidate = Mirage_crypto_rng.generate ?g Param.byte_length in
match S.of_octets (Cstruct.to_string candidate) with
let candidate = Cstruct.to_string (Mirage_crypto_rng.generate ?g Param.byte_length) in
match S.of_octets candidate with
| Ok secret -> secret
| Error _ -> generate_private_key ?g ()

let gen_key_octets ?compress ?g () =
let private_key = generate_private_key ?g () in
(private_key, share ?compress private_key)

let gen_key ?compress ?g () =
let private_key, share = gen_key_octets ?compress ?g () in
private_key, Cstruct.of_string share
let private_key = generate_private_key ?g () in
private_key, share ?compress private_key

let key_exchange_octets secret received =
let key_exchange secret received =
match point_of_octets received with
| Error _ as err -> err
| Ok shared -> Ok (P.x_of_finite_point (S.scalar_mult secret shared))

let key_exchange secret received =
match key_exchange_octets secret (Cstruct.to_string received) with
| Error _ as err -> err
| Ok shared -> Ok (Cstruct.of_string shared)
end

module type Foreign_n = sig
Expand Down Expand Up @@ -616,10 +603,6 @@ module Make_dsa (Param : Parameters) (F : Fn) (P : Point) (S : Scalar) (H : Mira

let priv_to_octets = S.to_octets

let priv_of_cstruct cs = priv_of_octets (Cstruct.to_string cs)

let priv_to_cstruct p = Cstruct.of_string (priv_to_octets p)

let padded msg =
let l = String.length msg in
let bl = Param.byte_length in
Expand All @@ -637,33 +620,12 @@ module Make_dsa (Param : Parameters) (F : Fn) (P : Point) (S : Scalar) (H : Mira
Bytes.blit_string msg 0 res (bl - l) (String.length msg) ;
Bytes.unsafe_to_string res )

let padded_cs msg =
let l = Cstruct.length msg in
let bl = Param.byte_length in
let first_byte_ok () =
match Param.first_byte_bits with
| None -> true
| Some m -> (Cstruct.get_uint8 msg 0) land (0xFF land (lnot m)) = 0
in
if l > bl || (l = bl && not (first_byte_ok ())) then
raise Message_too_long
else if l = bl then
msg
else
Cstruct.append (Cstruct.create (bl - l)) msg

(* RFC 6979: compute a deterministic k *)
module K_gen (H : Mirage_crypto.Hash.S) = struct
let drbg : 'a Mirage_crypto_rng.generator =
let module M = Mirage_crypto_rng.Hmac_drbg (H) in (module M)

let g ~key cs =
let g = Mirage_crypto_rng.create ~strict:true drbg in
Mirage_crypto_rng.reseed ~g
(Cstruct.append (Cstruct.of_string (S.to_octets key)) cs);
g

let g_octets ~key msg =
let g ~key msg =
let g = Mirage_crypto_rng.create ~strict:true drbg in
Mirage_crypto_rng.reseed ~g
(Cstruct.of_string (String.concat "" [ S.to_octets key ; msg ]));
Expand All @@ -672,16 +634,12 @@ module Make_dsa (Param : Parameters) (F : Fn) (P : Point) (S : Scalar) (H : Mira
(* take qbit length, and ensure it is suitable for ECDSA (> 0 & < n) *)
let gen g =
let rec go () =
let r = Mirage_crypto_rng.generate ~g Param.byte_length in
let r = Cstruct.to_string r in
let r = Cstruct.to_string (Mirage_crypto_rng.generate ~g Param.byte_length) in
if S.is_in_range r then r else go ()
in
go ()

(* let generate_octets ~key buf = gen (g ~key (Cstruct.of_string (padded buf))) *)

let generate ~key buf =
Cstruct.of_string (gen (g ~key (padded_cs buf)))
let generate ~key buf = gen (g ~key (padded buf))
end

module K_gen_default = K_gen(H)
Expand All @@ -692,11 +650,6 @@ module Make_dsa (Param : Parameters) (F : Fn) (P : Point) (S : Scalar) (H : Mira

let pub_to_octets ?(compress = false) pk = P.to_octets ~compress pk

let pub_of_cstruct cs = pub_of_octets (Cstruct.to_string cs)

let pub_to_cstruct ?compress p =
Cstruct.of_string (pub_to_octets ?compress p)

let generate ?g () =
(* FIPS 186-4 B 4.2 *)
let d =
Expand All @@ -719,10 +672,10 @@ module Make_dsa (Param : Parameters) (F : Fn) (P : Point) (S : Scalar) (H : Mira
let x = F.from_montgomery x in
Some (F.to_be_octets x)

let sign_octets ~key ?k msg =
let sign ~key ?k msg =
let msg = padded msg in
let e = F.from_be_octets msg in
let g = K_gen_default.g_octets ~key msg in
let g = K_gen_default.g ~key msg in
let rec do_sign g =
let again () =
match k with
Expand Down Expand Up @@ -754,13 +707,9 @@ module Make_dsa (Param : Parameters) (F : Fn) (P : Point) (S : Scalar) (H : Mira
in
do_sign g

let sign ~key ?k msg =
let r, s = sign_octets ~key ?k:(Option.map Cstruct.to_string k) (Cstruct.to_string msg) in
Cstruct.of_string r, Cstruct.of_string s

let pub_of_priv priv = S.scalar_mult_base priv

let verify_octets ~key (r, s) msg =
let verify ~key (r, s) msg =
try
let r = padded r and s = padded s in
if not (S.is_in_range r && S.is_in_range s) then
Expand Down Expand Up @@ -793,9 +742,6 @@ module Make_dsa (Param : Parameters) (F : Fn) (P : Point) (S : Scalar) (H : Mira
with
| Message_too_long -> false

let verify ~key (r, s) digest =
verify_octets ~key (Cstruct.to_string r, Cstruct.to_string s) (Cstruct.to_string digest)

module Precompute = struct
let generator_tables = S.generator_tables
end
Expand Down Expand Up @@ -971,38 +917,26 @@ module X25519 = struct

let public priv = scalar_mult priv basepoint

let gen_key_octets ?compress:_ ?g () =
let gen_key ?compress:_ ?g () =
let secret = Cstruct.to_string (Mirage_crypto_rng.generate ?g key_len) in
secret, public secret

let gen_key ?compress ?g () =
let secret, public = gen_key_octets ~compress ?g () in
secret, Cstruct.of_string public

let secret_of_octets ?compress:_ s =
if String.length s = key_len then
Ok (s, public s)
else
Error `Invalid_length

let secret_of_cs ?compress cs =
Result.map (fun (secret, public) -> secret, Cstruct.of_string public)
(secret_of_octets ~compress (Cstruct.to_string cs))

let is_zero =
let zero = String.make key_len '\000' in
fun buf -> String.equal zero buf

let key_exchange_octets secret public =
let key_exchange secret public =
if String.length public = key_len then
let res = scalar_mult secret public in
if is_zero res then Error `Low_order else Ok res
else
Error `Invalid_length

let key_exchange secret public =
Result.map Cstruct.of_string
(key_exchange_octets secret (Cstruct.to_string public))
end

module Ed25519 = struct
Expand Down Expand Up @@ -1053,11 +987,7 @@ module Ed25519 = struct
let priv_of_octets buf =
if String.length buf = key_len then Ok buf else Error `Invalid_length

let priv_of_cstruct p = priv_of_octets (Cstruct.to_string p)

let priv_to_octets priv = priv

let priv_to_cstruct p = Cstruct.of_string (priv_to_octets p)
let priv_to_octets (priv : priv) = priv

let pub_of_octets buf =
if String.length buf = key_len then
Expand All @@ -1068,18 +998,13 @@ module Ed25519 = struct
else
Error `Invalid_length

let pub_of_cstruct p = pub_of_octets (Cstruct.to_string p)

let pub_to_octets pub = pub

let pub_to_cstruct p = Cstruct.of_string (pub_to_octets p)

let generate ?g () =
let secret = Mirage_crypto_rng.generate ?g key_len in
let secret = Cstruct.to_string secret in
let secret = Cstruct.to_string (Mirage_crypto_rng.generate ?g key_len) in
secret, pub_of_priv secret

let sign_octets ~key msg =
let sign ~key msg =
(* section 5.1.6 *)
let pub, (s, prefix) = public key in
let r = Mirage_crypto.Hash.SHA512.digest (Cstruct.of_string (String.concat "" [ prefix; msg ])) in
Expand All @@ -1097,9 +1022,7 @@ module Ed25519 = struct
Bytes.blit_string s_out 0 res key_len key_len ;
Bytes.unsafe_to_string res

let sign ~key msg = Cstruct.of_string (sign_octets ~key (Cstruct.to_string msg))

let verify_octets ~key signature ~msg =
let verify ~key signature ~msg =
(* section 5.1.7 *)
if String.length signature = 2 * key_len then
let r, s =
Expand Down Expand Up @@ -1129,7 +1052,4 @@ module Ed25519 = struct
false
else
false

let verify ~key signature ~msg =
verify_octets ~key (Cstruct.to_string signature) ~msg:(Cstruct.to_string msg)
end
Loading

0 comments on commit db1c855

Please sign in to comment.