experimental hashing with oxcaml
1open Bigarray
2
3type state = (int32, int32_elt, c_layout) Array1.t
4type digest = (int, int8_unsigned_elt, c_layout) Array1.t
5type buffer = (int, int8_unsigned_elt, c_layout) Array1.t
6
7(* External C functions *)
8external init : unit -> state = "oxcaml_sha256_init"
9external process_block : state -> buffer -> unit = "oxcaml_sha256_process_block" [@@noalloc]
10external finalize : state -> buffer -> int64 -> digest = "oxcaml_sha256_finalize"
11external oneshot : buffer -> int64 -> digest = "oxcaml_sha256_oneshot"
12
13(* High-level interface *)
14
15let hash_bytes bytes =
16 let len = Bytes.length bytes in
17 let buffer = Array1.create int8_unsigned c_layout len in
18 for i = 0 to len - 1 do
19 Array1.set buffer i (Char.code (Bytes.get bytes i))
20 done;
21 oneshot buffer (Int64.of_int len)
22
23let hash_string str =
24 let len = String.length str in
25 let buffer = Array1.create int8_unsigned c_layout len in
26 for i = 0 to len - 1 do
27 Array1.set buffer i (Char.code str.[i])
28 done;
29 oneshot buffer (Int64.of_int len)
30
31(* Utilities *)
32
33let digest_to_hex digest =
34 let hex_of_byte b =
35 Printf.sprintf "%02x" b
36 in
37 let buf = Buffer.create 64 in
38 for i = 0 to 31 do
39 Buffer.add_string buf (hex_of_byte (Array1.get digest i))
40 done;
41 Buffer.contents buf
42
43let digest_to_bytes digest =
44 let bytes = Bytes.create 32 in
45 for i = 0 to 31 do
46 Bytes.set bytes i (Char.chr (Array1.get digest i))
47 done;
48 bytes
49
50let digest_equal d1 d2 =
51 let rec compare i =
52 if i >= 32 then true
53 else if Array1.get d1 i <> Array1.get d2 i then false
54 else compare (i + 1)
55 in
56 compare 0
57
58(* Zero-allocation variants using OxCaml features *)
59
60module Fast = struct
61 (* Stack-allocated processing for temporary computations *)
62 let[@inline] [@zero_alloc assume] process_block_local state block =
63 process_block state block
64
65 (* Process multiple blocks efficiently *)
66 let[@zero_alloc assume] process_blocks state blocks num_blocks =
67 for i = 0 to num_blocks - 1 do
68 let offset = i * 64 in
69 let block = Array1.sub blocks offset 64 in
70 process_block state block
71 done
72
73 (* Parallel hashing for multiple inputs *)
74 let parallel_hash_many par inputs =
75 match inputs with
76 | [] -> []
77 | [x] -> [hash_bytes x]
78 | _ ->
79 let process_batch batch =
80 List.map hash_bytes batch
81 in
82 let mid = List.length inputs / 2 in
83 let rec split n lst =
84 if n = 0 then ([], lst)
85 else match lst with
86 | [] -> ([], [])
87 | h::t -> let (l1, l2) = split (n-1) t in (h::l1, l2)
88 in
89 let (left, right) = split mid inputs in
90 let left_results, right_results =
91 Parallel.fork_join2 par
92 (fun _ -> process_batch left)
93 (fun _ -> process_batch right)
94 in
95 left_results @ right_results
96end