Skip to content

Commit

Permalink
Merge pull request privacy-scaling-explorations#35 from input-output-…
Browse files Browse the repository at this point in the history
…hk/features/x-lt-p-range-check2

Add benchmarks and docs for scalar_fits_in_base_range_check
  • Loading branch information
iquerejeta authored Dec 15, 2023
2 parents ae4fdbb + cfac52c commit 6c816a0
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 24 deletions.
4 changes: 4 additions & 0 deletions halo2_gadgets/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,7 @@ harness = false
[[bench]]
name = "endoscale"
harness = false

[[bench]]
name = "scalar_fits_in_base_range_check"
harness = false
2 changes: 2 additions & 0 deletions halo2_gadgets/benches/eccops_goldenfiles/scalar-decomp.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
max_deg,advice_columns,lookups,permutations,column_queries,point_sets,proof_size
11,3,1,3,25,4,2944
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
max_deg,advice_columns,lookups,permutations,column_queries,point_sets,proof_size
18,2,1,2,30,4,3488
43 changes: 43 additions & 0 deletions halo2_gadgets/benches/scalar_fits_in_base_range_check.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
mod utilities;

use criterion::{criterion_group, criterion_main, Criterion};

use halo2curves::pasta::pallas;

use pprof::criterion::{Output, PProfProfiler};

use halo2_gadgets::utilities::scalar_fits_in_base_range_check::test_and_bench as rc;

/// Full-width scalar decomposition benchmark
fn bench_scalar_fits_in_base_range_check(c: &mut Criterion) {
let scalar = pallas::Scalar::zero();
let circuit = rc::RangeCheckCircuit {
mode: rc::Mode::InRangeTest {
high: scalar,
iterations: 10,
},
};
let circuit_small = rc::RangeCheckCircuit {
mode: rc::Mode::InRangeTest {
high: scalar,
iterations: 1,
},
};

let name = "scalar-fits-in-base-range-check";

utilities::circuit_to_csv::<pallas::Affine>(11, name, &[], circuit_small);
utilities::bench_circuit::<pallas::Affine>(c, 11, name, &[], circuit);
}

#[cfg(unix)]
criterion_group! {
name = benches;
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
targets = bench_scalar_fits_in_base_range_check
}

#[cfg(not(unix))]
criterion_group!(benches, bench_scalar_fits_in_base_range_check);

