Merge pull request #75 from zcash/ecc-gadget

Modify ECC gadget to work with chip refactor
This commit is contained in:
str4d 2021-05-18 20:34:28 +01:00 committed by GitHub
commit 38f1c9e14f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 300 additions and 62 deletions

View File

@ -32,7 +32,7 @@ subtle = "2.3"
[dependencies.halo2] [dependencies.halo2]
git = "https://github.com/zcash/halo2.git" git = "https://github.com/zcash/halo2.git"
rev = "6acacf1aca12f34fc311aa59056e40adc0e6d8bd" rev = "cae6f6af725cf1f5bc94e126a0b41e9ac602a302"
[dependencies.pasta_curves] [dependencies.pasta_curves]
git = "https://github.com/zcash/pasta_curves.git" git = "https://github.com/zcash/pasta_curves.git"

View File

@ -1,140 +1,378 @@
//! Gadgets for elliptic curve operations. //! Gadgets for elliptic curve operations.
use std::fmt; use ff::Field;
use std::fmt::Debug;
use halo2::{ use halo2::{
arithmetic::CurveAffine, arithmetic::{CurveAffine, FieldExt},
circuit::{Chip, Layouter}, circuit::{Chip, Layouter},
plonk::Error, plonk::Error,
}; };
/// Trait allowing circuit's fixed points to be enumerated.
pub trait FixedPoints<C: CurveAffine>: Clone + fmt::Debug {}
/// The set of circuit instructions required to use the ECC gadgets. /// The set of circuit instructions required to use the ECC gadgets.
pub trait EccInstructions<C: CurveAffine>: Chip<Field = C::Base> { pub trait EccInstructions<C: CurveAffine>: Chip<C::Base> {
/// Variable representing an element of the elliptic curve's scalar field. /// Variable representing an element of the elliptic curve's base field, that
type Scalar: Clone + fmt::Debug; /// 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 + 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. /// Variable representing an elliptic curve point.
type Point: Clone + fmt::Debug; type Point: Clone + Debug;
/// 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. /// Variable representing the set of fixed bases in the circuit.
type FixedPoints: FixedPoints<C>; 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). /// Variable representing a fixed elliptic curve point (constant in the circuit).
type FixedPoint: Clone + fmt::Debug; 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 scalar as a private input to the circuit. /// Witnesses the given base field element as a private input to the circuit
fn witness_scalar( /// for variable-base scalar mul.
layouter: &mut impl Layouter<Self>, fn witness_scalar_var(
&self,
layouter: &mut impl Layouter<C::Base>,
value: Option<C::Base>,
) -> Result<Self::ScalarVar, Error>;
/// 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<C::Base>,
value: Option<C::Scalar>, value: Option<C::Scalar>,
) -> Result<Self::Scalar, Error>; ) -> Result<Self::ScalarFixed, Error>;
/// 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<C::Base>,
value: Option<C::Scalar>,
) -> Result<Self::ScalarFixedShort, Error>;
/// Witnesses the given point as a private input to the circuit. /// Witnesses the given point as a private input to the circuit.
fn witness_point( fn witness_point(
layouter: &mut impl Layouter<Self>, &self,
layouter: &mut impl Layouter<C::Base>,
value: Option<C>, value: Option<C>,
) -> Result<Self::Point, Error>; ) -> Result<Self::Point, Error>;
/// Gets a fixed point into the circuit. /// Extracts the x-coordinate of a point.
fn get_fixed( fn extract_p(point: &Self::Point) -> &Self::X;
layouter: &mut impl Layouter<Self>,
fixed_points: Self::FixedPoints,
) -> Result<Self::FixedPoint, Error>;
/// Performs point addition, returning `a + b`. /// 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<Self::FixedPoint, Error>;
/// Returns a fixed point to be used in scalar multiplication with a signed
/// short exponent.
fn get_fixed_short(
&self,
fixed_points: Self::FixedPointsShort,
) -> Result<Self::FixedPointShort, Error>;
/// Performs incomplete point addition, returning `a + b`.
///
/// This returns an error in exceptional cases.
fn add_incomplete(
&self,
layouter: &mut impl Layouter<C::Base>,
a: &Self::Point,
b: &Self::Point,
) -> Result<Self::Point, Error>;
/// Performs complete point addition, returning `a + b`.
fn add( fn add(
layouter: &mut impl Layouter<Self>, &self,
layouter: &mut impl Layouter<C::Base>,
a: &Self::Point, a: &Self::Point,
b: &Self::Point, b: &Self::Point,
) -> Result<Self::Point, Error>; ) -> Result<Self::Point, Error>;
/// Performs point doubling, returning `[2] a`. /// Performs point doubling, returning `[2] a`.
fn double(layouter: &mut impl Layouter<Self>, a: &Self::Point) -> Result<Self::Point, Error>; fn double(
&self,
layouter: &mut impl Layouter<C::Base>,
a: &Self::Point,
) -> Result<Self::Point, Error>;
/// Performs variable-base scalar multiplication, returning `[scalar] base`. /// Performs variable-base scalar multiplication, returning `[scalar] base`.
fn mul( fn mul(
layouter: &mut impl Layouter<Self>, &self,
scalar: &Self::Scalar, layouter: &mut impl Layouter<C::Base>,
scalar: &Self::ScalarVar,
base: &Self::Point, base: &Self::Point,
) -> Result<Self::Point, Error>; ) -> Result<Self::Point, Error>;
/// Performs fixed-base scalar multiplication, returning `[scalar] base`. /// Performs fixed-base scalar multiplication using a full-width scalar, returning `[scalar] base`.
fn mul_fixed( fn mul_fixed(
layouter: &mut impl Layouter<Self>, &self,
scalar: &Self::Scalar, layouter: &mut impl Layouter<C::Base>,
scalar: &Self::ScalarFixed,
base: &Self::FixedPoint, base: &Self::FixedPoint,
) -> Result<Self::Point, Error>; ) -> Result<Self::Point, Error>;
/// Performs fixed-base scalar multiplication using a short signed scalar, returning `[scalar] base`.
fn mul_fixed_short(
&self,
layouter: &mut impl Layouter<C::Base>,
scalar: &Self::ScalarFixedShort,
base: &Self::FixedPointShort,
) -> Result<Self::Point, Error>;
} }
/// An element of the given elliptic curve's scalar field. /// 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)] #[derive(Debug)]
pub struct Scalar<C: CurveAffine, EccChip: EccInstructions<C>> { pub struct ScalarVar<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> {
inner: EccChip::Scalar, chip: EccChip,
inner: EccChip::ScalarVar,
} }
impl<C: CurveAffine, EccChip: EccInstructions<C>> Scalar<C, EccChip> { impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> ScalarVar<C, EccChip> {
/// Constructs a new point with the given value. /// Constructs a new ScalarVar with the given value.
pub fn new( pub fn new(
mut layouter: impl Layouter<EccChip>, chip: EccChip,
mut layouter: impl Layouter<C::Base>,
value: Option<C::Base>,
) -> Result<Self, Error> {
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<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> {
chip: EccChip,
inner: EccChip::ScalarFixed,
}
impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> ScalarFixed<C, EccChip> {
/// Constructs a new ScalarFixed with the given value.
pub fn new(
chip: EccChip,
mut layouter: impl Layouter<C::Base>,
value: Option<C::Scalar>, value: Option<C::Scalar>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
EccChip::witness_scalar(&mut layouter, value).map(|inner| Scalar { inner }) chip.witness_scalar_fixed(&mut layouter, value)
.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<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> {
chip: EccChip,
inner: EccChip::ScalarFixedShort,
}
impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq>
ScalarFixedShort<C, EccChip>
{
/// 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<C::Base>,
value: Option<C::Scalar>,
) -> Result<Self, Error> {
// 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 })
} }
} }
/// An elliptic curve point over the given curve. /// An elliptic curve point over the given curve.
#[derive(Debug)] #[derive(Debug)]
pub struct Point<C: CurveAffine, EccChip: EccInstructions<C>> { pub struct Point<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> {
chip: EccChip,
inner: EccChip::Point, inner: EccChip::Point,
} }
impl<C: CurveAffine, EccChip: EccInstructions<C>> Point<C, EccChip> { impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> Point<C, EccChip> {
/// Constructs a new point with the given value. /// Constructs a new point with the given value.
pub fn new(mut layouter: impl Layouter<EccChip>, value: Option<C>) -> Result<Self, Error> { pub fn new(
EccChip::witness_point(&mut layouter, value).map(|inner| Point { inner }) chip: EccChip,
mut layouter: impl Layouter<C::Base>,
value: Option<C>,
) -> Result<Self, Error> {
let point = chip.witness_point(&mut layouter, value);
point.map(|inner| Point { chip, inner })
} }
/// Returns `self + other`. /// Extracts the x-coordinate of a point.
pub fn add(&self, mut layouter: impl Layouter<EccChip>, other: &Self) -> Result<Self, Error> { pub fn extract_p(&self) -> X<C, EccChip> {
EccChip::add(&mut layouter, &self.inner, &other.inner).map(|inner| Point { inner }) X::from_inner(self.chip.clone(), EccChip::extract_p(&self.inner).clone())
} }
/// Returns `[2] self`. /// Wraps the given point (obtained directly from an instruction) in a gadget.
pub fn double(&self, mut layouter: impl Layouter<EccChip>) -> Result<Self, Error> { pub fn from_inner(chip: EccChip, inner: EccChip::Point) -> Self {
EccChip::double(&mut layouter, &self.inner).map(|inner| Point { inner }) Point { chip, inner }
}
/// Returns `self + other` using complete addition.
pub fn add(&self, mut layouter: impl Layouter<C::Base>, other: &Self) -> Result<Self, Error> {
assert_eq!(self.chip, other.chip);
self.chip
.add(&mut layouter, &self.inner, &other.inner)
.map(|inner| Point {
chip: self.chip.clone(),
inner,
})
}
/// Returns `self + other` using incomplete addition.
pub fn add_incomplete(
&self,
mut layouter: impl Layouter<C::Base>,
other: &Self,
) -> Result<Self, Error> {
assert_eq!(self.chip, other.chip);
self.chip
.add_incomplete(&mut layouter, &self.inner, &other.inner)
.map(|inner| Point {
chip: self.chip.clone(),
inner,
})
} }
/// Returns `[by] self`. /// Returns `[by] self`.
pub fn mul( pub fn mul(
&self, &self,
mut layouter: impl Layouter<EccChip>, mut layouter: impl Layouter<C::Base>,
by: &Scalar<C, EccChip>, by: &ScalarVar<C, EccChip>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
EccChip::mul(&mut layouter, &by.inner, &self.inner).map(|inner| Point { inner }) assert_eq!(self.chip, by.chip);
self.chip
.mul(&mut layouter, &by.inner, &self.inner)
.map(|inner| Point {
chip: self.chip.clone(),
inner,
})
} }
} }
/// A constant elliptic curve point over the given curve, for which scalar multiplication /// The affine short Weierstrass x-coordinate of an elliptic curve point over the
/// is more efficient. /// given curve.
#[derive(Debug)] #[derive(Debug)]
pub struct FixedPoint<C: CurveAffine, EccChip: EccInstructions<C>> { pub struct X<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> {
chip: EccChip,
inner: EccChip::X,
}
impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> X<C, EccChip> {
/// 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 window tables have
/// been provided to make scalar multiplication more efficient.
#[derive(Clone, Debug)]
pub struct FixedPoint<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> {
chip: EccChip,
inner: EccChip::FixedPoint, inner: EccChip::FixedPoint,
} }
impl<C: CurveAffine, EccChip: EccInstructions<C>> FixedPoint<C, EccChip> { impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> FixedPoint<C, EccChip> {
/// Gets a reference to the specified fixed point in the circuit. /// Gets a reference to the specified fixed point in the circuit.
pub fn get( pub fn get(chip: EccChip, point: EccChip::FixedPoints) -> Result<Self, Error> {
mut layouter: impl Layouter<EccChip>, chip.get_fixed(point)
point: EccChip::FixedPoints, .map(|inner| FixedPoint { chip, inner })
) -> Result<Self, Error> {
EccChip::get_fixed(&mut layouter, point).map(|inner| FixedPoint { inner })
} }
/// Returns `[by] self`. /// Returns `[by] self`.
pub fn mul( pub fn mul(
&self, &self,
mut layouter: impl Layouter<EccChip>, mut layouter: impl Layouter<C::Base>,
by: &Scalar<C, EccChip>, by: &ScalarFixed<C, EccChip>,
) -> Result<Point<C, EccChip>, Error> { ) -> Result<Point<C, EccChip>, Error> {
EccChip::mul_fixed(&mut layouter, &by.inner, &self.inner).map(|inner| Point { inner }) assert_eq!(self.chip, by.chip);
self.chip
.mul_fixed(&mut layouter, &by.inner, &self.inner)
.map(|inner| Point {
chip: self.chip.clone(),
inner,
})
}
}
/// A constant elliptic curve point over the given curve, used in scalar multiplication
/// with a short signed exponent
#[derive(Clone, Debug)]
pub struct FixedPointShort<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> {
chip: EccChip,
inner: EccChip::FixedPointShort,
}
impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> FixedPointShort<C, EccChip> {
/// Gets a reference to the specified fixed point in the circuit.
pub fn get(chip: EccChip, point: EccChip::FixedPointsShort) -> Result<Self, Error> {
chip.get_fixed_short(point)
.map(|inner| FixedPointShort { chip, inner })
}
/// Returns `[by] self`.
pub fn mul(
&self,
mut layouter: impl Layouter<C::Base>,
by: &ScalarFixedShort<C, EccChip>,
) -> Result<Point<C, EccChip>, Error> {
assert_eq!(self.chip, by.chip);
self.chip
.mul_fixed_short(&mut layouter, &by.inner, &self.inner)
.map(|inner| Point {
chip: self.chip.clone(),
inner,
})
} }
} }