From 4bf6202c350adbcef6827714cb47dfc8553cb3cd Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Mon, 26 Apr 2021 23:17:08 +0800 Subject: [PATCH 01/11] Modify ECC gadget to work with chip refactor --- Cargo.toml | 2 +- src/circuit/gadget/ecc.rs | 208 ++++++++++++++++++++++++++++---------- 2 files changed, 154 insertions(+), 56 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1fb2e67c..828299e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ subtle = "2.3" [dependencies.halo2] git = "https://github.com/zcash/halo2.git" -rev = "6acacf1aca12f34fc311aa59056e40adc0e6d8bd" +rev = "cae6f6af725cf1f5bc94e126a0b41e9ac602a302" [dependencies.pasta_curves] git = "https://github.com/zcash/pasta_curves.git" diff --git a/src/circuit/gadget/ecc.rs b/src/circuit/gadget/ecc.rs index 049c6b9e..36f27446 100644 --- a/src/circuit/gadget/ecc.rs +++ b/src/circuit/gadget/ecc.rs @@ -12,129 +12,227 @@ use halo2::{ 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 scalar field. - type Scalar: Clone + fmt::Debug; +pub trait EccInstructions: Chip { + /// 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; + /// 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; /// Variable representing an elliptic curve point. type Point: Clone + fmt::Debug; + /// Variable representing the x-coordinate of an elliptic curve point. + type X: Clone + fmt::Debug; /// Variable representing the set of fixed bases in the circuit. type FixedPoints: FixedPoints; /// Variable representing a fixed elliptic curve point (constant in the circuit). type FixedPoint: Clone + fmt::Debug; - /// Witnesses the given scalar as a private input to the circuit. - fn witness_scalar( - layouter: &mut impl Layouter, + /// Witnesses the given full-width scalar as a private input to the circuit for fixed-based scalar mul. + fn witness_scalar_fixed( + &self, + layouter: &mut impl Layouter, value: Option, - ) -> Result; + ) -> Result; + + /// Witnesses the given signed short scalar as a private input to the circuit for fixed-based scalar mul. + fn witness_scalar_fixed_short( + &self, + layouter: &mut impl Layouter, + value: Option, + ) -> Result; /// Witnesses the given point as a private input to the circuit. fn witness_point( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, value: Option, ) -> Result; + /// Extracts the x-coordinate of a point. + fn extract_p(point: &Self::Point) -> &Self::X; + /// Gets a fixed point into the circuit. - fn get_fixed( - layouter: &mut impl Layouter, - fixed_points: Self::FixedPoints, - ) -> Result; + fn get_fixed(&self, fixed_points: Self::FixedPoints) -> Result; /// Performs point addition, returning `a + b`. fn add( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, a: &Self::Point, b: &Self::Point, ) -> Result; - /// Performs point doubling, returning `[2] a`. - fn double(layouter: &mut impl Layouter, a: &Self::Point) -> Result; + /// Performs complete point addition, returning `a + b`. + fn add_complete( + &self, + layouter: &mut impl Layouter, + a: &Self::Point, + b: &Self::Point, + ) -> Result; /// Performs variable-base scalar multiplication, returning `[scalar] base`. fn mul( - layouter: &mut impl Layouter, - scalar: &Self::Scalar, + &self, + layouter: &mut impl Layouter, + scalar: C::Scalar, base: &Self::Point, ) -> Result; - /// Performs fixed-base scalar multiplication, returning `[scalar] base`. + /// Performs fixed-base scalar multiplication using a full-width scalar, returning `[scalar] base`. fn mul_fixed( - layouter: &mut impl Layouter, - scalar: &Self::Scalar, + &self, + layouter: &mut impl Layouter, + scalar: &Self::ScalarFixed, + base: &Self::FixedPoint, + ) -> Result; + + /// Performs fixed-base scalar multiplication using a short signed scalar, returning `[scalar] base`. + fn mul_fixed_short( + &self, + layouter: &mut impl Layouter, + scalar: &Self::ScalarFixedShort, base: &Self::FixedPoint, ) -> Result; } -/// An element of the given elliptic curve's scalar field. +/// A full-width element of the given elliptic curve's scalar field, to be used for fixed-base scalar mul. #[derive(Debug)] -pub struct Scalar> { - inner: EccChip::Scalar, +pub struct ScalarFixed + Clone> { + chip: EccChip, + inner: EccChip::ScalarFixed, } -impl> Scalar { - /// Constructs a new point with the given value. +impl + Clone> ScalarFixed { + /// Constructs a new ScalarFixed with the given value. pub fn new( - mut layouter: impl Layouter, + chip: EccChip, + mut layouter: impl Layouter, value: Option, ) -> Result { - EccChip::witness_scalar(&mut layouter, value).map(|inner| Scalar { inner }) + chip.witness_scalar_fixed(&mut layouter, value) + .map(|inner| ScalarFixed { + chip: chip.clone(), + 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> { + chip: EccChip, + inner: EccChip::ScalarFixedShort, +} + +impl + Clone> ScalarFixedShort { + /// Constructs a new ScalarFixedShort with the given value. + pub fn new( + chip: EccChip, + mut layouter: impl Layouter, + value: Option, + ) -> Result { + chip.witness_scalar_fixed_short(&mut layouter, value) + .map(|inner| ScalarFixedShort { + chip: chip.clone(), + inner, + }) } } /// An elliptic curve point over the given curve. #[derive(Debug)] -pub struct Point> { +pub struct Point + Clone> { + chip: EccChip, inner: EccChip::Point, } -impl> Point { +impl + Clone> Point { /// Constructs a new point with the given value. - pub fn new(mut layouter: impl Layouter, value: Option) -> Result { - EccChip::witness_point(&mut layouter, value).map(|inner| Point { inner }) + pub fn new( + &self, + mut layouter: impl Layouter, + value: Option, + ) -> Result { + self.chip + .witness_point(&mut layouter, value) + .map(|inner| Point { + chip: self.chip.clone(), + inner, + }) + } + + /// Extracts the x-coordinate of a point. + pub fn extract_p(&self) -> X { + X::from_inner(self.chip.clone(), EccChip::extract_p(&self.inner).clone()) + } + + /// Wraps the given point (obtained directly from an instruction) in a gadget. + pub fn from_inner(chip: EccChip, inner: EccChip::Point) -> Self { + Point { chip, inner } } /// Returns `self + other`. - pub fn add(&self, mut layouter: impl Layouter, other: &Self) -> Result { - EccChip::add(&mut layouter, &self.inner, &other.inner).map(|inner| Point { inner }) - } - - /// Returns `[2] self`. - pub fn double(&self, mut layouter: impl Layouter) -> Result { - EccChip::double(&mut layouter, &self.inner).map(|inner| Point { inner }) + pub fn add(&self, mut layouter: impl Layouter, other: &Self) -> Result { + self.chip + .add(&mut layouter, &self.inner, &other.inner) + .map(|inner| Point { + chip: self.chip.clone(), + inner, + }) } /// Returns `[by] self`. - pub fn mul( - &self, - mut layouter: impl Layouter, - by: &Scalar, - ) -> Result { - EccChip::mul(&mut layouter, &by.inner, &self.inner).map(|inner| Point { inner }) + pub fn mul(&self, mut layouter: impl Layouter, by: C::Scalar) -> Result { + self.chip + .mul(&mut layouter, by, &self.inner) + .map(|inner| Point { + chip: self.chip.clone(), + inner, + }) + } +} + +/// The x-coordinate of an elliptic curve point over the given curve. +#[derive(Debug)] +pub struct X + Clone> { + chip: EccChip, + inner: EccChip::X, +} + +impl + Clone> 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 } } } /// A constant elliptic curve point over the given curve, for which scalar multiplication /// is more efficient. -#[derive(Debug)] -pub struct FixedPoint> { +#[derive(Clone, Debug)] +pub struct FixedPoint + Clone> { + chip: EccChip, inner: EccChip::FixedPoint, } -impl> FixedPoint { +impl + Clone> FixedPoint { /// Gets a reference to the specified fixed point in the circuit. - pub fn get( - mut layouter: impl Layouter, - point: EccChip::FixedPoints, - ) -> Result { - EccChip::get_fixed(&mut layouter, point).map(|inner| FixedPoint { inner }) + pub fn get(chip: EccChip, point: EccChip::FixedPoints) -> Result { + chip.get_fixed(point).map(|inner| FixedPoint { + chip: chip.clone(), + inner, + }) } /// Returns `[by] self`. pub fn mul( &self, - mut layouter: impl Layouter, - by: &Scalar, + mut layouter: impl Layouter, + by: &ScalarFixed, ) -> Result, Error> { - EccChip::mul_fixed(&mut layouter, &by.inner, &self.inner).map(|inner| Point { inner }) + self.chip + .mul_fixed(&mut layouter, &by.inner, &self.inner) + .map(|inner| Point { + chip: self.chip.clone(), + inner, + }) } } From 4f2b4d29355825c35cbefcb928013985b64f6dda Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Tue, 4 May 2021 13:13:04 +0800 Subject: [PATCH 02/11] Address review comments Co-authored-by: Jack Grigg --- src/circuit/gadget/ecc.rs | 169 +++++++++++++++++++++++++++----------- 1 file changed, 121 insertions(+), 48 deletions(-) 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, + }) + } +} From 6a64bc1c37052d45c66bc6a82ac2436be8741da9 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 6 May 2021 12:50:50 +0800 Subject: [PATCH 03/11] Expose Point.add_incomplete() --- src/circuit/gadget/ecc.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/circuit/gadget/ecc.rs b/src/circuit/gadget/ecc.rs index 5e325c86..9164ae97 100644 --- a/src/circuit/gadget/ecc.rs +++ b/src/circuit/gadget/ecc.rs @@ -207,7 +207,7 @@ impl + Clone + Debug> Point, other: &Self) -> Result { assert_eq!(format!("{:?}", self.chip), format!("{:?}", other.chip)); self.chip @@ -218,6 +218,21 @@ impl + Clone + Debug> Point, + other: &Self, + ) -> Result { + assert_eq!(format!("{:?}", self.chip), format!("{:?}", other.chip)); + self.chip + .add_incomplete(&mut layouter, &self.inner, &other.inner) + .map(|inner| Point { + chip: self.chip.clone(), + inner, + }) + } + /// Returns `[by] self`. pub fn mul( &self, From db60fd226277bfa02e9bfd5c9b022d6f8066d6c7 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 6 May 2021 15:42:01 +0800 Subject: [PATCH 04/11] Add FixedPointShort associated type --- src/circuit/gadget/ecc.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/circuit/gadget/ecc.rs b/src/circuit/gadget/ecc.rs index 9164ae97..4f2d4ef5 100644 --- a/src/circuit/gadget/ecc.rs +++ b/src/circuit/gadget/ecc.rs @@ -34,6 +34,9 @@ pub trait EccInstructions: Chip { type FixedPoints: Clone + Debug; /// Variable representing a fixed elliptic curve point (constant in the circuit). type FixedPoint: Clone + Debug; + /// Variable representing a fixed elliptic curve point (constant in the circuit) + /// to be used in scalar multiplication with a short signed exponent. + type FixedPointShort: Clone + Debug; /// Witnesses the given base field element as a private input to the circuit for variable-base scalar mul. fn witness_scalar_var( @@ -71,6 +74,13 @@ pub trait EccInstructions: Chip { /// parts of the circuit where the fixed base is used. fn get_fixed(&self, fixed_points: Self::FixedPoints) -> Result; + /// Returns a fixed point to be used in scalar multiplication with a signed + /// short exponent. + fn get_fixed_short( + &self, + fixed_points: Self::FixedPoints, + ) -> Result; + /// Performs incomplete point addition, returning `a + b`. fn add_incomplete( &self, @@ -108,7 +118,7 @@ pub trait EccInstructions: Chip { &self, layouter: &mut impl Layouter, scalar: &Self::ScalarFixedShort, - base: &Self::FixedPoint, + base: &Self::FixedPointShort, ) -> Result; } @@ -299,13 +309,13 @@ impl + Clone + Debug> FixedPoint + Clone + Debug> { chip: EccChip, - inner: EccChip::FixedPoint, + inner: EccChip::FixedPointShort, } 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) + chip.get_fixed_short(point) .map(|inner| FixedPointShort { chip, inner }) } From 74c797165f13607beb5894c20de5852476b0d943 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Tue, 18 May 2021 12:03:40 +0800 Subject: [PATCH 05/11] Add range check for short scalar --- src/circuit/gadget/ecc.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/circuit/gadget/ecc.rs b/src/circuit/gadget/ecc.rs index 4f2d4ef5..abd84748 100644 --- a/src/circuit/gadget/ecc.rs +++ b/src/circuit/gadget/ecc.rs @@ -1,9 +1,10 @@ //! Gadgets for elliptic curve operations. +use ff::Field; use std::fmt::Debug; use halo2::{ - arithmetic::CurveAffine, + arithmetic::{CurveAffine, FieldExt}, circuit::{Chip, Layouter}, plonk::Error, }; @@ -25,6 +26,8 @@ pub trait EccInstructions: Chip { /// Variable representing a full-width element of the elliptic curve's scalar field, to be used for fixed-base scalar mul. 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. + /// + /// A `ScalarFixedShort` must be in the range [-(2^64 - 1), 2^64 - 1]. type ScalarFixedShort: Clone + Debug; /// Variable representing an elliptic curve point. type Point: Clone + Debug; @@ -179,11 +182,29 @@ pub struct ScalarFixedShort + Clone impl + Clone + Debug> ScalarFixedShort { /// Constructs a new ScalarFixedShort with the given value. + /// + /// # Panics + /// + /// The short scalar must be in the range [-(2^64 - 1), (2^64 - 1)]. pub fn new( chip: EccChip, mut layouter: impl Layouter, value: Option, ) -> Result { + // Check that the scalar is in the range [-(2^64 - 1), (2^64 - 1)] + if let Some(value) = value { + let mut sign = C::Scalar::one(); + + // T = (p-1) / 2 + let t = (C::Scalar::zero() - C::Scalar::one()) * C::Scalar::TWO_INV; + + if value > t { + sign = -sign; + } + let magnitude = value * sign; + assert!(magnitude < C::Scalar::from_u128(1 << 64)); + } + chip.witness_scalar_fixed_short(&mut layouter, value) .map(|inner| ScalarFixedShort { chip, inner }) } From c8076c2864e64c0d70eb9658d4f019dc5f817b0e Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Tue, 18 May 2021 12:09:49 +0800 Subject: [PATCH 06/11] Add FixedPointsShort associated type --- src/circuit/gadget/ecc.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/circuit/gadget/ecc.rs b/src/circuit/gadget/ecc.rs index abd84748..6351d6b4 100644 --- a/src/circuit/gadget/ecc.rs +++ b/src/circuit/gadget/ecc.rs @@ -35,6 +35,9 @@ pub trait EccInstructions: Chip { type X: Clone + Debug; /// Variable representing the set of fixed bases in the circuit. type FixedPoints: Clone + Debug; + /// Variable representing the set of fixed bases to be used in scalar multiplication + /// with a short signed exponent. + type FixedPointsShort: Clone + Debug; /// Variable representing a fixed elliptic curve point (constant in the circuit). type FixedPoint: Clone + Debug; /// Variable representing a fixed elliptic curve point (constant in the circuit) @@ -81,7 +84,7 @@ pub trait EccInstructions: Chip { /// short exponent. fn get_fixed_short( &self, - fixed_points: Self::FixedPoints, + fixed_points: Self::FixedPointsShort, ) -> Result; /// Performs incomplete point addition, returning `a + b`. @@ -335,7 +338,7 @@ pub struct FixedPointShort + Clone + impl + Clone + Debug> FixedPointShort { /// Gets a reference to the specified fixed point in the circuit. - pub fn get(chip: EccChip, point: EccChip::FixedPoints) -> Result { + pub fn get(chip: EccChip, point: EccChip::FixedPointsShort) -> Result { chip.get_fixed_short(point) .map(|inner| FixedPointShort { chip, inner }) } From edea9bde73cb409f7cfb8c4e7640369c0d07c0d8 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Tue, 18 May 2021 12:26:59 +0800 Subject: [PATCH 07/11] Document incomplete point addition error handling --- src/circuit/gadget/ecc.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/circuit/gadget/ecc.rs b/src/circuit/gadget/ecc.rs index 6351d6b4..50ba31dd 100644 --- a/src/circuit/gadget/ecc.rs +++ b/src/circuit/gadget/ecc.rs @@ -88,6 +88,8 @@ pub trait EccInstructions: Chip { ) -> Result; /// Performs incomplete point addition, returning `a + b`. + /// + /// This returns an error in exceptional cases. fn add_incomplete( &self, layouter: &mut impl Layouter, From caa37915621a53168a9a97a482735a303ed05140 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Tue, 18 May 2021 16:07:40 +0800 Subject: [PATCH 08/11] Documentation fixes. Co-authored-by: Daira Hopwood --- src/circuit/gadget/ecc.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/circuit/gadget/ecc.rs b/src/circuit/gadget/ecc.rs index 50ba31dd..dd0e1b47 100644 --- a/src/circuit/gadget/ecc.rs +++ b/src/circuit/gadget/ecc.rs @@ -23,20 +23,23 @@ pub trait EccInstructions: Chip { /// 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. + /// Variable representing a full-width element of the elliptic curve's + /// scalar field, to be used for fixed-base scalar mul. 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. + /// Variable representing a signed short element of the elliptic curve's + /// scalar field, to be used for fixed-base scalar mul. /// /// A `ScalarFixedShort` must be in the range [-(2^64 - 1), 2^64 - 1]. type ScalarFixedShort: Clone + Debug; /// Variable representing an elliptic curve point. type Point: Clone + Debug; - /// Variable representing the x-coordinate of an elliptic curve point. + /// Variable representing the affine short Weierstrass x-coordinate of an + /// elliptic curve point. type X: Clone + Debug; /// Variable representing the set of fixed bases in the circuit. type FixedPoints: Clone + Debug; - /// Variable representing the set of fixed bases to be used in scalar multiplication - /// with a short signed exponent. + /// Variable representing the set of fixed bases to be used in scalar + /// multiplication with a short signed exponent. type FixedPointsShort: Clone + Debug; /// Variable representing a fixed elliptic curve point (constant in the circuit). type FixedPoint: Clone + Debug; @@ -44,21 +47,24 @@ pub trait EccInstructions: Chip { /// to be used in scalar multiplication with a short signed exponent. type FixedPointShort: Clone + Debug; - /// Witnesses the given base field element as a private input to the circuit for variable-base 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. + /// 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-base 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, From af30f4b141879354c5f9285acf49642e970d34ba Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Tue, 18 May 2021 16:12:06 +0800 Subject: [PATCH 09/11] Add Eq to the EccChip trait --- src/circuit/gadget/ecc.rs | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/circuit/gadget/ecc.rs b/src/circuit/gadget/ecc.rs index dd0e1b47..6dcc6945 100644 --- a/src/circuit/gadget/ecc.rs +++ b/src/circuit/gadget/ecc.rs @@ -148,12 +148,12 @@ pub trait EccInstructions: Chip { /// 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> { +pub struct ScalarVar + Clone + Debug + Eq> { chip: EccChip, inner: EccChip::ScalarVar, } -impl + Clone + Debug> ScalarVar { +impl + Clone + Debug + Eq> ScalarVar { /// Constructs a new ScalarVar with the given value. pub fn new( chip: EccChip, @@ -167,12 +167,12 @@ impl + Clone + Debug> ScalarVar + Clone + Debug> { +pub struct ScalarFixed + Clone + Debug + Eq> { chip: EccChip, inner: EccChip::ScalarFixed, } -impl + Clone + Debug> ScalarFixed { +impl + Clone + Debug + Eq> ScalarFixed { /// Constructs a new ScalarFixed with the given value. pub fn new( chip: EccChip, @@ -186,12 +186,14 @@ impl + Clone + Debug> ScalarFixed + Clone + Debug> { +pub struct ScalarFixedShort + Clone + Debug + Eq> { chip: EccChip, inner: EccChip::ScalarFixedShort, } -impl + Clone + Debug> ScalarFixedShort { +impl + Clone + Debug + Eq> + ScalarFixedShort +{ /// Constructs a new ScalarFixedShort with the given value. /// /// # Panics @@ -223,12 +225,12 @@ impl + Clone + Debug> ScalarFixedSho /// An elliptic curve point over the given curve. #[derive(Debug)] -pub struct Point + Clone + Debug> { +pub struct Point + Clone + Debug + Eq> { chip: EccChip, inner: EccChip::Point, } -impl + Clone + Debug> Point { +impl + Clone + Debug + Eq> Point { /// Constructs a new point with the given value. pub fn new( chip: EccChip, @@ -251,7 +253,7 @@ impl + Clone + Debug> Point, other: &Self) -> Result { - assert_eq!(format!("{:?}", self.chip), format!("{:?}", other.chip)); + assert_eq!(self.chip, other.chip); self.chip .add(&mut layouter, &self.inner, &other.inner) .map(|inner| Point { @@ -266,7 +268,7 @@ impl + Clone + Debug> Point, other: &Self, ) -> Result { - assert_eq!(format!("{:?}", self.chip), format!("{:?}", other.chip)); + assert_eq!(self.chip, other.chip); self.chip .add_incomplete(&mut layouter, &self.inner, &other.inner) .map(|inner| Point { @@ -293,12 +295,12 @@ impl + Clone + Debug> Point + Clone + Debug> { +pub struct X + Clone + Debug + Eq> { chip: EccChip, inner: EccChip::X, } -impl + Clone + Debug> X { +impl + Clone + Debug + Eq> 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 } @@ -308,12 +310,12 @@ impl + Clone + Debug> X /// A constant elliptic curve point over the given curve, for which scalar multiplication /// is more efficient. #[derive(Clone, Debug)] -pub struct FixedPoint + Clone + Debug> { +pub struct FixedPoint + Clone + Debug + Eq> { chip: EccChip, inner: EccChip::FixedPoint, } -impl + Clone + Debug> FixedPoint { +impl + Clone + Debug + Eq> 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) @@ -339,12 +341,12 @@ impl + Clone + Debug> FixedPoint + Clone + Debug> { +pub struct FixedPointShort + Clone + Debug + Eq> { chip: EccChip, inner: EccChip::FixedPointShort, } -impl + Clone + Debug> FixedPointShort { +impl + Clone + Debug + Eq> FixedPointShort { /// Gets a reference to the specified fixed point in the circuit. pub fn get(chip: EccChip, point: EccChip::FixedPointsShort) -> Result { chip.get_fixed_short(point) From 2962115aef13bd8612acecba08f2b0709fed03f2 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Tue, 18 May 2021 16:45:43 +0800 Subject: [PATCH 10/11] Reintroduce point doubling API --- src/circuit/gadget/ecc.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/circuit/gadget/ecc.rs b/src/circuit/gadget/ecc.rs index 6dcc6945..ea26dcb8 100644 --- a/src/circuit/gadget/ecc.rs +++ b/src/circuit/gadget/ecc.rs @@ -111,6 +111,13 @@ pub trait EccInstructions: Chip { b: &Self::Point, ) -> Result; + /// Performs point doubling, returning `[2] a`. + fn double( + &self, + layouter: &mut impl Layouter, + a: &Self::Point, + ) -> Result; + /// Performs variable-base scalar multiplication, returning `[scalar] base`. fn mul( &self, @@ -293,7 +300,8 @@ impl + Clone + Debug + Eq> Point + Clone + Debug + Eq> { chip: EccChip, From ff504c1a3f0adb8d2b9ae77136c86aefd75ffd71 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Tue, 18 May 2021 17:14:13 +0800 Subject: [PATCH 11/11] Address review comments. Co-authored-by: Daira Hopwood --- src/circuit/gadget/ecc.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/circuit/gadget/ecc.rs b/src/circuit/gadget/ecc.rs index ea26dcb8..31d252e3 100644 --- a/src/circuit/gadget/ecc.rs +++ b/src/circuit/gadget/ecc.rs @@ -290,7 +290,7 @@ impl + Clone + Debug + Eq> Point, by: &ScalarVar, ) -> Result { - assert_eq!(format!("{:?}", self.chip), format!("{:?}", by.chip)); + assert_eq!(self.chip, by.chip); self.chip .mul(&mut layouter, &by.inner, &self.inner) .map(|inner| Point { @@ -315,8 +315,8 @@ impl + Clone + Debug + Eq> X + Clone + Debug + Eq> { chip: EccChip, @@ -336,7 +336,7 @@ impl + Clone + Debug + Eq> FixedPoin mut layouter: impl Layouter, by: &ScalarFixed, ) -> Result, Error> { - assert_eq!(format!("{:?}", self.chip), format!("{:?}", by.chip)); + assert_eq!(self.chip, by.chip); self.chip .mul_fixed(&mut layouter, &by.inner, &self.inner) .map(|inner| Point { @@ -367,7 +367,7 @@ impl + Clone + Debug + Eq> FixedPoin mut layouter: impl Layouter, by: &ScalarFixedShort, ) -> Result, Error> { - assert_eq!(format!("{:?}", self.chip), format!("{:?}", by.chip)); + assert_eq!(self.chip, by.chip); self.chip .mul_fixed_short(&mut layouter, &by.inner, &self.inner) .map(|inner| Point {