1
 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
module List = Core.List
module String = Core.String
module Char = Core.Char
module Int = Core.Int
module Str = Re.Str

(* 16 hex chars and 128 chars/string length for hash under hex string format *)
let _HASH_LENGTH = 128

let _HEX_SPACE = 16

let _KEY_LENGTH = _HEX_SPACE * _HASH_LENGTH

let regexp = Str.regexp "^[a-f0-9]+$"

let id value = value

let is_hash text =
  Str.string_match regexp text 0 && String.length text = _HASH_LENGTH


let validate_key list =
  let filtered = List.filter list ~f:is_hash in
  if List.length filtered = _KEY_LENGTH then Some list else None


let to_hex text = "0x" ^ text

let tag_index entries =
  let length = List.length entries in
  let indexes = List.init length ~f:id in
  List.zip_exn indexes entries


let calculate_index (position, key) = (position * _HEX_SPACE) + key

let index_at ~list position = List.nth_exn list position

let replace_index ~matrix pairs = pairs |> List.map ~f:(index_at ~list:matrix)

let verify_at ~digest ~list (position, hash) =
  let commitment = List.nth_exn list position in
  digest hash = commitment


let verify_with ~matrix ~digest pairs =
  pairs
  |> List.map ~f:(verify_at ~digest ~list:matrix)
  |> List.reduce_exn ~f:( && )


let concat_hashes left right = left ^ "-" ^ right

let indexed_keys msg =
  msg
  |> Hash.digest
  |> String.to_list
  |> List.map ~f:Char.to_string
  |> List.map ~f:to_hex
  |> List.map ~f:Int.of_string
  |> tag_index
  |> List.map ~f:calculate_index


let nullchar = Char.of_int_exn 0

let pad ~basis msg =
  let length = String.length msg in
  let remainder = Int.( % ) length basis in
  let zerofill = String.make (basis - remainder) nullchar in
  Cstruct.of_string (msg ^ zerofill)


let nonzero char = char != nullchar

let unpad msg = String.filter ~f:nonzero msg