Skip to content
Closed
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
15 changes: 13 additions & 2 deletions halo2_gadgets/src/sinsemilla.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,19 @@ pub trait SinsemillaInstructions<C: CurveAffine, const K: usize, const MAX_WORDS
message: Self::Message,
) -> Result<(Self::NonIdentityPoint, Vec<Self::RunningSum>), Error>;

/// Same as hash_to_point, but continuing from the given initial point.
/// The initial point can be the hashing domain, or the hash of a previous
/// message to append to.
///
#[allow(non_snake_case)]
#[allow(clippy::type_complexity)]
fn append_hash_to_point(
&self,
layouter: impl Layouter<C::Base>,
Q: Self::NonIdentityPoint,
message: Self::Message,
) -> Result<(Self::NonIdentityPoint, Vec<Self::RunningSum>), Error>;

/// Extracts the x-coordinate of the output of a Sinsemilla hash.
fn extract(point: &Self::NonIdentityPoint) -> Self::X;
}
Expand Down Expand Up @@ -577,15 +590,13 @@ pub(crate) mod tests {
meta,
advices[..5].try_into().unwrap(),
advices[2],
lagrange_coeffs[0],
lookup,
range_check,
);
let config2 = SinsemillaChip::configure(
meta,
advices[5..].try_into().unwrap(),
advices[7],
lagrange_coeffs[1],
lookup,
range_check,
);
Expand Down
23 changes: 18 additions & 5 deletions halo2_gadgets/src/sinsemilla/chip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ where
/// the y-coordinate of the domain $Q$.
q_sinsemilla4: Selector,
/// Fixed column used to load the y-coordinate of the domain $Q$.
fixed_y_q: Column<Fixed>,
y_q: Column<Advice>,
/// Logic specific to merged double-and-add.
double_and_add: DoubleAndAdd,
/// Advice column used to load the message.
Expand Down Expand Up @@ -152,7 +152,6 @@ where
meta: &mut ConstraintSystem<pallas::Base>,
advices: [Column<Advice>; 5],
witness_pieces: Column<Advice>,
fixed_y_q: Column<Fixed>,
lookup: (TableColumn, TableColumn, TableColumn),
range_check: LookupRangeCheckConfig<pallas::Base, { sinsemilla::K }>,
) -> <Self as Chip<pallas::Base>>::Config {
Expand All @@ -165,7 +164,7 @@ where
q_sinsemilla1: meta.complex_selector(),
q_sinsemilla2: meta.fixed_column(),
q_sinsemilla4: meta.selector(),
fixed_y_q,
y_q: advices[0],
double_and_add: DoubleAndAdd {
x_a: advices[0],
x_p: advices[1],
Expand Down Expand Up @@ -203,10 +202,10 @@ where
// https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial
meta.create_gate("Initial y_Q", |meta| {
let q_s4 = meta.query_selector(config.q_sinsemilla4);
let y_q = meta.query_fixed(config.fixed_y_q, Rotation::cur());
let y_q = meta.query_advice(config.y_q, Rotation::cur());

// Y_A = (lambda_1 + lambda_2) * (x_a - x_r)
let Y_A_cur = Y_A(meta, Rotation::cur());
let Y_A_cur = Y_A(meta, Rotation::next());

// 2 * y_q - Y_{A,0} = 0
let init_y_q_check = y_q * two - Y_A_cur;
Expand Down Expand Up @@ -321,6 +320,20 @@ where
)
}

#[allow(non_snake_case)]
#[allow(clippy::type_complexity)]
fn append_hash_to_point(
&self,
mut layouter: impl Layouter<pallas::Base>,
Q: Self::NonIdentityPoint,
message: Self::Message,
) -> Result<(Self::NonIdentityPoint, Vec<Self::RunningSum>), Error> {
layouter.assign_region(
|| "hash_to_point",
|mut region| self.append_hash_message(&mut region, Q.clone(), &message),
)
}

fn extract(point: &Self::NonIdentityPoint) -> Self::X {
point.x()
}
Expand Down
128 changes: 122 additions & 6 deletions halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ where
Fixed: FixedPoints<pallas::Affine>,
Commit: CommitDomains<pallas::Affine, Fixed, Hash>,
{

/// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial).
#[allow(non_snake_case)]
#[allow(clippy::type_complexity)]
Expand All @@ -42,31 +43,71 @@ where
Vec<Vec<AssignedCell<pallas::Base, pallas::Base>>>,
),
Error,
> {
let (x_a, y_a) = self.init_fixed(region, Q)?;
self.append_message(region, x_a, y_a, message)
}

/// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial).
#[allow(non_snake_case)]
#[allow(clippy::type_complexity)]
pub(super) fn append_hash_message(
&self,
region: &mut Region<'_, pallas::Base>,
Q: NonIdentityEccPoint,
message: &<Self as SinsemillaInstructions<
pallas::Affine,
{ sinsemilla::K },
{ sinsemilla::C },
>>::Message,
) -> Result<
(
NonIdentityEccPoint,
Vec<Vec<AssignedCell<pallas::Base, pallas::Base>>>,
),
Error,
> {
let (x_a, y_a) = self.init_variable(region, Q)?;
self.append_message(region, x_a, y_a, message)
}

#[allow(non_snake_case)]
#[allow(clippy::type_complexity)]
fn init_fixed(
&self,
region: &mut Region<'_, pallas::Base>,
Q: pallas::Affine,
) -> Result<
(X<pallas::Base>, Y<pallas::Base>),
Error,
> {
let config = self.config().clone();
let mut offset = 0;
let offset = 0;

// Get the `x`- and `y`-coordinates of the starting `Q` base.
let x_q = *Q.coordinates().unwrap().x();
let y_q = *Q.coordinates().unwrap().y();

// Constrain the initial x_a, lambda_1, lambda_2, x_p using the q_sinsemilla4
// selector.
let mut y_a: Y<pallas::Base> = {
let y_a: Y<pallas::Base> = {
// Enable `q_sinsemilla4` on the first row.
config.q_sinsemilla4.enable(region, offset)?;
region.assign_fixed(

region.assign_advice_from_constant(
|| "fixed y_q",
config.fixed_y_q,
config.y_q,
offset,
|| Value::known(y_q),
y_q,
)?;

Value::known(y_q.into()).into()
};

let offset = 1;

// Constrain the initial x_q to equal the x-coordinate of the domain's `Q`.
let mut x_a: X<pallas::Base> = {
let x_a: X<pallas::Base> = {
let x_a = region.assign_advice_from_constant(
|| "fixed x_q",
config.double_and_add.x_a,
Expand All @@ -77,6 +118,76 @@ where
x_a.into()
};

Ok((x_a, y_a))
}


#[allow(non_snake_case)]
#[allow(clippy::type_complexity)]
fn init_variable(
&self,
region: &mut Region<'_, pallas::Base>,
Q: NonIdentityEccPoint,
) -> Result<
(X<pallas::Base>, Y<pallas::Base>),
Error,
> {
let config = self.config().clone();
let offset = 0;

// Constrain the initial x_a, lambda_1, lambda_2, x_p using the q_sinsemilla4
// selector.
let y_a: Y<pallas::Base> = {
// Enable `q_sinsemilla4` on the first row.
config.q_sinsemilla4.enable(region, offset)?;

let y_q = Q.y().copy_advice(|| "initial y_q", region, config.y_q, offset)?;
y_q.value_field().into()
};

let offset = 1;

// Constrain the initial x_q to equal the x-coordinate of the domain's `Q`.
let x_a: X<pallas::Base> = {
let x_q = Q.x().copy_advice(|| "initial x_q", region, config.double_and_add.x_a, offset)?;
let x_q: AssignedCell<Assigned<_>, _> = x_q.into();
x_q.into()
};

Ok((x_a, y_a))
}

#[allow(non_snake_case)]
#[allow(clippy::type_complexity)]
fn append_message(
&self,
region: &mut Region<'_, pallas::Base>,
x_q: X<pallas::Base>,
y_q: Y<pallas::Base>,
message: &<Self as SinsemillaInstructions<
pallas::Affine,
{ sinsemilla::K },
{ sinsemilla::C },
>>::Message,
) -> Result<
(
NonIdentityEccPoint,
Vec<Vec<AssignedCell<pallas::Base, pallas::Base>>>,
),
Error,
> {
let config = self.config().clone();
let mut offset = 1;

// TODO: a better way to test with these values.
#[cfg(test)]
let x_q_val = x_q.value().unwrap().evaluate();
#[cfg(test)]
let y_q_val = y_q.0.unwrap().evaluate();

let mut x_a = x_q;
let mut y_a = y_q;

let mut zs_sum: Vec<Vec<AssignedCell<pallas::Base, pallas::Base>>> = Vec::new();

// Hash each piece in the message.
Expand Down Expand Up @@ -132,6 +243,11 @@ where
use group::{prime::PrimeCurveAffine, Curve};
use pasta_curves::arithmetic::CurveExt;

let Q = pallas::Affine::from_xy(
x_q_val,
y_q_val
).unwrap();

let field_elems: Value<Vec<_>> = message
.iter()
.map(|piece| piece.field_elem().map(|elem| (elem, piece.num_words())))
Expand Down
7 changes: 0 additions & 7 deletions halo2_gadgets/src/sinsemilla/merkle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,6 @@ pub mod tests {
let constants = meta.fixed_column();
meta.enable_constant(constants);

// NB: In the actual Action circuit, these fixed columns will be reused
// by other chips. For this test, we are creating new fixed columns.
let fixed_y_q_1 = meta.fixed_column();
let fixed_y_q_2 = meta.fixed_column();

// Fixed columns for the Sinsemilla generator lookup table
let lookup = (
meta.lookup_table_column(),
Expand All @@ -254,7 +249,6 @@ pub mod tests {
meta,
advices[5..].try_into().unwrap(),
advices[7],
fixed_y_q_1,
lookup,
range_check,
);
Expand All @@ -264,7 +258,6 @@ pub mod tests {
meta,
advices[..5].try_into().unwrap(),
advices[2],
fixed_y_q_2,
lookup,
range_check,
);
Expand Down
13 changes: 13 additions & 0 deletions halo2_gadgets/src/sinsemilla/merkle/chip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,19 @@ where
chip.hash_to_point(layouter, Q, message)
}

#[allow(non_snake_case)]
#[allow(clippy::type_complexity)]
fn append_hash_to_point(
&self,
layouter: impl Layouter<pallas::Base>,
Q: Self::NonIdentityPoint,
message: Self::Message,
) -> Result<(Self::NonIdentityPoint, Vec<Vec<Self::CellValue>>), Error> {
let config = self.config().sinsemilla_config.clone();
let chip = SinsemillaChip::<Hash, Commit, F>::construct(config);
chip.append_hash_to_point(layouter, Q, message)
}

fn extract(point: &Self::NonIdentityPoint) -> Self::X {
SinsemillaChip::<Hash, Commit, F>::extract(point)
}
Expand Down
13 changes: 13 additions & 0 deletions halo2_proofs/src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,19 @@ where
}
}

impl<F: Field> From<AssignedCell<F, F>> for AssignedCell<Assigned<F>, F>
where
for<'v> Assigned<F>: From<&'v F>,
{
fn from(val: AssignedCell<F, F>) -> Self {
AssignedCell {
value: val.value().map(|v| v.into()),
cell: val.cell,
_marker: Default::default(),
}
}
}

impl<F: Field> AssignedCell<Assigned<F>, F> {
/// Evaluates this assigned cell's value directly, performing an unbatched inversion
/// if necessary.
Expand Down
6 changes: 6 additions & 0 deletions halo2_proofs/src/circuit/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ impl<V> Value<V> {
inner: self.inner.zip(other.inner),
}
}

// TODO: for tests only like #[cfg(test)]
/// Unwrap, only for tests.
pub fn unwrap(self) -> V {
self.inner.unwrap()
}
}

impl<V, W> Value<(V, W)> {
Expand Down