Skip to content

Commit

Permalink
Use two Sinsemilla chips in parallel
Browse files Browse the repository at this point in the history
  • Loading branch information
therealyingtong committed Apr 26, 2021
1 parent c8360c3 commit 2395853
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 61 deletions.
72 changes: 49 additions & 23 deletions src/circuit/gadget/sinsemilla.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ mod tests {
circuit::{layouter::SingleChipLayouter, Chip, Layouter, Loaded},
dev::MockProver,
pasta::pallas,
plonk::{Assignment, Circuit, ConstraintSystem, Error, Permutation},
plonk::{Assignment, Circuit, ConstraintSystem, Error},
};

use super::{
Expand All @@ -193,16 +193,16 @@ mod tests {
}

impl<C: CurveAffine> Circuit<C::Base> for MyCircuit<C> {
type Config = SinsemillaConfigEnum;
type Config = (SinsemillaConfigEnum, SinsemillaConfigEnum);

#[allow(non_snake_case)]
fn configure(meta: &mut ConstraintSystem<C::Base>) -> Self::Config {
let bits = meta.advice_column();
let P = (meta.advice_column(), meta.advice_column());
let A = (meta.advice_column(), meta.advice_column());
let P = (meta.advice_column(), meta.advice_column());
let lambda = (meta.advice_column(), meta.advice_column());

let mul_fixed_u = meta.advice_column().into();
let mul_fixed_u = meta.advice_column();

let add_complete_bool = [
meta.advice_column(),
Expand All @@ -218,62 +218,88 @@ mod tests {
meta.advice_column(),
];

let perm_bits = Permutation::new(meta, &[bits.into()]);
let perm_sum =
Permutation::new(meta, &[P.0.into(), P.1.into(), A.0.into(), A.1.into()]);
// Fixed columns for the Sinsemilla generator lookup table
let lookup = (
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
);

let mut chip = SinsemillaChip::<C>::new();
chip.configure(
let mut chip1 = SinsemillaChip::<C>::new();
let config1 = chip1.configure(
meta,
bits,
mul_fixed_u,
P,
A,
P,
lambda,
add_complete_bool,
add_complete_inv,
perm_bits,
perm_sum,
)
lookup,
);
let mut chip2 = SinsemillaChip::<C>::new();
let config2 = chip2.configure(
meta,
add_complete_bool[0], // bits
add_complete_bool[1], // mul_fixed_u
(add_complete_bool[2], add_complete_bool[3]), // P
(add_complete_inv[0], add_complete_inv[1]), // A
(add_complete_inv[2], add_complete_inv[3]), // lambda
add_complete_bool,
add_complete_inv,
lookup,
);
(config1, config2)
}

fn synthesize(
&self,
cs: &mut impl Assignment<C::Base>,
config: Self::Config,
) -> Result<(), Error> {
let mut chip = SinsemillaChip::<C>::construct(
config,
let mut chip1 = SinsemillaChip::<C>::construct(
config.0,
<SinsemillaChip<C> as Chip<C::Base>>::Loaded::empty(),
);
let mut layouter = SingleChipLayouter::new(cs)?;
chip.load(&mut layouter)?;
chip1.load(&mut layouter)?;

let merkle_crh = HashDomain::new(
chip.clone(),
chip1.clone(),
layouter.namespace(|| "merkle_crh"),
&SinsemillaHashDomains::MerkleCrh,
)?;
merkle_crh.hash_to_point(
chip.clone(),
chip1,
layouter.namespace(|| "hash_to_point"),
vec![true, true, false, false],
vec![
true, true, false, true, true, false, false, false, true, true, false, false,
],
)?;

let mut chip2 = SinsemillaChip::<C>::construct(
config.1,
<SinsemillaChip<C> as Chip<C::Base>>::Loaded::empty(),
);
chip2.load(&mut layouter)?;

let commit_ivk = CommitDomain::new(
chip.clone(),
chip2.clone(),
layouter.namespace(|| "commit_ivk"),
&SinsemillaCommitDomains::CommitIvk,
)?;
let r = ScalarFixed::<C, SinsemillaChip<C>>::new(
chip.clone(),
chip2.clone(),
layouter.namespace(|| "r"),
Some(C::Scalar::rand()),
)?;
commit_ivk.commit(
chip.clone(),
chip2,
layouter.namespace(|| "commit"),
vec![true, true, false, false],
vec![
true, true, false, false, true, false, true, true, false, true, false, true,
true, false,
],
r,
)?;

Expand Down
75 changes: 50 additions & 25 deletions src/circuit/gadget/sinsemilla/chip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use group::Curve;
use halo2::{
arithmetic::{CurveAffine, FieldExt},
circuit::{CellValue, Chip, Config, Layouter, Loaded, Region},
plonk::{Advice, Column, ConstraintSystem, Error, Permutation, Selector},
plonk::{Advice, Column, ConstraintSystem, Error, Fixed, Permutation, Selector},
poly::Rotation,
};

Expand All @@ -31,8 +31,7 @@ pub struct Message(Vec<CellValue<u32>>);
#[allow(non_snake_case)]
pub struct SinsemillaConfig {
bits: Column<Advice>,
mul_fixed_u: Column<Advice>,
A: (Column<Advice>, Column<Advice>),
x_a: Column<Advice>,
x_p: Column<Advice>,
lambda: (Column<Advice>, Column<Advice>),
perm_bits: Permutation,
Expand All @@ -45,6 +44,7 @@ pub struct SinsemillaConfig {
/// Enum for the Sinsemilla hash chip
#[derive(Clone, Debug)]
#[allow(non_snake_case)]
#[allow(clippy::large_enum_variant)]
pub enum SinsemillaConfigEnum {
Empty,
Config(SinsemillaConfig),
Expand Down Expand Up @@ -91,29 +91,35 @@ impl<C: CurveAffine> SinsemillaChip<C> {
}

#[allow(non_snake_case)]
#[allow(clippy::too_many_arguments)]
pub fn configure(
&mut self,
meta: &mut ConstraintSystem<C::Base>,
bits: Column<Advice>,
mul_fixed_u: Column<Advice>,
P: (Column<Advice>, Column<Advice>),
A: (Column<Advice>, Column<Advice>),
P: (Column<Advice>, Column<Advice>),
lambda: (Column<Advice>, Column<Advice>),
add_complete_bool: [Column<Advice>; 4],
add_complete_inv: [Column<Advice>; 4],
perm_bits: Permutation,
perm_sum: Permutation,
lookup: (Column<Fixed>, Column<Fixed>, Column<Fixed>),
) -> <Self as Chip<C::Base>>::Config {
// Sinsemilla selector
let q_sinsemilla = meta.selector();

let perm_bits = Permutation::new(meta, &[bits.into()]);
let perm_sum = Permutation::new(
meta,
&[P.0.into(), P.1.into(), A.0.into(), A.1.into(), bits.into()],
);

let mut ecc_chip = EccChip::<C>::new();
let ecc_config = ecc_chip.configure(
meta,
bits,
mul_fixed_u,
P,
A,
P,
lambda,
add_complete_bool,
add_complete_inv,
Expand All @@ -123,7 +129,7 @@ impl<C: CurveAffine> SinsemillaChip<C> {

let mut generator_table_chip = GeneratorTableChip::<C>::new();
let generator_table =
generator_table_chip.configure(meta, q_sinsemilla, bits, A.0, P.0, lambda);
generator_table_chip.configure(meta, q_sinsemilla, lookup, bits, A.0, P.0, lambda);

let sinsemilla_cur = meta.query_selector(q_sinsemilla, Rotation::cur());

Expand Down Expand Up @@ -167,8 +173,7 @@ impl<C: CurveAffine> SinsemillaChip<C> {

let config = SinsemillaConfigEnum::Config(SinsemillaConfig {
bits,
mul_fixed_u,
A,
x_a: A.0,
x_p: P.0,
lambda,
perm_bits,
Expand Down Expand Up @@ -239,7 +244,7 @@ impl<C: CurveAffine> SinsemillaInstructions<C> for SinsemillaChip<C> {
type HashDomains = SinsemillaHashDomains;
type CommitDomains = SinsemillaCommitDomains;

type Q = EccPoint<C::Base>;
type Q = (CellValue<C::Base>, C::Base);

type Message = Message;

Expand All @@ -258,11 +263,9 @@ impl<C: CurveAffine> SinsemillaInstructions<C> for SinsemillaChip<C> {
layouter.assign_region(
|| format!("{:?} Q", domain),
|mut region: Region<'_, C::Base>| {
let x = region.assign_advice(|| "x_q", config.A.0, 0, || Ok(*q.x()))?;
let x = region.assign_advice(|| "x_q", config.x_a, 0, || Ok(*q.x()))?;
let x = CellValue::new(x, Some(*q.x()));
let y = region.assign_advice(|| "y_q", config.A.1, 0, || Ok(*q.y()))?;
let y = CellValue::new(y, Some(*q.y()));
Ok(EccPoint { x, y })
Ok((x, *q.y()))
},
)
}
Expand All @@ -283,7 +286,7 @@ impl<C: CurveAffine> SinsemillaInstructions<C> for SinsemillaChip<C> {

// Pad message to nearest multiple of `k`.
let pad_length = K - (message.len() % K);
let mut message = message.clone();
let mut message = message;
message.extend_from_slice(&vec![false; pad_length]);

// Chunk message into `k`-bit words
Expand Down Expand Up @@ -372,18 +375,18 @@ impl<C: CurveAffine> SinsemillaInstructions<C> for SinsemillaChip<C> {
// Copy the `x`-coordinate of our starting `Q` base.
let x_q_cell = region.assign_advice(
|| "x_q",
config.A.0,
config.x_a,
0,
|| Q.x.value.ok_or(Error::SynthesisError),
|| Q.0.value.ok_or(Error::SynthesisError),
)?;
region.constrain_equal(&config.perm_sum, Q.x.cell, x_q_cell)?;
region.constrain_equal(&config.perm_sum, Q.0.cell, x_q_cell)?;

// Initialize `x_a`, `y_a` as `x_q`, `y_q`.
let mut x_a = Q.x.value;
let mut x_a_cell = Q.x.cell;
let mut y_a = Q.y.value;
let mut x_a = Q.0.value;
let mut x_a_cell = Q.0.cell;
let mut y_a = Some(Q.1);

for row in 0..message.0.len() {
for (row, _) in message.0.iter().enumerate() {
let gen = generators[row];
let x_p = gen.0;
let y_p = gen.1;
Expand Down Expand Up @@ -430,7 +433,7 @@ impl<C: CurveAffine> SinsemillaInstructions<C> for SinsemillaChip<C> {

x_a_cell = region.assign_advice(
|| "x_a",
config.A.0,
config.x_a,
row + 1,
|| x_a_new.ok_or(Error::SynthesisError),
)?;
Expand All @@ -441,11 +444,33 @@ impl<C: CurveAffine> SinsemillaInstructions<C> for SinsemillaChip<C> {
// Assign the final `y_a`
let y_a_cell = region.assign_advice(
|| "y_a",
config.A.1,
config.bits,
message.0.len(),
|| y_a.ok_or(Error::SynthesisError),
)?;

#[cfg(test)]
if let Some((x_a, y_a)) = x_a.zip(y_a) {
let computed_point: C = C::from_xy(x_a, y_a).unwrap();
let expected_point: C = {
let Q = C::from_xy(Q.0.value.unwrap(), Q.1).unwrap();
let message: Vec<u32> =
message.0.iter().map(|word| word.value.unwrap()).collect();

use crate::primitives::sinsemilla::S_PERSONALIZATION;
use pasta_curves::arithmetic::CurveExt;

let hasher_S = C::CurveExt::hash_to_curve(S_PERSONALIZATION);
let S = |chunk: u32| -> C { hasher_S(&chunk.to_le_bytes()).to_affine() };

message
.iter()
.fold(C::CurveExt::from(Q), |acc, &chunk| (acc + S(chunk)) + acc)
.to_affine()
};
assert_eq!(computed_point, expected_point);
}

let y_a = CellValue::new(y_a_cell, y_a);
let x_a = CellValue::new(x_a_cell, x_a);

Expand Down
25 changes: 12 additions & 13 deletions src/circuit/gadget/sinsemilla/chip/generator_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,54 +66,53 @@ impl<C: CurveAffine> GeneratorTableChip<C> {
}
}

#[allow(clippy::too_many_arguments)]
pub fn configure(
&mut self,
meta: &mut ConstraintSystem<C::Base>,
q_sinsemilla: Selector,
lookup: (Column<Fixed>, Column<Fixed>, Column<Fixed>),
bits: Column<Advice>,
x_a: Column<Advice>,
x_p: Column<Advice>,
lambda: (Column<Advice>, Column<Advice>),
) -> <Self as Chip<C::Base>>::Config {
let sinsemilla_cur = meta.query_selector(q_sinsemilla, Rotation::cur());

let table_idx = meta.fixed_column();
let table_idx_cur = meta.query_fixed(table_idx, Rotation::cur());
let table_x = meta.fixed_column();
let table_x_cur = meta.query_fixed(table_x, Rotation::cur());
let table_y = meta.fixed_column();
let table_y_cur = meta.query_fixed(table_y, Rotation::cur());
let table_idx_cur = meta.query_fixed(lookup.0, Rotation::cur());
let table_x_cur = meta.query_fixed(lookup.1, Rotation::cur());
let table_y_cur = meta.query_fixed(lookup.2, Rotation::cur());

let bits = meta.query_advice(bits, Rotation::cur());
let x_a_cur = meta.query_advice(x_a, Rotation::cur());
let x_p_cur = meta.query_advice(x_p, Rotation::cur());
let lambda1_cur = meta.query_advice(lambda.0, Rotation::cur());
let lambda2_cur = meta.query_advice(lambda.1, Rotation::cur());
let y_a_cur = (lambda1_cur.clone() + lambda2_cur.clone())
let y_a_cur = (lambda1_cur.clone() + lambda2_cur)
* (x_a_cur.clone()
- (lambda1_cur.clone() * lambda1_cur.clone() - x_a_cur.clone() - x_p_cur.clone()))
* C::Base::TWO_INV;

// y_p = y_a - lambda1 ⋅ (x_a - x_p)
let y_p = y_a_cur.clone() - lambda1_cur.clone() * (x_a_cur.clone() - x_p_cur.clone());
let y_p = y_a_cur - lambda1_cur * (x_a_cur - x_p_cur.clone());

let init_p = get_s_by_idx::<C>(0).to_affine().coordinates().unwrap();

// Lookup expressions default to the first entry when `q_sinsemilla`
// is not enabled.
let m = sinsemilla_cur.clone() * bits
+ (Expression::Constant(C::Base::one()) - sinsemilla_cur.clone()) * C::Base::zero();
let x_p = sinsemilla_cur.clone() * x_p_cur.clone()
let x_p = sinsemilla_cur.clone() * x_p_cur
+ (Expression::Constant(C::Base::one()) - sinsemilla_cur.clone()) * *init_p.x();
let y_p = sinsemilla_cur.clone() * y_p
+ (Expression::Constant(C::Base::one()) - sinsemilla_cur.clone()) * *init_p.y();
+ (Expression::Constant(C::Base::one()) - sinsemilla_cur) * *init_p.y();

meta.lookup(&[m, x_p, y_p], &[table_idx_cur, table_x_cur, table_y_cur]);

let config = GeneratorTableConfigEnum::Config(GeneratorTableConfig {
table_idx,
table_x,
table_y,
table_idx: lookup.0,
table_x: lookup.1,
table_y: lookup.2,
});

self.config = config.clone();
Expand Down

0 comments on commit 2395853

Please sign in to comment.