/
msm.rs
112 lines (99 loc) · 3.83 KB
/
msm.rs
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
use crate::ff::{Field, PrimeField};
use std::{
fs::{self, File},
io::{BufRead, BufReader},
};
use super::*;
pub fn msm_test(
pool: &mut SinglePhaseCoreManager<Fr>,
range: &RangeChip<Fr>,
params: MSMCircuitParams,
bases: Vec<G1Affine>,
scalars: Vec<Fr>,
) {
let fp_chip = FpChip::<Fr>::new(range, params.limb_bits, params.num_limbs);
let ecc_chip = EccChip::new(&fp_chip);
let ctx = pool.main();
let scalars_assigned =
scalars.iter().map(|scalar| vec![ctx.load_witness(*scalar)]).collect::<Vec<_>>();
let bases_assigned = bases
.iter()
.map(|base| ecc_chip.load_private_unchecked(ctx, (base.x, base.y)))
.collect::<Vec<_>>();
let msm = ecc_chip.variable_base_msm_custom::<G1Affine>(
pool,
&bases_assigned,
scalars_assigned,
Fr::NUM_BITS as usize,
params.window_bits,
);
let msm_answer = bases
.iter()
.zip(scalars.iter())
.map(|(base, scalar)| base * scalar)
.reduce(|a, b| a + b)
.unwrap()
.to_affine();
let msm_x = msm.x.value();
let msm_y = msm.y.value();
assert_eq!(msm_x, fe_to_biguint(&msm_answer.x));
assert_eq!(msm_y, fe_to_biguint(&msm_answer.y));
}
fn random_pairs(batch_size: usize, rng: &StdRng) -> (Vec<G1Affine>, Vec<Fr>) {
(0..batch_size).map(|_| (G1Affine::random(rng.clone()), Fr::random(rng.clone()))).unzip()
}
#[test]
fn test_msm() {
let path = "configs/bn254/msm_circuit.config";
let params: MSMCircuitParams = serde_json::from_reader(
File::open(path).unwrap_or_else(|e| panic!("{path} does not exist: {e:?}")),
)
.unwrap();
let (bases, scalars) = random_pairs(params.batch_size, &StdRng::seed_from_u64(0));
base_test().k(params.degree).lookup_bits(params.lookup_bits).run_builder(|pool, range| {
msm_test(pool, range, params, bases, scalars);
});
}
#[test]
fn bench_msm() -> Result<(), Box<dyn std::error::Error>> {
let config_path = "configs/bn254/bench_msm.config";
let bench_params_file =
File::open(config_path).unwrap_or_else(|e| panic!("{config_path} does not exist: {e:?}"));
fs::create_dir_all("results/bn254").unwrap();
fs::create_dir_all("data").unwrap();
let results_path = "results/bn254/msm_bench.csv";
let mut fs_results = File::create(results_path).unwrap();
writeln!(fs_results, "degree,num_advice,num_lookup,num_fixed,lookup_bits,limb_bits,num_limbs,batch_size,window_bits,proof_time,proof_size,verify_time")?;
let bench_params_reader = BufReader::new(bench_params_file);
for line in bench_params_reader.lines() {
let bench_params: MSMCircuitParams = serde_json::from_str(line.unwrap().as_str()).unwrap();
let k = bench_params.degree;
println!("---------------------- degree = {k} ------------------------------",);
let (bases, scalars) = random_pairs(bench_params.batch_size, &StdRng::seed_from_u64(0));
let stats =
base_test().k(bench_params.degree).lookup_bits(bench_params.lookup_bits).bench_builder(
(bases.clone(), scalars.clone()),
(bases, scalars),
|pool, range, (bases, scalars)| {
msm_test(pool, range, bench_params, bases, scalars);
},
);
writeln!(
fs_results,
"{},{},{},{},{},{},{},{},{},{:?},{},{:?}",
bench_params.degree,
bench_params.num_advice,
bench_params.num_lookup_advice,
bench_params.num_fixed,
bench_params.lookup_bits,
bench_params.limb_bits,
bench_params.num_limbs,
bench_params.batch_size,
bench_params.window_bits,
stats.proof_time.time.elapsed(),
stats.proof_size,
stats.verify_time.time.elapsed(),
)?;
}
Ok(())
}