Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/msm tests output identity #75

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions halo2-ecc/src/bn254/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ pub mod fixed_base_msm;
pub mod msm;
pub mod pairing;
pub mod msm_sum_infinity;
pub mod msm_sum_infinity_fixed_base;
198 changes: 198 additions & 0 deletions halo2-ecc/src/bn254/tests/msm_sum_infinity_fixed_base.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
use crate::fields::FpStrategy;
use ff::PrimeField;
use halo2_base::gates::{
builder::{
CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, RangeCircuitBuilder,
},
RangeChip,
};
use rand_core::OsRng;
use std::fs::File;

use super::*;

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
struct MSMCircuitParams {
strategy: FpStrategy,
degree: u32,
num_advice: usize,
num_lookup_advice: usize,
num_fixed: usize,
lookup_bits: usize,
limb_bits: usize,
num_limbs: usize,
batch_size: usize,
window_bits: usize,
}

fn msm_test(
builder: &mut GateThreadBuilder<Fr>,
params: MSMCircuitParams,
bases: Vec<G1Affine>,
scalars: Vec<Fr>,
window_bits: usize,
) {
std::env::set_var("LOOKUP_BITS", params.lookup_bits.to_string());
let range = RangeChip::<Fr>::default(params.lookup_bits);
let fp_chip = FpChip::<Fr>::new(&range, params.limb_bits, params.num_limbs);
let ecc_chip = EccChip::new(&fp_chip);

let ctx = builder.main(0);
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.fixed_base_msm_in::<G1Affine>(
builder,
&bases_assigned,
scalars_assigned,
Fr::NUM_BITS as usize,
window_bits,
0,
);

let msm_answer = bases_assigned
.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 custom_msm_circuit(
params: MSMCircuitParams,
stage: CircuitBuilderStage,
break_points: Option<MultiPhaseThreadBreakPoints>,
bases: Vec<G1Affine>,
scalars: Vec<Fr>,
) -> RangeCircuitBuilder<Fr> {
let k = params.degree as usize;
let mut builder = match stage {
CircuitBuilderStage::Mock => GateThreadBuilder::mock(),
CircuitBuilderStage::Prover => GateThreadBuilder::prover(),
CircuitBuilderStage::Keygen => GateThreadBuilder::keygen(),
};

let start0 = start_timer!(|| format!("Witness generation for circuit in {stage:?} stage"));
msm_test(&mut builder, params, bases, scalars, params.window_bits);

let circuit = match stage {
CircuitBuilderStage::Mock => {
builder.config(k, Some(20));
RangeCircuitBuilder::mock(builder)
}
CircuitBuilderStage::Keygen => {
builder.config(k, Some(20));
RangeCircuitBuilder::keygen(builder)
}
CircuitBuilderStage::Prover => RangeCircuitBuilder::prover(builder, break_points.unwrap()),
};
end_timer!(start0);
circuit
}

#[test]
fn test_fb_msm1() {
let path = "configs/bn254/msm_circuit.config";
let mut params: MSMCircuitParams = serde_json::from_reader(
File::open(path).unwrap_or_else(|e| panic!("{path} does not exist: {e:?}")),
)
.unwrap();
params.batch_size = 3;

let random_point = G1Affine::random(OsRng);
let bases = vec![random_point, random_point, random_point];
let scalars = vec![Fr::one(), Fr::one(), -Fr::one() - Fr::one()];

let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, bases, scalars);
MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied();
}

#[test]
fn test_fb_msm2() {
let path = "configs/bn254/msm_circuit.config";
let mut params: MSMCircuitParams = serde_json::from_reader(
File::open(path).unwrap_or_else(|e| panic!("{path} does not exist: {e:?}")),
)
.unwrap();
params.batch_size = 3;

let random_point = G1Affine::random(OsRng);
let bases = vec![random_point, random_point, (random_point + random_point).to_affine()];
let scalars = vec![Fr::one(), Fr::one(), -Fr::one()];

let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, bases, scalars);
MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied();
}

#[test]
fn test_fb_msm3() {
let path = "configs/bn254/msm_circuit.config";
let mut params: MSMCircuitParams = serde_json::from_reader(
File::open(path).unwrap_or_else(|e| panic!("{path} does not exist: {e:?}")),
)
.unwrap();
params.batch_size = 4;

let random_point = G1Affine::random(OsRng);
let bases = vec![
random_point,
random_point,
random_point,
(random_point + random_point + random_point).to_affine(),
];
let scalars = vec![Fr::one(), Fr::one(), Fr::one(), -Fr::one()];

let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, bases, scalars);
MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied();
}

#[test]
fn test_fb_msm4() {
let path = "configs/bn254/msm_circuit.config";
let mut params: MSMCircuitParams = serde_json::from_reader(
File::open(path).unwrap_or_else(|e| panic!("{path} does not exist: {e:?}")),
)
.unwrap();
params.batch_size = 4;

let generator_point = G1Affine::generator();
let bases = vec![
generator_point,
generator_point,
generator_point,
(generator_point + generator_point + generator_point).to_affine(),
];
let scalars = vec![Fr::one(), Fr::one(), Fr::one(), -Fr::one()];

let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, bases, scalars);
MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied();
}

#[test]
fn test_fb_msm5() {
// Very similar example that does not add to infinity. It works fine.
let path = "configs/bn254/msm_circuit.config";
let mut params: MSMCircuitParams = serde_json::from_reader(
File::open(path).unwrap_or_else(|e| panic!("{path} does not exist: {e:?}")),
)
.unwrap();
params.batch_size = 4;

let random_point = G1Affine::random(OsRng);
let bases =
vec![random_point, random_point, random_point, (random_point + random_point).to_affine()];
let scalars = vec![-Fr::one(), -Fr::one(), Fr::one(), Fr::one()];

let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, bases, scalars);
MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied();
}