Skip to content

Commit

Permalink
Merge pull request privacy-scaling-explorations#128 from input-output…
Browse files Browse the repository at this point in the history
…-hk/dev-feature/endoscale-chip-impl

Add `Chip` implementation to endoscaling
  • Loading branch information
b13decker authored Feb 27, 2024
2 parents 16bec5a + f75446c commit 7e5b7a1
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 73 deletions.
30 changes: 13 additions & 17 deletions halo2_gadgets/benches/endoscale.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ mod utilities;

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

Expand Down Expand Up @@ -70,7 +70,7 @@ where
let endoscalars = meta.instance_column();

(
EndoscaleConfig::configure(meta, advices, running_sum, endoscalars),
EndoscaleChip::configure(meta, advices, running_sum, endoscalars),
running_sum,
)
}
Expand All @@ -80,18 +80,15 @@ where
config: Self::Config,
mut layouter: impl Layouter<C::Base>,
) -> Result<(), Error> {
config.0.alg_2().table.load(&mut layouter)?;
let chip = EndoscaleChip::construct(config.0);
chip.load(&mut layouter)?;

let bitstring =
config
.0
.witness_bitstring(&mut layouter, &self.bitstring.transpose_array(), true)?;
chip.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])?;
chip.endoscale_fixed_base(&mut layouter, bitstring.clone(), vec![g_lagrange])?;

// Alg 1 (variable base)
let g_lagrange = layouter.assign_region(
Expand All @@ -116,9 +113,7 @@ where
))
},
)?;
config
.0
.endoscale_var_base(&mut layouter, bitstring, vec![g_lagrange])?;
chip.endoscale_var_base(&mut layouter, bitstring, vec![g_lagrange])?;

Ok(())
}
Expand Down Expand Up @@ -173,24 +168,25 @@ where
let running_sum = meta.advice_column();
let endoscalars = meta.instance_column();

EndoscaleConfig::configure(meta, advices, running_sum, endoscalars)
EndoscaleChip::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 chip = EndoscaleChip::construct(config);
chip.load(&mut layouter)?;

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

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

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

Ok(())
}
Expand Down
23 changes: 14 additions & 9 deletions halo2_gadgets/examples/endoscaling_demo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ use ff::Field;
use group::{prime::PrimeCurveAffine, Curve};
use halo2_gadgets::{
ecc::chip::NonIdentityEccPoint,
endoscale::{chip::EndoscaleConfig, EndoscaleInstructions},
endoscale::{
chip::{EndoscaleChip, EndoscaleConfig},
EndoscaleInstructions,
},
poseidon::{Pow5Chip, Pow5Config},
transcript::{chip::TranscriptChipP128Pow5T3, TranscriptInstructions},
};
Expand Down Expand Up @@ -312,7 +315,7 @@ impl Circuit<pallas::Base> for ChallengeMultiplicationCircuit {
);

