bellman_ce/plonk/transparent_engine/
mod.rs1use crate::ff::*;
2
3use crate::pairing::Engine;
4
5#[macro_use]
6mod impl_macro;
7
8#[derive(PrimeField)]
9#[PrimeFieldModulus = "3618502788666131213697322783095070105623107215331596699973092056135872020481"]
10#[PrimeFieldGenerator = "3"]
11pub struct Fr(FrRepr);
12
13pub trait TransparentEngine: Engine {}
14
15pub trait PartialReductionField: PrimeField {
16 fn add_assign_unreduced(&mut self, other: &Self);
18
19 fn sub_assign_unreduced(&mut self, other: &Self);
21
22 fn mul_assign_unreduced(&mut self, other: &Self);
24
25 fn reduce_once(&mut self);
27
28 fn reduce_completely(&mut self);
30
31 fn overflow_factor(&self) -> usize;
32}
33
34pub trait PartialTwoBitReductionField: PartialReductionField {
35 fn sub_assign_twice_unreduced(&mut self, other: &Self);
37
38 fn reduce_twice(&mut self);
40
41 fn reduce_completely(&mut self);
43}
44
45pub mod engine {
46 use super::Fr;
47
48 use super::impl_macro::*;
49
50 transparent_engine_impl!{Transparent252, Fr}
51}
52
53pub use self::engine::Transparent252;
54
55pub(crate) mod proth;
56pub(crate) mod proth_engine;
57
58#[cfg(test)]
59mod test {
60 #[test]
61 fn test_bench_proth_lde() {
62 use rand::{XorShiftRng, SeedableRng, Rand, Rng};
63 use super::Fr as FrMontNaive;
64 use super::proth::Fr as FrOptimized;
65 use crate::plonk::polynomials::*;
66 use std::time::Instant;
67 use crate::worker::*;
68 use crate::plonk::commitments::transparent::utils::*;
69
70 let poly_sizes = vec![1_000_000, 2_000_000, 4_000_000];
71
72 let worker = Worker::new();
73
74 for poly_size in poly_sizes.into_iter() {
75 let res1 = {
76 let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
77 let coeffs = (0..poly_size).map(|_| FrMontNaive::rand(rng)).collect::<Vec<_>>();
78
79 let poly = Polynomial::<FrMontNaive, _>::from_coeffs(coeffs).unwrap();
80 let start = Instant::now();
81 let eval_result = poly.lde(&worker, 16).unwrap();
82 println!("LDE with factor 16 for size {} with naive mont reduction taken {:?}", poly_size, start.elapsed());
83
84 eval_result.into_coeffs()
85 };
86
87 let res2 = {
88 let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
89 let coeffs = (0..poly_size).map(|_| FrOptimized::rand(rng)).collect::<Vec<_>>();
90
91 let poly = Polynomial::<FrOptimized, _>::from_coeffs(coeffs).unwrap();
92 let start = Instant::now();
93 let eval_result = poly.lde(&worker, 16).unwrap();
94 println!("LDE with factor 16 for size {} with optimized mont reduction taken {:?}", poly_size, start.elapsed());
95
96 eval_result.into_coeffs()
97 };
98
99 assert_eq!(format!("{}", res1[0]), format!("{}", res2[0]));
100
101 }
102 }
103
104 #[test]
105 fn test_proth_field() {
106 use crate::ff::{Field, PrimeField, to_hex};
107 use super::Fr as FrMontNaive;
108 use super::proth::Fr as FrOptimized;
109
110 let one_naive = FrMontNaive::from_str("1").unwrap();
111 let one_optimized = FrOptimized::from_str("1").unwrap();
112
113 println!("{}", FrMontNaive::one());
114 println!("{}", FrOptimized::one());
115
116 println!("{}", one_naive.into_raw_repr());
117 println!("{}", one_optimized.into_raw_repr());
118
119 let mut tmp0 = one_naive;
120 tmp0.mul_assign(&one_naive);
121
122 let mut tmp1 = one_optimized;
123 tmp1.mul_assign(&one_optimized);
124
125 assert_eq!(to_hex(&tmp0), to_hex(&tmp1));
126
127 assert_eq!(to_hex(&FrMontNaive::multiplicative_generator()), to_hex(&FrOptimized::multiplicative_generator()));
128 }
129
130 #[test]
131 fn test_bench_precomputations_for_proth_fft() {
132 use rand::{XorShiftRng, SeedableRng, Rand, Rng};
133 use super::Fr as FrMontNaive;
134 use super::proth::Fr as FrOptimized;
135 use crate::plonk::polynomials::*;
136 use std::time::Instant;
137 use crate::worker::*;
138 use crate::plonk::commitments::transparent::utils::*;
139 use crate::plonk::fft::fft::best_fft;
140 use crate::plonk::fft::with_precomputation::FftPrecomputations;
141 use crate::plonk::fft::with_precomputation::fft::best_fft as best_fft_with_precomputations;
142 use crate::plonk::commitments::transparent::precomputations::*;
143 use crate::plonk::domains::Domain;
144 let poly_sizes = vec![32_000_000, 64_000_000];
145
146 let worker = Worker::new();
147
148 for poly_size in poly_sizes.into_iter() {
149 let domain = Domain::<FrOptimized>::new_for_size(poly_size).unwrap();
150 let precomp = PrecomputedOmegas::<FrOptimized>::new_for_domain_size(domain.size as usize);
151 let omega = domain.generator;
152 let log_n = domain.power_of_two as u32;
153
154 let poly_size = domain.size as usize;
155
156 let res1 = {
157 let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
158 let mut coeffs = (0..poly_size).map(|_| FrOptimized::rand(rng)).collect::<Vec<_>>();
159 let start = Instant::now();
160 best_fft(&mut coeffs, &worker, &omega, log_n, None);
161 println!("FFT for size {} without precomputation taken {:?}", poly_size, start.elapsed());
162
163 coeffs
164 };
165
166 let res2 = {
167 let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
168 let mut coeffs = (0..poly_size).map(|_| FrOptimized::rand(rng)).collect::<Vec<_>>();
169 let start = Instant::now();
170 best_fft_with_precomputations(&mut coeffs, &worker, &omega, log_n, None, &precomp);
171 println!("FFT for size {} with precomputation taken {:?}", poly_size, start.elapsed());
172
173 coeffs
174 };
175
176 assert!(res1 == res2);
177
178 }
179 }
180
181 #[test]
182 fn test_bench_precomputations_for_proth_lde() {
183 use rand::{XorShiftRng, SeedableRng, Rand, Rng};
184 use super::Fr as FrMontNaive;
185 use super::proth::Fr as FrOptimized;
186 use crate::plonk::polynomials::*;
187 use std::time::Instant;
188 use crate::worker::*;
189 use crate::plonk::commitments::transparent::utils::*;
190 use crate::plonk::fft::with_precomputation::FftPrecomputations;
191 use crate::plonk::commitments::transparent::precomputations::*;
192
193 let poly_sizes = vec![1_000_000, 2_000_000, 4_000_000];
194
195 let worker = Worker::new();
196
197 for poly_size in poly_sizes.into_iter() {
198 let res1 = {
199 let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
200 let coeffs = (0..poly_size).map(|_| FrMontNaive::rand(rng)).collect::<Vec<_>>();
201
202 let poly = Polynomial::<FrMontNaive, _>::from_coeffs(coeffs).unwrap();
203 let start = Instant::now();
204 let eval_result = poly.lde(&worker, 16).unwrap();
205 println!("LDE with factor 16 for size {} with naive mont reduction taken {:?}", poly_size, start.elapsed());
206
207 eval_result.into_coeffs()
208 };
209
210 let res2 = {
211 let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
212 let coeffs = (0..poly_size).map(|_| FrOptimized::rand(rng)).collect::<Vec<_>>();
213
214 let poly = Polynomial::<FrOptimized, _>::from_coeffs(coeffs).unwrap();
215 let precomp = PrecomputedOmegas::<FrOptimized>::new_for_domain_size(poly.size());
216 let start = Instant::now();
217 let eval_result = poly.lde_using_multiple_cosets_with_precomputation(&worker, 16, &precomp).unwrap();
218 println!("LDE with factor 16 for size {} with optimized mont reduction and precomputation taken {:?}", poly_size, start.elapsed());
219
220 eval_result.into_coeffs()
221 };
222
223 assert_eq!(format!("{}", res1[0]), format!("{}", res2[0]));
224
225 }
226 }
227
228 #[test]
229 fn test_bench_ct_ploth_lde() {
230 use rand::{XorShiftRng, SeedableRng, Rand, Rng};
231 use super::proth::Fr as Fr;
232 use crate::plonk::polynomials::*;
233 use std::time::Instant;
234 use crate::worker::*;
235 use crate::plonk::commitments::transparent::utils::*;
236 use crate::plonk::fft::cooley_tukey_ntt::{CTPrecomputations, BitReversedOmegas};
237
238 let poly_sizes = vec![1_000_000, 2_000_000, 4_000_000];
239
240 let worker = Worker::new();
243
244 for poly_size in poly_sizes.into_iter() {
245 let poly_size = poly_size as usize;
246
247 let res1 = {
248 let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
249 let coeffs = (0..poly_size).map(|_| Fr::rand(rng)).collect::<Vec<_>>();
250
251 let poly = Polynomial::<Fr, _>::from_coeffs(coeffs).unwrap();
252 let start = Instant::now();
253 let eval_result = poly.lde_using_multiple_cosets(&worker, 16).unwrap();
254 println!("LDE with factor 16 for size {} taken {:?}", poly_size, start.elapsed());
255
256 eval_result.into_coeffs()
257 };
258
259 let res2 = {
260 let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
261 let coeffs = (0..poly_size).map(|_| Fr::rand(rng)).collect::<Vec<_>>();
262
263 let poly = Polynomial::<Fr, _>::from_coeffs(coeffs).unwrap();
264 let precomp = BitReversedOmegas::<Fr>::new_for_domain_size(poly.size());
265 let start = Instant::now();
266 let eval_result = poly.lde_using_bitreversed_ntt(&worker, 16, &precomp).unwrap();
267 println!("LDE with factor 16 for size {} with optimized ntt taken {:?}", poly_size, start.elapsed());
268
269 eval_result.into_coeffs()
270 };
271
272 assert_eq!(res1, res2);
273
274 assert!(res1 == res2);
275 }
276 }
277
278 #[test]
356 fn test_bench_partial_reduction_bitreversed_lde() {
357 use crate::ff::Field;
358 use crate::ff::PrimeField;
359 use rand::{XorShiftRng, SeedableRng, Rand, Rng};
360 use super::proth::Fr as Fr;
361 use super::PartialTwoBitReductionField;
362 use crate::plonk::polynomials::*;
363 use std::time::Instant;
364 use crate::worker::*;
365 use crate::plonk::commitments::transparent::utils::*;
366 use crate::plonk::fft::cooley_tukey_ntt::{CTPrecomputations, BitReversedOmegas};
367
368 let poly_sizes = vec![32, 64, 1_000_000, 2_000_000, 4_000_000];
369
370 let worker = Worker::new();
371
372 for poly_size in poly_sizes.into_iter() {
373 let poly_size = poly_size as usize;
374
375 let res1 = {
376 let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
377 let coeffs = (0..poly_size).map(|_| Fr::rand(rng)).collect::<Vec<_>>();
378
379 let poly = Polynomial::<Fr, _>::from_coeffs(coeffs).unwrap();
380 let start = Instant::now();
381 let eval_result = poly.lde(&worker, 16).unwrap();
382 println!("LDE with factor 16 for size {} taken {:?}", poly_size, start.elapsed());
383
384 eval_result.into_coeffs()
385 };
386
387 let mut res2 = {
388 let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
389 let coeffs = (0..poly_size).map(|_| Fr::rand(rng)).collect::<Vec<_>>();
390
391 let poly = Polynomial::<Fr, _>::from_coeffs(coeffs).unwrap();
392 let precomp = BitReversedOmegas::<Fr>::new_for_domain_size(poly.size());
393 let start = Instant::now();
394 let eval_result = poly.bitreversed_lde_using_bitreversed_ntt(&worker, 16, &precomp, &<Fr as Field>::one()).unwrap();
395 println!("LDE with factor 16 for size {} bitreversed {:?}", poly_size, start.elapsed());
396
397 eval_result
398 };
399
400 if poly_size < 1000 {
401 res2.bitreverse_enumeration(&worker);
402 assert!(res1 == res2.into_coeffs());
403 }
404 }
405 }
406
407 #[test]
408 fn test_bench_ct_proth_fft() {
409 use rand::{XorShiftRng, SeedableRng, Rand, Rng};
410 use super::proth::Fr as Fr;
411 use crate::plonk::polynomials::*;
412 use std::time::Instant;
413 use crate::worker::*;
414 use crate::plonk::commitments::transparent::utils::*;
415 use crate::plonk::fft::cooley_tukey_ntt::{CTPrecomputations, BitReversedOmegas, best_ct_ntt};
416 use crate::plonk::fft::fft::best_fft;
417 use crate::plonk::domains::Domain;
418
419 let poly_sizes = vec![1_000_000];
421
422 let worker = Worker::new();
425
426 for poly_size in poly_sizes.into_iter() {
427 let poly_size = poly_size as usize;
428 let poly_size = poly_size.next_power_of_two();
429
430 let _res1 = {
431 let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
432 let mut coeffs = (0..poly_size).map(|_| Fr::rand(rng)).collect::<Vec<_>>();
433 let log_n = log2_floor(coeffs.len());
434 let domain = Domain::new_for_size(coeffs.len() as u64).unwrap();
435
436 let start = Instant::now();
437 best_fft(&mut coeffs, &worker, &domain.generator, log_n, Some(8));
438 println!("FFT for size {} taken {:?}", poly_size, start.elapsed());
439
440 coeffs
441 };
442
443 let (input, output) = {
444 let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
445 let mut coeffs = (0..poly_size).map(|_| Fr::rand(rng)).collect::<Vec<_>>();
446 let input = coeffs.clone();
447 let log_n = log2_floor(coeffs.len());
448 let precomp = BitReversedOmegas::<Fr>::new_for_domain_size(coeffs.len());
449
450 let start = Instant::now();
451 best_ct_ntt(&mut coeffs, &worker, log_n, Some(8), &precomp);
452 println!("CT FFT for size {} taken {:?}", poly_size, start.elapsed());
453
454 (input, coeffs)
455 };
456
457 let mut writer = std::io::BufWriter::with_capacity(
458 1<<24,
459 std::fs::File::create("./fft_test_input.data").unwrap()
460 );
461
462 use crate::pairing::ff::{Field, PrimeField};
463 use std::io::Write;
464 use crate::pairing::ff::PrimeFieldRepr;
465
466 let mut scratch = vec![];
467 for el in input.into_iter() {
468 let repr = el.into_raw_repr();
469 repr.write_le(&mut scratch).unwrap();
470 writer.write_all(&scratch).unwrap();
471 scratch.truncate(0);
472 }
473
474 println!("Results");
475 for el in output[0..16].iter() {
476 println!("{}", el.into_raw_repr());
477 }
478
479 let domain = Domain::<Fr>::new_for_size(poly_size as u64).unwrap();
480
481 println!("Omegas");
482
483 assert!(domain.generator.pow(&[1u64<<20]) == Fr::one());
484
485 for i in 0..=20 {
486 let pow = 1u64 << i;
487 println!("Omega^{} = {}", pow, domain.generator.pow(&[pow]).into_raw_repr());
488 }
489
490 println!("Idenity = {}", Fr::one().into_raw_repr());
491 }
492 }
493
494}
495
496
497
498