• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MinaProtocol / mina / 3409

26 Feb 2025 01:10PM UTC coverage: 32.353% (-28.4%) from 60.756%
3409

push

buildkite

web-flow
Merge pull request #16687 from MinaProtocol/dw/merge-compatible-into-develop-20250225

Merge compatible into develop [20250224]

23144 of 71535 relevant lines covered (32.35%)

16324.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

49.18
/src/lib/hex/hex.ml
1
open Core_kernel
36✔
2

3
module Digit = struct
4
  (* A number between 0 and 15 *)
5
  type t =
6
    | H0
7
    | H1
8
    | H2
9
    | H3
10
    | H4
11
    | H5
12
    | H6
13
    | H7
14
    | H8
15
    | H9
16
    | H10
17
    | H11
18
    | H12
19
    | H13
20
    | H14
21
    | H15
22

23
  let of_char_exn c =
24
    match Char.lowercase c with
794,176✔
25
    | '0' ->
602,095✔
26
        H0
27
    | '1' ->
12,341✔
28
        H1
29
    | '2' ->
13,862✔
30
        H2
31
    | '3' ->
10,177✔
32
        H3
33
    | '4' ->
16,101✔
34
        H4
35
    | '5' ->
20,082✔
36
        H5
37
    | '6' ->
9,559✔
38
        H6
39
    | '7' ->
8,204✔
40
        H7
41
    | '8' ->
9,575✔
42
        H8
43
    | '9' ->
15,363✔
44
        H9
45
    | 'a' ->
20,670✔
46
        H10
47
    | 'b' ->
8,664✔
48
        H11
49
    | 'c' ->
11,705✔
50
        H12
51
    | 'd' ->
8,683✔
52
        H13
53
    | 'e' ->
8,341✔
54
        H14
55
    | 'f' ->
18,754✔
56
        H15
57
    | _ ->
×
58
        failwithf "bad hex digit %c" c ()
59

60
  let to_int = function
61
    | H0 ->
602,095✔
62
        0
63
    | H1 ->
12,341✔
64
        1
65
    | H2 ->
13,862✔
66
        2
67
    | H3 ->
10,177✔
68
        3
69
    | H4 ->
16,101✔
70
        4
71
    | H5 ->
20,082✔
72
        5
73
    | H6 ->
9,559✔
74
        6
75
    | H7 ->
8,204✔
76
        7
77
    | H8 ->
9,575✔
78
        8
79
    | H9 ->
15,363✔
80
        9
81
    | H10 ->
20,670✔
82
        10
83
    | H11 ->
8,664✔
84
        11
85
    | H12 ->
11,705✔
86
        12
87
    | H13 ->
8,683✔
88
        13
89
    | H14 ->
8,341✔
90
        14
91
    | H15 ->
18,754✔
92
        15
93
end
94

95
let hex_char_of_int_exn = function
96
  | 0 ->
3,074,594✔
97
      '0'
98
  | 1 ->
185,961✔
99
      '1'
100
  | 2 ->
139,712✔
101
      '2'
102
  | 3 ->
142,112✔
103
      '3'
104
  | 4 ->
132,040✔
105
      '4'
106
  | 5 ->
132,563✔
107
      '5'
108
  | 6 ->
129,907✔
109
      '6'
110
  | 7 ->
132,861✔
111
      '7'
112
  | 8 ->
128,781✔
113
      '8'
114
  | 9 ->
130,235✔
115
      '9'
116
  | 10 ->
133,028✔
117
      'a'
118
  | 11 ->
130,812✔
119
      'b'
120
  | 12 ->
129,470✔
121
      'c'
122
  | 13 ->
131,346✔
123
      'd'
124
  | 14 ->
130,951✔
125
      'e'
126
  | 15 ->
130,571✔
127
      'f'
128
  | d ->
×
129
      failwithf "bad hex digit %d" d ()
130

131
module Sequence_be = struct
132
  type t = Digit.t array
133

134
  let decode ?(pos = 0) s =
×
135
    let n = String.length s - pos in
×
136
    Array.init n ~f:(fun i -> Digit.of_char_exn s.[pos + i])
×
137

138
  let to_bytes_like ~init (t : t) =
139
    let n = Array.length t in
×
140
    let k = n / 2 in
×
141
    assert (n = k + k) ;
×
142
    init k ~f:(fun i ->
143
        Char.of_int_exn
×
144
          ((16 * Digit.to_int t.(2 * i)) + Digit.to_int t.((2 * i) + 1)) )
×
145

146
  let to_string = to_bytes_like ~init:String.init
147

148
  let to_bytes = to_bytes_like ~init:Bytes.init
149

150
  let to_bigstring = to_bytes_like ~init:Bigstring.init
151
end
152

