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",
"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"
ff = "0.11"
group = "0.11"
halo2 = "0.0"
halo2 = "=0.1.0-beta.1"
lazy_static = "1"
pasta_curves = "0.2.1"
rand = "0.8"

View File

@ -86,7 +86,7 @@ impl EccPoint {
self.y
}
#[cfg(test)]
#[cfg(feature = "testing")]
fn is_identity(&self) -> Option<bool> {
self.x.value().map(|x| x == pallas::Base::zero())
}
@ -103,17 +103,6 @@ pub struct 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.
pub fn point(&self) -> Option<pallas::Affine> {
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 {
let point: EccPoint = (point.clone()).into();
point.x()

View File

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

View File

@ -145,11 +145,13 @@ impl Config {
#[cfg(feature = "testing")]
pub mod tests {
use group::{prime::PrimeCurveAffine, Curve, Group};
use group::{Curve, Group};
use halo2::{circuit::Layouter, plonk::Error};
use pasta_curves::pallas;
use crate::gadget::{EccInstructions, NonIdentityPoint};
use crate::{
gadget::{EccInstructions, NonIdentityPoint},
};
#[allow(clippy::too_many_arguments)]
pub fn test_add_incomplete<
@ -171,15 +173,6 @@ pub mod tests {
// Make sure P and Q are not the same point.
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
{
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")]
pub mod tests {
use group::{prime::PrimeCurveAffine, Curve, Group};
use group::{Curve, Group};
use halo2::{
circuit::{Chip, Layouter},
plonk::Error,
@ -452,7 +452,7 @@ pub mod tests {
use pasta_curves::{arithmetic::FieldExt, pallas};
use crate::{
chip::EccChip,
chip::{EccChip, EccPoint},
gadget::{EccInstructions, FixedPoints, NonIdentityPoint, Point},
};
use utilities::UtilitiesInstructions;
@ -465,15 +465,6 @@ pub mod tests {
let p_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); // P
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];
fn constrain_equal_non_id<

View File

@ -364,7 +364,7 @@ pub mod tests {
*magnitude,
*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());
}

View File

@ -8,7 +8,6 @@ use halo2::{
poly::Rotation,
};
use pasta_curves::{arithmetic::CurveAffine, pallas};
use utilities::copy;
#[derive(Clone, Debug)]
pub struct Config {
@ -147,20 +146,20 @@ impl Config {
}
}
#[cfg(test)]
#[cfg(feature = "testing")]
pub mod tests {
use halo2::circuit::Layouter;
use pasta_curves::pallas;
use super::*;
use crate::circuit::gadget::ecc::{EccInstructions, NonIdentityPoint};
use crate::gadget::{EccInstructions, NonIdentityPoint};
pub fn test_witness_non_id<
EccChip: EccInstructions<pallas::Affine> + Clone + Eq + std::fmt::Debug,
>(
chip: EccChip,
mut layouter: impl Layouter<pallas::Base>,
) {
) -> Result<(), Error> {
// Witnessing the identity should return an error.
NonIdentityPoint::new(
chip,
@ -168,23 +167,7 @@ pub mod tests {
Some(pallas::Affine::identity()),
)
.expect_err("witnessing 𝒪 should return an error");
}
pub(super) fn copy_point(
&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 })
Ok(())
}
}

View File

@ -1,9 +1,9 @@
//! Gadgets for elliptic curve operations.
use pasta_curves::arithmetic::CurveAffine;
use std::fmt::Debug;
use halo2::{
arithmetic::CurveAffine,
circuit::{Chip, Layouter},
plonk::Error,
};
@ -79,11 +79,19 @@ pub trait EccInstructions<C: CurveAffine>:
/// checking that the coordinates indeed belong to a valid point.
/// This maps the identity to (0, 0) in affine coordinates.
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,
layouter: &mut impl Layouter<C::Base>,
x: Self::Var,
y: Self::Var,
) -> Result<Self::Point, Error>;
) -> Result<Self::NonIdentityPoint, Error>;
/// Extracts the x-coordinate of a point.
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 })
}
/// 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.
pub fn constrain_equal<Other: Into<Point<C, EccChip>> + Clone>(
&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.
pub fn inner(&self) -> &EccChip::NonIdentityPoint {
&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)
}
/// 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.
pub fn inner(&self) -> &EccChip::Point {
&self.inner

View File

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

View File

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

View File

@ -1,5 +1,5 @@
use super::{
gadget::{self, CommitDomains, HashDomains, SinsemillaInstructions},
gadget::{CommitDomains, HashDomains, SinsemillaInstructions, Point as PointTrait},
message::{Message, MessagePiece},
primitive as sinsemilla,
};
@ -26,12 +26,12 @@ mod hash_to_point;
/// A point output by hash_to_point
#[derive(Clone, Debug)]
struct Point {
pub struct Point {
x: 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> {
self.x
}

View File

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

View File

@ -164,26 +164,20 @@ where
pub mod testing {
use super::{
chip::{MerkleChip, MerkleConfig},
i2lebsp, MerklePath, L_PALLAS_BASE, MERKLE_DEPTH,
MerklePath, MERKLE_DEPTH,
};
use crate::{
chip::SinsemillaChip,
gadget::{CommitDomains, HashDomains},
primitive::HashDomain,
};
use ecc::gadget::FixedPoints;
use utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions, Var};
use ff::PrimeFieldBits;
use group::prime::PrimeCurveAffine;
use halo2::{
circuit::{Layouter, SimpleFloorPlanner},
dev::MockProver,
note::commitment::ExtractedNoteCommitment,
plonk::{Circuit, ConstraintSystem, Error},
tree,
};
use pasta_curves::pallas;
@ -313,25 +307,29 @@ pub mod testing {
path.calculate_root(layouter.namespace(|| "calculate root"), leaf)?;
if let Some(leaf_pos) = self.leaf_pos {
let domain = HashDomain {
Q: S::hash_domain().Q().to_curve(),
};
// The expected final root
let final_root = {
let path = tree::MerklePath::new(leaf_pos, self.merkle_path.unwrap());
let leaf = ExtractedNoteCommitment::from_bytes(&self.leaf.unwrap().to_bytes())
.unwrap();
path.root(leaf)
};
let final_root = S::root(
self.merkle_path.unwrap(),
leaf_pos,
self.leaf.unwrap(),
);
// 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(())
}
}
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")]
@ -344,9 +342,11 @@ pub mod tests {
use crate::{
gadget::{CommitDomains, HashDomains},
merkle::{i2lebsp, L_PALLAS_BASE, MERKLE_DEPTH},
primitive::{CommitDomain, HashDomain},
};
use ff::PrimeFieldBits;
use group::Curve;
use pasta_curves::pallas;
@ -406,11 +406,50 @@ pub mod tests {
fn hash_domain() -> 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]
fn merkle_chip() {
use crate::merkle::{i2lebsp, MERKLE_DEPTH};
use crate::merkle::{MERKLE_DEPTH};
use halo2::dev::MockProver;
use pasta_curves::arithmetic::FieldExt;
use rand::random;

View File

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

View File

@ -303,6 +303,7 @@ fn test_orchard_domains() {
#[cfg(feature = "test-ecc")]
#[test]
fn test_merkle_crh() {
use crate::constants::MERKLE_DEPTH_ORCHARD;
use halo2::dev::MockProver;
use rand::random;
use sinsemilla::merkle::testing;
@ -313,6 +314,17 @@ fn test_merkle_crh() {
fn hash_domain() -> OrchardHashDomains {
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

View File

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