Skip to content

Commit

Permalink
[ec] Handle K_gen correctly for bitlen mod 8 <> 0 (mirage#230)
Browse files Browse the repository at this point in the history
* [ec] Handle K_gen correctly for bitlen mod 8 <> 0
  • Loading branch information
Firobe authored and ansiwen committed Jun 30, 2024
1 parent 040ef22 commit 9e9ada0
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 5 deletions.
31 changes: 30 additions & 1 deletion ec/mirage_crypto_ec.ml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ module type Dsa = sig
type priv
type pub
val byte_length : int
val bit_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
Expand Down Expand Up @@ -85,6 +86,7 @@ module type Parameters = sig
val n : field_element
val pident: string
val byte_length : int
val bit_length : int
val fe_length : int
val first_byte_bits : int option
end
Expand Down Expand Up @@ -612,6 +614,8 @@ module Make_dsa (Param : Parameters) (F : Fn) (P : Point) (S : Scalar) (H : Mira

let byte_length = Param.byte_length

let bit_length = Param.bit_length

let priv_of_octets= S.of_octets

let priv_to_octets = S.to_octets
Expand Down Expand Up @@ -669,11 +673,33 @@ module Make_dsa (Param : Parameters) (F : Fn) (P : Point) (S : Scalar) (H : Mira
(Cstruct.of_string (String.concat "" [ S.to_octets key ; msg ]));
g

(* Defined in RFC 6979 sec 2.3.2 with
- blen = 8 * Param.byte_length
- qlen = Param.bit_length *)
let bits2int r =
(* keep qlen *leftmost* bits *)
let shift = (8 * Param.byte_length) - Param.bit_length in
if shift = 0 then
Bytes.unsafe_to_string r
else
(* Assuming shift is < 8 *)
let r' = Bytes.create Param.byte_length in
let p = ref 0x00 in
for i = 0 to Param.byte_length - 1 do
let x = Bytes.get_uint8 r i in
let v = (x lsr shift) lor (!p lsl (8 - shift)) in
p := x;
Bytes.set_uint8 r' i v
done;
Bytes.unsafe_to_string r'

(* 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 b = Cstruct.to_bytes r in
(* truncate to the desired number of bits *)
let r = bits2int b in
if S.is_in_range r then r else go ()
in
go ()
Expand Down Expand Up @@ -861,6 +887,7 @@ module P256 : Dh_dsa = struct
let n = "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xBC\xE6\xFA\xAD\xA7\x17\x9E\x84\xF3\xB9\xCA\xC2\xFC\x63\x25\x51"
let pident = "\x3F\xFF\xFF\xFF\xC0\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" |> rev_string (* (Params.p + 1) / 4*)
let byte_length = 32
let bit_length = 256
let fe_length = 32
let first_byte_bits = None
end
Expand Down Expand Up @@ -912,6 +939,7 @@ module P384 : Dh_dsa = struct
let n = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC7\x63\x4D\x81\xF4\x37\x2D\xDF\x58\x1A\x0D\xB2\x48\xB0\xA7\x7A\xEC\xEC\x19\x6A\xCC\xC5\x29\x73"
let pident = "\x3F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xBF\xFF\xFF\xFF\xC0\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00" |> rev_string (* (Params.p + 1) / 4*)
let byte_length = 48
let bit_length = 384
let fe_length = 48
let first_byte_bits = None
end
Expand Down Expand Up @@ -964,6 +992,7 @@ module P521 : Dh_dsa = struct
let n = "\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFA\x51\x86\x87\x83\xBF\x2F\x96\x6B\x7F\xCC\x01\x48\xF7\x09\xA5\xD0\x3B\xB5\xC9\xB8\x89\x9C\x47\xAE\xBB\x6F\xB7\x1E\x91\x38\x64\x09"
let pident = "\x01\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" |> rev_string
let byte_length = 66
let bit_length = 521
let fe_length = if Sys.word_size == 64 then 72 else 68 (* TODO: is this congruent with C code? *)
let first_byte_bits = Some 0x01
end
Expand Down
3 changes: 3 additions & 0 deletions ec/mirage_crypto_ec.mli
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ module type Dsa = sig
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_cstruct : Cstruct.t -> (priv, error) result
Expand Down
8 changes: 4 additions & 4 deletions tests/test_ec.ml
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ let ecdsa_rfc6979_p521 =
let sig' = P521.Dsa.sign ~key:priv ~k msg in
Alcotest.(check bool __LOC__ true (sig_eq sig'))
in
let _cases = [
let cases = [

case `SHA1 ~message:"sample"
~k:"089C071B419E1C2820962321787258469511958E80582E95D8378E0C2CCDB3CB
Expand Down Expand Up @@ -789,9 +789,9 @@ let ecdsa_rfc6979_p521 =
CE3"

] in
[ ("public key matches", `Quick, pub_rfc); ("public key compression and decompression", `Quick, pub_key_compression)]
(* TODO: our deterministic generator for bit_size mod 8 <> 0 is different from RFC 6979 *)
(* List.mapi (fun i c -> "RFC 6979 A.2.7 " ^ string_of_int i, `Quick, c) cases *)
("public key matches", `Quick, pub_rfc) ::
("public key compression and decompression", `Quick, pub_key_compression) ::
List.mapi (fun i c -> "RFC 6979 A.2.7 " ^ string_of_int i, `Quick, c) cases

let x25519 () =
(* RFC 7748, 6.1 *)
Expand Down

0 comments on commit 9e9ada0

Please sign in to comment.