Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
uuidm.ml1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322(*--------------------------------------------------------------------------- Copyright (c) 2008 The uuidm programmers. All rights reserved. SPDX-License-Identifier: ISC ---------------------------------------------------------------------------*) (* Bits *) type bits62 = int64 type bits4 = int type bits12 = int (* Hashing *) let md5 = Digest.string let sha_1 s = (* Based on pseudo-code of RFC 3174. Slow and ugly but does the job. *) let sha_1_pad s = let len = String.length s in let blen = 8 * len in let rem = len mod 64 in let mlen = if rem > 55 then len + 128 - rem else len + 64 - rem in let m = Bytes.create mlen in Bytes.blit_string s 0 m 0 len; Bytes.fill m len (mlen - len) '\x00'; Bytes.set m len '\x80'; if Sys.word_size > 32 then begin Bytes.set_uint8 m (mlen - 8) (blen lsr 56 land 0xFF); Bytes.set_uint8 m (mlen - 7) (blen lsr 48 land 0xFF); Bytes.set_uint8 m (mlen - 6) (blen lsr 40 land 0xFF); Bytes.set_uint8 m (mlen - 5) (blen lsr 32 land 0xFF); end; Bytes.set_uint8 m (mlen - 4) (blen lsr 24 land 0xFF); Bytes.set_uint8 m (mlen - 3) (blen lsr 16 land 0xFF); Bytes.set_uint8 m (mlen - 2) (blen lsr 8 land 0xFF); Bytes.set_uint8 m (mlen - 1) (blen land 0xFF); m in (* Operations on int32 *) let ( &&& ) = ( land ) in let ( lor ) = Int32.logor in let ( lxor ) = Int32.logxor in let ( land ) = Int32.logand in let ( ++ ) = Int32.add in let lnot = Int32.lognot in let sl = Int32.shift_left in let cls n x = (sl x n) lor (Int32.shift_right_logical x (32 - n)) in (* Start *) let m = sha_1_pad s in let w = Array.make 16 0l in let h0 = ref 0x67452301l in let h1 = ref 0xEFCDAB89l in let h2 = ref 0x98BADCFEl in let h3 = ref 0x10325476l in let h4 = ref 0xC3D2E1F0l in let a = ref 0l in let b = ref 0l in let c = ref 0l in let d = ref 0l in let e = ref 0l in for i = 0 to ((Bytes.length m) / 64) - 1 do (* For each block *) (* Fill w *) let base = i * 64 in for j = 0 to 15 do w.(j) <- Bytes.get_int32_be m (base + (j * 4)); done; (* Loop *) a := !h0; b := !h1; c := !h2; d := !h3; e := !h4; for t = 0 to 79 do let f, k = if t <= 19 then (!b land !c) lor ((lnot !b) land !d), 0x5A827999l else if t <= 39 then !b lxor !c lxor !d, 0x6ED9EBA1l else if t <= 59 then (!b land !c) lor (!b land !d) lor (!c land !d), 0x8F1BBCDCl else !b lxor !c lxor !d, 0xCA62C1D6l in let s = t &&& 0xF in if (t >= 16) then begin w.(s) <- cls 1 begin w.((s + 13) &&& 0xF) lxor w.((s + 8) &&& 0xF) lxor w.((s + 2) &&& 0xF) lxor w.(s) end end; let temp = (cls 5 !a) ++ f ++ !e ++ w.(s) ++ k in e := !d; d := !c; c := cls 30 !b; b := !a; a := temp; done; (* Update *) h0 := !h0 ++ !a; h1 := !h1 ++ !b; h2 := !h2 ++ !c; h3 := !h3 ++ !d; h4 := !h4 ++ !e done; let h = Bytes.create 20 in let i2s h k i = Bytes.set_int32_be h k i in i2s h 0 !h0; i2s h 4 !h1; i2s h 8 !h2; i2s h 12 !h3; i2s h 16 !h4; Bytes.unsafe_to_string h (* Uuids *) type t = string (* 16 bytes *) let make u ~version = let b6 = (version lsl 4) lor ((Bytes.get_uint8 u 6) land 0b0000_1111) in let b8 = 0b1000_0000 lor ((Bytes.get_uint8 u 8) land 0b0011_1111) in Bytes.set_uint8 u 6 b6; Bytes.set_uint8 u 8 b8; Bytes.unsafe_to_string u let make_named ~version digest ns n = let hash = Bytes.unsafe_of_string (digest (ns ^ n)) in make (Bytes.sub hash 0 16) ~version let v3 ns n = make_named ~version:3 md5 ns n let v5 ns n = make_named ~version:5 sha_1 ns n let v4 b = make (Bytes.sub b 0 16) ~version:4 let v7 ~time_ms ~rand_a ~rand_b = let u = Bytes.create 16 in Bytes.set_int64_be u 0 (Int64.shift_left time_ms 16); Bytes.set_int16_be u 6 rand_a; Bytes.set_int64_be u 8 rand_b; make u ~version:7 let v7_ns ~time_ns ~rand_b = let ns_in_ms = 1_000_000L in let sub_ms_frac_multiplier = Int64.unsigned_div Int64.minus_one ns_in_ms in let u = Bytes.create 16 in (* RFC 9562 requires we use 48 bits for a timestamp in milliseconds, and allows for 12 bits to store a sub-millisecond fraction. We get the latter by multiplying to put the fraction in a 64-bit range, then shifting into 12 bits. *) let ms = Int64.unsigned_div time_ns ns_in_ms in let ns = Int64.unsigned_rem time_ns ns_in_ms in let sub_ms_frac = Int64.shift_right_logical (Int64.mul ns sub_ms_frac_multiplier) 52 in Bytes.set_int64_be u 0 (Int64.shift_left ms 16); Bytes.set_int16_be u 6 (Int64.to_int sub_ms_frac); Bytes.set_int64_be u 8 rand_b; make u ~version:7 let v8 s = let l = String.length s in if l = 16 then make (Bytes.of_string s) ~version:8 else invalid_arg (Printf.sprintf "expected 16 bytes but found: %d" l) (* Generators *) type posix_ms_clock = unit -> int64 let v4_random rstate = let r0 = Random.State.bits64 rstate in let r1 = Random.State.bits64 rstate in let u = Bytes.create 16 in Bytes.set_int64_be u 0 r0; Bytes.set_int64_be u 8 r1; make u ~version:4 let v4_gen rstate = function () -> v4_random rstate let v7_non_monotonic_gen ~now_ms rstate = fun () -> let time_ms = now_ms () in let rand_a = Random.State.bits (* 30 bits *) rstate in let rand_b = Random.State.bits64 rstate in v7 ~time_ms ~rand_a ~rand_b let v7_monotonic_gen ~now_ms rstate = let last_ms = ref 0L in let count = ref 0 in fun () -> let time_ms = now_ms () in let rand_b = Random.State.bits64 rstate in if Int64.equal time_ms !last_ms then let rand_a = incr count; !count in if rand_a >= 4096 then None else Some (v7 ~time_ms ~rand_a ~rand_b) else (count := 0; last_ms := time_ms; Some (v7 ~time_ms ~rand_a:0 ~rand_b)) (* Constants *) let nil = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" let max = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" let ns_dns = "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8" let ns_url = "\x6b\xa7\xb8\x11\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8" let ns_oid = "\x6b\xa7\xb8\x12\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8" let ns_X500 ="\x6b\xa7\xb8\x14\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8" (* Properties *) let variant u = (String.get_uint8 u 8) lsr 4 let version u = (String.get_uint8 u 6) lsr 4 let time_ms u = let variant = variant u in if not (0x8 <= variant && variant <= 0xB && version u = 7) then None else Some (Int64.shift_right_logical (String.get_int64_be u 0) 16) (* Predicates and comparisons *) let equal = String.equal let compare = String.compare (* Standard binary format *) let to_binary_string s = s let of_binary_string ?(pos = 0) s = let len = String.length s in if pos + 16 > len then None else if pos = 0 && len = 16 then Some s else Some (String.sub s pos 16) (* Mixed endian binary format *) let mixed_swaps s = let swap b i j = let t = Bytes.get b i in Bytes.set b i (Bytes.get b j); Bytes.set b j t in let b = Bytes.of_string s in swap b 0 3; swap b 1 2; swap b 4 5; swap b 6 7; Bytes.unsafe_to_string b let to_mixed_endian_binary_string s = mixed_swaps s let of_mixed_endian_binary_string ?pos s = Option.map mixed_swaps (of_binary_string ?pos s) (* Unsafe conversions *) let unsafe_of_binary_string u = u let unsafe_to_binary_string u = u (* US-ASCII format *) let of_string ?(pos = 0) s = let len = String.length s in if pos + 36 > len || s.[pos + 8] <> '-' || s.[pos + 13] <> '-' || s.[pos + 18] <> '-' || s.[pos + 23] <> '-' then None else try let u = Bytes.create 16 in let i = ref 0 in let j = ref pos in let ihex c = let i = Char.code c in if i < 0x30 then raise Exit else if i <= 0x39 then i - 0x30 else if i < 0x41 then raise Exit else if i <= 0x46 then i - 0x37 else if i < 0x61 then raise Exit else if i <= 0x66 then i - 0x57 else raise Exit in let byte s j = Char.unsafe_chr (ihex s.[j] lsl 4 lor ihex s.[j + 1]) in while (!i < 4) do Bytes.set u !i (byte s !j); j := !j + 2; incr i done; incr j; while (!i < 6) do Bytes.set u !i (byte s !j); j := !j + 2; incr i done; incr j; while (!i < 8) do Bytes.set u !i (byte s !j); j := !j + 2; incr i done; incr j; while (!i < 10) do Bytes.set u !i (byte s !j); j := !j + 2; incr i done; incr j; while (!i < 16) do Bytes.set u !i (byte s !j); j := !j + 2; incr i done; Some (Bytes.unsafe_to_string u) with Exit -> None let to_string ?(upper = false) u = let hbase = if upper then 0x37 else 0x57 in let hex hbase i = Char.unsafe_chr (if i < 10 then 0x30 + i else hbase + i) in let s = Bytes.of_string "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" in let i = ref 0 in let j = ref 0 in let byte s i c = Bytes.set s i @@ hex hbase (c lsr 4); Bytes.set s (i + 1) @@ hex hbase (c land 0x0F) in while (!j < 4) do byte s !i (Char.code u.[!j]); i := !i + 2; incr j; done; incr i; while (!j < 6) do byte s !i (Char.code u.[!j]); i := !i + 2; incr j; done; incr i; while (!j < 8) do byte s !i (Char.code u.[!j]); i := !i + 2; incr j; done; incr i; while (!j < 10) do byte s !i (Char.code u.[!j]); i := !i + 2; incr j; done; incr i; while (!j < 16) do byte s !i (Char.code u.[!j]); i := !i + 2; incr j; done; Bytes.unsafe_to_string s (* Pretty-printing *) let pp ppf u = Format.pp_print_string ppf (to_string u) let pp' ~upper ppf u = Format.pp_print_string ppf (to_string ~upper u) (* Deprecated *) let default_seed = lazy (Random.State.make_self_init ()) type version = [ `V3 of t * string | `V4 | `V5 of t * string ] let v = function | `V4 -> v4_random (Lazy.force default_seed) | `V3 (ns, n) -> v3 ns n | `V5 (ns, n) -> v5 ns n let create = v (* deprecated *) let pp_string ?upper ppf u = Format.pp_print_string ppf (to_string ?upper u) let print = pp_string (* deprecated *) let to_bytes = to_binary_string let of_bytes = of_binary_string let to_mixed_endian_bytes = to_mixed_endian_binary_string let of_mixed_endian_bytes = of_mixed_endian_binary_string let unsafe_of_bytes = unsafe_of_binary_string let unsafe_to_bytes = unsafe_to_binary_string