diff --git a/src/circuit/gadget/ecc.rs b/src/circuit/gadget/ecc.rs index 7c41f579..23efe03f 100644 --- a/src/circuit/gadget/ecc.rs +++ b/src/circuit/gadget/ecc.rs @@ -68,6 +68,7 @@ pub trait EccInstructions: Chip { ) -> Result; /// 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, @@ -447,7 +448,13 @@ mod tests { assert_ne!(p_val, q_val); // Generate a (0,0) point to be used in other tests. - let zero = p.add(layouter.namespace(|| "P + (-P)"), &p_neg)?; + let zero = { + super::Point::new( + chip.clone(), + layouter.namespace(|| "identity"), + Some(C::identity()), + )? + }; // Test complete addition { diff --git a/src/circuit/gadget/ecc/chip/witness_point.rs b/src/circuit/gadget/ecc/chip/witness_point.rs index 1d1377b0..c582e9cd 100644 --- a/src/circuit/gadget/ecc/chip/witness_point.rs +++ b/src/circuit/gadget/ecc/chip/witness_point.rs @@ -1,5 +1,6 @@ use super::{CellValue, EccConfig, EccPoint, Var}; +use ff::Field; use halo2::{ arithmetic::CurveAffine, circuit::Region, @@ -33,14 +34,22 @@ impl From<&EccConfig> for Config { impl Config { pub(super) fn create_gate(&self, meta: &mut ConstraintSystem) { meta.create_gate("witness point", |meta| { + // Check that either the point being witness 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()); - // Check that y^2 = x^3 + b, where b = 5 in the Pallas equation + // y^2 = x^3 + b + let curve_eqn = y.clone() * y.clone() + - (x.clone() * x.clone() * x.clone()) + - Expression::Constant(C::b()); + vec![ - q_point - * (y.clone() * y - (x.clone() * x.clone() * x) - Expression::Constant(C::b())), + q_point.clone() * x * curve_eqn.clone(), + q_point * y * curve_eqn, ] }); } @@ -54,10 +63,18 @@ impl Config { // Enable `q_point` selector self.q_point.enable(region, offset)?; - let value = value.map(|value| value.coordinates().unwrap()); + let value = value.map(|value| { + // Map the identity to (0, 0). + if value == C::identity() { + (C::Base::zero(), C::Base::zero()) + } else { + let value = value.coordinates().unwrap(); + (*value.x(), *value.y()) + } + }); // Assign `x` value - let x_val = value.map(|value| *value.x()); + let x_val = value.map(|value| value.0); let x_var = region.assign_advice( || "x", self.x, @@ -66,7 +83,7 @@ impl Config { )?; // Assign `y` value - let y_val = value.map(|value| *value.y()); + let y_val = value.map(|value| value.1); let y_var = region.assign_advice( || "y", self.y,