criterion_main!(benches);
3 changes: 3 additions & 0 deletions halo2_gadgets/benches/utilities/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ fn generate_csv(name: &str, model: ModelCircuit) -> io::Result<()> {
/// # Limitations
/// Currently the benchmark only supports an IPA prover/verifier
///
///
/// The proof will fail if `public == &[&[]]`. If you want to pass
/// emtpy `public`, use `&[]` instead.
pub fn bench_circuit<C: CurveAffine>(
c: &mut Criterion,
k: u32,
Expand Down
83 changes: 59 additions & 24 deletions halo2_gadgets/src/utilities/scalar_fits_in_base_range_check.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
//! Scalar-field fits in base-field range check: given x in Fq, where
//! p < q, check that x < p.
//!
//! TODO(ntc2): update link after updating book:
//! See the variable-base scalar-mul decomposition section of the
//! [Halo 2 book](http://localhost:3000/design/gadgets/ecc/var-base-scalar-mul.html#handling-full-width-scalar-field-scalars-when-qp)
//! This gadget implements a range check that is similar to, but simpler
//! than, the full-width-scalar-decomposition range check. Whereas
//! that gadget checks two values, `high` and `low`, this gadget only
//! checks a single value, `high`. The check on `high` here is
//! analogous to check `high` in the other gadget, in the case where
//! `low = 1`, except the upper bound is different (here it's `p`, there it's`(q-1)/2`).
//!
//! See the [Halo 2
//! book](http://localhost:3000/design/gadgets/ecc/var-base-scalar-mul.html#full-width-scalar-decomposition-range-check)
//! for more details.
use crate::{
ecc::chip::T_P,
Expand Down Expand Up @@ -200,38 +206,44 @@ impl Config {
}
}

#[cfg(test)]
mod tests {
// Don't show this module in generatd docs, since it's not really
// "public". We only make it public so we can share it between the
// test suite and the bench suite.
#[doc(hidden)]
pub mod test_and_bench {
use super::*;
use crate::{
ecc::chip::T_Q, utilities::lookup_range_check::LookupRangeCheckConfig,
utilities::lookup_range_check::LookupRangeCheckConfig,
utilities::scalar_fits_in_base_range_check as range_check,
};
use ff::Field;
use ff::PrimeField;

use halo2_proofs::{
circuit::{Layouter, SimpleFloorPlanner, Value},
dev::MockProver,
plonk::{Advice, Circuit, Column, ConstraintSystem},
};
use halo2curves::pasta::pallas;
use rand::{rngs::OsRng, Rng};

#[derive(Copy, Clone)]
enum Mode {
InRangeTest { high: pallas::Scalar },
OutOfRangeTest { high: pallas::Scalar },
#[derive(Copy, Clone, Debug)]
pub enum Mode {
InRangeTest {
high: pallas::Scalar,
iterations: u32,
},
OutOfRangeTest {
high: pallas::Scalar,
iterations: u32,
},
NoTest,
}

/// Computes a single range check.
#[derive(Clone, Copy)]
struct RangeCheckCircuit {
mode: Mode,
#[derive(Clone, Copy, Debug)]
pub struct RangeCheckCircuit {
pub mode: Mode,
}

#[derive(Debug, Clone)]
struct RangeCheckConfig {
pub struct RangeCheckConfig {
lookup: LookupRangeCheckConfig<pallas::Scalar, { sinsemilla::K }>,
range_check: range_check::Config,
}
Expand Down Expand Up @@ -269,7 +281,8 @@ mod tests {
match self.mode {
// Whether we expect this to verify or not depends on
// the mode.
Mode::OutOfRangeTest { high } | Mode::InRangeTest { high } => {
Mode::OutOfRangeTest { high, iterations }
| Mode::InRangeTest { high, iterations } => {
let scalar = layouter.assign_region(
|| "Test x < p range check",
|mut region| {
Expand All @@ -282,20 +295,36 @@ mod tests {
)
},
)?;
config.range_check.range_check(&mut layouter, scalar)?;
for _ in 0..iterations {
config
.range_check
.range_check(&mut layouter, scalar.clone())?;
}
}
Mode::NoTest => (),
}
Ok(())
}
}
}

#[cfg(test)]
mod tests {
use super::test_and_bench::*;
use super::*;
use crate::ecc::chip::T_Q;
use ff::Field;
use ff::PrimeField;
use halo2_proofs::dev::MockProver;
use halo2curves::pasta::pallas;
use rand::{rngs::OsRng, Rng};

// Run one test.
fn test(mode: Mode, msg: &str) {
let circuit = RangeCheckCircuit { mode };
let prover = MockProver::<pallas::Scalar>::run(11, &circuit, vec![]).unwrap();
match mode {
Mode::InRangeTest { high } => {
Mode::InRangeTest { high, .. } => {
assert_eq!(
prover.verify(),
Ok(()),
Expand All @@ -304,7 +333,7 @@ mod tests {
high
);
}
Mode::OutOfRangeTest { high } => {
Mode::OutOfRangeTest { high, .. } => {
assert!(
prover.verify().is_err(),
"Unexpected range check success for {} ({:?})",
Expand Down Expand Up @@ -339,7 +368,10 @@ mod tests {
.try_into()
.unwrap();
for (msg, scalar) in fixed_scalars.iter().chain(random_scalars.iter()) {
let mode = Mode::InRangeTest { high: *scalar };
let mode = Mode::InRangeTest {
high: *scalar,
iterations: 1,
};
test(mode, msg);
}
}
Expand All @@ -360,7 +392,10 @@ mod tests {
.try_into()
.unwrap();
for (msg, scalar) in fixed_scalars.iter().chain(random_scalars.iter()) {
let mode = Mode::OutOfRangeTest { high: *scalar };
let mode = Mode::OutOfRangeTest {
high: *scalar,
iterations: 1,
};
test(mode, msg);
}
}
Expand Down

0 comments on commit 6c816a0

Please sign in to comment.