Skip to content

Commit

Permalink
Merge pull request privacy-scaling-explorations#34 from input-output-…
Browse files Browse the repository at this point in the history
…hk/features/endoscalling

Endoscaling Integration
  • Loading branch information
iquerejeta authored Dec 15, 2023
2 parents e6b62bc + 442260e commit ae4fdbb
Show file tree
Hide file tree
Showing 26 changed files with 2,778 additions and 25 deletions.
1 change: 1 addition & 0 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
- [SHA-256](design/gadgets/sha256.md)
- [16-bit table chip](design/gadgets/sha256/table16.md)
- [Double-and-add](design/gadgets/double-and-add.md)
- [Endoscaling](design/gadgets/endoscaling.md)
- [Background Material](background.md)
- [Fields](background/fields.md)
- [Polynomials](background/polynomials.md)
Expand Down
424 changes: 424 additions & 0 deletions book/src/design/gadgets/endoscaling.md

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions halo2_gadgets/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,7 @@ required-features = ["unstable"]
[[bench]]
name = "decompose_running_sum"
harness = false

[[bench]]
name = "endoscale"
harness = false
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
12,9,2,11,52,4,4448
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
12,9,2,11,52,4,4448
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
12,9,2,11,52,4,4448
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
12,9,2,11,52,4,4448
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
12,9,2,11,52,4,4448
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
12,9,2,11,52,4,4448
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
12,9,2,11,52,4,4448
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
12,9,2,11,52,4,4448
317 changes: 317 additions & 0 deletions halo2_gadgets/benches/endoscale.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,317 @@
mod utilities;

use halo2_gadgets::ecc::chip::NonIdentityEccPoint;
use halo2_gadgets::endoscale::{
chip::{CurveEndoscale, EndoscaleConfig},
util::compute_endoscalar_with_acc,
EndoscaleInstructions,
};

use ff::{Field, FromUniformBytes, PrimeFieldBits};
use halo2_proofs::{
circuit::{Layouter, SimpleFloorPlanner, Value},
plonk::{
Advice, Circuit, Column, ConstraintSystem, Error,
},
poly::{
commitment::ParamsProver,
ipa::commitment::ParamsIPA,
},
};
use halo2curves::pasta::{pallas, vesta};
use halo2curves::CurveAffine;

use std::{any::type_name, convert::TryInto, marker::PhantomData};

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

#[derive(Clone)]
struct BaseCircuit<
C: CurveAffine,
const K: usize,
const NUM_BITS: usize,
const NUM_BITS_DIV_K_CEIL: usize,
> where
C::Base: PrimeFieldBits,
{
bitstring: Value<[bool; NUM_BITS]>,
pub_input_rows: [usize; NUM_BITS_DIV_K_CEIL],
_marker: PhantomData<C>,
}

impl<
C: CurveAffine + CurveEndoscale,
const K: usize,
const NUM_BITS: usize,
const NUM_BITS_DIV_K_CEIL: usize,
> Circuit<C::Base> for BaseCircuit<C, K, NUM_BITS, NUM_BITS_DIV_K_CEIL>
where
C::Base: PrimeFieldBits,
{
type Config = (EndoscaleConfig<C, K, 248>, Column<Advice>);
type FloorPlanner = SimpleFloorPlanner;

fn without_witnesses(&self) -> Self {
Self {
bitstring: Value::unknown(),
pub_input_rows: self.pub_input_rows,
_marker: PhantomData,
}
}

fn configure(meta: &mut ConstraintSystem<C::Base>) -> Self::Config {
let constants = meta.fixed_column();
meta.enable_constant(constants);

let advices = (0..8)
.map(|_| meta.advice_column())
.collect::<Vec<_>>()
.try_into()
.unwrap();
let running_sum = meta.advice_column();
let endoscalars = meta.instance_column();

(
EndoscaleConfig::configure(meta, advices, running_sum, endoscalars),
running_sum,
)
}

fn synthesize(
&self,
config: Self::Config,
mut layouter: impl Layouter<C::Base>,
) -> Result<(), Error> {
config.0.alg_2.table.load(&mut layouter)?;

let bitstring =
config
.0
.witness_bitstring(&mut layouter, &self.bitstring.transpose_array(), true)?;

// Alg 1 (fixed base)
let g_lagrange = ParamsIPA::<C>::new(11).g_lagrange()[0];
config
.0
.endoscale_fixed_base(&mut layouter, bitstring.clone(), vec![g_lagrange])?;

// Alg 1 (variable base)
let g_lagrange = layouter.assign_region(
|| "g_lagrange",
|mut region| {
let x = region.assign_advice(
|| "x",
config.1,
0,
|| Value::known(*g_lagrange.coordinates().unwrap().x()),
)?;
let y = region.assign_advice(
|| "y",
config.1,
1,
|| Value::known(*g_lagrange.coordinates().unwrap().y()),
)?;

Ok(NonIdentityEccPoint::<C>::from_coordinates_unchecked(
x.into(),
y.into(),
))
},
)?;
config
.0
.endoscale_var_base(&mut layouter, bitstring, vec![g_lagrange])?;

Ok(())
}
}

