Skip to content

Commit

Permalink
Add functions to evaluate a Sinsemilla hash from an initial private p…
Browse files Browse the repository at this point in the history
…oint
  • Loading branch information
ConstanceBeguier committed Oct 5, 2023
1 parent 7e88834 commit d188ba6
Show file tree
Hide file tree
Showing 5 changed files with 316 additions and 53 deletions.
2 changes: 1 addition & 1 deletion halo2_gadgets/src/ecc/chip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ impl NonIdentityEccPoint {
///
/// This is an internal API that we only use where we know we have a valid non-identity
/// curve point.
pub(crate) fn from_coordinates_unchecked(
pub fn from_coordinates_unchecked(
x: AssignedCell<Assigned<pallas::Base>, pallas::Base>,
y: AssignedCell<Assigned<pallas::Base>, pallas::Base>,
) -> Self {
Expand Down
62 changes: 61 additions & 1 deletion halo2_gadgets/src/sinsemilla.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ pub trait SinsemillaInstructions<C: CurveAffine, const K: usize, const MAX_WORDS
/// This returns both the resulting point, as well as the message
/// decomposition in the form of intermediate values in a cumulative
/// sum.
///
/// The initial point `Q` is a public point.
#[allow(non_snake_case)]
#[allow(clippy::type_complexity)]
fn hash_to_point(
Expand All @@ -88,6 +88,20 @@ pub trait SinsemillaInstructions<C: CurveAffine, const K: usize, const MAX_WORDS
message: Self::Message,
) -> Result<(Self::NonIdentityPoint, Vec<Self::RunningSum>), Error>;

/// Hashes a message to an ECC curve point.
/// This returns both the resulting point, as well as the message
/// decomposition in the form of intermediate values in a cumulative
/// sum.
/// The initial point `Q` is a private point.
#[allow(non_snake_case)]
#[allow(clippy::type_complexity)]
fn hash_to_point_with_private_init(
&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 @@ -329,6 +343,23 @@ where
.map(|(point, zs)| (ecc::NonIdentityPoint::from_inner(self.ecc_chip.clone(), point), zs))
}

#[allow(non_snake_case)]
#[allow(clippy::type_complexity)]
/// $\mathsf{SinsemillaHashToPoint}$ from [§ 5.4.1.9][concretesinsemillahash].
///
/// [concretesinsemillahash]: https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash
pub fn hash_to_point_with_private_init(
&self,
layouter: impl Layouter<C::Base>,
Q: &<SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::NonIdentityPoint,
message: Message<C, SinsemillaChip, K, MAX_WORDS>,
) -> Result<(ecc::NonIdentityPoint<C, EccChip>, Vec<SinsemillaChip::RunningSum>), Error> {
assert_eq!(self.sinsemilla_chip, message.chip);
self.sinsemilla_chip
.hash_to_point_with_private_init(layouter, Q, message.inner)
.map(|(point, zs)| (ecc::NonIdentityPoint::from_inner(self.ecc_chip.clone(), point), zs))
}

/// $\mathsf{SinsemillaHash}$ from [§ 5.4.1.9][concretesinsemillahash].
///
/// [concretesinsemillahash]: https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash
Expand Down Expand Up @@ -431,6 +462,35 @@ where
self.M.hash_to_point(layouter, message)
}

#[allow(non_snake_case)]
#[allow(clippy::type_complexity)]
/// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit].
///
/// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit
pub fn hash_with_private_init(
&self,
layouter: impl Layouter<C::Base>,
Q: &<SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::NonIdentityPoint,
message: Message<C, SinsemillaChip, K, MAX_WORDS>,
) -> Result<
(
ecc::NonIdentityPoint<C, EccChip>,
Vec<SinsemillaChip::RunningSum>,
),
Error,
> {
assert_eq!(self.M.sinsemilla_chip, message.chip);
self.M.hash_to_point_with_private_init(layouter, Q, message)
}

#[allow(clippy::type_complexity)]
/// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit].
///
/// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit
pub fn q_init(&self) -> C {
self.M.Q
}

#[allow(clippy::type_complexity)]
/// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit].
///
Expand Down
37 changes: 35 additions & 2 deletions halo2_gadgets/src/sinsemilla/chip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,11 @@ where
/// q_sinsemilla2 is used to define a synthetic selector,
/// q_sinsemilla3 = (q_sinsemilla2) ⋅ (q_sinsemilla2 - 1)
/// Simple selector used to constrain hash initialization to be consistent with
/// the y-coordinate of the domain $Q$.
/// the y-coordinate of the domain $Q$ when $y_Q$ is a public constant.
q_sinsemilla4: Selector,
/// Simple selector used to constrain hash initialization to be consistent with
/// the y-coordinate of the domain $Q$ when $y_Q$ is a private value.
q_sinsemilla4_private: Selector,
/// Fixed column used to load the y-coordinate of the domain $Q$.
fixed_y_q: Column<Fixed>,
/// Logic specific to merged double-and-add.
Expand Down Expand Up @@ -165,6 +168,7 @@ where
q_sinsemilla1: meta.complex_selector(),
q_sinsemilla2: meta.fixed_column(),
q_sinsemilla4: meta.selector(),
q_sinsemilla4_private: meta.selector(),
fixed_y_q,
double_and_add: DoubleAndAdd {
x_a: advices[0],
Expand Down Expand Up @@ -202,7 +206,7 @@ where

// Check that the initial x_A, x_P, lambda_1, lambda_2 are consistent with y_Q.
// https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial
meta.create_gate("Initial y_Q", |meta| {
meta.create_gate("Initial y_Q (public)", |meta| {
let q_s4 = meta.query_selector(config.q_sinsemilla4);
let y_q = meta.query_fixed(config.fixed_y_q);

Expand All @@ -215,6 +219,21 @@ where
Constraints::with_selector(q_s4, Some(("init_y_q_check", init_y_q_check)))
});

// Check that the initial x_A, x_P, lambda_1, lambda_2 are consistent with y_Q.
// https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial
meta.create_gate("Initial y_Q (private)", |meta| {
let q_s4 = meta.query_selector(config.q_sinsemilla4_private);
let y_q = meta.query_advice(config.double_and_add.x_p, Rotation::prev());

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

// 2 * y_q - Y_{A,0} = 0
let init_y_q_check = y_q * two - Y_A_cur;

Constraints::with_selector(q_s4, Some(("init_y_q_check", init_y_q_check)))
});

// https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial
meta.create_gate("Sinsemilla gate", |meta| {
let q_s1 = meta.query_selector(config.q_sinsemilla1);
Expand Down Expand Up @@ -322,6 +341,20 @@ where
)
}

#[allow(non_snake_case)]
#[allow(clippy::type_complexity)]
fn hash_to_point_with_private_init(
&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.hash_message_with_private_init(&mut region, Q, &message),
)
}

fn extract(point: &Self::NonIdentityPoint) -> Self::X {
point.x()
}
Expand Down
Loading

0 comments on commit d188ba6

Please sign in to comment.