mirror of https://github.com/zcash/halo2.git
Remove Point::new() API and introduce is_identity() instruction.
Also remove the q_point selector and gate from the circuit.
This commit is contained in:
parent
ec27989b9b
commit
8ad3003e27
|
@ -57,14 +57,6 @@ pub trait EccInstructions<C: CurveAffine>: Chip<C::Base> + UtilitiesInstructions
|
||||||
b: &Self::Point,
|
b: &Self::Point,
|
||||||
) -> Result<(), Error>;
|
) -> Result<(), Error>;
|
||||||
|
|
||||||
/// Witnesses the given point as a private input to the circuit.
|
|
||||||
/// This maps the identity to (0, 0) in affine coordinates.
|
|
||||||
fn witness_point(
|
|
||||||
&self,
|
|
||||||
layouter: &mut impl Layouter<C::Base>,
|
|
||||||
value: Option<C>,
|
|
||||||
) -> Result<Self::Point, Error>;
|
|
||||||
|
|
||||||
/// Witnesses the given point as a private input to the circuit.
|
/// Witnesses the given point as a private input to the circuit.
|
||||||
/// This returns an error if the point is the identity.
|
/// This returns an error if the point is the identity.
|
||||||
fn witness_point_non_id(
|
fn witness_point_non_id(
|
||||||
|
@ -73,6 +65,9 @@ pub trait EccInstructions<C: CurveAffine>: Chip<C::Base> + UtilitiesInstructions
|
||||||
value: Option<C>,
|
value: Option<C>,
|
||||||
) -> Result<Self::NonIdentityPoint, Error>;
|
) -> Result<Self::NonIdentityPoint, Error>;
|
||||||
|
|
||||||
|
/// Checks if a point is the identity.
|
||||||
|
fn is_identity(point: &Self::Point) -> Option<bool>;
|
||||||
|
|
||||||
/// 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;
|
||||||
|
|
||||||
|
@ -310,17 +305,6 @@ pub struct Point<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + E
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> Point<C, EccChip> {
|
impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> Point<C, EccChip> {
|
||||||
/// Constructs a new point with the given value.
|
|
||||||
#[cfg(test)]
|
|
||||||
pub fn new(
|
|
||||||
chip: EccChip,
|
|
||||||
mut layouter: impl Layouter<C::Base>,
|
|
||||||
value: Option<C>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let point = chip.witness_point(&mut layouter, value);
|
|
||||||
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,
|
||||||
|
@ -337,6 +321,11 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> Point<C,
|
||||||
&self.inner
|
&self.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks is a point is the identity.
|
||||||
|
pub fn is_identity(&self) -> Option<bool> {
|
||||||
|
EccChip::is_identity(&self.inner)
|
||||||
|
}
|
||||||
|
|
||||||
/// Extracts the x-coordinate of a point.
|
/// Extracts the x-coordinate of a point.
|
||||||
pub fn extract_p(&self) -> X<C, EccChip> {
|
pub fn extract_p(&self) -> X<C, EccChip> {
|
||||||
X::from_inner(self.chip.clone(), EccChip::extract_p(&self.inner))
|
X::from_inner(self.chip.clone(), EccChip::extract_p(&self.inner))
|
||||||
|
@ -513,7 +502,7 @@ where
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use group::{prime::PrimeCurveAffine, Curve, Group};
|
use group::{Curve, Group};
|
||||||
|
|
||||||
use halo2::{
|
use halo2::{
|
||||||
circuit::{Layouter, SimpleFloorPlanner},
|
circuit::{Layouter, SimpleFloorPlanner},
|
||||||
|
@ -604,15 +593,6 @@ 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 = {
|
|
||||||
super::Point::new(
|
|
||||||
chip.clone(),
|
|
||||||
layouter.namespace(|| "identity"),
|
|
||||||
Some(pallas::Affine::identity()),
|
|
||||||
)?
|
|
||||||
};
|
|
||||||
|
|
||||||
// Test witness non-identity point
|
// Test witness non-identity point
|
||||||
{
|
{
|
||||||
super::chip::witness_point::tests::test_witness_non_id(
|
super::chip::witness_point::tests::test_witness_non_id(
|
||||||
|
@ -626,7 +606,6 @@ mod tests {
|
||||||
super::chip::add::tests::test_add(
|
super::chip::add::tests::test_add(
|
||||||
chip.clone(),
|
chip.clone(),
|
||||||
layouter.namespace(|| "complete addition"),
|
layouter.namespace(|| "complete addition"),
|
||||||
&zero,
|
|
||||||
p_val,
|
p_val,
|
||||||
&p,
|
&p,
|
||||||
q_val,
|
q_val,
|
||||||
|
|
|
@ -181,8 +181,6 @@ pub struct EccConfig {
|
||||||
/// when the scalar is a signed short exponent or a base-field element.
|
/// when the scalar is a signed short exponent or a base-field element.
|
||||||
pub q_mul_fixed_running_sum: Selector,
|
pub q_mul_fixed_running_sum: Selector,
|
||||||
|
|
||||||
/// Witness point
|
|
||||||
pub q_point: Selector,
|
|
||||||
/// Witness non-identity point
|
/// Witness non-identity point
|
||||||
pub q_point_non_id: Selector,
|
pub q_point_non_id: Selector,
|
||||||
|
|
||||||
|
@ -280,7 +278,6 @@ impl EccChip {
|
||||||
q_mul_fixed_short: meta.selector(),
|
q_mul_fixed_short: meta.selector(),
|
||||||
q_mul_fixed_base_field: meta.selector(),
|
q_mul_fixed_base_field: meta.selector(),
|
||||||
q_mul_fixed_running_sum,
|
q_mul_fixed_running_sum,
|
||||||
q_point: meta.selector(),
|
|
||||||
q_point_non_id: meta.selector(),
|
q_point_non_id: meta.selector(),
|
||||||
lookup_config: range_check,
|
lookup_config: range_check,
|
||||||
running_sum_config,
|
running_sum_config,
|
||||||
|
@ -419,18 +416,6 @@ impl EccInstructions<pallas::Affine> for EccChip {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn witness_point(
|
|
||||||
&self,
|
|
||||||
layouter: &mut impl Layouter<pallas::Base>,
|
|
||||||
value: Option<pallas::Affine>,
|
|
||||||
) -> Result<Self::Point, Error> {
|
|
||||||
let config: witness_point::Config = self.config().into();
|
|
||||||
layouter.assign_region(
|
|
||||||
|| "witness point",
|
|
||||||
|mut region| config.point(value, 0, &mut region),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn witness_point_non_id(
|
fn witness_point_non_id(
|
||||||
&self,
|
&self,
|
||||||
layouter: &mut impl Layouter<pallas::Base>,
|
layouter: &mut impl Layouter<pallas::Base>,
|
||||||
|
@ -443,6 +428,10 @@ impl EccInstructions<pallas::Affine> for EccChip {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_identity(point: &Self::Point) -> Option<bool> {
|
||||||
|
point.is_identity()
|
||||||
|
}
|
||||||
|
|
||||||
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()
|
||||||
|
|
|
@ -391,13 +391,12 @@ 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::circuit::gadget::ecc::{EccInstructions, NonIdentityPoint, Point};
|
use crate::circuit::gadget::ecc::{EccInstructions, NonIdentityPoint};
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn test_add<EccChip: EccInstructions<pallas::Affine> + Clone + Eq + std::fmt::Debug>(
|
pub fn test_add<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>,
|
||||||
zero: &Point<pallas::Affine, EccChip>,
|
|
||||||
p_val: pallas::Affine,
|
p_val: pallas::Affine,
|
||||||
p: &NonIdentityPoint<pallas::Affine, EccChip>,
|
p: &NonIdentityPoint<pallas::Affine, EccChip>,
|
||||||
q_val: pallas::Affine,
|
q_val: pallas::Affine,
|
||||||
|
@ -408,21 +407,22 @@ pub mod tests {
|
||||||
assert_ne!(p_val, q_val);
|
assert_ne!(p_val, q_val);
|
||||||
|
|
||||||
// Check complete addition P + (-P)
|
// Check complete addition P + (-P)
|
||||||
{
|
let zero = {
|
||||||
let result = p.add(layouter.namespace(|| "P + (-P)"), p_neg)?;
|
let result = p.add(layouter.namespace(|| "P + (-P)"), p_neg)?;
|
||||||
result.constrain_equal(layouter.namespace(|| "P + (-P) = 𝒪"), zero)?;
|
assert!(result.is_identity().unwrap());
|
||||||
}
|
result
|
||||||
|
};
|
||||||
|
|
||||||
// Check complete addition 𝒪 + 𝒪
|
// Check complete addition 𝒪 + 𝒪
|
||||||
{
|
{
|
||||||
let result = zero.add(layouter.namespace(|| "𝒪 + 𝒪"), zero)?;
|
let result = zero.add(layouter.namespace(|| "𝒪 + 𝒪"), &zero)?;
|
||||||
result.constrain_equal(layouter.namespace(|| "𝒪 + 𝒪 = 𝒪"), zero)?;
|
result.constrain_equal(layouter.namespace(|| "𝒪 + 𝒪 = 𝒪"), &zero)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check P + Q
|
// Check P + Q
|
||||||
{
|
{
|
||||||
let result = p.add(layouter.namespace(|| "P + Q"), q)?;
|
let result = p.add(layouter.namespace(|| "P + Q"), q)?;
|
||||||
let witnessed_result = Point::new(
|
let witnessed_result = NonIdentityPoint::new(
|
||||||
chip.clone(),
|
chip.clone(),
|
||||||
layouter.namespace(|| "witnessed P + Q"),
|
layouter.namespace(|| "witnessed P + Q"),
|
||||||
Some((p_val + q_val).to_affine()),
|
Some((p_val + q_val).to_affine()),
|
||||||
|
@ -433,7 +433,7 @@ pub mod tests {
|
||||||
// P + P
|
// P + P
|
||||||
{
|
{
|
||||||
let result = p.add(layouter.namespace(|| "P + P"), p)?;
|
let result = p.add(layouter.namespace(|| "P + P"), p)?;
|
||||||
let witnessed_result = Point::new(
|
let witnessed_result = NonIdentityPoint::new(
|
||||||
chip.clone(),
|
chip.clone(),
|
||||||
layouter.namespace(|| "witnessed P + P"),
|
layouter.namespace(|| "witnessed P + P"),
|
||||||
Some((p_val + p_val).to_affine()),
|
Some((p_val + p_val).to_affine()),
|
||||||
|
@ -443,7 +443,7 @@ pub mod tests {
|
||||||
|
|
||||||
// P + 𝒪
|
// P + 𝒪
|
||||||
{
|
{
|
||||||
let result = p.add(layouter.namespace(|| "P + 𝒪"), zero)?;
|
let result = p.add(layouter.namespace(|| "P + 𝒪"), &zero)?;
|
||||||
result.constrain_equal(layouter.namespace(|| "P + 𝒪 = P"), p)?;
|
result.constrain_equal(layouter.namespace(|| "P + 𝒪 = P"), p)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,7 +455,7 @@ pub mod tests {
|
||||||
|
|
||||||
// (x, y) + (ζx, y) should behave like normal P + Q.
|
// (x, y) + (ζx, y) should behave like normal P + Q.
|
||||||
let endo_p = p_val.to_curve().endo();
|
let endo_p = p_val.to_curve().endo();
|
||||||
let endo_p = Point::new(
|
let endo_p = NonIdentityPoint::new(
|
||||||
chip.clone(),
|
chip.clone(),
|
||||||
layouter.namespace(|| "endo(P)"),
|
layouter.namespace(|| "endo(P)"),
|
||||||
Some(endo_p.to_affine()),
|
Some(endo_p.to_affine()),
|
||||||
|
@ -464,7 +464,7 @@ pub mod tests {
|
||||||
|
|
||||||
// (x, y) + (ζx, -y) should also behave like normal P + Q.
|
// (x, y) + (ζx, -y) should also behave like normal P + Q.
|
||||||
let endo_p_neg = (-p_val).to_curve().endo();
|
let endo_p_neg = (-p_val).to_curve().endo();
|
||||||
let endo_p_neg = Point::new(
|
let endo_p_neg = NonIdentityPoint::new(
|
||||||
chip.clone(),
|
chip.clone(),
|
||||||
layouter.namespace(|| "endo(-P)"),
|
layouter.namespace(|| "endo(-P)"),
|
||||||
Some(endo_p_neg.to_affine()),
|
Some(endo_p_neg.to_affine()),
|
||||||
|
@ -473,7 +473,7 @@ pub mod tests {
|
||||||
|
|
||||||
// (x, y) + ((ζ^2)x, y)
|
// (x, y) + ((ζ^2)x, y)
|
||||||
let endo_2_p = p_val.to_curve().endo().endo();
|
let endo_2_p = p_val.to_curve().endo().endo();
|
||||||
let endo_2_p = Point::new(
|
let endo_2_p = NonIdentityPoint::new(
|
||||||
chip.clone(),
|
chip.clone(),
|
||||||
layouter.namespace(|| "endo^2(P)"),
|
layouter.namespace(|| "endo^2(P)"),
|
||||||
Some(endo_2_p.to_affine()),
|
Some(endo_2_p.to_affine()),
|
||||||
|
@ -482,7 +482,7 @@ pub mod tests {
|
||||||
|
|
||||||
// (x, y) + ((ζ^2)x, -y)
|
// (x, y) + ((ζ^2)x, -y)
|
||||||
let endo_2_p_neg = (-p_val).to_curve().endo().endo();
|
let endo_2_p_neg = (-p_val).to_curve().endo().endo();
|
||||||
let endo_2_p_neg = Point::new(
|
let endo_2_p_neg = NonIdentityPoint::new(
|
||||||
chip,
|
chip,
|
||||||
layouter.namespace(|| "endo^2(-P)"),
|
layouter.namespace(|| "endo^2(-P)"),
|
||||||
Some(endo_2_p_neg.to_affine()),
|
Some(endo_2_p_neg.to_affine()),
|
||||||
|
|
|
@ -464,7 +464,7 @@ pub mod tests {
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let column = chip.config().advices[0];
|
let column = chip.config().advices[0];
|
||||||
|
|
||||||
fn constrain_equal<
|
fn constrain_equal_non_id<
|
||||||
EccChip: EccInstructions<pallas::Affine> + Clone + Eq + std::fmt::Debug,
|
EccChip: EccInstructions<pallas::Affine> + Clone + Eq + std::fmt::Debug,
|
||||||
>(
|
>(
|
||||||
chip: EccChip,
|
chip: EccChip,
|
||||||
|
@ -476,7 +476,7 @@ pub mod tests {
|
||||||
// Move scalar from base field into scalar field (which always fits
|
// Move scalar from base field into scalar field (which always fits
|
||||||
// for Pallas).
|
// for Pallas).
|
||||||
let scalar = pallas::Scalar::from_bytes(&scalar_val.to_bytes()).unwrap();
|
let scalar = pallas::Scalar::from_bytes(&scalar_val.to_bytes()).unwrap();
|
||||||
let expected = Point::new(
|
let expected = NonIdentityPoint::new(
|
||||||
chip,
|
chip,
|
||||||
layouter.namespace(|| "expected point"),
|
layouter.namespace(|| "expected point"),
|
||||||
Some((base_val * scalar).to_affine()),
|
Some((base_val * scalar).to_affine()),
|
||||||
|
@ -495,7 +495,7 @@ pub mod tests {
|
||||||
)?;
|
)?;
|
||||||
p.mul(layouter.namespace(|| "random [a]B"), &scalar)?
|
p.mul(layouter.namespace(|| "random [a]B"), &scalar)?
|
||||||
};
|
};
|
||||||
constrain_equal(
|
constrain_equal_non_id(
|
||||||
chip.clone(),
|
chip.clone(),
|
||||||
layouter.namespace(|| "random [a]B"),
|
layouter.namespace(|| "random [a]B"),
|
||||||
p_val,
|
p_val,
|
||||||
|
@ -513,13 +513,7 @@ pub mod tests {
|
||||||
chip.load_private(layouter.namespace(|| "zero"), column, Some(scalar_val))?;
|
chip.load_private(layouter.namespace(|| "zero"), column, Some(scalar_val))?;
|
||||||
p.mul(layouter.namespace(|| "[0]B"), &scalar)?
|
p.mul(layouter.namespace(|| "[0]B"), &scalar)?
|
||||||
};
|
};
|
||||||
constrain_equal(
|
assert!(result.is_identity().unwrap());
|
||||||
chip.clone(),
|
|
||||||
layouter.namespace(|| "[0]B"),
|
|
||||||
p_val,
|
|
||||||
scalar_val,
|
|
||||||
result,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// [-1]B (the largest possible base field element)
|
// [-1]B (the largest possible base field element)
|
||||||
|
@ -530,7 +524,7 @@ pub mod tests {
|
||||||
chip.load_private(layouter.namespace(|| "-1"), column, Some(scalar_val))?;
|
chip.load_private(layouter.namespace(|| "-1"), column, Some(scalar_val))?;
|
||||||
p.mul(layouter.namespace(|| "[-1]B"), &scalar)?
|
p.mul(layouter.namespace(|| "[-1]B"), &scalar)?
|
||||||
};
|
};
|
||||||
constrain_equal(
|
constrain_equal_non_id(
|
||||||
chip,
|
chip,
|
||||||
layouter.namespace(|| "[-1]B"),
|
layouter.namespace(|| "[-1]B"),
|
||||||
p_val,
|
p_val,
|
||||||
|
|
|
@ -389,7 +389,7 @@ pub mod tests {
|
||||||
use crate::circuit::gadget::{
|
use crate::circuit::gadget::{
|
||||||
ecc::{
|
ecc::{
|
||||||
chip::{EccChip, NullifierK},
|
chip::{EccChip, NullifierK},
|
||||||
FixedPointBaseField, Point,
|
FixedPointBaseField, NonIdentityPoint, Point,
|
||||||
},
|
},
|
||||||
utilities::UtilitiesInstructions,
|
utilities::UtilitiesInstructions,
|
||||||
};
|
};
|
||||||
|
@ -418,7 +418,7 @@ pub mod tests {
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let column = chip.config().advices[0];
|
let column = chip.config().advices[0];
|
||||||
|
|
||||||
fn constrain_equal(
|
fn constrain_equal_non_id(
|
||||||
chip: EccChip,
|
chip: EccChip,
|
||||||
mut layouter: impl Layouter<pallas::Base>,
|
mut layouter: impl Layouter<pallas::Base>,
|
||||||
base_val: pallas::Affine,
|
base_val: pallas::Affine,
|
||||||
|
@ -427,7 +427,7 @@ pub mod tests {
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Move scalar from base field into scalar field (which always fits for Pallas).
|
// Move scalar from base field into scalar field (which always fits for Pallas).
|
||||||
let scalar = pallas::Scalar::from_bytes(&scalar_val.to_bytes()).unwrap();
|
let scalar = pallas::Scalar::from_bytes(&scalar_val.to_bytes()).unwrap();
|
||||||
let expected = Point::new(
|
let expected = NonIdentityPoint::new(
|
||||||
chip,
|
chip,
|
||||||
layouter.namespace(|| "expected point"),
|
layouter.namespace(|| "expected point"),
|
||||||
Some((base_val * scalar).to_affine()),
|
Some((base_val * scalar).to_affine()),
|
||||||
|
@ -446,7 +446,7 @@ pub mod tests {
|
||||||
)?;
|
)?;
|
||||||
base.mul(layouter.namespace(|| "random [a]B"), scalar_fixed)?
|
base.mul(layouter.namespace(|| "random [a]B"), scalar_fixed)?
|
||||||
};
|
};
|
||||||
constrain_equal(
|
constrain_equal_non_id(
|
||||||
chip.clone(),
|
chip.clone(),
|
||||||
layouter.namespace(|| "random [a]B"),
|
layouter.namespace(|| "random [a]B"),
|
||||||
base_val,
|
base_val,
|
||||||
|
@ -474,7 +474,7 @@ pub mod tests {
|
||||||
)?;
|
)?;
|
||||||
base.mul(layouter.namespace(|| "mul with double"), scalar_fixed)?
|
base.mul(layouter.namespace(|| "mul with double"), scalar_fixed)?
|
||||||
};
|
};
|
||||||
constrain_equal(
|
constrain_equal_non_id(
|
||||||
chip.clone(),
|
chip.clone(),
|
||||||
layouter.namespace(|| "mul with double"),
|
layouter.namespace(|| "mul with double"),
|
||||||
base_val,
|
base_val,
|
||||||
|
@ -492,13 +492,7 @@ pub mod tests {
|
||||||
chip.load_private(layouter.namespace(|| "zero"), column, Some(scalar_fixed))?;
|
chip.load_private(layouter.namespace(|| "zero"), column, Some(scalar_fixed))?;
|
||||||
base.mul(layouter.namespace(|| "mul by zero"), scalar_fixed)?
|
base.mul(layouter.namespace(|| "mul by zero"), scalar_fixed)?
|
||||||
};
|
};
|
||||||
constrain_equal(
|
assert!(result.is_identity().unwrap());
|
||||||
chip.clone(),
|
|
||||||
layouter.namespace(|| "mul by zero"),
|
|
||||||
base_val,
|
|
||||||
scalar_fixed,
|
|
||||||
result,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// [-1]B is the largest base field element
|
// [-1]B is the largest base field element
|
||||||
|
@ -509,7 +503,7 @@ pub mod tests {
|
||||||
chip.load_private(layouter.namespace(|| "-1"), column, Some(scalar_fixed))?;
|
chip.load_private(layouter.namespace(|| "-1"), column, Some(scalar_fixed))?;
|
||||||
base.mul(layouter.namespace(|| "mul by -1"), scalar_fixed)?
|
base.mul(layouter.namespace(|| "mul by -1"), scalar_fixed)?
|
||||||
};
|
};
|
||||||
constrain_equal(
|
constrain_equal_non_id(
|
||||||
chip,
|
chip,
|
||||||
layouter.namespace(|| "mul by -1"),
|
layouter.namespace(|| "mul by -1"),
|
||||||
base_val,
|
base_val,
|
||||||
|
|
|
@ -175,7 +175,7 @@ pub mod tests {
|
||||||
|
|
||||||
use crate::circuit::gadget::ecc::{
|
use crate::circuit::gadget::ecc::{
|
||||||
chip::{EccChip, OrchardFixedBasesFull},
|
chip::{EccChip, OrchardFixedBasesFull},
|
||||||
FixedPoint, Point,
|
FixedPoint, NonIdentityPoint, Point,
|
||||||
};
|
};
|
||||||
use crate::constants;
|
use crate::constants;
|
||||||
|
|
||||||
|
@ -229,14 +229,14 @@ pub mod tests {
|
||||||
base: FixedPoint<pallas::Affine, EccChip>,
|
base: FixedPoint<pallas::Affine, EccChip>,
|
||||||
base_val: pallas::Affine,
|
base_val: pallas::Affine,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
fn constrain_equal(
|
fn constrain_equal_non_id(
|
||||||
chip: EccChip,
|
chip: EccChip,
|
||||||
mut layouter: impl Layouter<pallas::Base>,
|
mut layouter: impl Layouter<pallas::Base>,
|
||||||
base_val: pallas::Affine,
|
base_val: pallas::Affine,
|
||||||
scalar_val: pallas::Scalar,
|
scalar_val: pallas::Scalar,
|
||||||
result: Point<pallas::Affine, EccChip>,
|
result: Point<pallas::Affine, EccChip>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let expected = Point::new(
|
let expected = NonIdentityPoint::new(
|
||||||
chip,
|
chip,
|
||||||
layouter.namespace(|| "expected point"),
|
layouter.namespace(|| "expected point"),
|
||||||
Some((base_val * scalar_val).to_affine()),
|
Some((base_val * scalar_val).to_affine()),
|
||||||
|
@ -249,7 +249,7 @@ pub mod tests {
|
||||||
let scalar_fixed = pallas::Scalar::rand();
|
let scalar_fixed = pallas::Scalar::rand();
|
||||||
|
|
||||||
let (result, _) = base.mul(layouter.namespace(|| "random [a]B"), Some(scalar_fixed))?;
|
let (result, _) = base.mul(layouter.namespace(|| "random [a]B"), Some(scalar_fixed))?;
|
||||||
constrain_equal(
|
constrain_equal_non_id(
|
||||||
chip.clone(),
|
chip.clone(),
|
||||||
layouter.namespace(|| "random [a]B"),
|
layouter.namespace(|| "random [a]B"),
|
||||||
base_val,
|
base_val,
|
||||||
|
@ -272,7 +272,7 @@ pub mod tests {
|
||||||
let (result, _) =
|
let (result, _) =
|
||||||
base.mul(layouter.namespace(|| "mul with double"), Some(scalar_fixed))?;
|
base.mul(layouter.namespace(|| "mul with double"), Some(scalar_fixed))?;
|
||||||
|
|
||||||
constrain_equal(
|
constrain_equal_non_id(
|
||||||
chip.clone(),
|
chip.clone(),
|
||||||
layouter.namespace(|| "mul with double"),
|
layouter.namespace(|| "mul with double"),
|
||||||
base_val,
|
base_val,
|
||||||
|
@ -286,20 +286,14 @@ pub mod tests {
|
||||||
{
|
{
|
||||||
let scalar_fixed = pallas::Scalar::zero();
|
let scalar_fixed = pallas::Scalar::zero();
|
||||||
let (result, _) = base.mul(layouter.namespace(|| "mul by zero"), Some(scalar_fixed))?;
|
let (result, _) = base.mul(layouter.namespace(|| "mul by zero"), Some(scalar_fixed))?;
|
||||||
constrain_equal(
|
assert!(result.is_identity().unwrap());
|
||||||
chip.clone(),
|
|
||||||
layouter.namespace(|| "mul by zero"),
|
|
||||||
base_val,
|
|
||||||
scalar_fixed,
|
|
||||||
result,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// [-1]B is the largest scalar field element.
|
// [-1]B is the largest scalar field element.
|
||||||
{
|
{
|
||||||
let scalar_fixed = -pallas::Scalar::one();
|
let scalar_fixed = -pallas::Scalar::one();
|
||||||
let (result, _) = base.mul(layouter.namespace(|| "mul by -1"), Some(scalar_fixed))?;
|
let (result, _) = base.mul(layouter.namespace(|| "mul by -1"), Some(scalar_fixed))?;
|
||||||
constrain_equal(
|
constrain_equal_non_id(
|
||||||
chip,
|
chip,
|
||||||
layouter.namespace(|| "mul by -1"),
|
layouter.namespace(|| "mul by -1"),
|
||||||
base_val,
|
base_val,
|
||||||
|
|
|
@ -244,7 +244,7 @@ pub mod tests {
|
||||||
use pasta_curves::{arithmetic::FieldExt, pallas};
|
use pasta_curves::{arithmetic::FieldExt, pallas};
|
||||||
|
|
||||||
use crate::circuit::gadget::{
|
use crate::circuit::gadget::{
|
||||||
ecc::{chip::EccChip, FixedPointShort, Point},
|
ecc::{chip::EccChip, FixedPointShort, NonIdentityPoint, Point},
|
||||||
utilities::{lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions},
|
utilities::{lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions},
|
||||||
};
|
};
|
||||||
use crate::constants::load::ValueCommitV;
|
use crate::constants::load::ValueCommitV;
|
||||||
|
@ -273,14 +273,14 @@ pub mod tests {
|
||||||
Ok((magnitude, sign))
|
Ok((magnitude, sign))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn constrain_equal(
|
fn constrain_equal_non_id(
|
||||||
chip: EccChip,
|
chip: EccChip,
|
||||||
mut layouter: impl Layouter<pallas::Base>,
|
mut layouter: impl Layouter<pallas::Base>,
|
||||||
base_val: pallas::Affine,
|
base_val: pallas::Affine,
|
||||||
scalar_val: pallas::Scalar,
|
scalar_val: pallas::Scalar,
|
||||||
result: Point<pallas::Affine, EccChip>,
|
result: Point<pallas::Affine, EccChip>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let expected = Point::new(
|
let expected = NonIdentityPoint::new(
|
||||||
chip,
|
chip,
|
||||||
layouter.namespace(|| "expected point"),
|
layouter.namespace(|| "expected point"),
|
||||||
Some((base_val * scalar_val).to_affine()),
|
Some((base_val * scalar_val).to_affine()),
|
||||||
|
@ -289,8 +289,6 @@ pub mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
let magnitude_signs = [
|
let magnitude_signs = [
|
||||||
("mul by +zero", pallas::Base::zero(), pallas::Base::one()),
|
|
||||||
("mul by -zero", pallas::Base::zero(), -pallas::Base::one()),
|
|
||||||
(
|
(
|
||||||
"random [a]B",
|
"random [a]B",
|
||||||
pallas::Base::from_u64(rand::random::<u64>()),
|
pallas::Base::from_u64(rand::random::<u64>()),
|
||||||
|
@ -347,7 +345,7 @@ pub mod tests {
|
||||||
};
|
};
|
||||||
magnitude * sign
|
magnitude * sign
|
||||||
};
|
};
|
||||||
constrain_equal(
|
constrain_equal_non_id(
|
||||||
chip.clone(),
|
chip.clone(),
|
||||||
layouter.namespace(|| *name),
|
layouter.namespace(|| *name),
|
||||||
base_val,
|
base_val,
|
||||||
|
@ -356,6 +354,24 @@ pub mod tests {
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let zero_magnitude_signs = [
|
||||||
|
("mul by +zero", pallas::Base::zero(), pallas::Base::one()),
|
||||||
|
("mul by -zero", pallas::Base::zero(), -pallas::Base::one()),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (name, magnitude, sign) in zero_magnitude_signs.iter() {
|
||||||
|
let (result, _) = {
|
||||||
|
let magnitude_sign = load_magnitude_sign(
|
||||||
|
chip.clone(),
|
||||||
|
layouter.namespace(|| *name),
|
||||||
|
*magnitude,
|
||||||
|
*sign,
|
||||||
|
)?;
|
||||||
|
value_commit_v.mul(layouter.namespace(|| *name), magnitude_sign)?
|
||||||
|
};
|
||||||
|
assert!(result.is_identity().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -489,7 +505,7 @@ pub mod tests {
|
||||||
Err(vec![
|
Err(vec![
|
||||||
VerifyFailure::ConstraintNotSatisfied {
|
VerifyFailure::ConstraintNotSatisfied {
|
||||||
constraint: (
|
constraint: (
|
||||||
(17, "Short fixed-base mul gate").into(),
|
(16, "Short fixed-base mul gate").into(),
|
||||||
0,
|
0,
|
||||||
"last_window_check"
|
"last_window_check"
|
||||||
)
|
)
|
||||||
|
@ -521,13 +537,13 @@ pub mod tests {
|
||||||
prover.verify(),
|
prover.verify(),
|
||||||
Err(vec![
|
Err(vec![
|
||||||
VerifyFailure::ConstraintNotSatisfied {
|
VerifyFailure::ConstraintNotSatisfied {
|
||||||
constraint: ((17, "Short fixed-base mul gate").into(), 1, "sign_check")
|
constraint: ((16, "Short fixed-base mul gate").into(), 1, "sign_check")
|
||||||
.into(),
|
.into(),
|
||||||
row: 26
|
row: 26
|
||||||
},
|
},
|
||||||
VerifyFailure::ConstraintNotSatisfied {
|
VerifyFailure::ConstraintNotSatisfied {
|
||||||
constraint: (
|
constraint: (
|
||||||
(17, "Short fixed-base mul gate").into(),
|
(16, "Short fixed-base mul gate").into(),
|
||||||
3,
|
3,
|
||||||
"negation_check"
|
"negation_check"
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
use super::{CellValue, EccConfig, EccPoint, NonIdentityEccPoint, Var};
|
use super::{CellValue, EccConfig, NonIdentityEccPoint, Var};
|
||||||
|
|
||||||
use group::prime::PrimeCurveAffine;
|
use group::prime::PrimeCurveAffine;
|
||||||
|
|
||||||
use halo2::{
|
use halo2::{
|
||||||
circuit::Region,
|
circuit::Region,
|
||||||
plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector, VirtualCells},
|
plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector},
|
||||||
poly::Rotation,
|
poly::Rotation,
|
||||||
};
|
};
|
||||||
use pasta_curves::{arithmetic::CurveAffine, pallas};
|
use pasta_curves::{arithmetic::CurveAffine, pallas};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
q_point: Selector,
|
|
||||||
q_point_non_id: Selector,
|
q_point_non_id: Selector,
|
||||||
// x-coordinate
|
// x-coordinate
|
||||||
pub x: Column<Advice>,
|
pub x: Column<Advice>,
|
||||||
|
@ -22,7 +21,6 @@ pub struct Config {
|
||||||
impl From<&EccConfig> for Config {
|
impl From<&EccConfig> for Config {
|
||||||
fn from(ecc_config: &EccConfig) -> Self {
|
fn from(ecc_config: &EccConfig) -> Self {
|
||||||
Self {
|
Self {
|
||||||
q_point: ecc_config.q_point,
|
|
||||||
q_point_non_id: ecc_config.q_point_non_id,
|
q_point_non_id: ecc_config.q_point_non_id,
|
||||||
x: ecc_config.advices[0],
|
x: ecc_config.advices[0],
|
||||||
y: ecc_config.advices[1],
|
y: ecc_config.advices[1],
|
||||||
|
@ -32,93 +30,23 @@ impl From<&EccConfig> for Config {
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub(super) fn create_gate(&self, meta: &mut ConstraintSystem<pallas::Base>) {
|
pub(super) fn create_gate(&self, meta: &mut ConstraintSystem<pallas::Base>) {
|
||||||
let curve_eqn = |meta: &mut VirtualCells<pallas::Base>| {
|
|
||||||
let x = meta.query_advice(self.x, Rotation::cur());
|
|
||||||
let y = meta.query_advice(self.y, Rotation::cur());
|
|
||||||
|
|
||||||
// y^2 = x^3 + b
|
|
||||||
y.square() - (x.clone().square() * x) - Expression::Constant(pallas::Affine::b())
|
|
||||||
};
|
|
||||||
|
|
||||||
meta.create_gate("witness point", |meta| {
|
|
||||||
// Check that the point being witnessed is either:
|
|
||||||
// - the identity, which is mapped to (0, 0) in affine coordinates; or
|
|
||||||
// - a valid curve point y^2 = x^3 + b, where b = 5 in the Pallas equation
|
|
||||||
|
|
||||||
let q_point = meta.query_selector(self.q_point);
|
|
||||||
let x = meta.query_advice(self.x, Rotation::cur());
|
|
||||||
let y = meta.query_advice(self.y, Rotation::cur());
|
|
||||||
|
|
||||||
vec![
|
|
||||||
("x == 0 v on_curve", q_point.clone() * x * curve_eqn(meta)),
|
|
||||||
("y == 0 v on_curve", q_point * y * curve_eqn(meta)),
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
meta.create_gate("witness non-identity point", |meta| {
|
meta.create_gate("witness non-identity point", |meta| {
|
||||||
// Check that the point being witnessed is a valid curve point y^2 = x^3 + b,
|
// Check that the point being witnessed is a valid curve point y^2 = x^3 + b,
|
||||||
// where b = 5 in the Pallas equation
|
// where b = 5 in the Pallas equation
|
||||||
|
|
||||||
let q_point_non_id = meta.query_selector(self.q_point_non_id);
|
let q_point_non_id = meta.query_selector(self.q_point_non_id);
|
||||||
|
|
||||||
vec![("on_curve", q_point_non_id * curve_eqn(meta))]
|
let x = meta.query_advice(self.x, Rotation::cur());
|
||||||
|
let y = meta.query_advice(self.y, Rotation::cur());
|
||||||
|
|
||||||
|
// y^2 = x^3 + b
|
||||||
|
let curve_eqn =
|
||||||
|
y.square() - (x.clone().square() * x) - Expression::Constant(pallas::Affine::b());
|
||||||
|
|
||||||
|
vec![("on_curve", q_point_non_id * curve_eqn)]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_xy(
|
|
||||||
&self,
|
|
||||||
value: Option<(pallas::Base, pallas::Base)>,
|
|
||||||
offset: usize,
|
|
||||||
region: &mut Region<'_, pallas::Base>,
|
|
||||||
) -> Result<(CellValue<pallas::Base>, CellValue<pallas::Base>), Error> {
|
|
||||||
// Assign `x` value
|
|
||||||
let x_val = value.map(|value| value.0);
|
|
||||||
let x_var = region.assign_advice(
|
|
||||||
|| "x",
|
|
||||||
self.x,
|
|
||||||
offset,
|
|
||||||
|| x_val.ok_or(Error::SynthesisError),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Assign `y` value
|
|
||||||
let y_val = value.map(|value| value.1);
|
|
||||||
let y_var = region.assign_advice(
|
|
||||||
|| "y",
|
|
||||||
self.y,
|
|
||||||
offset,
|
|
||||||
|| y_val.ok_or(Error::SynthesisError),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok((
|
|
||||||
CellValue::<pallas::Base>::new(x_var, x_val),
|
|
||||||
CellValue::<pallas::Base>::new(y_var, y_val),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Assigns a point that can be the identity.
|
|
||||||
pub(super) fn point(
|
|
||||||
&self,
|
|
||||||
value: Option<pallas::Affine>,
|
|
||||||
offset: usize,
|
|
||||||
region: &mut Region<'_, pallas::Base>,
|
|
||||||
) -> Result<EccPoint, Error> {
|
|
||||||
// Enable `q_point` selector
|
|
||||||
self.q_point.enable(region, offset)?;
|
|
||||||
|
|
||||||
let value = value.map(|value| {
|
|
||||||
// Map the identity to (0, 0).
|
|
||||||
if value == pallas::Affine::identity() {
|
|
||||||
(pallas::Base::zero(), pallas::Base::zero())
|
|
||||||
} else {
|
|
||||||
let value = value.coordinates().unwrap();
|
|
||||||
(*value.x(), *value.y())
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
self.assign_xy(value, offset, region)
|
|
||||||
.map(|(x, y)| EccPoint { x, y })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Assigns a non-identity point.
|
/// Assigns a non-identity point.
|
||||||
pub(super) fn point_non_id(
|
pub(super) fn point_non_id(
|
||||||
&self,
|
&self,
|
||||||
|
@ -139,8 +67,28 @@ impl Config {
|
||||||
(*value.x(), *value.y())
|
(*value.x(), *value.y())
|
||||||
});
|
});
|
||||||
|
|
||||||
self.assign_xy(value, offset, region)
|
// Assign `x` value
|
||||||
.map(|(x, y)| NonIdentityEccPoint { x, y })
|
let x_val = value.map(|value| value.0);
|
||||||
|
let x_var = region.assign_advice(
|
||||||
|
|| "x",
|
||||||
|
self.x,
|
||||||
|
offset,
|
||||||
|
|| x_val.ok_or(Error::SynthesisError),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Assign `y` value
|
||||||
|
let y_val = value.map(|value| value.1);
|
||||||
|
let y_var = region.assign_advice(
|
||||||
|
|| "y",
|
||||||
|
self.y,
|
||||||
|
offset,
|
||||||
|
|| y_val.ok_or(Error::SynthesisError),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(NonIdentityEccPoint {
|
||||||
|
x: CellValue::<pallas::Base>::new(x_var, x_val),
|
||||||
|
y: CellValue::<pallas::Base>::new(y_var, y_val),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -426,7 +426,7 @@ mod tests {
|
||||||
circuit::gadget::{
|
circuit::gadget::{
|
||||||
ecc::{
|
ecc::{
|
||||||
chip::{EccChip, EccConfig},
|
chip::{EccChip, EccConfig},
|
||||||
Point,
|
NonIdentityPoint,
|
||||||
},
|
},
|
||||||
utilities::lookup_range_check::LookupRangeCheckConfig,
|
utilities::lookup_range_check::LookupRangeCheckConfig,
|
||||||
},
|
},
|
||||||
|
@ -580,7 +580,7 @@ mod tests {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
Point::new(
|
NonIdentityPoint::new(
|
||||||
ecc_chip.clone(),
|
ecc_chip.clone(),
|
||||||
layouter.namespace(|| "Witness expected parent"),
|
layouter.namespace(|| "Witness expected parent"),
|
||||||
expected_parent,
|
expected_parent,
|
||||||
|
@ -631,7 +631,7 @@ mod tests {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
Point::new(
|
NonIdentityPoint::new(
|
||||||
ecc_chip,
|
ecc_chip,
|
||||||
layouter.namespace(|| "Witness expected result"),
|
layouter.namespace(|| "Witness expected result"),
|
||||||
expected_result,
|
expected_result,
|
||||||
|
|
Loading…
Reference in New Issue