Skip to content
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
5 changes: 3 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ jobs:
cd halo2-ecc
cargo test -- --test-threads=1 test_fp
cargo test -- test_ecc
cargo test -- test_secp256k1_ecdsa
cargo test -- test_secp
cargo test -- test_ecdsa
cargo test -- test_ec_add
cargo test -- test_fixed_base_msm
cargo test -- test_fixed
cargo test -- test_msm
cargo test -- test_fb
cargo test -- test_pairing
cd ..
- name: Run halo2-ecc tests real prover
Expand Down
6 changes: 3 additions & 3 deletions halo2-base/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub(crate) fn decompose_u64_digits_to_limbs(
core::cmp::Ordering::Less => {
let mut limb = u64_digit;
u64_digit = e.next().unwrap_or(0);
limb |= (u64_digit & ((1 << (bit_len - rem)) - 1)) << rem;
limb |= (u64_digit & ((1u64 << (bit_len - rem)) - 1u64)) << rem;
u64_digit >>= bit_len - rem;
rem += 64 - bit_len;
limb
Expand Down Expand Up @@ -218,7 +218,7 @@ pub fn decompose_biguint<F: BigPrimeField>(
let mut rem = bit_len - 64;
let mut u64_digit = e.next().unwrap_or(0);
// Extract second limb (bit length 64) from e
limb0 |= ((u64_digit & ((1 << rem) - 1u64)) as u128) << 64u32;
limb0 |= ((u64_digit & ((1u64 << rem) - 1u64)) as u128) << 64u32;
u64_digit >>= rem;
rem = 64 - rem;

Expand All @@ -234,7 +234,7 @@ pub fn decompose_biguint<F: BigPrimeField>(
bits += 64;
}
rem = bit_len - bits;
limb |= ((u64_digit & ((1 << rem) - 1)) as u128) << bits;
limb |= ((u64_digit & ((1u64 << rem) - 1u64)) as u128) << bits;
u64_digit >>= rem;
rem = 64 - rem;
F::from_u128(limb)
Expand Down
28 changes: 23 additions & 5 deletions halo2-ecc/src/bn254/tests/fixed_base_msm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use itertools::Itertools;
use rand_core::OsRng;

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
struct MSMCircuitParams {
struct FixedMSMCircuitParams {
strategy: FpStrategy,
degree: u32,
num_advice: usize,
Expand All @@ -39,7 +39,7 @@ struct MSMCircuitParams {

fn fixed_base_msm_test(
builder: &mut GateThreadBuilder<Fr>,
params: MSMCircuitParams,
params: FixedMSMCircuitParams,
bases: Vec<G1Affine>,
scalars: Vec<Fr>,
) {
Expand Down Expand Up @@ -68,7 +68,7 @@ fn fixed_base_msm_test(
}

fn random_fixed_base_msm_circuit(
params: MSMCircuitParams,
params: FixedMSMCircuitParams,
bases: Vec<G1Affine>, // bases are fixed in vkey so don't randomly generate
stage: CircuitBuilderStage,
break_points: Option<MultiPhaseThreadBreakPoints>,
Expand Down Expand Up @@ -102,7 +102,7 @@ fn random_fixed_base_msm_circuit(
#[test]
fn test_fixed_base_msm() {
let path = "configs/bn254/fixed_msm_circuit.config";
let params: MSMCircuitParams = serde_json::from_reader(
let params: FixedMSMCircuitParams = serde_json::from_reader(
File::open(path).unwrap_or_else(|e| panic!("{path} does not exist: {e:?}")),
)
.unwrap();
Expand All @@ -112,6 +112,23 @@ fn test_fixed_base_msm() {
MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied();
}

#[test]
fn test_fixed_msm_minus_1() {
let path = "configs/bn254/fixed_msm_circuit.config";
let params: FixedMSMCircuitParams = serde_json::from_reader(
File::open(path).unwrap_or_else(|e| panic!("{path} does not exist: {e:?}")),
)
.unwrap();
let base = G1Affine::random(OsRng);
let k = params.degree as usize;
let mut builder = GateThreadBuilder::mock();
fixed_base_msm_test(&mut builder, params, vec![base], vec![-Fr::one()]);

builder.config(k, Some(20));
let circuit = RangeCircuitBuilder::mock(builder);
MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied();
}

#[test]
fn bench_fixed_base_msm() -> Result<(), Box<dyn std::error::Error>> {
let config_path = "configs/bn254/bench_fixed_msm.config";
Expand All @@ -126,7 +143,8 @@ fn bench_fixed_base_msm() -> Result<(), Box<dyn std::error::Error>> {

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 bench_params: FixedMSMCircuitParams =
serde_json::from_str(line.unwrap().as_str()).unwrap();
let k = bench_params.degree;
println!("---------------------- degree = {k} ------------------------------",);
let rng = OsRng;
Expand Down
43 changes: 31 additions & 12 deletions halo2-ecc/src/bn254/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
#![allow(non_snake_case)]
use super::pairing::PairingChip;
use super::*;
use crate::halo2_proofs::{
dev::MockProver,
halo2curves::bn256::{pairing, Bn256, Fr, G1Affine},
plonk::*,
poly::commitment::ParamsProver,
poly::kzg::{
commitment::KZGCommitmentScheme,
multiopen::{ProverSHPLONK, VerifierSHPLONK},
strategy::SingleStrategy,
use crate::{ecc::EccChip, fields::PrimeField};
use crate::{
fields::FpStrategy,
halo2_proofs::{
dev::MockProver,
halo2curves::bn256::{pairing, Bn256, Fr, G1Affine},
plonk::*,
poly::commitment::ParamsProver,
poly::kzg::{
commitment::KZGCommitmentScheme,
multiopen::{ProverSHPLONK, VerifierSHPLONK},
strategy::SingleStrategy,
},
transcript::{Blake2bRead, Blake2bWrite, Challenge255},
transcript::{TranscriptReadBuffer, TranscriptWriterBuffer},
},
transcript::{Blake2bRead, Blake2bWrite, Challenge255},
transcript::{TranscriptReadBuffer, TranscriptWriterBuffer},
};
use crate::{ecc::EccChip, fields::PrimeField};
use ark_std::{end_timer, start_timer};
use group::Curve;
use halo2_base::utils::fe_to_biguint;
Expand All @@ -24,4 +27,20 @@ use std::io::Write;
pub mod ec_add;
pub mod fixed_base_msm;
pub mod msm;
pub mod msm_sum_infinity;
pub mod msm_sum_infinity_fixed_base;
pub mod pairing;

#[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,
}
183 changes: 183 additions & 0 deletions halo2-ecc/src/bn254/tests/msm_sum_infinity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
use ff::PrimeField;
use halo2_base::gates::{
builder::{
CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, RangeCircuitBuilder,
},
RangeChip,
};
use rand_core::OsRng;
use std::fs::File;

use super::*;

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

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 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_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_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_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_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_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();
}
Loading