#[derive(Clone)]
struct ScalarCircuit<
C: CurveAffine,
const K: usize,
const NUM_BITS: usize,
const NUM_BITS_DIV_K_CEIL: usize,
> where
C::Base: PrimeFieldBits,
{
bitstring: Value<[bool; NUM_BITS]>,
pub_input_rows: [usize; NUM_BITS_DIV_K_CEIL],
_marker: PhantomData<C>,
}

impl<
C: CurveAffine + CurveEndoscale,
const K: usize,
const NUM_BITS: usize,
const NUM_BITS_DIV_K_CEIL: usize,
> Circuit<C::Base> for ScalarCircuit<C, K, NUM_BITS, NUM_BITS_DIV_K_CEIL>
where
C::Base: PrimeFieldBits,
{
type Config = EndoscaleConfig<C, K, 248>;
type FloorPlanner = SimpleFloorPlanner;

fn without_witnesses(&self) -> Self {
Self {
bitstring: Value::unknown(),
pub_input_rows: self.pub_input_rows,
_marker: PhantomData,
}
}

fn configure(meta: &mut ConstraintSystem<C::Base>) -> Self::Config {
let constants = meta.fixed_column();
meta.enable_constant(constants);

let advices = (0..8)
.map(|_| meta.advice_column())
.collect::<Vec<_>>()
.try_into()
.unwrap();
let running_sum = meta.advice_column();
let endoscalars = meta.instance_column();

EndoscaleConfig::configure(meta, advices, running_sum, endoscalars)
}

fn synthesize(
&self,
config: Self::Config,
mut layouter: impl Layouter<C::Base>,
) -> Result<(), Error> {
config.alg_2.table.load(&mut layouter)?;

let bitstring =
config.witness_bitstring(&mut layouter, &self.bitstring.transpose_array(), false)?;

// Alg 2 with lookup
config.compute_endoscalar(&mut layouter, &bitstring[0])?;

// Constrain bitstring
config.constrain_bitstring(&mut layouter, &bitstring[0], self.pub_input_rows.to_vec())?;

Ok(())
}
}

fn bench_endoscale_base<
C1,
C2,
const K: usize,
const NUM_BITS: usize,
const NUM_BITS_DIV_K_CEIL: usize,
>(
c: &mut Criterion,
) where
C1::Scalar: FromUniformBytes<64>,
C1::Base: PrimeFieldBits + FromUniformBytes<64>,
C2::Scalar: FromUniformBytes<64>,
C2::Base: PrimeFieldBits + FromUniformBytes<64>,
C1: CurveAffine<Base = C2::Scalar> + CurveEndoscale,
C2: CurveAffine + CurveEndoscale,
{
let bitstring: [bool; NUM_BITS] = (0..NUM_BITS)
.map(|_| rand::random::<bool>())
.collect::<Vec<_>>()
.try_into()
.unwrap();

// Public input of endoscalars in the base field corresponding to the bits.
let pub_inputs_base: Vec<C2::Scalar> = {
// Pad bitstring to multiple of K.
let bitstring = bitstring
.iter()
.copied()
.chain(std::iter::repeat(false))
.take(K * NUM_BITS_DIV_K_CEIL)
.collect::<Vec<_>>();
bitstring
.chunks(K)
.map(|chunk| compute_endoscalar_with_acc(Some(C1::Base::ZERO), chunk))
.collect()
};

let base_circuit = BaseCircuit::<C1, K, NUM_BITS, NUM_BITS_DIV_K_CEIL> {
bitstring: Value::known(bitstring),
pub_input_rows: (0..NUM_BITS_DIV_K_CEIL)
.collect::<Vec<_>>()
.try_into()
.unwrap(),
_marker: PhantomData,
};

// There needs to be an extra row, compared to testing, since it needs extra room for binding factors and stuff for ZK.
let name = format!("endoscale-base-{}-{}-{}-{}-{}", type_name::<C1>(), type_name::<C2>(), K, NUM_BITS, NUM_BITS_DIV_K_CEIL);
let k = (K + 1) as u32;
utilities::circuit_to_csv::<C2>(k, &name, &[&pub_inputs_base[..]], base_circuit.clone());
utilities::bench_circuit::<C2>(c, k, &name, &[&pub_inputs_base[..]], base_circuit);
}

