···1515let pp_error fmt e =
1616 Format.fprintf fmt "Cannot parse point: %s" (error_to_string e)
17171818+exception Message_too_long
1919+1820module type Dh = sig
1921 type secret
2022···6466 val n : Cstruct.t
6567 val byte_length : int
6668 val fe_length : int
6969+ val first_byte_bits : int option
6770end
68716972type field_element = Cstruct.buffer
···166169167170 val to_cstruct : point -> Cstruct.t
168171172172+ val to_affine_raw : point -> (field_element * field_element) option
173173+169174 val x_of_finite_point : point -> Cstruct.t
170175171176 val params_g : point
···236241 | 0x00 | 0x04 -> Error `Invalid_length
237242 | _ -> Error `Invalid_format
238243239239- let to_affine p =
240240- if is_infinity p then None
244244+ let to_affine_raw p =
245245+ if is_infinity p then
246246+ None
241247 else
242242- let out_x = Cstruct.create P.byte_length in
243243- let out_y = Cstruct.create P.byte_length in
244248 let z1 = Fe.create () in
245249 let z2 = Fe.create () in
246250 Fe.copy z1 p.f_z;
···251255 let x = Fe.create () in
252256 Fe.copy x p.f_x;
253257 Fe.mul x x z1;
254254- Fe.to_bytes out_x x;
255258 let y = Fe.create () in
256259 Fe.copy y p.f_y;
257260 Fe.mul z1 z1 z2;
258261 Fe.mul y y z1;
262262+ Some (x, y)
263263+264264+ let to_affine p =
265265+ match to_affine_raw p with
266266+ | None -> None
267267+ | Some (x, y) ->
268268+ let out_x = Cstruct.create P.byte_length in
269269+ let out_y = Cstruct.create P.byte_length in
270270+ Fe.to_bytes out_x x;
259271 Fe.to_bytes out_y y;
260272 Some (out_x, out_y)
261273···295307end
296308297309module type Scalar = sig
310310+ val not_zero : Cstruct.t -> bool
311311+312312+ val is_in_range : Cstruct.t -> bool
313313+298314 val of_cstruct : Cstruct.t -> (scalar, error) result
299315300316 val to_cstruct : scalar -> Cstruct.t
···303319end
304320305321module Make_scalar (Param : Parameters) (P : Point) : Scalar = struct
322322+ let not_zero =
323323+ let zero = Cstruct.create Param.byte_length in
324324+ fun cs -> Eqaf_cstruct.compare_be_with_len ~len:Param.byte_length cs zero > 0
325325+306326 let is_in_range cs =
307307- let zero = Cstruct.create Param.byte_length in
308308- Eqaf_cstruct.compare_be_with_len ~len:Param.byte_length cs zero > 0
327327+ not_zero cs
309328 && Eqaf_cstruct.compare_be_with_len ~len:Param.byte_length Param.n cs > 0
310329311330 let of_cstruct cs =
···392411 let padded msg =
393412 let l = Cstruct.len msg in
394413 let bl = Param.byte_length in
395395- if l >= bl then
396396- Cstruct.sub msg 0 (min l bl)
414414+ let first_byte_ok () =
415415+ match Param.first_byte_bits with
416416+ | None -> true
417417+ | Some m -> (Cstruct.get_uint8 msg 0) land (0xFF land (lnot m)) = 0
418418+ in
419419+ if l > bl || (l = bl && not (first_byte_ok ())) then
420420+ raise Message_too_long
421421+ else if l = bl then
422422+ msg
397423 else
398424 Cstruct.append (Cstruct.create (bl - l)) msg
399425···407433 F.to_bytes (Cstruct.to_bigarray cs) v;
408434 Cstruct.rev cs
409435410410- let not_zero =
411411- let zero = Cstruct.create Param.byte_length in
412412- fun n -> not (Cstruct.equal zero n)
413413-414414- let mod_n v =
415415- let v' = from_be_cstruct v in
416416- F.to_montgomery v' v';
417417- let o = create () in
418418- F.one o;
419419- F.mul v' v' o;
420420- F.from_montgomery v' v';
421421- to_be_cstruct v'
422422-423423- let smaller_n v =
424424- Cstruct.equal v (mod_n v)
425425-426436 (* RFC 6979: compute a deterministic k *)
427437 module K_gen (H : Mirage_crypto.Hash.S) = struct
428438···439449 let gen g =
440450 let rec go () =
441451 let r = Mirage_crypto_rng.generate ~g Param.byte_length in
442442- if not_zero r && smaller_n r then r else go ()
452452+ if S.is_in_range r then r else go ()
443453 in
444454 go ()
445455···466476 let q = S.scalar_mult d P.params_g in
467477 (d, q)
468478479479+ let x_of_finite_point_mod_n p =
480480+ match P.to_affine_raw p with
481481+ | None -> None
482482+ | Some (x, _) ->
483483+ F.to_montgomery x x;
484484+ let o = create () in
485485+ F.one o;
486486+ F.mul x x o;
487487+ F.from_montgomery x x;
488488+ Some (to_be_cstruct x)
489489+469490 let sign ~key ?k msg =
470470- (* blinding: literature: s = k^-1 * (m + r * priv_key) mod n
471471- we blind, similar to OpenSSL (https://github.com/openssl/openssl/commit/a3e9d5aa980f238805970f420adf5e903d35bf09):
472472- s = k^-1 * blind^-1 (blind * m + blind * r * priv_key) mod n
473473- *)
474491 let msg = padded msg in
475492 let e = from_be_cstruct msg in
476493 let g = K_gen_default.g ~key msg in
···486503 | Error _ -> invalid_arg "k not in range" (* if no k is provided, this cannot happen since K_gen_*.gen already preserves the Scalar invariants *)
487504 in
488505 let point = S.scalar_mult ksc P.params_g in
489489- if P.is_infinity point then
490490- again ()
491491- else
492492- let x1 = P.x_of_finite_point point in
493493- let r = mod_n x1 in
506506+ match x_of_finite_point_mod_n point with
507507+ | None -> again ()
508508+ | Some r ->
494509 let r_mon = from_be_cstruct r in
495510 F.to_montgomery r_mon r_mon;
496511 let kinv = create () in
···511526 let s = create () in
512527 F.from_montgomery s smon;
513528 let s = to_be_cstruct s in
514514- if not_zero s && not_zero r then
529529+ if S.not_zero s && S.not_zero r then
515530 r, s
516531 else
517532 again ()
···521536 let pub_of_priv priv = S.scalar_mult priv P.params_g
522537523538 let verify ~key (r, s) msg =
524524- if not (smaller_n r && not_zero r && smaller_n s && not_zero s) then
539539+ if not (S.is_in_range r && S.is_in_range s) then
525540 false
526541 else
527527- (* take the Ln leftmost bits (with Ln bitsize of group order n = 256) *)
528528- let msg = padded msg in
529529- let z = from_be_cstruct msg in
530530- let s_inv = create () in
531531- let s_mon = from_be_cstruct s in
532532- F.to_montgomery s_mon s_mon;
533533- F.inv s_inv s_mon;
534534- let u1 = create () in
535535- let s_inv_mon = create () in
536536- F.to_montgomery s_inv_mon s_inv;
537537- let z_mon = create () in
538538- F.to_montgomery z_mon z;
539539- F.mul u1 z_mon s_inv_mon;
540540- let u2 = create () in
541541- let r_mon = from_be_cstruct r in
542542- F.to_montgomery r_mon r_mon;
543543- F.mul u2 r_mon s_inv_mon;
544544- let u1_out = create () in
545545- F.from_montgomery u1_out u1;
546546- let u2_out = create () in
547547- F.from_montgomery u2_out u2;
548548- match
549549- S.of_cstruct (to_be_cstruct u1_out),
550550- S.of_cstruct (to_be_cstruct u2_out)
542542+ try
543543+ let msg = padded msg in
544544+ let z = from_be_cstruct msg in
545545+ let s_inv = create () in
546546+ let s_mon = from_be_cstruct s in
547547+ F.to_montgomery s_mon s_mon;
548548+ F.inv s_inv s_mon;
549549+ let u1 = create () in
550550+ let s_inv_mon = create () in
551551+ F.to_montgomery s_inv_mon s_inv;
552552+ let z_mon = create () in
553553+ F.to_montgomery z_mon z;
554554+ F.mul u1 z_mon s_inv_mon;
555555+ let u2 = create () in
556556+ let r_mon = from_be_cstruct r in
557557+ F.to_montgomery r_mon r_mon;
558558+ F.mul u2 r_mon s_inv_mon;
559559+ let u1_out = create () in
560560+ F.from_montgomery u1_out u1;
561561+ let u2_out = create () in
562562+ F.from_montgomery u2_out u2;
563563+ match
564564+ S.of_cstruct (to_be_cstruct u1_out),
565565+ S.of_cstruct (to_be_cstruct u2_out)
566566+ with
567567+ | Ok u1, Ok u2 ->
568568+ let point =
569569+ P.add
570570+ (S.scalar_mult u1 P.params_g)
571571+ (S.scalar_mult u2 key)
572572+ in
573573+ begin match x_of_finite_point_mod_n point with
574574+ | None -> false (* point is infinity *)
575575+ | Some r' -> Cstruct.equal r r'
576576+ end
577577+ | Error _, _ | _, Error _ -> false
551578 with
552552- | Ok u1, Ok u2 ->
553553- let point =
554554- P.add
555555- (S.scalar_mult u1 P.params_g)
556556- (S.scalar_mult u2 key)
557557- in
558558- not (P.is_infinity point) &&
559559- Cstruct.equal (mod_n (P.x_of_finite_point point)) r
560560- | _ -> false
579579+ | Message_too_long -> false
561580end
562581563582module P224 : Dh_dsa = struct
···570589 let n = Cstruct.of_hex "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D"
571590 let byte_length = 28
572591 let fe_length = if Sys.word_size == 64 then 32 else 28 (* TODO: is this congruent with C code? *)
592592+ let first_byte_bits = None
573593 end
574594575595 module Foreign = struct
···619639 let n = Cstruct.of_hex "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"
620640 let byte_length = 32
621641 let fe_length = 32
642642+ let first_byte_bits = None
622643 end
623644624645 module Foreign = struct
···668689 let n = Cstruct.of_hex "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"
669690 let byte_length = 48
670691 let fe_length = 48
692692+ let first_byte_bits = None
671693 end
672694673695 module Foreign = struct
···717739 let n = Cstruct.of_hex "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409"
718740 let byte_length = 66
719741 let fe_length = if Sys.word_size == 64 then 72 else 68 (* TODO: is this congruent with C code? *)
742742+ let first_byte_bits = Some 0x01
720743 end
721744722745 module Foreign = struct
+10-4
ec/mirage_crypto_ec.mli
···2020val pp_error : Format.formatter -> error -> unit
2121(** Pretty printer for errors *)
22222323+exception Message_too_long
2424+(** Raised if the provided message is too long for the curve. *)
2525+2326(** Diffie-Hellman key exchange. *)
2427module type Dh = sig
2528···102105103106 val sign : key:priv -> ?k:Cstruct.t -> Cstruct.t -> Cstruct.t * Cstruct.t
104107 (** [sign ~key ~k digest] signs the message [digest] using the private
105105- [key]. Only the leftmost bits within the curve order are considered.
106106- If [k] is not provided, it is computed using the deterministic
107107- construction from RFC 6979. The result is a pair of [r] and [s]. *)
108108+ [key]. If [k] is not provided, it is computed using the deterministic
109109+ construction from RFC 6979. The result is a pair of [r] and [s].
110110+111111+ @raise Invalid_argument if [k] is not suitable or not in range.
112112+ @raise Message_too_long if [msg] is too long for the curve. *)
108113109114 val verify : key:pub -> Cstruct.t * Cstruct.t -> Cstruct.t -> bool
110115 (** [verify ~key (r, s) digest] verifies the signature [r, s] on the message
111116 [digest] with the public [key]. The return value is [true] if verification
112112- was successful, [false] otherwise. *)
117117+ was successful, [false] otherwise. If the message has more bits than the
118118+ group order, the result is false. *)
113119114120 (** [K_gen] can be instantiated over a hashing module to obtain an RFC6979
115121 compliant [k]-generator for that hash. *)
+9-3
tests/test_ec.ml
···289289 | Error _ -> Alcotest.fail "bad public key"
290290 in
291291 let case hash ~message ~k ~r ~s () =
292292- let msg = Mirage_crypto.Hash.digest hash (Cstruct.of_string message)
292292+ let msg =
293293+ let h = Mirage_crypto.Hash.digest hash (Cstruct.of_string message) in
294294+ Cstruct.sub h 0 (min (Cstruct.len h) 28)
293295 and k = Cstruct.of_hex k
294296 in
295297 let k' =
···383385 | Error _ -> Alcotest.fail "bad public key"
384386 in
385387 let case hash ~message ~k ~r ~s () =
386386- let msg = Mirage_crypto.Hash.digest hash (Cstruct.of_string message)
388388+ let msg =
389389+ let h = Mirage_crypto.Hash.digest hash (Cstruct.of_string message) in
390390+ Cstruct.sub h 0 (min (Cstruct.len h) 32)
387391 and k = Cstruct.of_hex k
388392 in
389393 let k' =
···466470 | Error _ -> Alcotest.fail "bad public key"
467471 in
468472 let case hash ~message ~k ~r ~s () =
469469- let msg = Mirage_crypto.Hash.digest hash (Cstruct.of_string message)
473473+ let msg =
474474+ let h = Mirage_crypto.Hash.digest hash (Cstruct.of_string message) in
475475+ Cstruct.sub h 0 (min (Cstruct.len h) 48)
470476 and k = Cstruct.of_hex k
471477 in
472478 let k' =
+4-1
tests/test_ec_wycheproof.ml
···158158159159let make_ecdsa_test curve key hash (tst : ecdsa_test) =
160160 let name = Printf.sprintf "%d - %s" tst.tcId tst.comment in
161161- let msg = Mirage_crypto.Hash.digest hash (Cstruct.of_string tst.msg) in
162161 let size = len curve in
162162+ let msg =
163163+ let h = Mirage_crypto.Hash.digest hash (Cstruct.of_string tst.msg) in
164164+ Cstruct.sub h 0 (min size (Cstruct.len h))
165165+ in
163166 let verified (r,s) =
164167 match curve with
165168 | "secp224r1" ->