mirror of https://github.com/zcash/halo2.git
Merge pull request #179 from zcash/sinsemilla-bases
primitives::sinsemilla: Use hard-coded generators in sinsemilla_s.
This commit is contained in:
commit
5f0c3b3585
|
@ -25,7 +25,6 @@ use halo2::{
|
|||
use pasta_curves::pallas;
|
||||
|
||||
mod generator_table;
|
||||
pub use generator_table::get_s_by_idx;
|
||||
use generator_table::GeneratorTableConfig;
|
||||
|
||||
mod hash_to_point;
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
use crate::primitives::sinsemilla::{self, sinsemilla_s_generators, S_PERSONALIZATION};
|
||||
use crate::primitives::sinsemilla::{self, SINSEMILLA_S};
|
||||
use halo2::{
|
||||
circuit::Layouter,
|
||||
plonk::{ConstraintSystem, Error, Expression, TableColumn},
|
||||
poly::Rotation,
|
||||
};
|
||||
|
||||
use pasta_curves::{
|
||||
arithmetic::{CurveAffine, CurveExt, FieldExt},
|
||||
pallas,
|
||||
};
|
||||
|
||||
use group::Curve;
|
||||
use pasta_curves::{arithmetic::FieldExt, pallas};
|
||||
|
||||
/// Table containing independent generators S[0..2^k]
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
|
@ -69,10 +64,7 @@ impl GeneratorTableConfig {
|
|||
|
||||
// Lookup expressions default to the first entry when `q_s1`
|
||||
// is not enabled.
|
||||
let (init_x, init_y) = {
|
||||
let init_p = get_s_by_idx(0).to_affine().coordinates().unwrap();
|
||||
(*init_p.x(), *init_p.y())
|
||||
};
|
||||
let (init_x, init_y) = SINSEMILLA_S[0];
|
||||
let not_q_s1 = Expression::Constant(pallas::Base::one()) - q_s1.clone();
|
||||
|
||||
let m = q_s1.clone() * word; // The first table index is 0.
|
||||
|
@ -87,41 +79,18 @@ impl GeneratorTableConfig {
|
|||
layouter.assign_table(
|
||||
|| "generator_table",
|
||||
|mut table| {
|
||||
// We generate the row values lazily (we only need them during keygen).
|
||||
let mut rows = sinsemilla_s_generators();
|
||||
|
||||
for index in 0..(1 << sinsemilla::K) {
|
||||
let mut row = None;
|
||||
for (index, (x, y)) in SINSEMILLA_S.iter().enumerate() {
|
||||
table.assign_cell(
|
||||
|| "table_idx",
|
||||
self.table_idx,
|
||||
index,
|
||||
|| {
|
||||
row = rows.next();
|
||||
Ok(pallas::Base::from_u64(index as u64))
|
||||
},
|
||||
)?;
|
||||
table.assign_cell(
|
||||
|| "table_x",
|
||||
self.table_x,
|
||||
index,
|
||||
|| row.map(|(x, _)| x).ok_or(Error::SynthesisError),
|
||||
)?;
|
||||
table.assign_cell(
|
||||
|| "table_y",
|
||||
self.table_y,
|
||||
index,
|
||||
|| row.map(|(_, y)| y).ok_or(Error::SynthesisError),
|
||||
|| Ok(pallas::Base::from_u64(index as u64)),
|
||||
)?;
|
||||
table.assign_cell(|| "table_x", self.table_x, index, || Ok(*x))?;
|
||||
table.assign_cell(|| "table_y", self.table_y, index, || Ok(*y))?;
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get generator S by index
|
||||
pub fn get_s_by_idx(idx: u32) -> pallas::Point {
|
||||
let hash = pallas::Point::hash_to_curve(S_PERSONALIZATION);
|
||||
hash(&idx.to_le_bytes())
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
use super::super::SinsemillaInstructions;
|
||||
use super::{get_s_by_idx, CellValue, EccPoint, SinsemillaChip, Var};
|
||||
use crate::primitives::sinsemilla::{self, lebs2ip_k, INV_TWO_POW_K};
|
||||
use super::{CellValue, EccPoint, SinsemillaChip, Var};
|
||||
use crate::primitives::sinsemilla::{self, lebs2ip_k, INV_TWO_POW_K, SINSEMILLA_S};
|
||||
use halo2::{
|
||||
circuit::{Chip, Region},
|
||||
plonk::Error,
|
||||
};
|
||||
|
||||
use ff::{Field, PrimeFieldBits};
|
||||
use group::Curve;
|
||||
use pasta_curves::{
|
||||
arithmetic::{CurveAffine, FieldExt},
|
||||
pallas,
|
||||
|
@ -112,7 +111,7 @@ impl SinsemillaChip {
|
|||
{
|
||||
use crate::circuit::gadget::sinsemilla::message::MessagePiece;
|
||||
use crate::primitives::sinsemilla::{K, S_PERSONALIZATION};
|
||||
use group::prime::PrimeCurveAffine;
|
||||
use group::{prime::PrimeCurveAffine, Curve};
|
||||
use pasta_curves::arithmetic::CurveExt;
|
||||
|
||||
let field_elems: Option<Vec<pallas::Base>> =
|
||||
|
@ -235,20 +234,11 @@ impl SinsemillaChip {
|
|||
.collect()
|
||||
});
|
||||
|
||||
// Get (x_p, y_p) for each word. We precompute this here so that we can use `batch_normalize()`.
|
||||
let generators_projective: Option<Vec<pallas::Point>> = words
|
||||
.clone()
|
||||
.map(|words| words.iter().map(|word| get_s_by_idx(*word)).collect());
|
||||
let generators: Option<Vec<(pallas::Base, pallas::Base)>> =
|
||||
generators_projective.map(|generators_projective| {
|
||||
let mut generators = vec![pallas::Affine::default(); generators_projective.len()];
|
||||
pallas::Point::batch_normalize(&generators_projective, &mut generators);
|
||||
generators
|
||||
// Get (x_p, y_p) for each word.
|
||||
let generators: Option<Vec<(pallas::Base, pallas::Base)>> = words.clone().map(|words| {
|
||||
words
|
||||
.iter()
|
||||
.map(|gen| {
|
||||
let point = gen.coordinates().unwrap();
|
||||
(*point.x(), *point.y())
|
||||
})
|
||||
.map(|word| SINSEMILLA_S[*word as usize])
|
||||
.collect()
|
||||
});
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! The Sinsemilla hash function and commitment scheme.
|
||||
|
||||
use halo2::arithmetic::CurveExt;
|
||||
use group::prime::PrimeCurveAffine;
|
||||
use halo2::arithmetic::{CurveAffine, CurveExt};
|
||||
use pasta_curves::pallas;
|
||||
use subtle::CtOption;
|
||||
|
||||
|
@ -12,6 +13,7 @@ use self::addition::IncompletePoint;
|
|||
mod constants;
|
||||
mod sinsemilla_s;
|
||||
pub use constants::*;
|
||||
pub(crate) use sinsemilla_s::*;
|
||||
|
||||
pub(crate) fn lebs2ip_k(bits: &[bool]) -> u32 {
|
||||
assert!(bits.len() == K);
|
||||
|
@ -114,13 +116,12 @@ impl HashDomain {
|
|||
fn hash_to_point_inner(&self, msg: impl Iterator<Item = bool>) -> IncompletePoint {
|
||||
let padded: Vec<_> = Pad::new(msg).collect();
|
||||
|
||||
let hasher_S = pallas::Point::hash_to_curve(S_PERSONALIZATION);
|
||||
let S = |chunk: &[bool]| hasher_S(&lebs2ip_k(chunk).to_le_bytes());
|
||||
|
||||
padded
|
||||
.chunks(K)
|
||||
.fold(IncompletePoint::from(self.Q), |acc, chunk| {
|
||||
(acc + S(chunk)) + acc
|
||||
let (S_x, S_y) = SINSEMILLA_S[lebs2ip_k(chunk) as usize];
|
||||
let S_chunk = pallas::Affine::from_xy(S_x, S_y).unwrap().to_curve();
|
||||
(acc + S_chunk) + acc
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
//! Sinsemilla generators
|
||||
use group::Curve;
|
||||
use halo2::arithmetic::{CurveAffine, CurveExt};
|
||||
use pasta_curves::pallas;
|
||||
|
||||
/// Number of bits of each message piece in $\mathsf{SinsemillaHashToPoint}$
|
||||
pub const K: usize = 10;
|
||||
|
@ -62,15 +59,6 @@ pub const Q_MERKLE_CRH: ([u8; 32], [u8; 32]) = (
|
|||
/// SWU hash-to-curve personalization for Sinsemilla $S$ generators.
|
||||
pub const S_PERSONALIZATION: &str = "z.cash:SinsemillaS";
|
||||
|
||||
/// Creates the Sinsemilla S generators used in each round of the Sinsemilla hash
|
||||
pub fn sinsemilla_s_generators() -> impl Iterator<Item = (pallas::Base, pallas::Base)> {
|
||||
let hasher = pallas::Point::hash_to_curve(S_PERSONALIZATION);
|
||||
(0..(1u32 << K)).map(move |j| {
|
||||
let point = hasher(&j.to_le_bytes()).to_affine().coordinates().unwrap();
|
||||
(*point.x(), *point.y())
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::{CommitDomain, HashDomain};
|
||||
|
@ -79,16 +67,21 @@ mod tests {
|
|||
COMMIT_IVK_PERSONALIZATION, MERKLE_CRH_PERSONALIZATION, NOTE_COMMITMENT_PERSONALIZATION,
|
||||
};
|
||||
use group::Curve;
|
||||
use halo2::arithmetic::FieldExt;
|
||||
use halo2::arithmetic::{CurveAffine, CurveExt, FieldExt};
|
||||
use halo2::pasta::pallas;
|
||||
|
||||
#[test]
|
||||
fn sinsemilla_s() {
|
||||
use super::super::sinsemilla_s::SINSEMILLA_S;
|
||||
let sinsemilla_s: Vec<_> = sinsemilla_s_generators().collect();
|
||||
assert_eq!(sinsemilla_s.len(), SINSEMILLA_S.len());
|
||||
for (expected, actual) in sinsemilla_s.iter().zip(&SINSEMILLA_S[..]) {
|
||||
assert_eq!(expected, actual);
|
||||
let hasher = pallas::Point::hash_to_curve(S_PERSONALIZATION);
|
||||
|
||||
for j in 0..(1u32 << K) {
|
||||
let computed = {
|
||||
let point = hasher(&j.to_le_bytes()).to_affine().coordinates().unwrap();
|
||||
(*point.x(), *point.y())
|
||||
};
|
||||
let actual = SINSEMILLA_S[j as usize];
|
||||
assert_eq!(computed, actual);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use super::K;
|
||||
use pasta_curves::pallas;
|
||||
|
||||
/// The precomputed bases for the Sinsemilla hash function.
|
||||
///
|
||||
/// https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash
|
||||
pub const SINSEMILLA_S: [(pallas::Base, pallas::Base); 1 << K] = [
|
||||
(
|
||||
pallas::Base::from_raw([
|
||||
|
|
Loading…
Reference in New Issue