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
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
module Hash = struct
let init () =
Hacl_star.EverCrypt.Hash.init ~alg:Hacl_star.SharedDefs.HashDefs.BLAKE2b
let update st msg = Hacl_star.EverCrypt.Hash.update ~st ~msg
let finish st = Hacl_star.EverCrypt.Hash.finish ~st
let hash_bytes bytes =
let blake2b msg =
let digest_size = 32 in
let open Hacl_star in
if AutoConfig2.(has_feature VEC256) then
Hacl.Blake2b_256.hash msg digest_size
else Hacl.Blake2b_32.hash msg digest_size
in
blake2b (Bytes.concat Bytes.empty bytes)
let bytes_to_seed b =
let hashed_b = hash_bytes [b] in
assert (Bytes.length hashed_b = 32) ;
let sys_int_size = Sys.int_size - 1 in
let modulo = Z.pow (Z.of_int 2) sys_int_size in
let n0_raw = Z.of_bits (Bytes.sub_string hashed_b 0 8) in
let n0 = Z.to_int (Z.erem n0_raw modulo) in
let n1_raw = Z.of_bits (Bytes.sub_string hashed_b 8 8) in
let n1 = Z.to_int (Z.erem n1_raw modulo) in
let n2_raw = Z.of_bits (Bytes.sub_string hashed_b 16 8) in
let n2 = Z.to_int (Z.erem n2_raw modulo) in
let n3_raw = Z.of_bits (Bytes.sub_string hashed_b 24 8) in
let n3 = Z.to_int (Z.erem n3_raw modulo) in
([|n0; n1; n2; n3|], hashed_b)
end
module Transcript = struct
type t = bytes [@@deriving repr]
let empty = Bytes.empty
let equal = Bytes.equal
let of_srs ~len1 ~len2 (srs1, srs2) =
let size1, size2 = Bls.(Srs_g1.size srs1, Srs_g2.size srs2) in
let open Hash in
let st = init () in
let srs1 = Bls.Srs_g1.to_array ~len:(min len1 size1) srs1 in
Array.iter (fun key -> update st (Bls.G1.to_bytes key)) srs1 ;
let srs2 = Bls.Srs_g2.to_array ~len:(min len2 size2) srs2 in
Array.iter (fun key -> update st (Bls.G2.to_bytes key)) srs2 ;
finish st
let list_expand repr list transcript =
let open Hash in
let st = init () in
update st transcript ;
List.iter
(fun a ->
update
st
(Bytes.unsafe_of_string @@ Repr.(unstage @@ to_bin_string repr) a))
list ;
finish st
let expand repr x transcript = list_expand repr [x] transcript
end
module Fr_generation = struct
open Bls
let build_array init next len =
let xi = ref init in
Array.init len (fun _ ->
let i = !xi in
xi := next !xi ;
i)
let powers d x = build_array Scalar.one Scalar.(mul x) d
let batch x l =
List.fold_left
(fun acc y -> Scalar.((x * acc) + y))
Scalar.zero
(List.rev l)
let build_quadratic_non_residues len =
let is_nonresidue n = Z.(equal (Scalar.legendre_symbol n) Z.(-one)) in
let rec next n =
Scalar.(n + one) |> fun n -> if is_nonresidue n then n else next n
in
build_array Scalar.one next len
let rec hash_to_Fr a =
let b = Z.to_bits a |> Bytes.of_string in
let hashed_b = Hash.hash_bytes [b] in
assert (Bytes.length hashed_b = 32) ;
let x_fr = Scalar.of_bytes_opt hashed_b in
match x_fr with
| Some a -> a
| None -> hash_to_Fr (Z.succ a)
let generate_random_fr ?state () =
(match state with None -> () | Some s -> Random.set_state s) ;
let n0 = Z.of_int64 @@ Random.int64 Int64.max_int in
let n1 = Z.of_int64 @@ Random.int64 Int64.max_int in
let n2 = Z.of_int64 @@ Random.int64 Int64.max_int in
let n3 = Z.of_int64 @@ Random.int64 Int64.max_int in
let n1_64 = Z.(n1 lsl 64) in
let n2_128 = Z.(n2 lsl 128) in
let n3_192 = Z.(n3 lsl 192) in
let gamma_z = Z.(n0 + n1_64 + n2_128 + n3_192) in
let gamma_fr = hash_to_Fr gamma_z in
gamma_fr
let random_fr_list transcript nb_values =
let transcript_array, hashed_transcript = Hash.bytes_to_seed transcript in
Random.full_init transcript_array ;
(List.init nb_values (fun _ -> generate_random_fr ()), hashed_transcript)
let random_fr transcript =
let l, hashed_transcript = random_fr_list transcript 1 in
(List.hd l, hashed_transcript)
end
let diff_next_power_of_two x = (1 lsl Z.log2up (Z.of_int x)) - x
let is_power_of_two n =
assert (n >= 0) ;
n <> 0 && n land (n - 1) = 0
module FFT = struct
let combinations_factors =
let rec powerset = function
| [] -> [[]]
| x :: xs ->
let ps = powerset xs in
List.concat [ps; List.map (fun ss -> x :: ss) ps]
in
powerset [3; 11; 19]
let select_fft_domain domain_size =
assert (domain_size > 0) ;
let order_multiplicative_group = Z.pred Bls.Scalar.order in
assert (
List.for_all
(fun x -> Z.(divisible order_multiplicative_group (of_int x)))
[3; 11; 19]) ;
if domain_size = 1 then (2, 2, 1)
else
let domain_from_factors (factors : int list) : int * int list =
let prod_factors = List.fold_left ( * ) 1 factors in
let rec get_next_power_of_two k =
if prod_factors lsl k >= domain_size then 1 lsl k
else get_next_power_of_two (k + 1)
in
let next_power_of_two = get_next_power_of_two 0 in
let size = prod_factors * next_power_of_two in
(size, next_power_of_two :: factors)
in
let candidate_domains =
List.map domain_from_factors combinations_factors
in
let domain_length, prime_factor_decomposition =
List.fold_left
min
(List.hd candidate_domains)
(List.tl candidate_domains)
in
let power_of_two = List.hd prime_factor_decomposition in
let remainder_product =
List.fold_left ( * ) 1 (List.tl prime_factor_decomposition)
in
(domain_length, power_of_two, remainder_product)
let fft_aux ~dft ~fft ~fft_pfa domain coefficients =
let size = Domain.length domain in
let _, power_of_two, remainder_product = select_fft_domain size in
if size = power_of_two || size = remainder_product then
(if is_power_of_two size then fft else dft) domain coefficients
else
let domain1 = Domain.build power_of_two in
let domain2 = Domain.build remainder_product in
fft_pfa ~domain1 ~domain2 coefficients
let fft =
fft_aux
~dft:Evaluations.dft
~fft:Evaluations.evaluation_fft
~fft_pfa:Evaluations.evaluation_fft_prime_factor_algorithm
let ifft_inplace =
fft_aux
~dft:Evaluations.idft
~fft:Evaluations.interpolation_fft
~fft_pfa:Evaluations.interpolation_fft_prime_factor_algorithm
end
let pad_array array final_size =
let size = Array.length array in
Array.init final_size (fun i ->
if i < size then array.(i) else array.(size - 1))
let resize_array array final_size =
let size = Array.length array in
if size = final_size then array
else if size > final_size then Array.sub array 0 final_size
else pad_array array final_size