153
let decode ?(reverse = false) ?(pos = 0) ~init t =
×
154
  let n = String.length t - pos in
12,409✔
155
  let k = n / 2 in
156
  assert (n = k + k) ;
12,409✔
157
  let h j = Digit.(to_int (of_char_exn t.[pos + j])) in
794,176✔
158
  init k ~f:(fun i ->
159
      let i = if reverse then k - 1 - i else i in
×
160
      Char.of_int_exn ((16 * h (2 * i)) + h ((2 * i) + 1)) )
397,088✔
161

162
let encode ?(reverse = false) t =
×
163
  let n = String.length t in
79,921✔
164
  String.init (2 * n) ~f:(fun i ->
79,921✔
165
      let c =
5,114,944✔
166
        let byte = i / 2 in
167
        Char.to_int t.[if reverse then n - 1 - byte else byte]
×
168
      in
169
      let c = if i mod 2 = 0 then (* hi *)
170
                c lsr 4 else (* lo *)
2,557,472✔
171
                          c in
2,557,472✔
172
      hex_char_of_int_exn (c land 15) )
173

174
let%test_unit "decode" =
175
  let t = String.init 100 ~f:(fun _ -> Char.of_int_exn (Random.int 256)) in
×
176
  let h = encode t in
×
177
  assert (String.equal t (decode ~init:String.init h)) ;
×
178
  assert (
×
179
    String.equal t
×
180
      (decode ~reverse:true ~init:String.init (encode ~reverse:true t)) ) ;
×
181
  assert (String.equal t Sequence_be.(to_string (decode h)))
×
182

183
(* TODO: Better deduplicate the hex coding between these two implementations #5711 *)
184
module Safe = struct
185
  (** to_hex : {0x0-0xff}* -> [A-F0-9]* *)
186
  let to_hex (data : string) : string =
187
    String.to_list data
×
188
    |> List.map ~f:(fun c ->
×
189
           let charify u4 =
×
190
             match u4 with
×
191
             | x when x <= 9 && x >= 0 ->
×
192
                 Char.(of_int_exn @@ (x + to_int '0'))
×
193
             | x when x <= 15 && x >= 10 ->
×
194
                 Char.(of_int_exn @@ (x - 10 + to_int 'A'))
×
195
             | _ ->
×
196
                 failwith "Unexpected u4 has only 4bits of information"
197
           in
198
           let high = charify @@ ((Char.to_int c land 0xF0) lsr 4) in
×
199
           let lo = charify (Char.to_int c land 0x0F) in
×
200
           String.of_char_list [ high; lo ] )
×
201
    |> String.concat
202

203
  let%test_unit "to_hex sane" =
204
    let start = "a" in
×
205
    let hexified = to_hex start in
206
    let expected = "61" in
×
207
    if String.equal expected hexified then ()
×
208
    else
209
      failwithf "start: %s ; hexified : %s ; expected: %s" start hexified
×
210
        expected ()
211

212
  (** of_hex : [a-fA-F0-9]* -> {0x0-0xff}* option *)
213
  let of_hex (hex : string) : string option =
214
    let to_u4 c =
×
215
      let open Char in
×
216
      assert (is_alphanum c) ;
×
217
      match c with
218
      | _ when is_digit c ->
×
219
          to_int c - to_int '0'
×
220
      | _ when is_uppercase c ->
×
221
          to_int c - to_int 'A' + 10
×
222
      | _ (* when is_alpha *) ->
×
223
          to_int c - to_int 'a' + 10
×
224
    in
225
    String.to_list hex |> List.chunks_of ~length:2
×
226
    |> List.fold_result ~init:[] ~f:(fun acc chunk ->
×
227
           match chunk with
×
228
           | [ a; b ] when Char.is_alphanum a && Char.is_alphanum b ->
×
229
               Or_error.return
×
230
               @@ (Char.((to_u4 a lsl 4) lor to_u4 b |> of_int_exn) :: acc)
×
231
           | _ ->
×
232
               Or_error.error_string "invalid hex" )
233
    |> Or_error.ok
×
234
    |> Option.map ~f:(Fn.compose String.of_char_list List.rev)
×
235

236
  let%test_unit "partial isomorphism" =
237
    Quickcheck.test ~sexp_of:[%sexp_of: string] ~examples:[ "\243"; "abc" ]
×
238
      Quickcheck.Generator.(map (list char) ~f:String.of_char_list)
×
239
      ~f:(fun s ->
240
        let hexified = to_hex s in
×
241
        let actual = Option.value_exn (of_hex hexified) in
×
242
        let expected = s in
×
243
        if String.equal actual expected then ()
×
244
        else
245
          failwithf
×
246
            !"expected: %s ; hexified: %s ; actual: %s"
247
            expected hexified actual () )
248
end
72✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc