forked from
gazagnaire.org/irmin
Persistent store with Git semantics: lazy reads, delayed writes, content-addressing
1(** Content-addressed hashes with phantom types for algorithm safety.
2
3 This module provides SHA-1 and SHA-256 hash types that are distinguished at
4 the type level, preventing accidental mixing of different hash algorithms.
5*)
6
7(** {1 Hash Algorithms} *)
8
9type algorithm =
10 | Sha1 (** SHA-1: 20 bytes, Git compatible *)
11 | Sha256 (** SHA-256: 32 bytes, ATProto compatible *)
12
13(** {1 Phantom-Typed Hashes} *)
14
15type 'a t
16(** ['a t] is a hash where ['a] is a phantom type indicating the algorithm. *)
17
18type sha1 = [ `Sha1 ] t
19(** SHA-1 hash: 20 bytes, used by Git. *)
20
21type sha256 = [ `Sha256 ] t
22(** SHA-256 hash: 32 bytes, used by ATProto MST. *)
23
24(** {1 Hash Construction} *)
25
26val sha1 : string -> sha1
27(** [sha1 data] computes the SHA-1 hash of [data]. *)
28
29val sha256 : string -> sha256
30(** [sha256 data] computes the SHA-256 hash of [data]. *)
31
32val sha1_of_bytes : string -> sha1
33(** [sha1_of_bytes raw] creates a SHA-1 hash from raw 20-byte digest. *)
34
35val sha256_of_bytes : string -> sha256
36(** [sha256_of_bytes raw] creates a SHA-256 hash from raw 32-byte digest. *)
37
38(** {1 Conversions} *)
39
40val to_bytes : _ t -> string
41(** [to_bytes h] returns the raw bytes of the hash digest. *)
42
43val to_hex : _ t -> string
44(** [to_hex h] returns the hexadecimal representation of the hash. *)
45
46type existential =
47 | Ex : _ t -> existential
48 (** Type-erased hash returned when algorithm is only known at runtime. *)
49
50val of_hex : algorithm -> string -> (existential, [> `Msg of string ]) result
51(** [of_hex algo hex] parses a hexadecimal hash string. *)
52
53val sha1_of_hex : string -> (sha1, [> `Msg of string ]) result
54(** [sha1_of_hex hex] parses a SHA-1 hex string. *)
55
56val sha256_of_hex : string -> (sha256, [> `Msg of string ]) result
57(** [sha256_of_hex hex] parses a SHA-256 hex string. *)
58
59(** {1 Comparison} *)
60
61val equal : 'a t -> 'a t -> bool
62(** [equal h1 h2] is [true] if [h1] and [h2] are the same hash. *)
63
64val compare : 'a t -> 'a t -> int
65(** [compare h1 h2] is a total ordering on hashes. *)
66
67(** {1 Algorithm Info} *)
68
69val length : _ t -> int
70(** [length h] returns the byte length of the hash (20 for SHA-1, 32 for
71 SHA-256). *)
72
73val algorithm_of : _ t -> algorithm
74(** [algorithm_of h] returns the algorithm used for [h]. *)
75
76val algorithm_length : algorithm -> int
77(** [algorithm_length algo] returns the byte length for [algo]. *)
78
79(** {1 MST Support} *)
80
81val mst_depth : sha256 -> int
82(** [mst_depth h] counts leading zeros in 2-bit chunks for ATProto MST. This
83 determines the tree depth for a given key hash. *)
84
85(** {1 Type-Erased Hashes} *)
86
87type any = Any : _ t -> any (** Type-erased hash for mixed-hash stores. *)
88
89val any_algorithm : any -> algorithm
90(** [any_algorithm (Any h)] returns the algorithm of the erased hash. *)
91
92val any_to_bytes : any -> string
93(** [any_to_bytes (Any h)] returns the raw bytes. *)
94
95val any_to_hex : any -> string
96(** [any_to_hex (Any h)] returns the hex representation. *)
97
98val equal_any : any -> any -> bool
99(** [equal_any a1 a2] compares two type-erased hashes. *)
100
101(** {1 Pretty Printing} *)
102
103val pp : Format.formatter -> _ t -> unit
104(** [pp fmt h] pretty-prints [h] as hex. *)
105
106val pp_short : Format.formatter -> _ t -> unit
107(** [pp_short fmt h] pretty-prints the first 7 characters of [h] (Git-style). *)