Further fixes.

This commit is contained in:
therealyingtong 2021-10-14 16:07:40 +02:00
parent 56225d603a
commit 96504e7162
18 changed files with 210 additions and 110 deletions

View File

@ -6,6 +6,3 @@ members = [
"halo2_poseidon", "halo2_poseidon",
"sinsemilla", "sinsemilla",
] ]
[patch.crates-io]
halo2 = { git = "https://github.com/zcash/halo2.git", rev = "27c4187673a9c6ade13fbdbd4f20955530c22d7f" }

View File

@ -20,7 +20,7 @@ arrayvec = "0.7.0"
bigint = "4" bigint = "4"
ff = "0.11" ff = "0.11"
group = "0.11" group = "0.11"
halo2 = "0.0" halo2 = "=0.1.0-beta.1"
lazy_static = "1" lazy_static = "1"
pasta_curves = "0.2.1" pasta_curves = "0.2.1"
rand = "0.8" rand = "0.8"

View File

@ -86,7 +86,7 @@ impl EccPoint {
self.y self.y
} }
#[cfg(test)] #[cfg(feature = "testing")]
fn is_identity(&self) -> Option<bool> { fn is_identity(&self) -> Option<bool> {
self.x.value().map(|x| x == pallas::Base::zero()) self.x.value().map(|x| x == pallas::Base::zero())
} }
@ -103,17 +103,6 @@ pub struct NonIdentityEccPoint {
} }
impl NonIdentityEccPoint { impl NonIdentityEccPoint {
/// Constructs a point from its coordinates, without checking they are on the curve.
///
/// This is an internal API that we only use where we know we have a valid non-identity
/// curve point (specifically inside Sinsemilla).
pub(in crate::circuit::gadget) fn from_coordinates_unchecked(
x: CellValue<pallas::Base>,
y: CellValue<pallas::Base>,
) -> Self {
NonIdentityEccPoint { x, y }
}
/// Returns the value of this curve point, if known. /// Returns the value of this curve point, if known.
pub fn point(&self) -> Option<pallas::Affine> { pub fn point(&self) -> Option<pallas::Affine> {
match (self.x.value(), self.y.value()) { match (self.x.value(), self.y.value()) {
@ -447,6 +436,81 @@ impl<Fixed: FixedPoints<pallas::Affine>> EccInstructions<pallas::Affine> for Ecc
) )
} }
fn copy_point(
&self,
layouter: &mut impl Layouter<pallas::Base>,
point: Self::Point,
) -> Result<Self::Point, Error> {
let config: witness_point::Config = self.config().into();
let (x, y) = layouter.assign_region(
|| "copy point",
|mut region| {
let x = {
let cell = region.assign_advice(
|| "copy x",
config.x,
0,
|| point.x().value().ok_or(Error::SynthesisError),
)?;
region.constrain_equal(cell, point.x().cell())?;
CellValue::new(cell, point.x().value())
};
let y = {
let cell = region.assign_advice(
|| "copy y",
config.y,
0,
|| point.y().value().ok_or(Error::SynthesisError),
)?;
region.constrain_equal(cell, point.y().cell())?;
CellValue::new(cell, point.y().value())
};
Ok((x, y))
},
)?;
Ok(EccPoint { x, y })
}
fn copy_point_non_id(
&self,
layouter: &mut impl Layouter<pallas::Base>,
x: Self::Var,
y: Self::Var,
) -> Result<Self::NonIdentityPoint, Error> {
let config: witness_point::Config = self.config().into();
let (x, y) = layouter.assign_region(
|| "copy point",
|mut region| {
let x = {
let cell = region.assign_advice(
|| "copy x",
config.x,
0,
|| x.value().ok_or(Error::SynthesisError),
)?;
region.constrain_equal(cell, x.cell())?;
CellValue::new(cell, x.value())
};
let y = {
let cell = region.assign_advice(
|| "copy y",
config.y,
0,
|| y.value().ok_or(Error::SynthesisError),
)?;
region.constrain_equal(cell, y.cell())?;
CellValue::new(cell, y.value())
};
Ok((x, y))
},
)?;
Ok(NonIdentityEccPoint { x, y })
}
fn extract_p<Point: Into<Self::Point> + Clone>(point: &Point) -> Self::X { fn extract_p<Point: Into<Self::Point> + Clone>(point: &Point) -> Self::X {
let point: EccPoint = (point.clone()).into(); let point: EccPoint = (point.clone()).into();
point.x() point.x()

View File

@ -391,7 +391,10 @@ pub mod tests {
use halo2::{circuit::Layouter, plonk::Error}; use halo2::{circuit::Layouter, plonk::Error};
use pasta_curves::{arithmetic::CurveExt, pallas}; use pasta_curves::{arithmetic::CurveExt, pallas};
use crate::gadget::{EccInstructions, NonIdentityPoint}; use crate::{
chip::EccPoint,
gadget::{EccInstructions, NonIdentityPoint, Point},
};
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn test_add< pub fn test_add<

View File

@ -145,11 +145,13 @@ impl Config {
#[cfg(feature = "testing")] #[cfg(feature = "testing")]
pub mod tests { pub mod tests {
use group::{prime::PrimeCurveAffine, Curve, Group}; use group::{Curve, Group};
use halo2::{circuit::Layouter, plonk::Error}; use halo2::{circuit::Layouter, plonk::Error};
use pasta_curves::pallas; use pasta_curves::pallas;
use crate::gadget::{EccInstructions, NonIdentityPoint}; use crate::{
gadget::{EccInstructions, NonIdentityPoint},
};
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn test_add_incomplete< pub fn test_add_incomplete<
@ -171,15 +173,6 @@ pub mod tests {
// Make sure P and Q are not the same point. // Make sure P and Q are not the same point.
assert_ne!(p_val, q_val); assert_ne!(p_val, q_val);
// Generate a (0,0) point to be used in other tests.
let zero = {
Point::new(
chip.clone(),
layouter.namespace(|| "identity"),
Some(pallas::Affine::identity()),
)?
};
// P + Q // P + Q
{ {
let result = p.add_incomplete(layouter.namespace(|| "P + Q"), &q)?; let result = p.add_incomplete(layouter.namespace(|| "P + Q"), &q)?;

View File

@ -444,7 +444,7 @@ fn decompose_for_scalar_mul(scalar: Option<pallas::Base>) -> Vec<Option<bool>> {
#[cfg(feature = "testing")] #[cfg(feature = "testing")]
pub mod tests { pub mod tests {
use group::{prime::PrimeCurveAffine, Curve, Group}; use group::{Curve, Group};
use halo2::{ use halo2::{
circuit::{Chip, Layouter}, circuit::{Chip, Layouter},
plonk::Error, plonk::Error,
@ -452,7 +452,7 @@ pub mod tests {
use pasta_curves::{arithmetic::FieldExt, pallas}; use pasta_curves::{arithmetic::FieldExt, pallas};
use crate::{ use crate::{
chip::EccChip, chip::{EccChip, EccPoint},
gadget::{EccInstructions, FixedPoints, NonIdentityPoint, Point}, gadget::{EccInstructions, FixedPoints, NonIdentityPoint, Point},
}; };
use utilities::UtilitiesInstructions; use utilities::UtilitiesInstructions;
@ -465,15 +465,6 @@ pub mod tests {
let p_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); // P let p_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); // P
let p = NonIdentityPoint::new(chip.clone(), layouter.namespace(|| "P"), Some(p_val))?; let p = NonIdentityPoint::new(chip.clone(), layouter.namespace(|| "P"), Some(p_val))?;
// Generate a (0,0) point to be used in other tests.
let zero = {
Point::new(
chip.clone(),
layouter.namespace(|| "identity"),
Some(pallas::Affine::identity()),
)?
};
let column = chip.config().advices[0]; let column = chip.config().advices[0];
fn constrain_equal_non_id< fn constrain_equal_non_id<

View File

@ -364,7 +364,7 @@ pub mod tests {
*magnitude, *magnitude,
*sign, *sign,
)?; )?;
value_commit_v.mul_short(layouter.namespace(|| *name), magnitude_sign)? base.mul_short(layouter.namespace(|| *name), magnitude_sign)?
}; };
assert!(result.inner().is_identity().unwrap()); assert!(result.inner().is_identity().unwrap());
} }

View File

@ -8,7 +8,6 @@ use halo2::{
poly::Rotation, poly::Rotation,
}; };
use pasta_curves::{arithmetic::CurveAffine, pallas}; use pasta_curves::{arithmetic::CurveAffine, pallas};
use utilities::copy;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Config { pub struct Config {
@ -147,20 +146,20 @@ impl Config {
} }
} }
#[cfg(test)] #[cfg(feature = "testing")]
pub mod tests { pub mod tests {
use halo2::circuit::Layouter; use halo2::circuit::Layouter;
use pasta_curves::pallas; use pasta_curves::pallas;
use super::*; use super::*;
use crate::circuit::gadget::ecc::{EccInstructions, NonIdentityPoint}; use crate::gadget::{EccInstructions, NonIdentityPoint};
pub fn test_witness_non_id< pub fn test_witness_non_id<
EccChip: EccInstructions<pallas::Affine> + Clone + Eq + std::fmt::Debug, EccChip: EccInstructions<pallas::Affine> + Clone + Eq + std::fmt::Debug,
>( >(
chip: EccChip, chip: EccChip,
mut layouter: impl Layouter<pallas::Base>, mut layouter: impl Layouter<pallas::Base>,
) { ) -> Result<(), Error> {
// Witnessing the identity should return an error. // Witnessing the identity should return an error.
NonIdentityPoint::new( NonIdentityPoint::new(
chip, chip,
@ -168,23 +167,7 @@ pub mod tests {
Some(pallas::Affine::identity()), Some(pallas::Affine::identity()),
) )
.expect_err("witnessing 𝒪 should return an error"); .expect_err("witnessing 𝒪 should return an error");
}
pub(super) fn copy_point( Ok(())
&self,
x: CellValue<pallas::Base>,
y: CellValue<pallas::Base>,
offset: usize,
region: &mut Region<'_, pallas::Base>,
) -> Result<EccPoint, Error> {
// Enable `q_point` selector
self.q_point.enable(region, offset)?;
// Copy `x` value
let x = copy(region, || "x", self.x, offset, &x)?;
// Copy `y` value
let y = copy(region, || "y", self.y, offset, &y)?;
Ok(EccPoint { x, y })
} }
} }

View File

@ -1,9 +1,9 @@
//! Gadgets for elliptic curve operations. //! Gadgets for elliptic curve operations.
use pasta_curves::arithmetic::CurveAffine;
use std::fmt::Debug; use std::fmt::Debug;
use halo2::{ use halo2::{
arithmetic::CurveAffine,
circuit::{Chip, Layouter}, circuit::{Chip, Layouter},
plonk::Error, plonk::Error,
}; };
@ -79,11 +79,19 @@ pub trait EccInstructions<C: CurveAffine>:
/// checking that the coordinates indeed belong to a valid point. /// checking that the coordinates indeed belong to a valid point.
/// This maps the identity to (0, 0) in affine coordinates. /// This maps the identity to (0, 0) in affine coordinates.
fn copy_point( fn copy_point(
&self,
layouter: &mut impl Layouter<C::Base>,
point: Self::Point,
) -> Result<Self::Point, Error>;
/// Copies a point given existing x- and y-coordinate variables,
/// checking that the coordinates indeed belong to a valid point.
fn copy_point_non_id(
&self, &self,
layouter: &mut impl Layouter<C::Base>, layouter: &mut impl Layouter<C::Base>,
x: Self::Var, x: Self::Var,
y: Self::Var, y: Self::Var,
) -> Result<Self::Point, Error>; ) -> Result<Self::NonIdentityPoint, Error>;
/// Extracts the x-coordinate of a point. /// Extracts the x-coordinate of a point.
fn extract_p<Point: Into<Self::Point> + Clone>(point: &Point) -> Self::X; fn extract_p<Point: Into<Self::Point> + Clone>(point: &Point) -> Self::X;
@ -199,17 +207,6 @@ impl<C: CurveAffine, EccChip: EccInstructions<C>> NonIdentityPoint<C, EccChip> {
point.map(|inner| NonIdentityPoint { chip, inner }) point.map(|inner| NonIdentityPoint { chip, inner })
} }
/// Constructs a new point by copying in its coordinates as `x`, `y` cells.
pub fn copy(
chip: EccChip,
mut layouter: impl Layouter<C::Base>,
x: EccChip::Var,
y: EccChip::Var,
) -> Result<Self, Error> {
let point = chip.copy_point(&mut layouter, x, y);
point.map(|inner| Point { chip, inner })
}
/// Constrains this point to be equal in value to another point. /// Constrains this point to be equal in value to another point.
pub fn constrain_equal<Other: Into<Point<C, EccChip>> + Clone>( pub fn constrain_equal<Other: Into<Point<C, EccChip>> + Clone>(
&self, &self,
@ -224,6 +221,17 @@ impl<C: CurveAffine, EccChip: EccInstructions<C>> NonIdentityPoint<C, EccChip> {
) )
} }
/// Constructs a new point by copying in its coordinates as `x`, `y` cells.
pub fn copy(
chip: EccChip,
mut layouter: impl Layouter<C::Base>,
x: EccChip::Var,
y: EccChip::Var,
) -> Result<Self, Error> {
let point = chip.copy_point_non_id(&mut layouter, x, y);
point.map(|inner| NonIdentityPoint { chip, inner })
}
/// Returns the inner point. /// Returns the inner point.
pub fn inner(&self) -> &EccChip::NonIdentityPoint { pub fn inner(&self) -> &EccChip::NonIdentityPoint {
&self.inner &self.inner
@ -338,6 +346,16 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> Point<C,
.constrain_equal(&mut layouter, &self.inner, &other.inner) .constrain_equal(&mut layouter, &self.inner, &other.inner)
} }
/// Constructs a new point by copying in its coordinates as `x`, `y` cells.
pub fn copy(
chip: EccChip,
mut layouter: impl Layouter<C::Base>,
point: EccChip::Point,
) -> Result<Self, Error> {
let point = chip.copy_point(&mut layouter, point);
point.map(|inner| Point { chip, inner })
}
/// Returns the inner point. /// Returns the inner point.
pub fn inner(&self) -> &EccChip::Point { pub fn inner(&self) -> &EccChip::Point {
&self.inner &self.inner

View File

@ -21,7 +21,7 @@ pprof = { version = "0.4.2", features = ["criterion", "flamegraph"] }
[dependencies] [dependencies]
bitvec = "0.22" bitvec = "0.22"
ff = "0.11" ff = "0.11"
halo2 = { version = "0.0", optional = true } halo2 = { version = "=0.1.0-beta.1", optional = true }
pasta_curves = "0.2.1" pasta_curves = "0.2.1"
rand = "0.8" rand = "0.8"
utilities = { package = "halo2_utilities", version = "0.0", path = "../halo2_utilities" } utilities = { package = "halo2_utilities", version = "0.0", path = "../halo2_utilities" }

View File

@ -18,7 +18,7 @@ publish = false
[dependencies] [dependencies]
bigint = "4" bigint = "4"
ff = "0.11" ff = "0.11"
halo2 = "0.0" halo2 = "=0.1.0-beta.1"
pasta_curves = "0.2.1" pasta_curves = "0.2.1"
proptest = { version = "1.0.0", optional = true } proptest = { version = "1.0.0", optional = true }
rand = "0.8" rand = "0.8"

View File

@ -22,7 +22,7 @@ pprof = { version = "0.4.2", features = ["criterion", "flamegraph"] }
ecc = { package = "halo2_ecc", version = "0.0", path = "../halo2_ecc" } ecc = { package = "halo2_ecc", version = "0.0", path = "../halo2_ecc" }
ff = "0.11" ff = "0.11"
group = "0.11" group = "0.11"
halo2 = { version = "0.0", optional = true } halo2 = { version = "=0.1.0-beta.1", optional = true }
lazy_static = "1" lazy_static = "1"
pasta_curves = "0.2.1" pasta_curves = "0.2.1"
rand = "0.8" rand = "0.8"

View File

@ -1,5 +1,5 @@
use super::{ use super::{
gadget::{self, CommitDomains, HashDomains, SinsemillaInstructions}, gadget::{CommitDomains, HashDomains, SinsemillaInstructions, Point as PointTrait},
message::{Message, MessagePiece}, message::{Message, MessagePiece},
primitive as sinsemilla, primitive as sinsemilla,
}; };
@ -26,12 +26,12 @@ mod hash_to_point;
/// A point output by hash_to_point /// A point output by hash_to_point
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct Point { pub struct Point {
x: CellValue<pallas::Base>, x: CellValue<pallas::Base>,
y: CellValue<pallas::Base>, y: CellValue<pallas::Base>,
} }
impl gadget::Point<pallas::Affine, CellValue<pallas::Base>> for Point { impl PointTrait<pallas::Affine, CellValue<pallas::Base>> for Point {
fn x(&self) -> CellValue<pallas::Base> { fn x(&self) -> CellValue<pallas::Base> {
self.x self.x
} }

View File

@ -231,7 +231,7 @@ pub struct HashDomain<
SinsemillaChip: SinsemillaInstructions<C, K, MAX_WORDS> + Clone + Debug + Eq, SinsemillaChip: SinsemillaInstructions<C, K, MAX_WORDS> + Clone + Debug + Eq,
EccChip: EccInstructions< EccChip: EccInstructions<
C, C,
NonIdentityPoint = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::NonIdentityPoint, // NonIdentityPoint = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::NonIdentityPoint,
FixedPoints = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::FixedPoints, FixedPoints = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::FixedPoints,
Var = SinsemillaChip::Var, Var = SinsemillaChip::Var,
> + Clone > + Clone
@ -249,7 +249,7 @@ where
SinsemillaChip: SinsemillaInstructions<C, K, MAX_WORDS> + Clone + Debug + Eq, SinsemillaChip: SinsemillaInstructions<C, K, MAX_WORDS> + Clone + Debug + Eq,
EccChip: EccInstructions< EccChip: EccInstructions<
C, C,
NonIdentityPoint = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::NonIdentityPoint, // NonIdentityPoint = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::NonIdentityPoint,
FixedPoints = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::FixedPoints, FixedPoints = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::FixedPoints,
Var = SinsemillaChip::Var, Var = SinsemillaChip::Var,
> + Clone > + Clone
@ -340,7 +340,7 @@ pub struct CommitDomain<
SinsemillaChip: SinsemillaInstructions<C, K, MAX_WORDS> + Clone + Debug + Eq, SinsemillaChip: SinsemillaInstructions<C, K, MAX_WORDS> + Clone + Debug + Eq,
EccChip: EccInstructions< EccChip: EccInstructions<
C, C,
NonIdentityPoint = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::NonIdentityPoint, // NonIdentityPoint = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::NonIdentityPoint,
FixedPoints = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::FixedPoints, FixedPoints = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::FixedPoints,
Var = SinsemillaChip::Var, Var = SinsemillaChip::Var,
> + Clone > + Clone
@ -357,7 +357,7 @@ where
SinsemillaChip: SinsemillaInstructions<C, K, MAX_WORDS> + Clone + Debug + Eq, SinsemillaChip: SinsemillaInstructions<C, K, MAX_WORDS> + Clone + Debug + Eq,
EccChip: EccInstructions< EccChip: EccInstructions<
C, C,
NonIdentityPoint = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::NonIdentityPoint, // NonIdentityPoint = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::NonIdentityPoint,
FixedPoints = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::FixedPoints, FixedPoints = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::FixedPoints,
Var = SinsemillaChip::Var, Var = SinsemillaChip::Var,
> + Clone > + Clone
@ -614,8 +614,8 @@ pub mod testing {
None None
}; };
NonIdentityPoint::new( Point::new(
ecc_chip, ecc_chip.clone(),
layouter.namespace(|| "Witness expected result"), layouter.namespace(|| "Witness expected result"),
expected_result, expected_result,
)? )?

View File

@ -164,26 +164,20 @@ where
pub mod testing { pub mod testing {
use super::{ use super::{
chip::{MerkleChip, MerkleConfig}, chip::{MerkleChip, MerkleConfig},
i2lebsp, MerklePath, L_PALLAS_BASE, MERKLE_DEPTH, MerklePath, MERKLE_DEPTH,
}; };
use crate::{ use crate::{
chip::SinsemillaChip, chip::SinsemillaChip,
gadget::{CommitDomains, HashDomains}, gadget::{CommitDomains, HashDomains},
primitive::HashDomain,
}; };
use ecc::gadget::FixedPoints; use ecc::gadget::FixedPoints;
use utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions, Var}; use utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions, Var};
use ff::PrimeFieldBits;
use group::prime::PrimeCurveAffine;
use halo2::{ use halo2::{
circuit::{Layouter, SimpleFloorPlanner}, circuit::{Layouter, SimpleFloorPlanner},
dev::MockProver,
note::commitment::ExtractedNoteCommitment,
plonk::{Circuit, ConstraintSystem, Error}, plonk::{Circuit, ConstraintSystem, Error},
tree,
}; };
use pasta_curves::pallas; use pasta_curves::pallas;
@ -313,25 +307,29 @@ pub mod testing {
path.calculate_root(layouter.namespace(|| "calculate root"), leaf)?; path.calculate_root(layouter.namespace(|| "calculate root"), leaf)?;
if let Some(leaf_pos) = self.leaf_pos { if let Some(leaf_pos) = self.leaf_pos {
let domain = HashDomain {
Q: S::hash_domain().Q().to_curve(),
};
// The expected final root // The expected final root
let final_root = { let final_root = S::root(
let path = tree::MerklePath::new(leaf_pos, self.merkle_path.unwrap()); self.merkle_path.unwrap(),
let leaf = ExtractedNoteCommitment::from_bytes(&self.leaf.unwrap().to_bytes()) leaf_pos,
.unwrap(); self.leaf.unwrap(),
path.root(leaf) );
};
// Check the computed final root against the expected final root. // Check the computed final root against the expected final root.
assert_eq!(computed_final_root.value().unwrap(), final_root.inner()); assert_eq!(computed_final_root.value().unwrap(), final_root);
} }
Ok(()) Ok(())
} }
} }
pub trait MerkleTest<Hash: HashDomains<pallas::Affine>> {
fn hash_domain() -> Hash;
fn root(
path: [pallas::Base; MERKLE_DEPTH],
leaf_pos: u32,
leaf: pallas::Base,
) -> pallas::Base;
}
} }
#[cfg(feature = "testing")] #[cfg(feature = "testing")]
@ -344,9 +342,11 @@ pub mod tests {
use crate::{ use crate::{
gadget::{CommitDomains, HashDomains}, gadget::{CommitDomains, HashDomains},
merkle::{i2lebsp, L_PALLAS_BASE, MERKLE_DEPTH},
primitive::{CommitDomain, HashDomain}, primitive::{CommitDomain, HashDomain},
}; };
use ff::PrimeFieldBits;
use group::Curve; use group::Curve;
use pasta_curves::pallas; use pasta_curves::pallas;
@ -406,11 +406,50 @@ pub mod tests {
fn hash_domain() -> Hash { fn hash_domain() -> Hash {
Hash Hash
} }
fn root(path: [pallas::Base; MERKLE_DEPTH],
leaf_pos: u32,
leaf: pallas::Base,) -> pallas::Base {
use group::prime::PrimeCurveAffine;
let domain = HashDomain { Q: Self::hash_domain().Q().to_curve() };
let pos_bool = i2lebsp::<32>(leaf_pos as u64);
// Compute the root
let mut node = leaf;
for (l, (sibling, pos)) in path.iter().zip(pos_bool.iter()).enumerate() {
let (left, right) = if *pos {
(*sibling, node)
} else {
(node, *sibling)
};
let l_star = i2lebsp::<10>(l as u64);
let left: Vec<_> = left
.to_le_bits()
.iter()
.by_val()
.take(L_PALLAS_BASE)
.collect();
let right: Vec<_> = right
.to_le_bits()
.iter()
.by_val()
.take(L_PALLAS_BASE)
.collect();
let mut message = l_star.to_vec();
message.extend_from_slice(&left);
message.extend_from_slice(&right);
node = domain.hash(message.into_iter()).unwrap();
}
node
}
} }
#[test] #[test]
fn merkle_chip() { fn merkle_chip() {
use crate::merkle::{i2lebsp, MERKLE_DEPTH}; use crate::merkle::{MERKLE_DEPTH};
use halo2::dev::MockProver; use halo2::dev::MockProver;
use pasta_curves::arithmetic::FieldExt; use pasta_curves::arithmetic::FieldExt;
use rand::random; use rand::random;

View File

@ -15,8 +15,7 @@ use pasta_curves::{
use crate::{ use crate::{
constants::{ constants::{
util::gen_const_array, OrchardCommitDomains, OrchardFixedBases, OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases, OrchardHashDomains, MERKLE_DEPTH_ORCHARD,
MERKLE_DEPTH_ORCHARD,
}, },
keys::{ keys::{
CommitIvkRandomness, DiversifiedTransmissionKey, NullifierDerivingKey, SpendValidatingKey, CommitIvkRandomness, DiversifiedTransmissionKey, NullifierDerivingKey, SpendValidatingKey,
@ -48,7 +47,8 @@ use sinsemilla::{
}, },
}; };
use utilities::{ use utilities::{
copy, lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions, Var, copy, gen_const_array, lookup_range_check::LookupRangeCheckConfig, CellValue,
UtilitiesInstructions, Var,
}; };
use std::convert::TryInto; use std::convert::TryInto;
@ -411,7 +411,7 @@ impl plonk::Circuit<pallas::Base> for Circuit {
config.merkle_chip_2(), config.merkle_chip_2(),
OrchardHashDomains::MerkleCrh, OrchardHashDomains::MerkleCrh,
self.pos, self.pos,
self.path, path,
); );
let leaf = *cm_old.extract_p().inner(); let leaf = *cm_old.extract_p().inner();
merkle_inputs.calculate_root(layouter.namespace(|| "MerkleCRH"), leaf)? merkle_inputs.calculate_root(layouter.namespace(|| "MerkleCRH"), leaf)?

View File

@ -303,6 +303,7 @@ fn test_orchard_domains() {
#[cfg(feature = "test-ecc")] #[cfg(feature = "test-ecc")]
#[test] #[test]
fn test_merkle_crh() { fn test_merkle_crh() {
use crate::constants::MERKLE_DEPTH_ORCHARD;
use halo2::dev::MockProver; use halo2::dev::MockProver;
use rand::random; use rand::random;
use sinsemilla::merkle::testing; use sinsemilla::merkle::testing;
@ -313,6 +314,17 @@ fn test_merkle_crh() {
fn hash_domain() -> OrchardHashDomains { fn hash_domain() -> OrchardHashDomains {
OrchardHashDomains::MerkleCrh OrchardHashDomains::MerkleCrh
} }
fn root(
path: [pallas::Base; MERKLE_DEPTH_ORCHARD],
leaf_pos: u32,
leaf: pallas::Base,
) -> pallas::Base {
use crate::{note::ExtractedNoteCommitment, tree::MerklePath};
let path = MerklePath::new(leaf_pos, path);
let leaf = ExtractedNoteCommitment::from_bytes(&leaf.to_bytes()).unwrap();
path.root(leaf).inner()
}
} }
// Choose a random leaf and position // Choose a random leaf and position

View File

@ -7,10 +7,10 @@ use crate::{
}, },
note::commitment::ExtractedNoteCommitment, note::commitment::ExtractedNoteCommitment,
}; };
use halo2_utilities::utilities::gen_const_array_with_default;
use incrementalmerkletree::{Altitude, Hashable}; use incrementalmerkletree::{Altitude, Hashable};
use pasta_curves::{arithmetic::FieldExt, pallas}; use pasta_curves::{arithmetic::FieldExt, pallas};
use sinsemilla::primitive::HashDomain; use sinsemilla::primitive::HashDomain;
use utilities::gen_const_array_with_default;
use ff::{Field, PrimeField, PrimeFieldBits}; use ff::{Field, PrimeField, PrimeFieldBits};
use lazy_static::lazy_static; use lazy_static::lazy_static;