mte/unikernel/duniverse/mirage-crypto/pk/z_extra.ml
2025-11-11 02:07:51 +01:00

135 lines
4.3 KiB
OCaml

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