mirror of https://github.com/zcash/halo2.git
chip::witness_point.rs: Constraints for non-identity point.
The point_non_id() method returns an error if the given point is the identity. Co-authored-by: Daira Hopwood <daira@jacaranda.org>
This commit is contained in:
parent
88eb762cf2
commit
df26a6c674
|
@ -615,6 +615,14 @@ mod tests {
|
|||
)?
|
||||
};
|
||||
|
||||
// Test witness non-identity point
|
||||
{
|
||||
super::chip::witness_point::tests::test_witness_non_id(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "witness non-identity point"),
|
||||
)
|
||||
}
|
||||
|
||||
// Test complete addition
|
||||
{
|
||||
super::chip::add::tests::test_add(
|
||||
|
|
|
@ -183,6 +183,8 @@ pub struct EccConfig {
|
|||
|
||||
/// Witness point
|
||||
pub q_point: Selector,
|
||||
/// Witness non-identity point
|
||||
pub q_point_non_id: Selector,
|
||||
|
||||
/// Lookup range check using 10-bit lookup table
|
||||
pub lookup_config: LookupRangeCheckConfig<pallas::Base, { sinsemilla::K }>,
|
||||
|
@ -279,11 +281,12 @@ impl EccChip {
|
|||
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,
|
||||
};
|
||||
|
||||
// Create witness point gate
|
||||
// Create witness point gates
|
||||
{
|
||||
let config: witness_point::Config = (&config).into();
|
||||
config.create_gate(meta);
|
||||
|
@ -393,6 +396,7 @@ impl EccInstructions<pallas::Affine> for EccChip {
|
|||
type ScalarFixedShort = EccScalarFixedShort;
|
||||
type ScalarVar = CellValue<pallas::Base>;
|
||||
type Point = EccPoint;
|
||||
type NonIdentityPoint = NonIdentityEccPoint;
|
||||
type X = CellValue<pallas::Base>;
|
||||
type FixedPoints = OrchardFixedBasesFull;
|
||||
type FixedPointsBaseField = NullifierK;
|
||||
|
@ -423,20 +427,33 @@ impl EccInstructions<pallas::Affine> for EccChip {
|
|||
let config: witness_point::Config = self.config().into();
|
||||
layouter.assign_region(
|
||||
|| "witness point",
|
||||
|mut region| config.assign_region(value, 0, &mut region),
|
||||
|mut region| config.point(value, 0, &mut region),
|
||||
)
|
||||
}
|
||||
|
||||
fn extract_p(point: &Self::Point) -> &Self::X {
|
||||
&point.x
|
||||
fn witness_point_non_id(
|
||||
&self,
|
||||
layouter: &mut impl Layouter<pallas::Base>,
|
||||
value: Option<pallas::Affine>,
|
||||
) -> Result<Self::NonIdentityPoint, Error> {
|
||||
let config: witness_point::Config = self.config().into();
|
||||
layouter.assign_region(
|
||||
|| "witness non-identity point",
|
||||
|mut region| config.point_non_id(value, 0, &mut region),
|
||||
)
|
||||
}
|
||||
|
||||
fn extract_p<Point: Into<Self::Point> + Clone>(point: &Point) -> Self::X {
|
||||
let point: EccPoint = (point.clone()).into();
|
||||
point.x()
|
||||
}
|
||||
|
||||
fn add_incomplete(
|
||||
&self,
|
||||
layouter: &mut impl Layouter<pallas::Base>,
|
||||
a: &Self::Point,
|
||||
b: &Self::Point,
|
||||
) -> Result<Self::Point, Error> {
|
||||
a: &Self::NonIdentityPoint,
|
||||
b: &Self::NonIdentityPoint,
|
||||
) -> Result<Self::NonIdentityPoint, Error> {
|
||||
let config: add_incomplete::Config = self.config().into();
|
||||
layouter.assign_region(
|
||||
|| "incomplete point addition",
|
||||
|
@ -444,16 +461,18 @@ impl EccInstructions<pallas::Affine> for EccChip {
|
|||
)
|
||||
}
|
||||
|
||||
fn add(
|
||||
fn add<A: Into<Self::Point> + Clone, B: Into<Self::Point> + Clone>(
|
||||
&self,
|
||||
layouter: &mut impl Layouter<pallas::Base>,
|
||||
a: &Self::Point,
|
||||
b: &Self::Point,
|
||||
a: &A,
|
||||
b: &B,
|
||||
) -> Result<Self::Point, Error> {
|
||||
let config: add::Config = self.config().into();
|
||||
layouter.assign_region(
|
||||
|| "complete point addition",
|
||||
|mut region| config.assign_region(a, b, 0, &mut region),
|
||||
|mut region| {
|
||||
config.assign_region(&(a.clone()).into(), &(b.clone()).into(), 0, &mut region)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -461,7 +480,7 @@ impl EccInstructions<pallas::Affine> for EccChip {
|
|||
&self,
|
||||
layouter: &mut impl Layouter<pallas::Base>,
|
||||
scalar: &Self::Var,
|
||||
base: &Self::Point,
|
||||
base: &Self::NonIdentityPoint,
|
||||
) -> Result<(Self::Point, Self::ScalarVar), Error> {
|
||||
let config: mul::Config = self.config().into();
|
||||
config.assign(
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use super::{CellValue, EccConfig, EccPoint, Var};
|
||||
use super::{CellValue, EccConfig, EccPoint, NonIdentityEccPoint, Var};
|
||||
|
||||
use group::prime::PrimeCurveAffine;
|
||||
|
||||
use halo2::{
|
||||
circuit::Region,
|
||||
plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector},
|
||||
plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector, VirtualCells},
|
||||
poly::Rotation,
|
||||
};
|
||||
use pasta_curves::{arithmetic::CurveAffine, pallas};
|
||||
|
@ -12,6 +12,7 @@ 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>,
|
||||
// y-coordinate
|
||||
|
@ -22,6 +23,7 @@ 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],
|
||||
}
|
||||
|
@ -30,8 +32,18 @@ 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.clone().square()
|
||||
- (x.clone().square() * x.clone())
|
||||
- Expression::Constant(pallas::Affine::b())
|
||||
};
|
||||
|
||||
meta.create_gate("witness point", |meta| {
|
||||
// Check that either the point being witness is either:
|
||||
// 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
|
||||
|
||||
|
@ -39,37 +51,28 @@ impl Config {
|
|||
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.clone().square()
|
||||
- (x.clone().square() * x.clone())
|
||||
- Expression::Constant(pallas::Affine::b());
|
||||
|
||||
vec![
|
||||
("x == 0 ∨ on_curve", q_point.clone() * x * curve_eqn.clone()),
|
||||
("y == 0 ∨ on_curve", q_point * y * curve_eqn),
|
||||
("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))]
|
||||
});
|
||||
}
|
||||
|
||||
pub(super) fn assign_region(
|
||||
fn assign_xy(
|
||||
&self,
|
||||
value: Option<pallas::Affine>,
|
||||
value: Option<(pallas::Base, pallas::Base)>,
|
||||
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())
|
||||
}
|
||||
});
|
||||
|
||||
) -> 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(
|
||||
|
@ -88,9 +91,83 @@ impl Config {
|
|||
|| y_val.ok_or(Error::SynthesisError),
|
||||
)?;
|
||||
|
||||
Ok(EccPoint {
|
||||
x: CellValue::<pallas::Base>::new(x_var, x_val),
|
||||
y: CellValue::<pallas::Base>::new(y_var, y_val),
|
||||
})
|
||||
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,
|
||||
value: Option<pallas::Affine>,
|
||||
offset: usize,
|
||||
region: &mut Region<'_, pallas::Base>,
|
||||
) -> Result<NonIdentityEccPoint, Error> {
|
||||
// Enable `q_point_non_id` selector
|
||||
self.q_point_non_id.enable(region, offset)?;
|
||||
|
||||
if let Some(value) = value {
|
||||
// Return an error if the point is the identity.
|
||||
if value == pallas::Affine::identity() {
|
||||
return Err(Error::SynthesisError);
|
||||
}
|
||||
};
|
||||
|
||||
let value = value.map(|value| {
|
||||
let value = value.coordinates().unwrap();
|
||||
(*value.x(), *value.y())
|
||||
});
|
||||
|
||||
self.assign_xy(value, offset, region)
|
||||
.map(|(x, y)| NonIdentityEccPoint { x, y })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use halo2::circuit::Layouter;
|
||||
use pasta_curves::pallas;
|
||||
|
||||
use super::*;
|
||||
use crate::circuit::gadget::ecc::{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>,
|
||||
) {
|
||||
// Witnessing the identity should return an error.
|
||||
NonIdentityPoint::new(
|
||||
chip,
|
||||
layouter.namespace(|| "witness identity"),
|
||||
Some(pallas::Affine::identity()),
|
||||
)
|
||||
.expect_err("witnessing 𝒪 should return an error");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue