diff --git a/src/circuit/gadget/ecc.rs b/src/circuit/gadget/ecc.rs index 36f27446..5e325c86 100644 --- a/src/circuit/gadget/ecc.rs +++ b/src/circuit/gadget/ecc.rs @@ -1,6 +1,6 @@ //! Gadgets for elliptic curve operations. -use std::fmt; +use std::fmt::Debug; use halo2::{ arithmetic::CurveAffine, @@ -8,32 +8,48 @@ use halo2::{ plonk::Error, }; -/// Trait allowing circuit's fixed points to be enumerated. -pub trait FixedPoints: Clone + fmt::Debug {} - /// The set of circuit instructions required to use the ECC gadgets. pub trait EccInstructions: Chip { + /// Variable representing an element of the elliptic curve's base field, that + /// is used as a scalar in variable-base scalar mul. + /// + /// It is not true in general that a scalar field element fits in a curve's + /// base field, and in particular it is untrue for the Pallas curve, whose + /// scalar field `Fq` is larger than its base field `Fp`. + /// + /// However, the only use of variable-base scalar mul in the Orchard protocol + /// is in deriving diversified addresses `[ivk] g_d`, and `ivk` is guaranteed + /// to be in the base field of the curve. (See non-normative notes in + /// https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents.) + type ScalarVar: Clone + Debug; /// Variable representing a full-width element of the elliptic curve's scalar field, to be used for fixed-base scalar mul. - type ScalarFixed: Clone + fmt::Debug; + type ScalarFixed: Clone + Debug; /// Variable representing a signed short element of the elliptic curve's scalar field, to be used for fixed-base scalar mul. - type ScalarFixedShort: Clone + fmt::Debug; + type ScalarFixedShort: Clone + Debug; /// Variable representing an elliptic curve point. - type Point: Clone + fmt::Debug; + type Point: Clone + Debug; /// Variable representing the x-coordinate of an elliptic curve point. - type X: Clone + fmt::Debug; + type X: Clone + Debug; /// Variable representing the set of fixed bases in the circuit. - type FixedPoints: FixedPoints; + type FixedPoints: Clone + Debug; /// Variable representing a fixed elliptic curve point (constant in the circuit). - type FixedPoint: Clone + fmt::Debug; + type FixedPoint: Clone + Debug; - /// Witnesses the given full-width scalar as a private input to the circuit for fixed-based scalar mul. + /// Witnesses the given base field element as a private input to the circuit for variable-base scalar mul. + fn witness_scalar_var( + &self, + layouter: &mut impl Layouter, + value: Option, + ) -> Result; + + /// Witnesses the given full-width scalar as a private input to the circuit for fixed-base scalar mul. fn witness_scalar_fixed( &self, layouter: &mut impl Layouter, value: Option, ) -> Result; - /// Witnesses the given signed short scalar as a private input to the circuit for fixed-based scalar mul. + /// Witnesses the given signed short scalar as a private input to the circuit for fixed-base scalar mul. fn witness_scalar_fixed_short( &self, layouter: &mut impl Layouter, @@ -50,11 +66,13 @@ pub trait EccInstructions: Chip { /// Extracts the x-coordinate of a point. fn extract_p(point: &Self::Point) -> &Self::X; - /// Gets a fixed point into the circuit. + /// Returns a fixed point that had been previously loaded into the circuit. + /// The pre-loaded cells are used to set up equality constraints in other + /// parts of the circuit where the fixed base is used. fn get_fixed(&self, fixed_points: Self::FixedPoints) -> Result; - /// Performs point addition, returning `a + b`. - fn add( + /// Performs incomplete point addition, returning `a + b`. + fn add_incomplete( &self, layouter: &mut impl Layouter, a: &Self::Point, @@ -62,7 +80,7 @@ pub trait EccInstructions: Chip { ) -> Result; /// Performs complete point addition, returning `a + b`. - fn add_complete( + fn add( &self, layouter: &mut impl Layouter, a: &Self::Point, @@ -73,7 +91,7 @@ pub trait EccInstructions: Chip { fn mul( &self, layouter: &mut impl Layouter, - scalar: C::Scalar, + scalar: &Self::ScalarVar, base: &Self::Point, ) -> Result; @@ -94,14 +112,43 @@ pub trait EccInstructions: Chip { ) -> Result; } +/// An element of the given elliptic curve's base field, that is used as a scalar +/// in variable-base scalar mul. +/// +/// It is not true in general that a scalar field element fits in a curve's +/// base field, and in particular it is untrue for the Pallas curve, whose +/// scalar field `Fq` is larger than its base field `Fp`. +/// +/// However, the only use of variable-base scalar mul in the Orchard protocol +/// is in deriving diversified addresses `[ivk] g_d`, and `ivk` is guaranteed +/// to be in the base field of the curve. (See non-normative notes in +/// https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents.) +#[derive(Debug)] +pub struct ScalarVar + Clone + Debug> { + chip: EccChip, + inner: EccChip::ScalarVar, +} + +impl + Clone + Debug> ScalarVar { + /// Constructs a new ScalarVar with the given value. + pub fn new( + chip: EccChip, + mut layouter: impl Layouter, + value: Option, + ) -> Result { + chip.witness_scalar_var(&mut layouter, value) + .map(|inner| ScalarVar { chip, inner }) + } +} + /// A full-width element of the given elliptic curve's scalar field, to be used for fixed-base scalar mul. #[derive(Debug)] -pub struct ScalarFixed + Clone> { +pub struct ScalarFixed + Clone + Debug> { chip: EccChip, inner: EccChip::ScalarFixed, } -impl + Clone> ScalarFixed { +impl + Clone + Debug> ScalarFixed { /// Constructs a new ScalarFixed with the given value. pub fn new( chip: EccChip, @@ -109,21 +156,18 @@ impl + Clone> ScalarFixed, ) -> Result { chip.witness_scalar_fixed(&mut layouter, value) - .map(|inner| ScalarFixed { - chip: chip.clone(), - inner, - }) + .map(|inner| ScalarFixed { chip, inner }) } } /// A signed short element of the given elliptic curve's scalar field, to be used for fixed-base scalar mul. #[derive(Debug)] -pub struct ScalarFixedShort + Clone> { +pub struct ScalarFixedShort + Clone + Debug> { chip: EccChip, inner: EccChip::ScalarFixedShort, } -impl + Clone> ScalarFixedShort { +impl + Clone + Debug> ScalarFixedShort { /// Constructs a new ScalarFixedShort with the given value. pub fn new( chip: EccChip, @@ -131,33 +175,26 @@ impl + Clone> ScalarFixedShort, ) -> Result { chip.witness_scalar_fixed_short(&mut layouter, value) - .map(|inner| ScalarFixedShort { - chip: chip.clone(), - inner, - }) + .map(|inner| ScalarFixedShort { chip, inner }) } } /// An elliptic curve point over the given curve. #[derive(Debug)] -pub struct Point + Clone> { +pub struct Point + Clone + Debug> { chip: EccChip, inner: EccChip::Point, } -impl + Clone> Point { +impl + Clone + Debug> Point { /// Constructs a new point with the given value. pub fn new( - &self, + chip: EccChip, mut layouter: impl Layouter, value: Option, ) -> Result { - self.chip - .witness_point(&mut layouter, value) - .map(|inner| Point { - chip: self.chip.clone(), - inner, - }) + let point = chip.witness_point(&mut layouter, value); + point.map(|inner| Point { chip, inner }) } /// Extracts the x-coordinate of a point. @@ -172,6 +209,7 @@ impl + Clone> Point { /// Returns `self + other`. pub fn add(&self, mut layouter: impl Layouter, other: &Self) -> Result { + assert_eq!(format!("{:?}", self.chip), format!("{:?}", other.chip)); self.chip .add(&mut layouter, &self.inner, &other.inner) .map(|inner| Point { @@ -181,9 +219,14 @@ impl + Clone> Point { } /// Returns `[by] self`. - pub fn mul(&self, mut layouter: impl Layouter, by: C::Scalar) -> Result { + pub fn mul( + &self, + mut layouter: impl Layouter, + by: &ScalarVar, + ) -> Result { + assert_eq!(format!("{:?}", self.chip), format!("{:?}", by.chip)); self.chip - .mul(&mut layouter, by, &self.inner) + .mul(&mut layouter, &by.inner, &self.inner) .map(|inner| Point { chip: self.chip.clone(), inner, @@ -193,12 +236,12 @@ impl + Clone> Point { /// The x-coordinate of an elliptic curve point over the given curve. #[derive(Debug)] -pub struct X + Clone> { +pub struct X + Clone + Debug> { chip: EccChip, inner: EccChip::X, } -impl + Clone> X { +impl + Clone + Debug> X { /// Wraps the given x-coordinate (obtained directly from an instruction) in a gadget. pub fn from_inner(chip: EccChip, inner: EccChip::X) -> Self { X { chip, inner } @@ -208,18 +251,16 @@ impl + Clone> X { /// A constant elliptic curve point over the given curve, for which scalar multiplication /// is more efficient. #[derive(Clone, Debug)] -pub struct FixedPoint + Clone> { +pub struct FixedPoint + Clone + Debug> { chip: EccChip, inner: EccChip::FixedPoint, } -impl + Clone> FixedPoint { +impl + Clone + Debug> FixedPoint { /// Gets a reference to the specified fixed point in the circuit. pub fn get(chip: EccChip, point: EccChip::FixedPoints) -> Result { - chip.get_fixed(point).map(|inner| FixedPoint { - chip: chip.clone(), - inner, - }) + chip.get_fixed(point) + .map(|inner| FixedPoint { chip, inner }) } /// Returns `[by] self`. @@ -228,6 +269,7 @@ impl + Clone> FixedPoint mut layouter: impl Layouter, by: &ScalarFixed, ) -> Result, Error> { + assert_eq!(format!("{:?}", self.chip), format!("{:?}", by.chip)); self.chip .mul_fixed(&mut layouter, &by.inner, &self.inner) .map(|inner| Point { @@ -236,3 +278,34 @@ impl + Clone> FixedPoint }) } } + +/// A constant elliptic curve point over the given curve, used in scalar multiplication +/// with a short signed exponent +#[derive(Clone, Debug)] +pub struct FixedPointShort + Clone + Debug> { + chip: EccChip, + inner: EccChip::FixedPoint, +} + +impl + Clone + Debug> FixedPointShort { + /// Gets a reference to the specified fixed point in the circuit. + pub fn get(chip: EccChip, point: EccChip::FixedPoints) -> Result { + chip.get_fixed(point) + .map(|inner| FixedPointShort { chip, inner }) + } + + /// Returns `[by] self`. + pub fn mul( + &self, + mut layouter: impl Layouter, + by: &ScalarFixedShort, + ) -> Result, Error> { + assert_eq!(format!("{:?}", self.chip), format!("{:?}", by.chip)); + self.chip + .mul_fixed_short(&mut layouter, &by.inner, &self.inner) + .map(|inner| Point { + chip: self.chip.clone(), + inner, + }) + } +}