open Mirage_crypto.Uncommon let bit_bound z = Z.size z * 64 let of_octets_be ?bits buf = let rec loop acc i = function | b when b >= 64 -> let x = String.get_int64_be buf i in let x = Z.of_int64_unsigned Int64.(shift_right_logical x 8) in loop Z.(x + acc lsl 56) (i + 7) (b - 56) | b when b >= 32 -> let x = String.get_int32_be buf i in let x = Z.of_int32_unsigned Int32.(shift_right_logical x 8) in loop Z.(x + acc lsl 24) (i + 3) (b - 24) | b when b >= 16 -> let x = Z.of_int (String.get_uint16_be buf i) in loop Z.(x + acc lsl 16) (i + 2) (b - 16) | b when b >= 8 -> let x = Z.of_int (String.get_uint8 buf i) in loop Z.(x + acc lsl 8 ) (i + 1) (b - 8 ) | b when b > 0 -> let x = String.get_uint8 buf i and b' = 8 - b in Z.(of_int x asr b' + acc lsl b) | _ -> acc in loop Z.zero 0 @@ match bits with | None -> String.length buf * 8 | Some b -> imin b (String.length buf * 8) let byte1 = Z.of_int64 0xffL and byte2 = Z.of_int64 0xffffL and byte3 = Z.of_int64 0xffffffL and byte7 = Z.of_int64 0xffffffffffffffL let into_octets_be n buf = let rec write n = function | i when i >= 7 -> Bytes.set_int64_be buf (i - 7) Z.(to_int64_unsigned (n land byte7)) ; write Z.(n asr 56) (i - 7) | i when i >= 3 -> Bytes.set_int32_be buf (i - 3) Z.(to_int32_unsigned (n land byte3)) ; write Z.(n asr 24) (i - 3) | i when i >= 1 -> Bytes.set_uint16_be buf (i - 1) Z.(to_int (n land byte2)) ; write Z.(n asr 16) (i - 2) | 0 -> Bytes.set_uint8 buf 0 Z.(to_int (n land byte1)) ; | _ -> () in write n (Bytes.length buf - 1) let to_octets_be ?size n = let buf = Bytes.create @@ match size with | Some s -> imax 0 s | None -> Z.numbits n // 8 in into_octets_be n buf; Bytes.unsafe_to_string buf (* Handbook of Applied Cryptography, Table 4.4: * Miller-Rabin rounds for composite probability <= 1/2^80. *) let pseudoprime z = let i = match Z.numbits z with | i when i >= 1300 -> 2 | i when i >= 850 -> 3 | i when i >= 650 -> 4 | i when i >= 350 -> 8 | i when i >= 250 -> 12 | i when i >= 150 -> 18 | _ -> 27 in Z.probab_prime z i <> 0 (* strip_factor ~f x = (s, t), where x = f^s t *) let strip_factor ~f x = let rec go n x = let (x1, r) = Z.div_rem x f in if r = Z.zero then go (succ n) x1 else Ok (n, x) in if Z.(~$2) <= f then go 0 x else Error (`Msg ("factor_count: f: " ^ Z.to_string f)) let gen ?g n = if n < Z.one then invalid_arg "Rng.gen: non-positive: %a" Z.pp_print n; let bs = Mirage_crypto_rng.block g in let bits = Z.(numbits (pred n)) in let octets = bits // 8 in let batch = if Mirage_crypto_rng.strict g then octets else 2 * octets // bs * bs in let rec attempt buf = if String.length buf >= octets then let x = of_octets_be ~bits buf in if x < n then x else attempt (String.sub buf octets (String.length buf - octets)) else attempt (Mirage_crypto_rng.generate ?g batch) in attempt (Mirage_crypto_rng.generate ?g batch) let rec gen_r ?g a b = if Mirage_crypto_rng.strict g then let x = gen ?g b in if x < a then gen_r ?g a b else x else Z.(a + gen ?g (b - a)) let set_msb bits buf = if bits > 0 then let n = Bytes.length buf in let rec go width = function | i when i = n -> () | i when width < 8 -> Bytes.set_uint8 buf i (Bytes.get_uint8 buf i lor (0xff lsl (8 - width))) | i -> Bytes.set_uint8 buf i 0xff ; go (width - 8) (succ i) in go bits 0 let gen_bits ?g ?(msb = 0) bits = let bytelen = bits // 8 in let buf = Bytes.create bytelen in Mirage_crypto_rng.generate_into ?g buf ~off:0 bytelen; set_msb msb buf ; of_octets_be ~bits (Bytes.unsafe_to_string buf) (* Invalid combinations of ~bits and ~msb will loop forever, but there is no * way to quickly determine upfront whether there are any primes in the * interval. * XXX Probability is distributed as inter-prime gaps. So? *) let rec prime ?g ?(msb = 1) bits = let p = Z.(nextprime @@ gen_bits ?g ~msb bits) in if p < Z.(one lsl bits) then p else prime ?g ~msb bits (* XXX Add ~msb param for p? *) let rec safe_prime ?g bits = let q = prime ?g ~msb:1 (bits - 1) in let p = Z.(q * ~$2 + ~$1) in if pseudoprime p then (q, p) else safe_prime ?g bits