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,
|
||||
) -> 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.
|
||||
/// This returns an error if the point is the identity.
|
||||
fn witness_point_non_id(
|
||||
|
@ -73,6 +65,9 @@ pub trait EccInstructions<C: CurveAffine>: Chip<C::Base> + UtilitiesInstructions
|
|||
value: Option<C>,
|
||||
) -> 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.
|
||||
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> {
|
||||
/// 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.
|
||||
pub fn constrain_equal<Other: Into<Point<C, EccChip>> + Clone>(
|
||||
&self,
|
||||
|
@ -337,6 +321,11 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> Point<C,
|
|||
&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.
|
||||
pub fn extract_p(&self) -> X<C, EccChip> {
|
||||
X::from_inner(self.chip.clone(), EccChip::extract_p(&self.inner))
|
||||
|
@ -513,7 +502,7 @@ where
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use group::{prime::PrimeCurveAffine, Curve, Group};
|
||||
use group::{Curve, Group};
|
||||
|
||||
use halo2::{
|
||||
circuit::{Layouter, SimpleFloorPlanner},
|
||||
|
@ -604,15 +593,6 @@ 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 = {
|
||||
super::Point::new(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "identity"),
|
||||
Some(pallas::Affine::identity()),
|
||||
)?
|
||||
};
|
||||
|
||||
// Test witness non-identity point
|
||||
{
|
||||
super::chip::witness_point::tests::test_witness_non_id(
|
||||
|
@ -626,7 +606,6 @@ mod tests {
|
|||
super::chip::add::tests::test_add(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "complete addition"),
|
||||
&zero,
|
||||
p_val,
|
||||
&p,
|
||||
q_val,
|
||||
|
|
|
@ -181,8 +181,6 @@ pub struct EccConfig {
|
|||
/// when the scalar is a signed short exponent or a base-field element.
|
||||
pub q_mul_fixed_running_sum: Selector,
|
||||
|
||||
/// Witness point
|
||||
pub q_point: Selector,
|
||||
/// Witness non-identity point
|
||||
pub q_point_non_id: Selector,
|
||||
|
||||
|
@ -280,7 +278,6 @@ impl EccChip {
|
|||
q_mul_fixed_short: meta.selector(),
|
||||
q_mul_fixed_base_field: meta.selector(),
|
||||
q_mul_fixed_running_sum,
|
||||
q_point: meta.selector(),
|
||||
q_point_non_id: meta.selector(),
|
||||
lookup_config: range_check,
|
||||
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(
|
||||
&self,
|
||||
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 {
|
||||
let point: EccPoint = (point.clone()).into();
|
||||
point.x()
|
||||
|
|
|
@ -391,13 +391,12 @@ pub mod tests {
|
|||
use halo2::{circuit::Layouter, plonk::Error};
|
||||
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)]
|
||||
pub fn test_add<EccChip: EccInstructions<pallas::Affine> + Clone + Eq + std::fmt::Debug>(
|
||||
chip: EccChip,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
zero: &Point<pallas::Affine, EccChip>,
|
||||
p_val: pallas::Affine,
|
||||
p: &NonIdentityPoint<pallas::Affine, EccChip>,
|
||||
q_val: pallas::Affine,
|
||||
|
@ -408,21 +407,22 @@ pub mod tests {
|
|||
assert_ne!(p_val, q_val);
|
||||
|
||||
// Check complete addition P + (-P)
|
||||
{
|
||||
let zero = {
|
||||
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 𝒪 + 𝒪
|
||||
{
|
||||
let result = zero.add(layouter.namespace(|| "𝒪 + 𝒪"), zero)?;
|
||||
result.constrain_equal(layouter.namespace(|| "𝒪 + 𝒪 = 𝒪"), zero)?;
|
||||
let result = zero.add(layouter.namespace(|| "𝒪 + 𝒪"), &zero)?;
|
||||
result.constrain_equal(layouter.namespace(|| "𝒪 + 𝒪 = 𝒪"), &zero)?;
|
||||
}
|
||||
|
||||
// Check P + Q
|
||||
{
|
||||
let result = p.add(layouter.namespace(|| "P + Q"), q)?;
|
||||
let witnessed_result = Point::new(
|
||||
let witnessed_result = NonIdentityPoint::new(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "witnessed P + Q"),
|
||||
Some((p_val + q_val).to_affine()),
|
||||
|
@ -433,7 +433,7 @@ pub mod tests {
|
|||
// P + P
|
||||
{
|
||||
let result = p.add(layouter.namespace(|| "P + P"), p)?;
|
||||
let witnessed_result = Point::new(
|
||||
let witnessed_result = NonIdentityPoint::new(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "witnessed P + P"),
|
||||
Some((p_val + p_val).to_affine()),
|
||||
|
@ -443,7 +443,7 @@ pub mod tests {
|
|||
|
||||
// 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)?;
|
||||
}
|
||||
|
||||
|
@ -455,7 +455,7 @@ pub mod tests {
|
|||
|
||||
// (x, y) + (ζx, y) should behave like normal P + Q.
|
||||
let endo_p = p_val.to_curve().endo();
|
||||
let endo_p = Point::new(
|
||||
let endo_p = NonIdentityPoint::new(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "endo(P)"),
|
||||
Some(endo_p.to_affine()),
|
||||
|
@ -464,7 +464,7 @@ pub mod tests {
|
|||
|
||||
// (x, y) + (ζx, -y) should also behave like normal P + Q.
|
||||
let endo_p_neg = (-p_val).to_curve().endo();
|
||||
let endo_p_neg = Point::new(
|
||||
let endo_p_neg = NonIdentityPoint::new(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "endo(-P)"),
|
||||
Some(endo_p_neg.to_affine()),
|
||||
|
@ -473,7 +473,7 @@ pub mod tests {
|
|||
|
||||
// (x, y) + ((ζ^2)x, y)
|
||||
let endo_2_p = p_val.to_curve().endo().endo();
|
||||
let endo_2_p = Point::new(
|
||||
let endo_2_p = NonIdentityPoint::new(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "endo^2(P)"),
|
||||
Some(endo_2_p.to_affine()),
|
||||
|
@ -482,7 +482,7 @@ pub mod tests {
|
|||
|
||||
// (x, y) + ((ζ^2)x, -y)
|
||||
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,
|
||||
layouter.namespace(|| "endo^2(-P)"),
|
||||
Some(endo_2_p_neg.to_affine()),
|
||||
|
|
|
@ -464,7 +464,7 @@ pub mod tests {
|
|||
) -> Result<(), Error> {
|
||||
let column = chip.config().advices[0];
|
||||
|
||||
fn constrain_equal<
|
||||
fn constrain_equal_non_id<
|
||||
EccChip: EccInstructions<pallas::Affine> + Clone + Eq + std::fmt::Debug,
|
||||
>(
|
||||
chip: EccChip,
|
||||
|
@ -476,7 +476,7 @@ pub mod tests {
|
|||
// 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 expected = Point::new(
|
||||
let expected = NonIdentityPoint::new(
|
||||
chip,
|
||||
layouter.namespace(|| "expected point"),
|
||||
Some((base_val * scalar).to_affine()),
|
||||
|
@ -495,7 +495,7 @@ pub mod tests {
|
|||
)?;
|
||||
p.mul(layouter.namespace(|| "random [a]B"), &scalar)?
|
||||
};
|
||||
constrain_equal(
|
||||
constrain_equal_non_id(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "random [a]B"),
|
||||
p_val,
|
||||
|
@ -513,13 +513,7 @@ pub mod tests {
|
|||
chip.load_private(layouter.namespace(|| "zero"), column, Some(scalar_val))?;
|
||||
p.mul(layouter.namespace(|| "[0]B"), &scalar)?
|
||||
};
|
||||
constrain_equal(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "[0]B"),
|
||||
p_val,
|
||||
scalar_val,
|
||||
result,
|
||||
)?;
|
||||
assert!(result.is_identity().unwrap());
|
||||
}
|
||||
|
||||
// [-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))?;
|
||||
p.mul(layouter.namespace(|| "[-1]B"), &scalar)?
|
||||
};
|
||||
constrain_equal(
|
||||
constrain_equal_non_id(
|
||||
chip,
|
||||
layouter.namespace(|| "[-1]B"),
|
||||
p_val,
|
||||
|
|
|
@ -389,7 +389,7 @@ pub mod tests {
|
|||
use crate::circuit::gadget::{
|
||||
ecc::{
|
||||
chip::{EccChip, NullifierK},
|
||||
FixedPointBaseField, Point,
|
||||
FixedPointBaseField, NonIdentityPoint, Point,
|
||||
},
|
||||
utilities::UtilitiesInstructions,
|
||||
};
|
||||
|
@ -418,7 +418,7 @@ pub mod tests {
|
|||
) -> Result<(), Error> {
|
||||
let column = chip.config().advices[0];
|
||||
|
||||
fn constrain_equal(
|
||||
fn constrain_equal_non_id(
|
||||
chip: EccChip,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
base_val: pallas::Affine,
|
||||
|
@ -427,7 +427,7 @@ pub mod tests {
|
|||
) -> Result<(), Error> {
|
||||
// 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 expected = Point::new(
|
||||
let expected = NonIdentityPoint::new(
|
||||
chip,
|
||||
layouter.namespace(|| "expected point"),
|
||||
Some((base_val * scalar).to_affine()),
|
||||
|
@ -446,7 +446,7 @@ pub mod tests {
|
|||
)?;
|
||||
base.mul(layouter.namespace(|| "random [a]B"), scalar_fixed)?
|
||||
};
|
||||
constrain_equal(
|
||||
constrain_equal_non_id(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "random [a]B"),
|
||||
base_val,
|
||||
|
@ -474,7 +474,7 @@ pub mod tests {
|
|||
)?;
|
||||
base.mul(layouter.namespace(|| "mul with double"), scalar_fixed)?
|
||||
};
|
||||
constrain_equal(
|
||||
constrain_equal_non_id(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "mul with double"),
|
||||
base_val,
|
||||
|
@ -492,13 +492,7 @@ pub mod tests {
|
|||
chip.load_private(layouter.namespace(|| "zero"), column, Some(scalar_fixed))?;
|
||||
base.mul(layouter.namespace(|| "mul by zero"), scalar_fixed)?
|
||||
};
|
||||
constrain_equal(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "mul by zero"),
|
||||
base_val,
|
||||
scalar_fixed,
|
||||
result,
|
||||
)?;
|
||||
assert!(result.is_identity().unwrap());
|
||||
}
|
||||
|
||||
// [-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))?;
|
||||
base.mul(layouter.namespace(|| "mul by -1"), scalar_fixed)?
|
||||
};
|
||||
constrain_equal(
|
||||
constrain_equal_non_id(
|
||||
chip,
|
||||
layouter.namespace(|| "mul by -1"),
|
||||
base_val,
|
||||
|
|
|
@ -175,7 +175,7 @@ pub mod tests {
|
|||
|
||||
use crate::circuit::gadget::ecc::{
|
||||
chip::{EccChip, OrchardFixedBasesFull},
|
||||
FixedPoint, Point,
|
||||
FixedPoint, NonIdentityPoint, Point,
|
||||
};
|
||||
use crate::constants;
|
||||
|
||||
|
@ -229,14 +229,14 @@ pub mod tests {
|
|||
base: FixedPoint<pallas::Affine, EccChip>,
|
||||
base_val: pallas::Affine,
|
||||
) -> Result<(), Error> {
|
||||
fn constrain_equal(
|
||||
fn constrain_equal_non_id(
|
||||
chip: EccChip,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
base_val: pallas::Affine,
|
||||
scalar_val: pallas::Scalar,
|
||||
result: Point<pallas::Affine, EccChip>,
|
||||
) -> Result<(), Error> {
|
||||
let expected = Point::new(
|
||||
let expected = NonIdentityPoint::new(
|
||||
chip,
|
||||
layouter.namespace(|| "expected point"),
|
||||
Some((base_val * scalar_val).to_affine()),
|
||||
|
@ -249,7 +249,7 @@ pub mod tests {
|
|||
let scalar_fixed = pallas::Scalar::rand();
|
||||
|
||||
let (result, _) = base.mul(layouter.namespace(|| "random [a]B"), Some(scalar_fixed))?;
|
||||
constrain_equal(
|
||||
constrain_equal_non_id(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "random [a]B"),
|
||||
base_val,
|
||||
|
@ -272,7 +272,7 @@ pub mod tests {
|
|||
let (result, _) =
|
||||
base.mul(layouter.namespace(|| "mul with double"), Some(scalar_fixed))?;
|
||||
|
||||
constrain_equal(
|
||||
constrain_equal_non_id(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "mul with double"),
|
||||
base_val,
|
||||
|
@ -286,20 +286,14 @@ pub mod tests {
|
|||
{
|
||||
let scalar_fixed = pallas::Scalar::zero();
|
||||
let (result, _) = base.mul(layouter.namespace(|| "mul by zero"), Some(scalar_fixed))?;
|
||||
constrain_equal(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "mul by zero"),
|
||||
base_val,
|
||||
scalar_fixed,
|
||||
result,
|
||||
)?;
|
||||
assert!(result.is_identity().unwrap());
|
||||
}
|
||||
|
||||
// [-1]B is the largest scalar field element.
|
||||
{
|
||||
let scalar_fixed = -pallas::Scalar::one();
|
||||
let (result, _) = base.mul(layouter.namespace(|| "mul by -1"), Some(scalar_fixed))?;
|
||||
constrain_equal(
|
||||
constrain_equal_non_id(
|
||||
chip,
|
||||
layouter.namespace(|| "mul by -1"),
|
||||
base_val,
|
||||
|
|
|
@ -244,7 +244,7 @@ pub mod tests {
|
|||
use pasta_curves::{arithmetic::FieldExt, pallas};
|
||||
|
||||
use crate::circuit::gadget::{
|
||||
ecc::{chip::EccChip, FixedPointShort, Point},
|
||||
ecc::{chip::EccChip, FixedPointShort, NonIdentityPoint, Point},
|
||||
utilities::{lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions},
|
||||
};
|
||||
use crate::constants::load::ValueCommitV;
|
||||
|
@ -273,14 +273,14 @@ pub mod tests {
|
|||
Ok((magnitude, sign))
|
||||
}
|
||||
|
||||
fn constrain_equal(
|
||||
fn constrain_equal_non_id(
|
||||
chip: EccChip,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
base_val: pallas::Affine,
|
||||
scalar_val: pallas::Scalar,
|
||||
result: Point<pallas::Affine, EccChip>,
|
||||
) -> Result<(), Error> {
|
||||
let expected = Point::new(
|
||||
let expected = NonIdentityPoint::new(
|
||||
chip,
|
||||
layouter.namespace(|| "expected point"),
|
||||
Some((base_val * scalar_val).to_affine()),
|
||||
|
@ -289,8 +289,6 @@ pub mod tests {
|
|||
}
|
||||
|
||||
let magnitude_signs = [
|
||||
("mul by +zero", pallas::Base::zero(), pallas::Base::one()),
|
||||
("mul by -zero", pallas::Base::zero(), -pallas::Base::one()),
|
||||
(
|
||||
"random [a]B",
|
||||
pallas::Base::from_u64(rand::random::<u64>()),
|
||||
|
@ -347,7 +345,7 @@ pub mod tests {
|
|||
};
|
||||
magnitude * sign
|
||||
};
|
||||
constrain_equal(
|
||||
constrain_equal_non_id(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| *name),
|
||||
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(())
|
||||
}
|
||||
|
||||
|
@ -489,7 +505,7 @@ pub mod tests {
|
|||
Err(vec![
|
||||
VerifyFailure::ConstraintNotSatisfied {
|
||||
constraint: (
|
||||
(17, "Short fixed-base mul gate").into(),
|
||||
(16, "Short fixed-base mul gate").into(),
|
||||
0,
|
||||
"last_window_check"
|
||||
)
|
||||
|
@ -521,13 +537,13 @@ pub mod tests {
|
|||
prover.verify(),
|
||||
Err(vec![
|
||||
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(),
|
||||
row: 26
|
||||
},
|
||||
VerifyFailure::ConstraintNotSatisfied {
|
||||
constraint: (
|
||||
(17, "Short fixed-base mul gate").into(),
|
||||
(16, "Short fixed-base mul gate").into(),
|
||||
3,
|
||||
"negation_check"
|
||||
)
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
use super::{CellValue, EccConfig, EccPoint, NonIdentityEccPoint, Var};
|
||||
use super::{CellValue, EccConfig, NonIdentityEccPoint, Var};
|
||||
|
||||
use group::prime::PrimeCurveAffine;
|
||||
|
||||
use halo2::{
|
||||
circuit::Region,
|
||||
plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector, VirtualCells},
|
||||
plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector},
|
||||
poly::Rotation,
|
||||
};
|
||||
use pasta_curves::{arithmetic::CurveAffine, pallas};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Config {
|
||||
q_point: Selector,
|
||||
q_point_non_id: Selector,
|
||||
// x-coordinate
|
||||
pub x: Column<Advice>,
|
||||
|
@ -22,7 +21,6 @@ pub struct Config {
|
|||
impl From<&EccConfig> for Config {
|
||||
fn from(ecc_config: &EccConfig) -> Self {
|
||||
Self {
|
||||
q_point: ecc_config.q_point,
|
||||
q_point_non_id: ecc_config.q_point_non_id,
|
||||
x: ecc_config.advices[0],
|
||||
y: ecc_config.advices[1],
|
||||
|
@ -32,93 +30,23 @@ impl From<&EccConfig> for Config {
|
|||
|
||||
impl Config {
|
||||
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| {
|
||||
// Check that the point being witnessed is a valid curve point y^2 = x^3 + b,
|
||||
// where b = 5 in the Pallas equation
|
||||
|
||||
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.
|
||||
pub(super) fn point_non_id(
|
||||
&self,
|
||||
|
@ -139,8 +67,28 @@ impl Config {
|
|||
(*value.x(), *value.y())
|
||||
});
|
||||
|
||||
self.assign_xy(value, offset, region)
|
||||
.map(|(x, y)| NonIdentityEccPoint { x, y })
|
||||
// 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(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::{
|
||||
ecc::{
|
||||
chip::{EccChip, EccConfig},
|
||||
Point,
|
||||
NonIdentityPoint,
|
||||
},
|
||||
utilities::lookup_range_check::LookupRangeCheckConfig,
|
||||
},
|
||||
|
@ -580,7 +580,7 @@ mod tests {
|
|||
None
|
||||
};
|
||||
|
||||
Point::new(
|
||||
NonIdentityPoint::new(
|
||||
ecc_chip.clone(),
|
||||
layouter.namespace(|| "Witness expected parent"),
|
||||
expected_parent,
|
||||
|
@ -631,7 +631,7 @@ mod tests {
|
|||
None
|
||||
};
|
||||
|
||||
Point::new(
|
||||
NonIdentityPoint::new(
|
||||
ecc_chip,
|
||||
layouter.namespace(|| "Witness expected result"),
|
||||
expected_result,
|
||||
|
|
Loading…
Reference in New Issue