fn bench_endoscale_scalar<
C1,
C2,
const K: usize,
const NUM_BITS: usize,
const NUM_BITS_DIV_K_CEIL: usize,
>(
c: &mut Criterion,
) where
C1::Scalar: FromUniformBytes<64>,
C1::Base: PrimeFieldBits + FromUniformBytes<64>,
C2::Scalar: FromUniformBytes<64>,
C2::Base: PrimeFieldBits + FromUniformBytes<64>,
C1: CurveAffine + CurveEndoscale,
C2: CurveAffine<Base = C1::Scalar> + CurveEndoscale,
{
let bitstring: [bool; NUM_BITS] = (0..NUM_BITS)
.map(|_| rand::random::<bool>())
.collect::<Vec<_>>()
.try_into()
.unwrap();

// Public input of endoscalars in the scalar field corresponding to the bits.
let pub_inputs_scalar: Vec<C1::Scalar> = {
// Pad bitstring to multiple of K.
let bitstring = bitstring
.iter()
.copied()
.chain(std::iter::repeat(false))
.take(K * NUM_BITS_DIV_K_CEIL)
.collect::<Vec<_>>();
bitstring
.chunks(K)
.map(|chunk| compute_endoscalar_with_acc(Some(C2::Base::ZERO), chunk))
.collect()
};

let scalar_circuit = ScalarCircuit::<C2, K, NUM_BITS, NUM_BITS_DIV_K_CEIL> {
bitstring: Value::known(bitstring),
pub_input_rows: (0..NUM_BITS_DIV_K_CEIL)
.collect::<Vec<_>>()
.try_into()
.unwrap(),
_marker: PhantomData,
};

// There needs to be an extra row, compared to testing, since it needs extra room for binding factors and stuff for ZK.
let name = format!("endoscale-scalar-{}-{}-{}-{}-{}", type_name::<C1>(), type_name::<C2>(), K, NUM_BITS, NUM_BITS_DIV_K_CEIL);
let k = (K + 1) as u32;
utilities::circuit_to_csv::<C1>(k, &name, &[&pub_inputs_scalar[..]], scalar_circuit.clone());
utilities::bench_circuit::<C1>(c, k, &name, &[&pub_inputs_scalar[..]], scalar_circuit);
}

fn bench_endoscale(c: &mut Criterion) {
bench_endoscale_base::<pallas::Affine, vesta::Affine, 8, 64, 8>(c);
bench_endoscale_scalar::<pallas::Affine, vesta::Affine, 8, 64, 8>(c);
bench_endoscale_base::<vesta::Affine, pallas::Affine, 8, 64, 8>(c);
bench_endoscale_scalar::<vesta::Affine, pallas::Affine, 8, 64, 8>(c);

bench_endoscale_base::<pallas::Affine, vesta::Affine, 8, 66, 9>(c);
bench_endoscale_scalar::<pallas::Affine, vesta::Affine, 8, 66, 9>(c);
bench_endoscale_base::<vesta::Affine, pallas::Affine, 8, 66, 9>(c);
bench_endoscale_scalar::<vesta::Affine, pallas::Affine, 8, 66, 9>(c);
}

criterion_group!(benches, bench_endoscale);
criterion_main!(benches);
6 changes: 3 additions & 3 deletions halo2_gadgets/src/ecc/chip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ use halo2curves::{pasta::pallas, CurveAffine};
use std::convert::TryInto;

pub(super) mod add;
pub(super) mod add_incomplete;
pub(crate) mod add_incomplete;
pub mod constants;

pub(super) mod double;
pub(crate) mod double;
pub(crate) mod mul;
pub(super) mod mul_fixed;
pub(super) mod witness_point;
Expand Down Expand Up @@ -153,7 +153,7 @@ pub struct EccConfig<FixedPoints: super::FixedPoints<pallas::Affine>> {
pub advices: [Column<Advice>; 10],

/// Incomplete addition
add_incomplete: add_incomplete::Config,
add_incomplete: add_incomplete::Config<pallas::Affine>,

/// Complete addition
add: add::Config,
Expand Down
Loading

0 comments on commit ae4fdbb

Please sign in to comment.