upstream: https://github.com/mirage/mirage-crypto
at main 1322 lines 42 kB view raw
1type error = 2 [ `Invalid_format 3 | `Invalid_length 4 | `Invalid_range 5 | `Not_on_curve 6 | `At_infinity 7 | `Low_order ] 8 9let error_to_string = function 10 | `Invalid_format -> "invalid format" 11 | `Not_on_curve -> "point is not on curve" 12 | `At_infinity -> "point is at infinity" 13 | `Invalid_length -> "invalid length" 14 | `Invalid_range -> "invalid range" 15 | `Low_order -> "low order" 16 17let pp_error fmt e = 18 Format.fprintf fmt "Cannot parse point: %s" (error_to_string e) 19 20let rev_string buf = 21 let len = String.length buf in 22 let res = Bytes.create len in 23 for i = 0 to len - 1 do 24 Bytes.set res (len - 1 - i) (String.get buf i) 25 done; 26 Bytes.unsafe_to_string res 27 28exception Message_too_long 29 30let bit_at buf i = 31 let byte_num = i / 8 in 32 let bit_num = i mod 8 in 33 let byte = String.get_uint8 buf byte_num in 34 byte land (1 lsl bit_num) <> 0 35 36module type Dh = sig 37 type secret 38 39 val secret_of_octets : 40 ?compress:bool -> string -> (secret * string, error) result 41 42 val secret_to_octets : secret -> string 43 val gen_key : ?compress:bool -> ?g:Crypto_rng.g -> unit -> secret * string 44 val key_exchange : secret -> string -> (string, error) result 45end 46 47module type Dsa = sig 48 type priv 49 type pub 50 51 val byte_length : int 52 val bit_length : int 53 val priv_of_octets : string -> (priv, error) result 54 val priv_to_octets : priv -> string 55 val pub_of_octets : string -> (pub, error) result 56 val pub_to_octets : ?compress:bool -> pub -> string 57 val pub_of_priv : priv -> pub 58 val generate : ?g:Crypto_rng.g -> unit -> priv * pub 59 val sign : key:priv -> ?k:string -> string -> string * string 60 val verify : key:pub -> string * string -> string -> bool 61 62 module K_gen (H : Digestif.S) : sig 63 val generate : key:priv -> string -> string 64 end 65 66 module Precompute : sig 67 val generator_tables : unit -> string array array array 68 end 69end 70 71module type Point = sig 72 type point 73 type scalar 74 75 val of_octets : string -> (point, error) result 76 val to_octets : ?compress:bool -> point -> string 77 val scalar_of_octets : string -> (scalar, error) result 78 val scalar_to_octets : scalar -> string 79 val generator : point 80 val add : point -> point -> point 81 val scalar_mult : scalar -> point -> point 82end 83 84module type Dh_dsa = sig 85 module Dh : Dh 86 module Dsa : Dsa 87 module Point : Point 88end 89 90type field_element = string 91type out_field_element = bytes 92 93module type Parameters = sig 94 val a : field_element 95 val b : field_element 96 val g_x : field_element 97 val g_y : field_element 98 val p : field_element 99 val n : field_element 100 val pident : string 101 val byte_length : int 102 val bit_length : int 103 val fe_length : int 104 val first_byte_bits : int option 105end 106 107type point = { f_x : field_element; f_y : field_element; f_z : field_element } 108 109type out_point = { 110 m_f_x : out_field_element; 111 m_f_y : out_field_element; 112 m_f_z : out_field_element; 113} 114 115type scalar = Scalar of string 116 117module type Foreign = sig 118 val mul : out_field_element -> field_element -> field_element -> unit 119 val sub : out_field_element -> field_element -> field_element -> unit 120 val add : out_field_element -> field_element -> field_element -> unit 121 val to_montgomery : out_field_element -> field_element -> unit 122 val from_octets : out_field_element -> string -> unit 123 val set_one : out_field_element -> unit 124 val nz : field_element -> bool 125 val sqr : out_field_element -> field_element -> unit 126 val from_montgomery : out_field_element -> field_element -> unit 127 val to_octets : bytes -> field_element -> unit 128 val inv : out_field_element -> field_element -> unit 129 130 val select_c : 131 out_field_element -> bool -> field_element -> field_element -> unit 132 133 val double_c : out_point -> point -> unit 134 val add_c : out_point -> point -> point -> unit 135 val scalar_mult_base_c : out_point -> string -> unit 136end 137 138module type Field_element = sig 139 val mul : field_element -> field_element -> field_element 140 val sub : field_element -> field_element -> field_element 141 val add : field_element -> field_element -> field_element 142 val from_montgomery : field_element -> field_element 143 val zero : field_element 144 val one : field_element 145 val nz : field_element -> bool 146 val sqr : field_element -> field_element 147 val inv : field_element -> field_element 148 149 val select : 150 bool -> then_:field_element -> else_:field_element -> field_element 151 152 val from_be_octets : string -> field_element 153 val to_octets : field_element -> string 154 val double_point : point -> point 155 val add_point : point -> point -> point 156 val scalar_mult_base_point : scalar -> point 157end 158 159module Make_field_element (P : Parameters) (F : Foreign) : Field_element = 160struct 161 let b_uts b = Bytes.unsafe_to_string b 162 let create () = Bytes.create P.fe_length 163 164 let mul a b = 165 let tmp = create () in 166 F.mul tmp a b; 167 b_uts tmp 168 169 let sub a b = 170 let tmp = create () in 171 F.sub tmp a b; 172 b_uts tmp 173 174 let add a b = 175 let tmp = create () in 176 F.add tmp a b; 177 b_uts tmp 178 179 let from_montgomery a = 180 let tmp = create () in 181 F.from_montgomery tmp a; 182 b_uts tmp 183 184 let zero = 185 let b = Bytes.make P.fe_length '\000' in 186 b_uts b 187 188 let one = 189 let fe = create () in 190 F.set_one fe; 191 b_uts fe 192 193 let nz a = F.nz a 194 195 let sqr a = 196 let tmp = create () in 197 F.sqr tmp a; 198 b_uts tmp 199 200 let inv a = 201 let tmp = create () in 202 F.inv tmp a; 203 b_uts tmp 204 205 let select bit ~then_ ~else_ = 206 let tmp = create () in 207 F.select_c tmp bit then_ else_; 208 b_uts tmp 209 210 let from_be_octets buf = 211 let buf_rev = rev_string buf in 212 let tmp = create () in 213 F.from_octets tmp buf_rev; 214 F.to_montgomery tmp (b_uts tmp); 215 b_uts tmp 216 217 let create_octets () = Bytes.create P.byte_length 218 219 let to_octets fe = 220 let tmp = create_octets () in 221 F.to_octets tmp fe; 222 b_uts tmp 223 224 let out_point () = { m_f_x = create (); m_f_y = create (); m_f_z = create () } 225 226 let out_p_to_p p = 227 { f_x = b_uts p.m_f_x; f_y = b_uts p.m_f_y; f_z = b_uts p.m_f_z } 228 229 let double_point p = 230 let tmp = out_point () in 231 F.double_c tmp p; 232 out_p_to_p tmp 233 234 let add_point a b = 235 let tmp = out_point () in 236 F.add_c tmp a b; 237 out_p_to_p tmp 238 239 let scalar_mult_base_point (Scalar d) = 240 let tmp = out_point () in 241 F.scalar_mult_base_c tmp d; 242 out_p_to_p tmp 243end 244 245module type Point_ops = sig 246 val at_infinity : unit -> point 247 val is_infinity : point -> bool 248 val add : point -> point -> point 249 val double : point -> point 250 val of_octets : string -> (point, error) result 251 val to_octets : compress:bool -> point -> string 252 val to_affine_raw : point -> (field_element * field_element) option 253 val x_of_finite_point : point -> string 254 val params_g : point 255 val select : bool -> then_:point -> else_:point -> point 256 val scalar_mult_base : scalar -> point 257end 258 259module Make_point_ops (P : Parameters) (F : Foreign) : Point_ops = struct 260 module Fe = Make_field_element (P) (F) 261 262 let at_infinity () = 263 let f_x = Fe.one in 264 let f_y = Fe.one in 265 let f_z = Fe.zero in 266 { f_x; f_y; f_z } 267 268 let is_infinity (p : point) = not (Fe.nz p.f_z) 269 270 let is_solution_to_curve_equation = 271 let a = Fe.from_be_octets P.a in 272 let b = Fe.from_be_octets P.b in 273 fun ~x ~y -> 274 let x3 = Fe.mul x x in 275 let x3 = Fe.mul x3 x in 276 let ax = Fe.mul a x in 277 let y2 = Fe.mul y y in 278 let sum = Fe.add x3 ax in 279 let sum = Fe.add sum b in 280 let sum = Fe.sub sum y2 in 281 not (Fe.nz sum) 282 283 let check_coordinate buf = 284 (* ensure buf < p: *) 285 match Eqaf.compare_be_with_len ~len:P.byte_length buf P.p >= 0 with 286 | true -> None 287 | exception Invalid_argument _ -> None 288 | false -> Some (Fe.from_be_octets buf) 289 290 (** Convert coordinates to a finite point ensuring: 291 - x < p 292 - y < p 293 - y^2 = ax^3 + ax + b *) 294 let validate_finite_point ~x ~y = 295 match (check_coordinate x, check_coordinate y) with 296 | Some f_x, Some f_y -> 297 if is_solution_to_curve_equation ~x:f_x ~y:f_y then 298 let f_z = Fe.one in 299 Ok { f_x; f_y; f_z } 300 else Error `Not_on_curve 301 | _ -> Error `Invalid_range 302 303 let to_affine_raw p = 304 if is_infinity p then None 305 else 306 let z1 = Fe.from_montgomery p.f_z in 307 let z2 = Fe.inv z1 in 308 let z1 = Fe.sqr z2 in 309 let z1 = Fe.from_montgomery z1 in 310 let x = Fe.mul p.f_x z1 in 311 let z1 = Fe.mul z1 z2 in 312 let y = Fe.mul p.f_y z1 in 313 Some (x, y) 314 315 let to_affine p = 316 Option.map 317 (fun (x, y) -> (Fe.to_octets x, Fe.to_octets y)) 318 (to_affine_raw p) 319 320 let to_octets ~compress p = 321 let buf = 322 match to_affine p with 323 | None -> String.make 1 '\000' 324 | Some (x, y) -> 325 let len_x = String.length x and len_y = String.length y in 326 let res = Bytes.create (1 + len_x + len_y) in 327 Bytes.set res 0 '\004'; 328 let rev_x = rev_string x and rev_y = rev_string y in 329 Bytes.unsafe_blit_string rev_x 0 res 1 len_x; 330 Bytes.unsafe_blit_string rev_y 0 res (1 + len_x) len_y; 331 Bytes.unsafe_to_string res 332 in 333 if compress then ( 334 let out = Bytes.create (P.byte_length + 1) in 335 let ident = 2 + (String.get_uint8 buf (P.byte_length * 2) land 1) in 336 Bytes.unsafe_blit_string buf 1 out 1 P.byte_length; 337 Bytes.set_uint8 out 0 ident; 338 Bytes.unsafe_to_string out) 339 else buf 340 341 let double p = Fe.double_point p 342 let add p q = Fe.add_point p q 343 344 let x_of_finite_point p = 345 match to_affine p with None -> assert false | Some (x, _) -> rev_string x 346 347 let params_g = 348 match validate_finite_point ~x:P.g_x ~y:P.g_y with 349 | Ok p -> p 350 | Error _ -> assert false 351 352 let select bit ~then_ ~else_ = 353 { 354 f_x = Fe.select bit ~then_:then_.f_x ~else_:else_.f_x; 355 f_y = Fe.select bit ~then_:then_.f_y ~else_:else_.f_y; 356 f_z = Fe.select bit ~then_:then_.f_z ~else_:else_.f_z; 357 } 358 359 let pow x exp = 360 let r0 = ref Fe.one in 361 let r1 = ref x in 362 for i = (P.byte_length * 8) - 1 downto 0 do 363 let bit = bit_at exp i in 364 let multiplied = Fe.mul !r0 !r1 in 365 let r0_sqr = Fe.sqr !r0 in 366 let r1_sqr = Fe.sqr !r1 in 367 r0 := Fe.select bit ~then_:multiplied ~else_:r0_sqr; 368 r1 := Fe.select bit ~then_:r1_sqr ~else_:multiplied 369 done; 370 !r0 371 372 let decompress = 373 (* When p = 4*k+3, as is the case of NIST-P256, there is an efficient square 374 root algorithm to recover the y, as follows: 375 376 Given the compact representation of Q as x, 377 y2 = x^3 + a*x + b 378 y' = y2^((p+1)/4) 379 y = min(y',p-y') 380 Q=(x,y) is the canonical representation of the point 381 *) 382 let pident = 383 P.pident 384 (* (Params.p + 1) / 4*) 385 in 386 let a = Fe.from_be_octets P.a in 387 let b = Fe.from_be_octets P.b in 388 let p = Fe.from_be_octets P.p in 389 fun pk -> 390 let x = Fe.from_be_octets (String.sub pk 1 P.byte_length) in 391 let x3 = Fe.mul x x in 392 let x3 = Fe.mul x3 x in 393 (* x3 *) 394 let ax = Fe.mul a x in 395 (* ax *) 396 let sum = Fe.add x3 ax in 397 let sum = Fe.add sum b in 398 (* y^2 *) 399 let y = pow sum pident in 400 (* https://tools.ietf.org/id/draft-jivsov-ecc-compact-00.xml#sqrt point 4.3*) 401 let y' = Fe.sub p y in 402 let y = Fe.from_montgomery y in 403 let y_struct = Fe.to_octets y in 404 (* number must not be in montgomery domain*) 405 let y_struct = rev_string y_struct in 406 let y' = Fe.from_montgomery y' in 407 let y_struct2 = Fe.to_octets y' in 408 (* number must not be in montgomery domain*) 409 let y_struct2 = rev_string y_struct2 in 410 let ident = String.get_uint8 pk 0 in 411 let signY = 2 + (String.get_uint8 y_struct (P.byte_length - 1) land 1) in 412 let res = if Int.equal signY ident then y_struct else y_struct2 in 413 let out = Bytes.create ((P.byte_length * 2) + 1) in 414 Bytes.set out 0 '\004'; 415 Bytes.unsafe_blit_string pk 1 out 1 P.byte_length; 416 Bytes.unsafe_blit_string res 0 out (P.byte_length + 1) P.byte_length; 417 Bytes.unsafe_to_string out 418 419 let of_octets buf = 420 let len = P.byte_length in 421 if String.length buf = 0 then Error `Invalid_format 422 else 423 let of_octets buf = 424 let x = String.sub buf 1 len in 425 let y = String.sub buf (1 + len) len in 426 validate_finite_point ~x ~y 427 in 428 match String.get_uint8 buf 0 with 429 | 0x00 when String.length buf = 1 -> Ok (at_infinity ()) 430 | (0x02 | 0x03) when String.length P.pident > 0 -> 431 let decompressed = decompress buf in 432 of_octets decompressed 433 | 0x04 when String.length buf = 1 + len + len -> of_octets buf 434 | 0x00 | 0x04 -> Error `Invalid_length 435 | _ -> Error `Invalid_format 436 437 let scalar_mult_base = Fe.scalar_mult_base_point 438end 439 440module type Scalar = sig 441 val not_zero : string -> bool 442 val is_in_range : string -> bool 443 val of_octets : string -> (scalar, error) result 444 val to_octets : scalar -> string 445 val scalar_mult : scalar -> point -> point 446 val scalar_mult_base : scalar -> point 447 val generator_tables : unit -> field_element array array array 448end 449 450module Make_scalar (Param : Parameters) (P : Point_ops) : Scalar = struct 451 let not_zero = 452 let zero = String.make Param.byte_length '\000' in 453 fun buf -> not (Eqaf.equal buf zero) 454 455 let is_in_range buf = 456 not_zero buf 457 && Eqaf.compare_be_with_len ~len:Param.byte_length Param.n buf > 0 458 459 let of_octets buf = 460 match is_in_range buf with 461 | exception Invalid_argument _ -> Error `Invalid_length 462 | true -> Ok (Scalar (rev_string buf)) 463 | false -> Error `Invalid_range 464 465 let to_octets (Scalar buf) = rev_string buf 466 467 (* Branchless Montgomery ladder method *) 468 let scalar_mult (Scalar s) p = 469 let r0 = ref (P.at_infinity ()) in 470 let r1 = ref p in 471 for i = (Param.byte_length * 8) - 1 downto 0 do 472 let bit = bit_at s i in 473 let sum = P.add !r0 !r1 in 474 let r0_double = P.double !r0 in 475 let r1_double = P.double !r1 in 476 r0 := P.select bit ~then_:sum ~else_:r0_double; 477 r1 := P.select bit ~then_:r1_double ~else_:sum 478 done; 479 !r0 480 481 (* Specialization of [scalar_mult d p] when [p] is the generator *) 482 let scalar_mult_base = P.scalar_mult_base 483 484 (* Pre-compute multiples of the generator point 485 returns the tables along with the number of significant bytes *) 486 let generator_tables () = 487 let len = Param.fe_length * 2 in 488 let one_table _ = Array.init 15 (fun _ -> P.at_infinity ()) in 489 let table = Array.init len one_table in 490 let base = ref P.params_g in 491 for i = 0 to len - 1 do 492 table.(i).(0) <- !base; 493 for j = 1 to 14 do 494 table.(i).(j) <- P.add !base table.(i).(j - 1) 495 done; 496 base := P.double !base; 497 base := P.double !base; 498 base := P.double !base; 499 base := P.double !base 500 done; 501 let convert { f_x; f_y; f_z } = [| f_x; f_y; f_z |] in 502 Array.map (Array.map convert) table 503end 504 505module Make_dh (Param : Parameters) (P : Point_ops) (S : Scalar) : Dh = struct 506 let point_of_octets c = 507 match P.of_octets c with 508 | Ok p when not (P.is_infinity p) -> Ok p 509 | Ok _ -> Error `At_infinity 510 | Error _ as e -> e 511 512 let point_to_octets = P.to_octets 513 514 type secret = scalar 515 516 let share ?(compress = false) private_key = 517 let public_key = S.scalar_mult_base private_key in 518 point_to_octets ~compress public_key 519 520 let secret_of_octets ?compress s = 521 match S.of_octets s with 522 | Ok p -> Ok (p, share ?compress p) 523 | Error _ as e -> e 524 525 let secret_to_octets s = S.to_octets s 526 527 let rec generate_private_key ?g () = 528 let candidate = Crypto_rng.generate ?g Param.byte_length in 529 match S.of_octets candidate with 530 | Ok secret -> secret 531 | Error _ -> generate_private_key ?g () 532 533 let gen_key ?compress ?g () = 534 let private_key = generate_private_key ?g () in 535 (private_key, share ?compress private_key) 536 537 let key_exchange secret received = 538 match point_of_octets received with 539 | Error _ as err -> err 540 | Ok shared -> Ok (P.x_of_finite_point (S.scalar_mult secret shared)) 541end 542 543module type Foreign_n = sig 544 val mul : out_field_element -> field_element -> field_element -> unit 545 val add : out_field_element -> field_element -> field_element -> unit 546 val inv : out_field_element -> field_element -> unit 547 val one : out_field_element -> unit 548 val from_bytes : out_field_element -> string -> unit 549 val to_bytes : bytes -> field_element -> unit 550 val from_montgomery : out_field_element -> field_element -> unit 551 val to_montgomery : out_field_element -> field_element -> unit 552end 553 554module type Fn = sig 555 val from_be_octets : string -> field_element 556 val to_be_octets : field_element -> string 557 val mul : field_element -> field_element -> field_element 558 val add : field_element -> field_element -> field_element 559 val inv : field_element -> field_element 560 val one : field_element 561 val from_montgomery : field_element -> field_element 562 val to_montgomery : field_element -> field_element 563end 564 565module Make_Fn (P : Parameters) (F : Foreign_n) : Fn = struct 566 let b_uts = Bytes.unsafe_to_string 567 let create () = Bytes.create P.fe_length 568 let create_octets () = Bytes.create P.byte_length 569 570 let from_be_octets v = 571 let v' = create () in 572 F.from_bytes v' (rev_string v); 573 F.to_montgomery v' (b_uts v'); 574 b_uts v' 575 576 let to_be_octets v = 577 let buf = create_octets () in 578 F.to_bytes buf v; 579 rev_string (b_uts buf) 580 581 let mul a b = 582 let tmp = create () in 583 F.mul tmp a b; 584 b_uts tmp 585 586 let add a b = 587 let tmp = create () in 588 F.add tmp a b; 589 b_uts tmp 590 591 let inv a = 592 let tmp = create () in 593 F.inv tmp a; 594 F.to_montgomery tmp (b_uts tmp); 595 b_uts tmp 596 597 let one = 598 let tmp = create () in 599 F.one tmp; 600 b_uts tmp 601 602 let from_montgomery a = 603 let tmp = create () in 604 F.from_montgomery tmp a; 605 b_uts tmp 606 607 let to_montgomery a = 608 let tmp = create () in 609 F.to_montgomery tmp a; 610 b_uts tmp 611end 612 613module Make_dsa 614 (Param : Parameters) 615 (F : Fn) 616 (P : Point_ops) 617 (S : Scalar) 618 (H : Digestif.S) = 619struct 620 type priv = scalar 621 622 let byte_length = Param.byte_length 623 let bit_length = Param.bit_length 624 let priv_of_octets = S.of_octets 625 let priv_to_octets = S.to_octets 626 627 let padded msg = 628 let l = String.length msg in 629 let bl = Param.byte_length in 630 let first_byte_ok () = 631 match Param.first_byte_bits with 632 | None -> true 633 | Some m -> String.get_uint8 msg 0 land (0xFF land lnot m) = 0 634 in 635 if l > bl || (l = bl && not (first_byte_ok ())) then raise Message_too_long 636 else if l = bl then msg 637 else 638 let res = Bytes.make bl '\000' in 639 Bytes.unsafe_blit_string msg 0 res (bl - l) l; 640 Bytes.unsafe_to_string res 641 642 (* RFC 6979: compute a deterministic k *) 643 module K_gen (H : Digestif.S) = struct 644 let drbg : 'a Crypto_rng.generator = 645 let module M = Crypto_rng.Hmac_drbg (H) in 646 (module M) 647 648 let g ~key msg = 649 let g = Crypto_rng.create ~strict:true drbg in 650 Crypto_rng.reseed ~g (S.to_octets key ^ msg); 651 g 652 653 (* Defined in RFC 6979 sec 2.3.2 with 654 - blen = 8 * Param.byte_length 655 - qlen = Param.bit_length *) 656 let bits2int r = 657 (* keep qlen *leftmost* bits *) 658 let shift = (8 * Param.byte_length) - Param.bit_length in 659 if shift = 0 then Bytes.unsafe_to_string r 660 else 661 (* Assuming shift is < 8 *) 662 let r' = Bytes.create Param.byte_length in 663 let p = ref 0x00 in 664 for i = 0 to Param.byte_length - 1 do 665 let x = Bytes.get_uint8 r i in 666 let v = (x lsr shift) lor (!p lsl (8 - shift)) in 667 p := x; 668 Bytes.set_uint8 r' i v 669 done; 670 Bytes.unsafe_to_string r' 671 672 (* take qbit length, and ensure it is suitable for ECDSA (> 0 & < n) *) 673 let gen g = 674 let rec go () = 675 let b = Bytes.create Param.byte_length in 676 Crypto_rng.generate_into ~g b Param.byte_length; 677 (* truncate to the desired number of bits *) 678 let r = bits2int b in 679 if S.is_in_range r then r else go () 680 in 681 go () 682 683 let generate ~key buf = gen (g ~key (padded buf)) 684 end 685 686 module K_gen_default = K_gen (H) 687 688 type pub = point 689 690 let pub_of_octets = P.of_octets 691 let pub_to_octets ?(compress = false) pk = P.to_octets ~compress pk 692 693 let generate ?g () = 694 (* FIPS 186-4 B 4.2 *) 695 let d = 696 let rec one () = 697 match S.of_octets (Crypto_rng.generate ?g Param.byte_length) with 698 | Ok x -> x 699 | Error _ -> one () 700 in 701 one () 702 in 703 let q = S.scalar_mult_base d in 704 (d, q) 705 706 let x_of_finite_point_mod_n p = 707 match P.to_affine_raw p with 708 | None -> None 709 | Some (x, _) -> 710 let x = F.to_montgomery x in 711 let x = F.mul x F.one in 712 let x = F.from_montgomery x in 713 Some (F.to_be_octets x) 714 715 let sign ~key ?k msg = 716 let msg = padded msg in 717 let e = F.from_be_octets msg in 718 let g = K_gen_default.g ~key msg in 719 let rec do_sign g = 720 let again () = 721 match k with 722 | None -> do_sign g 723 | Some _ -> invalid_arg "k not suitable" 724 in 725 let k' = match k with None -> K_gen_default.gen g | Some k -> k in 726 let ksc = 727 match S.of_octets k' with 728 | Ok ksc -> ksc 729 | Error _ -> invalid_arg "k not in range" 730 (* if no k is provided, this cannot happen since K_gen_*.gen already preserves the Scalar invariants *) 731 in 732 let point = S.scalar_mult_base ksc in 733 match x_of_finite_point_mod_n point with 734 | None -> again () 735 | Some r -> 736 let r_mon = F.from_be_octets r in 737 let kmon = F.from_be_octets k' in 738 let kinv = F.inv kmon in 739 let dmon = F.from_be_octets (S.to_octets key) in 740 let rd = F.mul r_mon dmon in 741 let cmon = F.add e rd in 742 let smon = F.mul kinv cmon in 743 let s = F.from_montgomery smon in 744 let s = F.to_be_octets s in 745 if S.not_zero s && S.not_zero r then (r, s) else again () 746 in 747 do_sign g 748 749 let pub_of_priv priv = S.scalar_mult_base priv 750 751 let verify ~key (r, s) msg = 752 try 753 let r = padded r and s = padded s in 754 if not (S.is_in_range r && S.is_in_range s) then false 755 else 756 let msg = padded msg in 757 let z = F.from_be_octets msg in 758 let s_mon = F.from_be_octets s in 759 let s_inv = F.inv s_mon in 760 let u1 = F.mul z s_inv in 761 let r_mon = F.from_be_octets r in 762 let u2 = F.mul r_mon s_inv in 763 let u1 = F.from_montgomery u1 in 764 let u2 = F.from_montgomery u2 in 765 match 766 (S.of_octets (F.to_be_octets u1), S.of_octets (F.to_be_octets u2)) 767 with 768 | Ok u1, Ok u2 -> 769 let point = P.add (S.scalar_mult_base u1) (S.scalar_mult u2 key) in 770 begin match x_of_finite_point_mod_n point with 771 | None -> false (* point is infinity *) 772 | Some r' -> String.equal r r' 773 end 774 | Error _, _ | _, Error _ -> false 775 with Message_too_long -> false 776 777 module Precompute = struct 778 let generator_tables = S.generator_tables 779 end 780end 781 782module Make_point (P : Point_ops) (S : Scalar) : 783 Point with type point = point and type scalar = scalar = struct 784 type nonrec point = point 785 type nonrec scalar = scalar 786 787 let of_octets = P.of_octets 788 let to_octets ?(compress = false) p = P.to_octets ~compress p 789 let scalar_of_octets = S.of_octets 790 let scalar_to_octets = S.to_octets 791 let generator = P.params_g 792 let add = P.add 793 let scalar_mult = S.scalar_mult 794end 795 796module P256 : Dh_dsa = struct 797 module Params = struct 798 let a = 799 "\xFF\xFF\xFF\xFF\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC" 800 801 let b = 802 "\x5A\xC6\x35\xD8\xAA\x3A\x93\xE7\xB3\xEB\xBD\x55\x76\x98\x86\xBC\x65\x1D\x06\xB0\xCC\x53\xB0\xF6\x3B\xCE\x3C\x3E\x27\xD2\x60\x4B" 803 804 let g_x = 805 "\x6B\x17\xD1\xF2\xE1\x2C\x42\x47\xF8\xBC\xE6\xE5\x63\xA4\x40\xF2\x77\x03\x7D\x81\x2D\xEB\x33\xA0\xF4\xA1\x39\x45\xD8\x98\xC2\x96" 806 807 let g_y = 808 "\x4F\xE3\x42\xE2\xFE\x1A\x7F\x9B\x8E\xE7\xEB\x4A\x7C\x0F\x9E\x16\x2B\xCE\x33\x57\x6B\x31\x5E\xCE\xCB\xB6\x40\x68\x37\xBF\x51\xF5" 809 810 let p = 811 "\xFF\xFF\xFF\xFF\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" 812 813 let n = 814 "\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" 815 816 let pident = 817 "\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" 818 |> rev_string (* (Params.p + 1) / 4*) 819 820 let byte_length = 32 821 let bit_length = 256 822 let fe_length = 32 823 let first_byte_bits = None 824 end 825 826 module Foreign = struct 827 external mul : out_field_element -> field_element -> field_element -> unit 828 = "mc_p256_mul" 829 [@@noalloc] 830 831 external sub : out_field_element -> field_element -> field_element -> unit 832 = "mc_p256_sub" 833 [@@noalloc] 834 835 external add : out_field_element -> field_element -> field_element -> unit 836 = "mc_p256_add" 837 [@@noalloc] 838 839 external to_montgomery : out_field_element -> field_element -> unit 840 = "mc_p256_to_montgomery" 841 [@@noalloc] 842 843 external from_octets : out_field_element -> string -> unit 844 = "mc_p256_from_bytes" 845 [@@noalloc] 846 847 external set_one : out_field_element -> unit = "mc_p256_set_one" [@@noalloc] 848 external nz : field_element -> bool = "mc_p256_nz" [@@noalloc] 849 850 external sqr : out_field_element -> field_element -> unit = "mc_p256_sqr" 851 [@@noalloc] 852 853 external from_montgomery : out_field_element -> field_element -> unit 854 = "mc_p256_from_montgomery" 855 [@@noalloc] 856 857 external to_octets : bytes -> field_element -> unit = "mc_p256_to_bytes" 858 [@@noalloc] 859 860 external inv : out_field_element -> field_element -> unit = "mc_p256_inv" 861 [@@noalloc] 862 863 external select_c : 864 out_field_element -> bool -> field_element -> field_element -> unit 865 = "mc_p256_select" 866 [@@noalloc] 867 868 external double_c : out_point -> point -> unit = "mc_p256_point_double" 869 [@@noalloc] 870 871 external add_c : out_point -> point -> point -> unit = "mc_p256_point_add" 872 [@@noalloc] 873 874 external scalar_mult_base_c : out_point -> string -> unit 875 = "mc_p256_scalar_mult_base" 876 [@@noalloc] 877 end 878 879 module Foreign_n = struct 880 external mul : out_field_element -> field_element -> field_element -> unit 881 = "mc_np256_mul" 882 [@@noalloc] 883 884 external add : out_field_element -> field_element -> field_element -> unit 885 = "mc_np256_add" 886 [@@noalloc] 887 888 external inv : out_field_element -> field_element -> unit = "mc_np256_inv" 889 [@@noalloc] 890 891 external one : out_field_element -> unit = "mc_np256_one" [@@noalloc] 892 893 external from_bytes : out_field_element -> string -> unit 894 = "mc_np256_from_bytes" 895 [@@noalloc] 896 897 external to_bytes : bytes -> field_element -> unit = "mc_np256_to_bytes" 898 [@@noalloc] 899 900 external from_montgomery : out_field_element -> field_element -> unit 901 = "mc_np256_from_montgomery" 902 [@@noalloc] 903 904 external to_montgomery : out_field_element -> field_element -> unit 905 = "mc_np256_to_montgomery" 906 [@@noalloc] 907 end 908 909 module P = Make_point_ops (Params) (Foreign) 910 module S = Make_scalar (Params) (P) 911 module Dh = Make_dh (Params) (P) (S) 912 module Fn = Make_Fn (Params) (Foreign_n) 913 module Dsa = Make_dsa (Params) (Fn) (P) (S) (Digestif.SHA256) 914 module Point = Make_point (P) (S) 915end 916 917module P384 : Dh_dsa = struct 918 module Params = struct 919 let a = 920 "\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\xFE\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFC" 921 922 let b = 923 "\xB3\x31\x2F\xA7\xE2\x3E\xE7\xE4\x98\x8E\x05\x6B\xE3\xF8\x2D\x19\x18\x1D\x9C\x6E\xFE\x81\x41\x12\x03\x14\x08\x8F\x50\x13\x87\x5A\xC6\x56\x39\x8D\x8A\x2E\xD1\x9D\x2A\x85\xC8\xED\xD3\xEC\x2A\xEF" 924 925 let g_x = 926 "\xAA\x87\xCA\x22\xBE\x8B\x05\x37\x8E\xB1\xC7\x1E\xF3\x20\xAD\x74\x6E\x1D\x3B\x62\x8B\xA7\x9B\x98\x59\xF7\x41\xE0\x82\x54\x2A\x38\x55\x02\xF2\x5D\xBF\x55\x29\x6C\x3A\x54\x5E\x38\x72\x76\x0A\xB7" 927 928 let g_y = 929 "\x36\x17\xde\x4a\x96\x26\x2c\x6f\x5d\x9e\x98\xbf\x92\x92\xdc\x29\xf8\xf4\x1d\xbd\x28\x9a\x14\x7c\xe9\xda\x31\x13\xb5\xf0\xb8\xc0\x0a\x60\xb1\xce\x1d\x7e\x81\x9d\x7a\x43\x1d\x7c\x90\xea\x0e\x5f" 930 931 let p = 932 "\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\xFE\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF" 933 934 let n = 935 "\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" 936 937 let pident = 938 "\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" 939 |> rev_string (* (Params.p + 1) / 4*) 940 941 let byte_length = 48 942 let bit_length = 384 943 let fe_length = 48 944 let first_byte_bits = None 945 end 946 947 module Foreign = struct 948 external mul : out_field_element -> field_element -> field_element -> unit 949 = "mc_p384_mul" 950 [@@noalloc] 951 952 external sub : out_field_element -> field_element -> field_element -> unit 953 = "mc_p384_sub" 954 [@@noalloc] 955 956 external add : out_field_element -> field_element -> field_element -> unit 957 = "mc_p384_add" 958 [@@noalloc] 959 960 external to_montgomery : out_field_element -> field_element -> unit 961 = "mc_p384_to_montgomery" 962 [@@noalloc] 963 964 external from_octets : out_field_element -> string -> unit 965 = "mc_p384_from_bytes" 966 [@@noalloc] 967 968 external set_one : out_field_element -> unit = "mc_p384_set_one" [@@noalloc] 969 external nz : field_element -> bool = "mc_p384_nz" [@@noalloc] 970 971 external sqr : out_field_element -> field_element -> unit = "mc_p384_sqr" 972 [@@noalloc] 973 974 external from_montgomery : out_field_element -> field_element -> unit 975 = "mc_p384_from_montgomery" 976 [@@noalloc] 977 978 external to_octets : bytes -> field_element -> unit = "mc_p384_to_bytes" 979 [@@noalloc] 980 981 external inv : out_field_element -> field_element -> unit = "mc_p384_inv" 982 [@@noalloc] 983 984 external select_c : 985 out_field_element -> bool -> field_element -> field_element -> unit 986 = "mc_p384_select" 987 [@@noalloc] 988 989 external double_c : out_point -> point -> unit = "mc_p384_point_double" 990 [@@noalloc] 991 992 external add_c : out_point -> point -> point -> unit = "mc_p384_point_add" 993 [@@noalloc] 994 995 external scalar_mult_base_c : out_point -> string -> unit 996 = "mc_p384_scalar_mult_base" 997 [@@noalloc] 998 end 999 1000 module Foreign_n = struct 1001 external mul : out_field_element -> field_element -> field_element -> unit 1002 = "mc_np384_mul" 1003 [@@noalloc] 1004 1005 external add : out_field_element -> field_element -> field_element -> unit 1006 = "mc_np384_add" 1007 [@@noalloc] 1008 1009 external inv : out_field_element -> field_element -> unit = "mc_np384_inv" 1010 [@@noalloc] 1011 1012 external one : out_field_element -> unit = "mc_np384_one" [@@noalloc] 1013 1014 external from_bytes : out_field_element -> string -> unit 1015 = "mc_np384_from_bytes" 1016 [@@noalloc] 1017 1018 external to_bytes : bytes -> field_element -> unit = "mc_np384_to_bytes" 1019 [@@noalloc] 1020 1021 external from_montgomery : out_field_element -> field_element -> unit 1022 = "mc_np384_from_montgomery" 1023 [@@noalloc] 1024 1025 external to_montgomery : out_field_element -> field_element -> unit 1026 = "mc_np384_to_montgomery" 1027 [@@noalloc] 1028 end 1029 1030 module P = Make_point_ops (Params) (Foreign) 1031 module S = Make_scalar (Params) (P) 1032 module Dh = Make_dh (Params) (P) (S) 1033 module Fn = Make_Fn (Params) (Foreign_n) 1034 module Dsa = Make_dsa (Params) (Fn) (P) (S) (Digestif.SHA384) 1035 module Point = Make_point (P) (S) 1036end 1037 1038module P521 : Dh_dsa = struct 1039 module Params = struct 1040 let a = 1041 "\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\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\xFC" 1042 1043 let b = 1044 "\x00\x51\x95\x3E\xB9\x61\x8E\x1C\x9A\x1F\x92\x9A\x21\xA0\xB6\x85\x40\xEE\xA2\xDA\x72\x5B\x99\xB3\x15\xF3\xB8\xB4\x89\x91\x8E\xF1\x09\xE1\x56\x19\x39\x51\xEC\x7E\x93\x7B\x16\x52\xC0\xBD\x3B\xB1\xBF\x07\x35\x73\xDF\x88\x3D\x2C\x34\xF1\xEF\x45\x1F\xD4\x6B\x50\x3F\x00" 1045 1046 let g_x = 1047 "\x00\xC6\x85\x8E\x06\xB7\x04\x04\xE9\xCD\x9E\x3E\xCB\x66\x23\x95\xB4\x42\x9C\x64\x81\x39\x05\x3F\xB5\x21\xF8\x28\xAF\x60\x6B\x4D\x3D\xBA\xA1\x4B\x5E\x77\xEF\xE7\x59\x28\xFE\x1D\xC1\x27\xA2\xFF\xA8\xDE\x33\x48\xB3\xC1\x85\x6A\x42\x9B\xF9\x7E\x7E\x31\xC2\xE5\xBD\x66" 1048 1049 let g_y = 1050 "\x01\x18\x39\x29\x6a\x78\x9a\x3b\xc0\x04\x5c\x8a\x5f\xb4\x2c\x7d\x1b\xd9\x98\xf5\x44\x49\x57\x9b\x44\x68\x17\xaf\xbd\x17\x27\x3e\x66\x2c\x97\xee\x72\x99\x5e\xf4\x26\x40\xc5\x50\xb9\x01\x3f\xad\x07\x61\x35\x3c\x70\x86\xa2\x72\xc2\x40\x88\xbe\x94\x76\x9f\xd1\x66\x50" 1051 1052 let p = 1053 "\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\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" 1054 1055 let n = 1056 "\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" 1057 1058 let pident = 1059 "\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" 1060 |> rev_string 1061 1062 let byte_length = 66 1063 let bit_length = 521 1064 1065 let fe_length = 1066 if Sys.word_size == 64 then 72 1067 else 68 (* TODO: is this congruent with C code? *) 1068 1069 let first_byte_bits = Some 0x01 1070 end 1071 1072 module Foreign = struct 1073 external mul : out_field_element -> field_element -> field_element -> unit 1074 = "mc_p521_mul" 1075 [@@noalloc] 1076 1077 external sub : out_field_element -> field_element -> field_element -> unit 1078 = "mc_p521_sub" 1079 [@@noalloc] 1080 1081 external add : out_field_element -> field_element -> field_element -> unit 1082 = "mc_p521_add" 1083 [@@noalloc] 1084 1085 external to_montgomery : out_field_element -> field_element -> unit 1086 = "mc_p521_to_montgomery" 1087 [@@noalloc] 1088 1089 external from_octets : out_field_element -> string -> unit 1090 = "mc_p521_from_bytes" 1091 [@@noalloc] 1092 1093 external set_one : out_field_element -> unit = "mc_p521_set_one" [@@noalloc] 1094 external nz : field_element -> bool = "mc_p521_nz" [@@noalloc] 1095 1096 external sqr : out_field_element -> field_element -> unit = "mc_p521_sqr" 1097 [@@noalloc] 1098 1099 external from_montgomery : out_field_element -> field_element -> unit 1100 = "mc_p521_from_montgomery" 1101 [@@noalloc] 1102 1103 external to_octets : bytes -> field_element -> unit = "mc_p521_to_bytes" 1104 [@@noalloc] 1105 1106 external inv : out_field_element -> field_element -> unit = "mc_p521_inv" 1107 [@@noalloc] 1108 1109 external select_c : 1110 out_field_element -> bool -> field_element -> field_element -> unit 1111 = "mc_p521_select" 1112 [@@noalloc] 1113 1114 external double_c : out_point -> point -> unit = "mc_p521_point_double" 1115 [@@noalloc] 1116 1117 external add_c : out_point -> point -> point -> unit = "mc_p521_point_add" 1118 [@@noalloc] 1119 1120 external scalar_mult_base_c : out_point -> string -> unit 1121 = "mc_p521_scalar_mult_base" 1122 [@@noalloc] 1123 end 1124 1125 module Foreign_n = struct 1126 external mul : out_field_element -> field_element -> field_element -> unit 1127 = "mc_np521_mul" 1128 [@@noalloc] 1129 1130 external add : out_field_element -> field_element -> field_element -> unit 1131 = "mc_np521_add" 1132 [@@noalloc] 1133 1134 external inv : out_field_element -> field_element -> unit = "mc_np521_inv" 1135 [@@noalloc] 1136 1137 external one : out_field_element -> unit = "mc_np521_one" [@@noalloc] 1138 1139 external from_bytes : out_field_element -> string -> unit 1140 = "mc_np521_from_bytes" 1141 [@@noalloc] 1142 1143 external to_bytes : bytes -> field_element -> unit = "mc_np521_to_bytes" 1144 [@@noalloc] 1145 1146 external from_montgomery : out_field_element -> field_element -> unit 1147 = "mc_np521_from_montgomery" 1148 [@@noalloc] 1149 1150 external to_montgomery : out_field_element -> field_element -> unit 1151 = "mc_np521_to_montgomery" 1152 [@@noalloc] 1153 end 1154 1155 module P = Make_point_ops (Params) (Foreign) 1156 module S = Make_scalar (Params) (P) 1157 module Dh = Make_dh (Params) (P) (S) 1158 module Fn = Make_Fn (Params) (Foreign_n) 1159 module Dsa = Make_dsa (Params) (Fn) (P) (S) (Digestif.SHA512) 1160 module Point = Make_point (P) (S) 1161end 1162 1163module X25519 = struct 1164 (* RFC 7748 *) 1165 external x25519_scalar_mult_generic : bytes -> string -> string -> unit 1166 = "mc_x25519_scalar_mult_generic" 1167 [@@noalloc] 1168 1169 let key_len = 32 1170 1171 let scalar_mult in_ base = 1172 let out = Bytes.create key_len in 1173 x25519_scalar_mult_generic out in_ base; 1174 Bytes.unsafe_to_string out 1175 1176 type secret = string 1177 1178 let basepoint = String.init key_len (function 0 -> '\009' | _ -> '\000') 1179 let public priv = scalar_mult priv basepoint 1180 1181 let gen_key ?compress:_ ?g () = 1182 let secret = Crypto_rng.generate ?g key_len in 1183 (secret, public secret) 1184 1185 let secret_of_octets ?compress:_ s = 1186 if String.length s = key_len then Ok (s, public s) 1187 else Error `Invalid_length 1188 1189 let secret_to_octets s = s 1190 1191 let is_zero = 1192 let zero = String.make key_len '\000' in 1193 fun buf -> String.equal zero buf 1194 1195 let key_exchange secret public = 1196 if String.length public = key_len then 1197 let res = scalar_mult secret public in 1198 if is_zero res then Error `Low_order else Ok res 1199 else Error `Invalid_length 1200end 1201 1202module Ed25519 = struct 1203 external scalar_mult_base_to_bytes : bytes -> string -> unit 1204 = "mc_25519_scalar_mult_base" 1205 [@@noalloc] 1206 1207 external reduce_l : bytes -> unit = "mc_25519_reduce_l" [@@noalloc] 1208 1209 external muladd : bytes -> string -> string -> string -> unit 1210 = "mc_25519_muladd" 1211 [@@noalloc] 1212 1213 external double_scalar_mult : bytes -> string -> string -> string -> bool 1214 = "mc_25519_double_scalar_mult" 1215 [@@noalloc] 1216 1217 external pub_ok : string -> bool = "mc_25519_pub_ok" [@@noalloc] 1218 1219 let key_len = 32 1220 1221 let scalar_mult_base_to_bytes p = 1222 let tmp = Bytes.create key_len in 1223 scalar_mult_base_to_bytes tmp p; 1224 Bytes.unsafe_to_string tmp 1225 1226 let muladd a b c = 1227 let tmp = Bytes.create key_len in 1228 muladd tmp a b c; 1229 Bytes.unsafe_to_string tmp 1230 1231 let double_scalar_mult a b c = 1232 let tmp = Bytes.create key_len in 1233 let s = double_scalar_mult tmp a b c in 1234 (s, Bytes.unsafe_to_string tmp) 1235 1236 type pub = string 1237 type priv = string 1238 1239 let sha512 datas = 1240 let open Digestif.SHA512 in 1241 let buf = Bytes.create digest_size in 1242 let ctx = List.fold_left (feed_string ?off:None ?len:None) empty datas in 1243 get_into_bytes ctx buf; 1244 buf 1245 1246 (* RFC 8032 *) 1247 let public secret = 1248 (* section 5.1.5 *) 1249 (* step 1 *) 1250 let h = sha512 [ secret ] in 1251 (* step 2 *) 1252 let s, rest = 1253 ( Bytes.sub h 0 key_len, 1254 Bytes.unsafe_to_string (Bytes.sub h key_len (Bytes.length h - key_len)) 1255 ) 1256 in 1257 Bytes.set_uint8 s 0 (Bytes.get_uint8 s 0 land 248); 1258 Bytes.set_uint8 s 31 (Bytes.get_uint8 s 31 land 127 lor 64); 1259 let s = Bytes.unsafe_to_string s in 1260 (* step 3 and 4 *) 1261 let public = scalar_mult_base_to_bytes s in 1262 (public, (s, rest)) 1263 1264 let pub_of_priv secret = fst (public secret) 1265 1266 let priv_of_octets buf = 1267 if String.length buf = key_len then Ok buf else Error `Invalid_length 1268 1269 let priv_to_octets (priv : priv) = priv 1270 1271 let pub_of_octets buf = 1272 if String.length buf = key_len then 1273 if pub_ok buf then Ok buf else Error `Not_on_curve 1274 else Error `Invalid_length 1275 1276 let pub_to_octets pub = pub 1277 1278 let generate ?g () = 1279 let secret = Crypto_rng.generate ?g key_len in 1280 (secret, pub_of_priv secret) 1281 1282 let sign ~key msg = 1283 (* section 5.1.6 *) 1284 let pub, (s, prefix) = public key in 1285 let r = sha512 [ prefix; msg ] in 1286 reduce_l r; 1287 let r = Bytes.unsafe_to_string r in 1288 let r_big = scalar_mult_base_to_bytes r in 1289 let k = sha512 [ r_big; pub; msg ] in 1290 reduce_l k; 1291 let k = Bytes.unsafe_to_string k in 1292 let s_out = muladd k s r in 1293 let res = Bytes.create (key_len + key_len) in 1294 Bytes.unsafe_blit_string r_big 0 res 0 key_len; 1295 Bytes.unsafe_blit_string s_out 0 res key_len key_len; 1296 Bytes.unsafe_to_string res 1297 1298 let verify ~key signature ~msg = 1299 (* section 5.1.7 *) 1300 if String.length signature = 2 * key_len then 1301 let r, s = 1302 (String.sub signature 0 key_len, String.sub signature key_len key_len) 1303 in 1304 let s_smaller_l = 1305 (* check s within 0 <= s < L *) 1306 let s' = Bytes.make (key_len * 2) '\000' in 1307 Bytes.unsafe_blit_string s 0 s' 0 key_len; 1308 reduce_l s'; 1309 let s' = Bytes.unsafe_to_string s' in 1310 let s'' = s ^ String.make key_len '\000' in 1311 String.equal s'' s' 1312 in 1313 if s_smaller_l then begin 1314 let k = sha512 [ r; key; msg ] in 1315 reduce_l k; 1316 let k = Bytes.unsafe_to_string k in 1317 let success, r' = double_scalar_mult k key s in 1318 success && String.equal r r' 1319 end 1320 else false 1321 else false 1322end