mirror of https://github.com/zcash/orchard.git
gadget::ecc.rs: Add EccInstructions::constrain_equal() instruction.
This allows us to constrain two points to be equal in value at the gadget level. Co-authored-by: Jack Grigg <jack@electriccoin.co>
This commit is contained in:
parent
a11c2066ef
commit
7341996d2c
|
@ -43,6 +43,14 @@ pub trait EccInstructions<C: CurveAffine>: Chip<C::Base> {
|
||||||
/// Enumeration of the set of fixed bases to be used in short signed scalar mul.
|
/// Enumeration of the set of fixed bases to be used in short signed scalar mul.
|
||||||
type FixedPointsShort: Clone + Debug;
|
type FixedPointsShort: Clone + Debug;
|
||||||
|
|
||||||
|
/// Constrains point `a` to be equal in value to point `b`.
|
||||||
|
fn constrain_equal(
|
||||||
|
&self,
|
||||||
|
layouter: &mut impl Layouter<C::Base>,
|
||||||
|
a: &Self::Point,
|
||||||
|
b: &Self::Point,
|
||||||
|
) -> Result<(), Error>;
|
||||||
|
|
||||||
/// Witnesses the given base field element as a private input to the circuit
|
/// Witnesses the given base field element as a private input to the circuit
|
||||||
/// for variable-base scalar mul.
|
/// for variable-base scalar mul.
|
||||||
fn witness_scalar_var(
|
fn witness_scalar_var(
|
||||||
|
@ -237,6 +245,16 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> Point<C,
|
||||||
point.map(|inner| Point { chip, inner })
|
point.map(|inner| Point { chip, inner })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constrains this point to be equal in value to another point.
|
||||||
|
pub fn constrain_equal(
|
||||||
|
&self,
|
||||||
|
mut layouter: impl Layouter<C::Base>,
|
||||||
|
other: &Self,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.chip
|
||||||
|
.constrain_equal(&mut layouter, &self.inner, &other.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).clone())
|
X::from_inner(self.chip.clone(), EccChip::extract_p(&self.inner).clone())
|
||||||
|
|
|
@ -178,6 +178,24 @@ impl EccInstructions<pallas::Affine> for EccChip {
|
||||||
type FixedPoints = (); // TODO
|
type FixedPoints = (); // TODO
|
||||||
type FixedPointsShort = (); // TODO
|
type FixedPointsShort = (); // TODO
|
||||||
|
|
||||||
|
fn constrain_equal(
|
||||||
|
&self,
|
||||||
|
layouter: &mut impl Layouter<pallas::Base>,
|
||||||
|
a: &Self::Point,
|
||||||
|
b: &Self::Point,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let config = self.config().clone();
|
||||||
|
layouter.assign_region(
|
||||||
|
|| "constrain equal",
|
||||||
|
|mut region| {
|
||||||
|
// Constrain x-coordinates
|
||||||
|
region.constrain_equal(&config.perm, a.x().cell(), b.x().cell())?;
|
||||||
|
// Constrain x-coordinates
|
||||||
|
region.constrain_equal(&config.perm, a.y().cell(), b.y().cell())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn witness_scalar_var(
|
fn witness_scalar_var(
|
||||||
&self,
|
&self,
|
||||||
_layouter: &mut impl Layouter<pallas::Base>,
|
_layouter: &mut impl Layouter<pallas::Base>,
|
||||||
|
|
|
@ -407,22 +407,50 @@ 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)
|
||||||
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) = 0"), zero)?;
|
||||||
|
}
|
||||||
|
|
||||||
// Check complete addition 𝒪 + 𝒪
|
// Check complete addition 𝒪 + 𝒪
|
||||||
zero.add(layouter.namespace(|| "𝒪 + 𝒪"), zero)?;
|
{
|
||||||
|
let result = zero.add(layouter.namespace(|| "𝒪 + 𝒪"), zero)?;
|
||||||
|
result.constrain_equal(layouter.namespace(|| "P + (-P) = 0"), zero)?;
|
||||||
|
}
|
||||||
|
|
||||||
// Check P + Q
|
// Check P + Q
|
||||||
p.add(layouter.namespace(|| "P + Q"), q)?;
|
{
|
||||||
|
let result = p.add(layouter.namespace(|| "P + Q"), q)?;
|
||||||
|
let witnessed_result = Point::new(
|
||||||
|
chip.clone(),
|
||||||
|
layouter.namespace(|| "witnessed P + Q"),
|
||||||
|
Some((p_val + q_val).to_affine()),
|
||||||
|
)?;
|
||||||
|
result.constrain_equal(layouter.namespace(|| "constrain P + Q"), &witnessed_result)?;
|
||||||
|
}
|
||||||
|
|
||||||
// P + P
|
// P + P
|
||||||
p.add(layouter.namespace(|| "P + P"), p)?;
|
{
|
||||||
|
let result = p.add(layouter.namespace(|| "P + P"), p)?;
|
||||||
|
let witnessed_result = Point::new(
|
||||||
|
chip.clone(),
|
||||||
|
layouter.namespace(|| "witnessed P + P"),
|
||||||
|
Some((p_val + p_val).to_affine()),
|
||||||
|
)?;
|
||||||
|
result.constrain_equal(layouter.namespace(|| "constrain P + P"), &witnessed_result)?;
|
||||||
|
}
|
||||||
|
|
||||||
// P + 𝒪
|
// P + 𝒪
|
||||||
p.add(layouter.namespace(|| "P + 𝒪"), zero)?;
|
{
|
||||||
|
let result = p.add(layouter.namespace(|| "P + 𝒪"), zero)?;
|
||||||
|
result.constrain_equal(layouter.namespace(|| "P + 𝒪 = P"), p)?;
|
||||||
|
}
|
||||||
|
|
||||||
// 𝒪 + P
|
// 𝒪 + P
|
||||||
zero.add(layouter.namespace(|| "𝒪 + P"), p)?;
|
{
|
||||||
|
let result = zero.add(layouter.namespace(|| "𝒪 + P"), p)?;
|
||||||
|
result.constrain_equal(layouter.namespace(|| "𝒪 + P = P"), p)?;
|
||||||
|
}
|
||||||
|
|
||||||
// (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();
|
||||||
|
|
Loading…
Reference in New Issue