// Set up config for endoscaling
let endoscale_config = EndoscaleConfig::configure(
let endoscale_config = EndoscaleChip::configure(
meta,
advices[0..8]
.try_into()
Expand Down Expand Up @@ -404,16 +407,18 @@ impl Circuit<pallas::Base> for ChallengeMultiplicationCircuit {
let challenge = chip.squeeze_challenge(layouter.namespace(|| "squeeze challenge"))?;
layouter.constrain_instance(challenge.cell(), config.outputs, 0)?;

// Use the endoscale config to convert that challenge into a bitstring that can be used
// All endoscaling-related functionality is implemented by `EndoscaleChip`
// We can construct it directly from the corresponding config
let endoscale_chip = EndoscaleChip::construct(config.endoscale_config.clone());

// Use the endoscale chip to convert that challenge into a bitstring that can be used
// with algorithm 1.
let bitstring = config
.endoscale_config
.convert_to_bitstring(&mut layouter, &challenge)?;
let bitstring = endoscale_chip.convert_to_bitstring(&mut layouter, &challenge)?;

// Endoscale two points with algorithm 1. We used `var_base` because the "base" point -- our
// `known_point` -- isn't known to both parties.
let scaled_points: [_; 2] = config
.endoscale_config
// `known_point` -- isn't known to both parties. You use `endoscale_fixed_base` when the
// base point is a fixed or instance value.
let scaled_points: [_; 2] = endoscale_chip
.endoscale_var_base(
&mut layouter,
vec![bitstring.clone(), bitstring],
Expand Down
4 changes: 2 additions & 2 deletions halo2_gadgets/src/endoscale.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Gadget for endoscaling.
use ff::PrimeFieldBits;
use halo2_proofs::{
circuit::{AssignedCell, Layouter, Value},
circuit::{AssignedCell, Chip, Layouter, Value},
plonk::{Assigned, Error},
};
use halo2curves::CurveAffine;
Expand All @@ -11,7 +11,7 @@ use std::fmt::Debug;
pub mod chip;

/// Instructions to map bitstrings to and from endoscalars.
pub trait EndoscaleInstructions<C: CurveAffine>
pub trait EndoscaleInstructions<C: CurveAffine>: Chip<C::Base> + Debug
where
C::Base: PrimeFieldBits,
{
Expand Down
134 changes: 89 additions & 45 deletions halo2_gadgets/src/endoscale/chip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use super::EndoscaleInstructions;
use ff::PrimeFieldBits;
use halo2_proofs::{
arithmetic::CurveAffine,
circuit::{AssignedCell, Layouter, Value},
circuit::{AssignedCell, Chip, Layouter, Value},
plonk::{Advice, Assigned, Column, ConstraintSystem, Error, Instance},
};
use halo2curves::{pasta, pluto_eris};
Expand Down Expand Up @@ -54,30 +54,35 @@ where
alg_2: Alg2Config<C, K, MAX_BITSTRING_LENGTH>,
}

impl<C: CurveAffine, const K: usize, const MAX_BITSTRING_LENGTH: usize>
EndoscaleConfig<C, K, MAX_BITSTRING_LENGTH>
/// Chip implementing [`EndoscaleInstructions`]
#[derive(Debug)]
pub struct EndoscaleChip<C: CurveAffine, const K: usize, const MAX_BITSTRING_LENGTH: usize>
where
C::Base: PrimeFieldBits,
{
/// Get the config for algorithm 1.
pub fn alg_1(&self) -> &Alg1Config<C> {
&self.alg_1
}
config: EndoscaleConfig<C, K, MAX_BITSTRING_LENGTH>,
}

/// Get the config for algorithm 2 .
pub fn alg_2(&self) -> &Alg2Config<C, K, MAX_BITSTRING_LENGTH> {
&self.alg_2
impl<C: CurveAffine + CurveEndoscale, const K: usize, const N: usize> EndoscaleChip<C, K, N>
where
C::Base: PrimeFieldBits,
{
/// Construct chip from inner config
pub fn construct(config: EndoscaleConfig<C, K, N>) -> Self {
Self { config }
}

/// TODO: docs
/// Instantiates configuration used by [`EndoscaleChip`].
/// The chip itself can be instantiated from [`EndoscaleConfig`]
/// using [`EndoscaleChip::construct`]
pub fn configure(
meta: &mut ConstraintSystem<C::Base>,
// Advice columns not shared across alg_1 and alg_2
advices: [Column<Advice>; 8],
// Running sum column shared across alg_1 and alg_2
running_sum: Column<Advice>,
endoscalars: Column<Instance>,
) -> Self {
) -> EndoscaleConfig<C, K, N> {
let running_sum_pairs = {
let q_pairs = meta.selector();
RunningSumConfig::configure(meta, q_pairs, running_sum)
Expand All @@ -103,8 +108,42 @@ where
advices[1],
running_sum_chunks,
);
EndoscaleConfig { alg_1, alg_2 }
}

/// Setup table used for Algorithm 2 of endoscaling.
///
/// Loads values [0..2^K) into one column and the endoscalars corresponding
/// to the K-bit bitstring encoding of each value into another column.
pub fn load(
&self,
layouter: &mut impl Layouter<C::Base>,
) -> Result<<Self as Chip<C::Base>>::Loaded, Error> {
self.alg_2().table.load(layouter)
}

fn alg_1(&self) -> &Alg1Config<C> {
self.config.alg_1()
}

fn alg_2(&self) -> &Alg2Config<C, K, N> {
self.config.alg_2()
}
}

Self { alg_1, alg_2 }
impl<C: CurveAffine, const K: usize, const MAX_BITSTRING_LENGTH: usize>
EndoscaleConfig<C, K, MAX_BITSTRING_LENGTH>
where
C::Base: PrimeFieldBits,
{
/// Get the config for algorithm 1.
pub fn alg_1(&self) -> &Alg1Config<C> {
&self.alg_1
}

/// Get the config for algorithm 2 .
pub fn alg_2(&self) -> &Alg2Config<C, K, MAX_BITSTRING_LENGTH> {
&self.alg_2
}
}

Expand All @@ -130,8 +169,25 @@ impl CurveEndoscale for pluto_eris::ErisAffine {
const MAX_BITSTRING_LENGTH: usize = 442;
}

impl<C: CurveAffine + CurveEndoscale, const K: usize, const N: usize> Chip<C::Base>
for EndoscaleChip<C, K, N>
where
C::Base: PrimeFieldBits,
{
type Config = EndoscaleConfig<C, K, N>;
type Loaded = ();

fn config(&self) -> &Self::Config {
&self.config
}

fn loaded(&self) -> &Self::Loaded {
&()
}
}

impl<C: CurveAffine + CurveEndoscale, const K: usize, const N: usize> EndoscaleInstructions<C>
for EndoscaleConfig<C, K, N>
for EndoscaleChip<C, K, N>
where
C::Base: PrimeFieldBits,
{
Expand All @@ -152,11 +208,11 @@ where
bits.chunks(Self::MAX_BITSTRING_LENGTH)
.map(|bits| {
if for_base {
self.alg_1
self.alg_1()
.witness_bitstring(layouter.namespace(|| "alg 1"), bits)
.map(Bitstring::Pair)
} else {
self.alg_2
self.alg_2()
.witness_bitstring(layouter.namespace(|| "alg 2"), bits)
.map(Bitstring::KBit)
}
Expand All @@ -171,7 +227,7 @@ where
) -> Result<Self::Bitstring, Error> {
// NB: This outputs a `Bitstring::Pair` variant compatible with Alg 1 only.
// There is currently no equivalent method for Alg 2.
self.alg_1
self.alg_1()
.convert_to_bitstring(
layouter.namespace(|| "alg 1: convert challenge to bitstring"),
challenge,
Expand Down Expand Up @@ -247,7 +303,7 @@ where
) -> Result<(), Error> {
match bitstring {
Bitstring::KBit(bitstring) => {
self.alg_2
self.alg_2()
.constrain_bitstring(layouter, bitstring, pub_input_rows)
}
// Constraining the bitstring only makes sense when the input is the `Bitstring::Kbit`
Expand All @@ -260,7 +316,7 @@ where

#[cfg(test)]
mod tests {
use super::{EndoscaleConfig, EndoscaleInstructions};
use super::{EndoscaleChip, EndoscaleConfig, EndoscaleInstructions};
use crate::ecc::chip::NonIdentityEccPoint;
use crate::endoscale::chip::CurveEndoscale;
use crate::utilities::cost_model::circuit_to_csv;
Expand Down Expand Up @@ -331,7 +387,7 @@ mod tests {
let endoscalars = meta.instance_column();

(
EndoscaleConfig::configure(meta, advices, running_sum, endoscalars),
EndoscaleChip::configure(meta, advices, running_sum, endoscalars),
running_sum,
)
}
Expand All @@ -341,19 +397,15 @@ mod tests {
config: Self::Config,
mut layouter: impl Layouter<C::Base>,
) -> Result<(), Error> {
config.0.alg_2().table.load(&mut layouter)?;
let chip = EndoscaleChip::construct(config.0);
chip.load(&mut layouter)?;

let bitstring = config.0.witness_bitstring(
&mut layouter,
&self.bitstring.transpose_array(),
true,
)?;
let bitstring =
chip.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])?;
chip.endoscale_fixed_base(&mut layouter, bitstring.clone(), vec![g_lagrange])?;

// Alg 1 (variable base)
let g_lagrange = layouter.assign_region(
Expand All @@ -378,9 +430,7 @@ mod tests {
))
},
)?;
config
.0
.endoscale_var_base(&mut layouter, bitstring, vec![g_lagrange])?;
chip.endoscale_var_base(&mut layouter, bitstring, vec![g_lagrange])?;

Ok(())
}
Expand Down Expand Up @@ -436,31 +486,25 @@ mod tests {
let running_sum = meta.advice_column();
let endoscalars = meta.instance_column();

EndoscaleConfig::configure(meta, advices, running_sum, endoscalars)
EndoscaleChip::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 chip = EndoscaleChip::construct(config);
chip.load(&mut layouter)?;

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

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

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

Ok(())
}
Expand Down
Loading

0 comments on commit 7e5b7a1

Please sign in to comment.