2021-02-25 10:11:46 -08:00
|
|
|
//! Gadgets for elliptic curve operations.
|
|
|
|
|
2021-05-03 22:13:04 -07:00
|
|
|
use std::fmt::Debug;
|
2021-02-25 10:11:46 -08:00
|
|
|
|
2022-01-27 15:28:02 -08:00
|
|
|
use halo2_proofs::{
|
2021-07-09 22:19:42 -07:00
|
|
|
arithmetic::CurveAffine,
|
2021-02-25 10:11:46 -08:00
|
|
|
circuit::{Chip, Layouter},
|
|
|
|
plonk::Error,
|
|
|
|
};
|
|
|
|
|
2022-01-27 13:53:10 -08:00
|
|
|
use crate::utilities::UtilitiesInstructions;
|
2021-06-18 02:41:13 -07:00
|
|
|
|
2021-06-04 23:05:58 -07:00
|
|
|
pub mod chip;
|
|
|
|
|
2021-02-25 10:11:46 -08:00
|
|
|
/// The set of circuit instructions required to use the ECC gadgets.
|
2021-08-18 23:59:39 -07:00
|
|
|
pub trait EccInstructions<C: CurveAffine>:
|
|
|
|
Chip<C::Base> + UtilitiesInstructions<C::Base> + Clone + Debug + Eq
|
|
|
|
{
|
2022-03-22 00:20:16 -07:00
|
|
|
/// Variable representing a scalar used in variable-base scalar mul.
|
2022-05-05 11:31:42 -07:00
|
|
|
///
|
|
|
|
/// This type is treated as a full-width scalar. However, if `Self` implements
|
|
|
|
/// [`BaseFitsInScalarInstructions`] then this may also be constructed from an element
|
|
|
|
/// of the base field.
|
2021-05-03 22:13:04 -07:00
|
|
|
type ScalarVar: Clone + Debug;
|
2021-05-18 01:07:40 -07:00
|
|
|
/// Variable representing a full-width element of the elliptic curve's
|
|
|
|
/// scalar field, to be used for fixed-base scalar mul.
|
2021-05-03 22:13:04 -07:00
|
|
|
type ScalarFixed: Clone + Debug;
|
2021-05-18 01:07:40 -07:00
|
|
|
/// Variable representing a signed short element of the elliptic curve's
|
|
|
|
/// scalar field, to be used for fixed-base scalar mul.
|
2021-05-17 21:03:40 -07:00
|
|
|
///
|
|
|
|
/// A `ScalarFixedShort` must be in the range [-(2^64 - 1), 2^64 - 1].
|
2021-05-03 22:13:04 -07:00
|
|
|
type ScalarFixedShort: Clone + Debug;
|
2021-02-25 10:11:46 -08:00
|
|
|
/// Variable representing an elliptic curve point.
|
2021-09-28 09:39:41 -07:00
|
|
|
type Point: From<Self::NonIdentityPoint> + Clone + Debug;
|
2021-09-27 01:33:13 -07:00
|
|
|
/// Variable representing a non-identity elliptic curve point.
|
2021-09-28 08:37:52 -07:00
|
|
|
type NonIdentityPoint: Clone + Debug;
|
2021-05-18 01:07:40 -07:00
|
|
|
/// Variable representing the affine short Weierstrass x-coordinate of an
|
|
|
|
/// elliptic curve point.
|
2021-05-03 22:13:04 -07:00
|
|
|
type X: Clone + Debug;
|
2021-08-18 23:59:39 -07:00
|
|
|
/// Enumeration of the set of fixed bases to be used in scalar mul.
|
|
|
|
/// TODO: When associated consts can be used as const generics, introduce
|
|
|
|
/// `Self::NUM_WINDOWS`, `Self::NUM_WINDOWS_BASE_FIELD`, `Self::NUM_WINDOWS_SHORT`
|
|
|
|
/// and use them to differentiate `FixedPoints` types.
|
|
|
|
type FixedPoints: FixedPoints<C>;
|
2021-05-03 22:13:04 -07:00
|
|
|
|
2021-06-13 06:26:30 -07:00
|
|
|
/// 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>;
|
|
|
|
|
2021-09-28 08:56:33 -07:00
|
|
|
/// Witnesses the given point as a private input to the circuit.
|
2021-09-28 13:09:39 -07:00
|
|
|
/// This allows the point to be the identity, mapped to (0, 0) in
|
|
|
|
/// affine coordinates.
|
2021-09-28 08:56:33 -07:00
|
|
|
fn witness_point(
|
|
|
|
&self,
|
|
|
|
layouter: &mut impl Layouter<C::Base>,
|
|
|
|
value: Option<C>,
|
|
|
|
) -> Result<Self::Point, Error>;
|
|
|
|
|
2021-09-27 01:33:13 -07:00
|
|
|
/// Witnesses the given point as a private input to the circuit.
|
|
|
|
/// This returns an error if the point is the identity.
|
|
|
|
fn witness_point_non_id(
|
|
|
|
&self,
|
|
|
|
layouter: &mut impl Layouter<C::Base>,
|
|
|
|
value: Option<C>,
|
|
|
|
) -> Result<Self::NonIdentityPoint, Error>;
|
|
|
|
|
2022-03-21 21:35:29 -07:00
|
|
|
/// Witnesses a full-width scalar to be used in variable-base multiplication.
|
|
|
|
fn witness_scalar_var(
|
|
|
|
&self,
|
|
|
|
layouter: &mut impl Layouter<C::Base>,
|
|
|
|
value: Option<C::Scalar>,
|
|
|
|
) -> Result<Self::ScalarVar, Error>;
|
|
|
|
|
2021-04-26 08:17:08 -07:00
|
|
|
/// Extracts the x-coordinate of a point.
|
2021-09-27 01:33:13 -07:00
|
|
|
fn extract_p<Point: Into<Self::Point> + Clone>(point: &Point) -> Self::X;
|
2021-04-26 08:17:08 -07:00
|
|
|
|
2021-05-03 22:13:04 -07:00
|
|
|
/// Performs incomplete point addition, returning `a + b`.
|
2021-05-17 21:26:59 -07:00
|
|
|
///
|
|
|
|
/// This returns an error in exceptional cases.
|
2021-05-03 22:13:04 -07:00
|
|
|
fn add_incomplete(
|
2021-04-26 08:17:08 -07:00
|
|
|
&self,
|
|
|
|
layouter: &mut impl Layouter<C::Base>,
|
2021-09-27 01:33:13 -07:00
|
|
|
a: &Self::NonIdentityPoint,
|
|
|
|
b: &Self::NonIdentityPoint,
|
|
|
|
) -> Result<Self::NonIdentityPoint, Error>;
|
2021-02-25 10:11:46 -08:00
|
|
|
|
2021-04-26 08:17:08 -07:00
|
|
|
/// Performs complete point addition, returning `a + b`.
|
2021-09-27 01:33:13 -07:00
|
|
|
fn add<A: Into<Self::Point> + Clone, B: Into<Self::Point> + Clone>(
|
2021-04-26 08:17:08 -07:00
|
|
|
&self,
|
|
|
|
layouter: &mut impl Layouter<C::Base>,
|
2021-09-27 01:33:13 -07:00
|
|
|
a: &A,
|
|
|
|
b: &B,
|
2021-04-26 08:17:08 -07:00
|
|
|
) -> Result<Self::Point, Error>;
|
2021-02-25 10:11:46 -08:00
|
|
|
|
|
|
|
/// Performs variable-base scalar multiplication, returning `[scalar] base`.
|
|
|
|
fn mul(
|
2021-04-26 08:17:08 -07:00
|
|
|
&self,
|
|
|
|
layouter: &mut impl Layouter<C::Base>,
|
2022-03-21 21:35:06 -07:00
|
|
|
scalar: &Self::ScalarVar,
|
2021-09-27 01:33:13 -07:00
|
|
|
base: &Self::NonIdentityPoint,
|
2021-07-09 22:19:42 -07:00
|
|
|
) -> Result<(Self::Point, Self::ScalarVar), Error>;
|
2021-02-25 10:11:46 -08:00
|
|
|
|
2021-04-26 08:17:08 -07:00
|
|
|
/// Performs fixed-base scalar multiplication using a full-width scalar, returning `[scalar] base`.
|
2021-02-25 10:11:46 -08:00
|
|
|
fn mul_fixed(
|
2021-04-26 08:17:08 -07:00
|
|
|
&self,
|
|
|
|
layouter: &mut impl Layouter<C::Base>,
|
2021-07-09 22:19:42 -07:00
|
|
|
scalar: Option<C::Scalar>,
|
2021-08-18 23:59:39 -07:00
|
|
|
base: &<Self::FixedPoints as FixedPoints<C>>::FullScalar,
|
2021-07-09 22:19:42 -07:00
|
|
|
) -> Result<(Self::Point, Self::ScalarFixed), Error>;
|
2021-04-26 08:17:08 -07:00
|
|
|
|
2021-07-16 09:44:56 -07:00
|
|
|
/// Performs fixed-base scalar multiplication using a short signed scalar, returning
|
|
|
|
/// `[magnitude * sign] base`.
|
2021-04-26 08:17:08 -07:00
|
|
|
fn mul_fixed_short(
|
|
|
|
&self,
|
|
|
|
layouter: &mut impl Layouter<C::Base>,
|
2021-07-10 08:56:24 -07:00
|
|
|
magnitude_sign: (Self::Var, Self::Var),
|
2021-08-18 23:59:39 -07:00
|
|
|
base: &<Self::FixedPoints as FixedPoints<C>>::ShortScalar,
|
2021-07-09 22:19:42 -07:00
|
|
|
) -> Result<(Self::Point, Self::ScalarFixedShort), Error>;
|
2021-06-18 02:41:13 -07:00
|
|
|
|
|
|
|
/// Performs fixed-base scalar multiplication using a base field element as the scalar.
|
|
|
|
/// In the current implementation, this base field element must be output from another
|
|
|
|
/// instruction.
|
|
|
|
fn mul_fixed_base_field_elem(
|
|
|
|
&self,
|
|
|
|
layouter: &mut impl Layouter<C::Base>,
|
2021-07-09 18:09:26 -07:00
|
|
|
base_field_elem: Self::Var,
|
2021-08-18 23:59:39 -07:00
|
|
|
base: &<Self::FixedPoints as FixedPoints<C>>::Base,
|
2021-06-18 02:41:13 -07:00
|
|
|
) -> Result<Self::Point, Error>;
|
2021-02-25 10:11:46 -08:00
|
|
|
}
|
|
|
|
|
2022-03-21 23:50:16 -07:00
|
|
|
/// Instructions that can be implemented for a curve whose base field fits into
|
|
|
|
/// its scalar field.
|
|
|
|
pub trait BaseFitsInScalarInstructions<C: CurveAffine>: EccInstructions<C> {
|
|
|
|
/// Converts a base field element that exists as a variable in the circuit
|
|
|
|
/// into a scalar to be used in variable-base scalar multiplication.
|
|
|
|
fn scalar_var_from_base(
|
|
|
|
&self,
|
|
|
|
layouter: &mut impl Layouter<C::Base>,
|
|
|
|
base: &Self::Var,
|
|
|
|
) -> Result<Self::ScalarVar, Error>;
|
|
|
|
}
|
|
|
|
|
2021-08-18 23:59:39 -07:00
|
|
|
/// Defines the fixed points for a given instantiation of the ECC chip.
|
|
|
|
pub trait FixedPoints<C: CurveAffine>: Debug + Eq + Clone {
|
2022-01-27 13:53:10 -08:00
|
|
|
/// Fixed points that can be used with full-width scalar multiplication.
|
2021-08-18 23:59:39 -07:00
|
|
|
type FullScalar: Debug + Eq + Clone;
|
2022-01-27 13:53:10 -08:00
|
|
|
/// Fixed points that can be used with short scalar multiplication.
|
2021-08-18 23:59:39 -07:00
|
|
|
type ShortScalar: Debug + Eq + Clone;
|
2022-01-27 13:53:10 -08:00
|
|
|
/// Fixed points that can be multiplied by base field elements.
|
2021-08-18 23:59:39 -07:00
|
|
|
type Base: Debug + Eq + Clone;
|
|
|
|
}
|
|
|
|
|
2021-05-03 22:13:04 -07:00
|
|
|
/// 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)]
|
2021-08-18 23:59:39 -07:00
|
|
|
pub struct ScalarVar<C: CurveAffine, EccChip: EccInstructions<C>> {
|
2021-05-03 22:13:04 -07:00
|
|
|
chip: EccChip,
|
|
|
|
inner: EccChip::ScalarVar,
|
|
|
|
}
|
|
|
|
|
2022-05-05 11:31:42 -07:00
|
|
|
impl<C: CurveAffine, EccChip: EccInstructions<C>> ScalarVar<C, EccChip> {
|
|
|
|
/// Witnesses the given full-width scalar.
|
|
|
|
///
|
|
|
|
/// Depending on the `EccChip` implementation, this may either witness the scalar
|
|
|
|
/// immediately, or delay witnessing until its first use in [`NonIdentityPoint::mul`].
|
|
|
|
pub fn new(
|
|
|
|
chip: EccChip,
|
|
|
|
mut layouter: impl Layouter<C::Base>,
|
|
|
|
value: Option<C::Scalar>,
|
|
|
|
) -> Result<Self, Error> {
|
|
|
|
let scalar = chip.witness_scalar_var(&mut layouter, value);
|
|
|
|
scalar.map(|inner| ScalarVar { chip, inner })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-06 08:28:20 -07:00
|
|
|
impl<C: CurveAffine, EccChip: BaseFitsInScalarInstructions<C>> ScalarVar<C, EccChip> {
|
2022-05-05 11:31:42 -07:00
|
|
|
/// Constructs a scalar from an existing base-field element.
|
|
|
|
pub fn from_base(
|
|
|
|
chip: EccChip,
|
|
|
|
mut layouter: impl Layouter<C::Base>,
|
|
|
|
base: &EccChip::Var,
|
|
|
|
) -> Result<Self, Error> {
|
|
|
|
let scalar = chip.scalar_var_from_base(&mut layouter, base);
|
|
|
|
scalar.map(|inner| ScalarVar { chip, inner })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-26 08:17:08 -07:00
|
|
|
/// A full-width element of the given elliptic curve's scalar field, to be used for fixed-base scalar mul.
|
2021-02-25 10:11:46 -08:00
|
|
|
#[derive(Debug)]
|
2021-08-18 23:59:39 -07:00
|
|
|
pub struct ScalarFixed<C: CurveAffine, EccChip: EccInstructions<C>> {
|
2021-04-26 08:17:08 -07:00
|
|
|
chip: EccChip,
|
|
|
|
inner: EccChip::ScalarFixed,
|
2021-02-25 10:11:46 -08:00
|
|
|
}
|
|
|
|
|
2021-04-26 08:17:08 -07:00
|
|
|
/// A signed short element of the given elliptic curve's scalar field, to be used for fixed-base scalar mul.
|
|
|
|
#[derive(Debug)]
|
2021-08-18 23:59:39 -07:00
|
|
|
pub struct ScalarFixedShort<C: CurveAffine, EccChip: EccInstructions<C>> {
|
2021-04-26 08:17:08 -07:00
|
|
|
chip: EccChip,
|
|
|
|
inner: EccChip::ScalarFixedShort,
|
|
|
|
}
|
|
|
|
|
2021-09-27 01:33:13 -07:00
|
|
|
/// A non-identity elliptic curve point over the given curve.
|
2021-06-04 22:59:48 -07:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
2021-08-18 23:59:39 -07:00
|
|
|
pub struct NonIdentityPoint<C: CurveAffine, EccChip: EccInstructions<C>> {
|
2021-04-26 08:17:08 -07:00
|
|
|
chip: EccChip,
|
2021-09-27 01:33:13 -07:00
|
|
|
inner: EccChip::NonIdentityPoint,
|
2021-02-25 10:11:46 -08:00
|
|
|
}
|
|
|
|
|
2021-08-18 23:59:39 -07:00
|
|
|
impl<C: CurveAffine, EccChip: EccInstructions<C>> NonIdentityPoint<C, EccChip> {
|
2021-02-25 10:11:46 -08:00
|
|
|
/// Constructs a new point with the given value.
|
2021-04-26 08:17:08 -07:00
|
|
|
pub fn new(
|
2021-05-03 22:13:04 -07:00
|
|
|
chip: EccChip,
|
2021-04-26 08:17:08 -07:00
|
|
|
mut layouter: impl Layouter<C::Base>,
|
|
|
|
value: Option<C>,
|
|
|
|
) -> Result<Self, Error> {
|
2021-09-27 01:33:13 -07:00
|
|
|
let point = chip.witness_point_non_id(&mut layouter, value);
|
|
|
|
point.map(|inner| NonIdentityPoint { chip, inner })
|
2021-02-25 10:11:46 -08:00
|
|
|
}
|
|
|
|
|
2021-06-13 06:26:30 -07:00
|
|
|
/// Constrains this point to be equal in value to another point.
|
2021-09-27 01:33:13 -07:00
|
|
|
pub fn constrain_equal<Other: Into<Point<C, EccChip>> + Clone>(
|
2021-06-13 06:26:30 -07:00
|
|
|
&self,
|
|
|
|
mut layouter: impl Layouter<C::Base>,
|
2021-09-27 01:33:13 -07:00
|
|
|
other: &Other,
|
2021-06-13 06:26:30 -07:00
|
|
|
) -> Result<(), Error> {
|
2021-09-27 01:33:13 -07:00
|
|
|
let other: Point<C, EccChip> = (other.clone()).into();
|
|
|
|
self.chip.constrain_equal(
|
|
|
|
&mut layouter,
|
|
|
|
&Point::<C, EccChip>::from(self.clone()).inner,
|
|
|
|
&other.inner,
|
|
|
|
)
|
2021-06-13 06:26:30 -07:00
|
|
|
}
|
|
|
|
|
2021-06-06 04:13:20 -07:00
|
|
|
/// Returns the inner point.
|
2021-09-27 01:33:13 -07:00
|
|
|
pub fn inner(&self) -> &EccChip::NonIdentityPoint {
|
2021-06-06 04:13:20 -07:00
|
|
|
&self.inner
|
|
|
|
}
|
|
|
|
|
2021-04-26 08:17:08 -07:00
|
|
|
/// Extracts the x-coordinate of a point.
|
|
|
|
pub fn extract_p(&self) -> X<C, EccChip> {
|
2021-09-27 02:13:23 -07:00
|
|
|
X::from_inner(self.chip.clone(), EccChip::extract_p(&self.inner))
|
2021-02-25 10:11:46 -08:00
|
|
|
}
|
|
|
|
|
2021-04-26 08:17:08 -07:00
|
|
|
/// Wraps the given point (obtained directly from an instruction) in a gadget.
|
2021-09-27 01:33:13 -07:00
|
|
|
pub fn from_inner(chip: EccChip, inner: EccChip::NonIdentityPoint) -> Self {
|
|
|
|
NonIdentityPoint { chip, inner }
|
2021-04-26 08:17:08 -07:00
|
|
|
}
|
|
|
|
|
2021-05-05 21:50:50 -07:00
|
|
|
/// Returns `self + other` using complete addition.
|
2021-09-27 01:33:13 -07:00
|
|
|
pub fn add<Other: Into<Point<C, EccChip>> + Clone>(
|
|
|
|
&self,
|
|
|
|
mut layouter: impl Layouter<C::Base>,
|
|
|
|
other: &Other,
|
|
|
|
) -> Result<Point<C, EccChip>, Error> {
|
|
|
|
let other: Point<C, EccChip> = (other.clone()).into();
|
|
|
|
|
2021-05-18 01:12:06 -07:00
|
|
|
assert_eq!(self.chip, other.chip);
|
2021-04-26 08:17:08 -07:00
|
|
|
self.chip
|
|
|
|
.add(&mut layouter, &self.inner, &other.inner)
|
|
|
|
.map(|inner| Point {
|
|
|
|
chip: self.chip.clone(),
|
|
|
|
inner,
|
|
|
|
})
|
2021-02-25 10:11:46 -08:00
|
|
|
}
|
|
|
|
|
2021-05-05 21:50:50 -07:00
|
|
|
/// Returns `self + other` using incomplete addition.
|
2021-09-27 14:19:06 -07:00
|
|
|
/// The arguments are type-constrained not to be the identity point,
|
|
|
|
/// and since exceptional cases return an Error, the result also cannot
|
|
|
|
/// be the identity point.
|
2021-05-05 21:50:50 -07:00
|
|
|
pub fn add_incomplete(
|
|
|
|
&self,
|
|
|
|
mut layouter: impl Layouter<C::Base>,
|
|
|
|
other: &Self,
|
|
|
|
) -> Result<Self, Error> {
|
2021-05-18 01:12:06 -07:00
|
|
|
assert_eq!(self.chip, other.chip);
|
2021-05-05 21:50:50 -07:00
|
|
|
self.chip
|
|
|
|
.add_incomplete(&mut layouter, &self.inner, &other.inner)
|
2021-09-27 01:33:13 -07:00
|
|
|
.map(|inner| NonIdentityPoint {
|
2021-05-05 21:50:50 -07:00
|
|
|
chip: self.chip.clone(),
|
|
|
|
inner,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-02-25 10:11:46 -08:00
|
|
|
/// Returns `[by] self`.
|
2021-09-27 02:13:23 -07:00
|
|
|
#[allow(clippy::type_complexity)]
|
2021-05-03 22:13:04 -07:00
|
|
|
pub fn mul(
|
|
|
|
&self,
|
|
|
|
mut layouter: impl Layouter<C::Base>,
|
2022-05-05 11:31:42 -07:00
|
|
|
by: ScalarVar<C, EccChip>,
|
2021-09-27 01:33:13 -07:00
|
|
|
) -> Result<(Point<C, EccChip>, ScalarVar<C, EccChip>), Error> {
|
2022-05-06 08:28:20 -07:00
|
|
|
assert_eq!(self.chip, by.chip);
|
2021-04-26 08:17:08 -07:00
|
|
|
self.chip
|
2022-05-05 11:31:42 -07:00
|
|
|
.mul(&mut layouter, &by.inner, &self.inner.clone())
|
2021-07-09 22:19:42 -07:00
|
|
|
.map(|(point, scalar)| {
|
|
|
|
(
|
|
|
|
Point {
|
|
|
|
chip: self.chip.clone(),
|
|
|
|
inner: point,
|
|
|
|
},
|
|
|
|
ScalarVar {
|
|
|
|
chip: self.chip.clone(),
|
|
|
|
inner: scalar,
|
|
|
|
},
|
|
|
|
)
|
2021-04-26 08:17:08 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-27 01:33:13 -07:00
|
|
|
impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq>
|
|
|
|
From<NonIdentityPoint<C, EccChip>> for Point<C, EccChip>
|
|
|
|
{
|
|
|
|
fn from(non_id_point: NonIdentityPoint<C, EccChip>) -> Self {
|
|
|
|
Self {
|
|
|
|
chip: non_id_point.chip,
|
|
|
|
inner: non_id_point.inner.into(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An elliptic curve point over the given curve.
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
|
|
pub struct Point<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> {
|
|
|
|
chip: EccChip,
|
|
|
|
inner: EccChip::Point,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> Point<C, EccChip> {
|
2021-09-28 08:56:33 -07:00
|
|
|
/// Constructs a new point with the given value.
|
|
|
|
pub fn new(
|
|
|
|
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 })
|
|
|
|
}
|
|
|
|
|
2021-09-27 01:33:13 -07:00
|
|
|
/// Constrains this point to be equal in value to another point.
|
|
|
|
pub fn constrain_equal<Other: Into<Point<C, EccChip>> + Clone>(
|
|
|
|
&self,
|
|
|
|
mut layouter: impl Layouter<C::Base>,
|
|
|
|
other: &Other,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
let other: Point<C, EccChip> = (other.clone()).into();
|
2021-09-27 02:13:23 -07:00
|
|
|
self.chip
|
|
|
|
.constrain_equal(&mut layouter, &self.inner, &other.inner)
|
2021-09-27 01:33:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the inner point.
|
|
|
|
pub fn inner(&self) -> &EccChip::Point {
|
|
|
|
&self.inner
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Extracts the x-coordinate of a point.
|
|
|
|
pub fn extract_p(&self) -> X<C, EccChip> {
|
2021-09-27 02:13:23 -07:00
|
|
|
X::from_inner(self.chip.clone(), EccChip::extract_p(&self.inner))
|
2021-09-27 01:33:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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` using complete addition.
|
|
|
|
pub fn add<Other: Into<Point<C, EccChip>> + Clone>(
|
|
|
|
&self,
|
|
|
|
mut layouter: impl Layouter<C::Base>,
|
|
|
|
other: &Other,
|
|
|
|
) -> Result<Point<C, EccChip>, Error> {
|
|
|
|
let other: Point<C, EccChip> = (other.clone()).into();
|
|
|
|
|
|
|
|
assert_eq!(self.chip, other.chip);
|
|
|
|
self.chip
|
|
|
|
.add(&mut layouter, &self.inner, &other.inner)
|
|
|
|
.map(|inner| Point {
|
|
|
|
chip: self.chip.clone(),
|
|
|
|
inner,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-18 01:45:43 -07:00
|
|
|
/// The affine short Weierstrass x-coordinate of an elliptic curve point over the
|
|
|
|
/// given curve.
|
2021-04-26 08:17:08 -07:00
|
|
|
#[derive(Debug)]
|
2021-08-18 23:59:39 -07:00
|
|
|
pub struct X<C: CurveAffine, EccChip: EccInstructions<C>> {
|
2021-04-26 08:17:08 -07:00
|
|
|
chip: EccChip,
|
|
|
|
inner: EccChip::X,
|
|
|
|
}
|
|
|
|
|
2021-08-18 23:59:39 -07:00
|
|
|
impl<C: CurveAffine, EccChip: EccInstructions<C>> X<C, EccChip> {
|
2021-04-26 08:17:08 -07:00
|
|
|
/// 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 }
|
2021-02-25 10:11:46 -08:00
|
|
|
}
|
2021-06-06 04:32:59 -07:00
|
|
|
|
|
|
|
/// Returns the inner x-coordinate.
|
|
|
|
pub fn inner(&self) -> &EccChip::X {
|
|
|
|
&self.inner
|
|
|
|
}
|
2021-02-25 10:11:46 -08:00
|
|
|
}
|
|
|
|
|
2021-05-18 02:14:13 -07:00
|
|
|
/// A constant elliptic curve point over the given curve, for which window tables have
|
|
|
|
/// been provided to make scalar multiplication more efficient.
|
2021-07-14 22:05:22 -07:00
|
|
|
///
|
|
|
|
/// Used in scalar multiplication with full-width scalars.
|
2021-04-26 08:17:08 -07:00
|
|
|
#[derive(Clone, Debug)]
|
2021-08-18 23:59:39 -07:00
|
|
|
pub struct FixedPoint<C: CurveAffine, EccChip: EccInstructions<C>> {
|
|
|
|
chip: EccChip,
|
|
|
|
inner: <EccChip::FixedPoints as FixedPoints<C>>::FullScalar,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A constant elliptic curve point over the given curve, used in scalar multiplication
|
|
|
|
/// with a base field element
|
|
|
|
#[derive(Clone, Debug)]
|
2022-01-26 16:10:18 -08:00
|
|
|
pub struct FixedPointBaseField<C: CurveAffine, EccChip: EccInstructions<C>> {
|
2021-04-26 08:17:08 -07:00
|
|
|
chip: EccChip,
|
2021-08-18 23:59:39 -07:00
|
|
|
inner: <EccChip::FixedPoints as FixedPoints<C>>::Base,
|
2021-02-25 10:11:46 -08:00
|
|
|
}
|
|
|
|
|
2021-08-18 23:59:39 -07:00
|
|
|
/// A constant elliptic curve point over the given curve, used in scalar multiplication
|
|
|
|
/// with a short signed exponent
|
|
|
|
#[derive(Clone, Debug)]
|
2022-01-26 16:10:18 -08:00
|
|
|
pub struct FixedPointShort<C: CurveAffine, EccChip: EccInstructions<C>> {
|
2021-08-18 23:59:39 -07:00
|
|
|
chip: EccChip,
|
|
|
|
inner: <EccChip::FixedPoints as FixedPoints<C>>::ShortScalar,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<C: CurveAffine, EccChip: EccInstructions<C>> FixedPoint<C, EccChip> {
|
2021-07-10 08:56:24 -07:00
|
|
|
#[allow(clippy::type_complexity)]
|
2021-02-25 10:11:46 -08:00
|
|
|
/// Returns `[by] self`.
|
|
|
|
pub fn mul(
|
|
|
|
&self,
|
2021-04-26 08:17:08 -07:00
|
|
|
mut layouter: impl Layouter<C::Base>,
|
2021-07-09 22:19:42 -07:00
|
|
|
by: Option<C::Scalar>,
|
|
|
|
) -> Result<(Point<C, EccChip>, ScalarFixed<C, EccChip>), Error> {
|
2021-04-26 08:17:08 -07:00
|
|
|
self.chip
|
2021-07-09 22:19:42 -07:00
|
|
|
.mul_fixed(&mut layouter, by, &self.inner)
|
|
|
|
.map(|(point, scalar)| {
|
|
|
|
(
|
|
|
|
Point {
|
|
|
|
chip: self.chip.clone(),
|
|
|
|
inner: point,
|
|
|
|
},
|
|
|
|
ScalarFixed {
|
|
|
|
chip: self.chip.clone(),
|
|
|
|
inner: scalar,
|
|
|
|
},
|
|
|
|
)
|
2021-04-26 08:17:08 -07:00
|
|
|
})
|
2021-02-25 10:11:46 -08:00
|
|
|
}
|
2021-06-04 22:59:48 -07:00
|
|
|
|
2021-07-14 22:05:22 -07:00
|
|
|
/// Wraps the given fixed base (obtained directly from an instruction) in a gadget.
|
2021-08-18 23:59:39 -07:00
|
|
|
pub fn from_inner(
|
|
|
|
chip: EccChip,
|
|
|
|
inner: <EccChip::FixedPoints as FixedPoints<C>>::FullScalar,
|
|
|
|
) -> Self {
|
|
|
|
Self { chip, inner }
|
2021-07-14 22:05:22 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-18 23:59:39 -07:00
|
|
|
impl<C: CurveAffine, EccChip: EccInstructions<C>> FixedPointBaseField<C, EccChip> {
|
2021-07-14 22:05:22 -07:00
|
|
|
#[allow(clippy::type_complexity)]
|
|
|
|
/// Returns `[by] self`.
|
|
|
|
pub fn mul(
|
2021-06-18 02:41:13 -07:00
|
|
|
&self,
|
|
|
|
mut layouter: impl Layouter<C::Base>,
|
2021-07-09 18:09:26 -07:00
|
|
|
by: EccChip::Var,
|
2021-06-18 02:41:13 -07:00
|
|
|
) -> Result<Point<C, EccChip>, Error> {
|
|
|
|
self.chip
|
|
|
|
.mul_fixed_base_field_elem(&mut layouter, by, &self.inner)
|
|
|
|
.map(|inner| Point {
|
|
|
|
chip: self.chip.clone(),
|
|
|
|
inner,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-06-04 22:59:48 -07:00
|
|
|
/// Wraps the given fixed base (obtained directly from an instruction) in a gadget.
|
2021-08-18 23:59:39 -07:00
|
|
|
pub fn from_inner(
|
|
|
|
chip: EccChip,
|
|
|
|
inner: <EccChip::FixedPoints as FixedPoints<C>>::Base,
|
|
|
|
) -> Self {
|
|
|
|
Self { chip, inner }
|
2021-06-04 22:59:48 -07:00
|
|
|
}
|
2021-02-25 10:11:46 -08:00
|
|
|
}
|
2021-05-03 22:13:04 -07:00
|
|
|
|
2021-08-18 23:59:39 -07:00
|
|
|
impl<C: CurveAffine, EccChip: EccInstructions<C>> FixedPointShort<C, EccChip> {
|
2021-07-10 08:56:24 -07:00
|
|
|
#[allow(clippy::type_complexity)]
|
2021-05-03 22:13:04 -07:00
|
|
|
/// Returns `[by] self`.
|
|
|
|
pub fn mul(
|
|
|
|
&self,
|
|
|
|
mut layouter: impl Layouter<C::Base>,
|
2021-07-10 08:56:24 -07:00
|
|
|
magnitude_sign: (EccChip::Var, EccChip::Var),
|
2021-07-09 22:19:42 -07:00
|
|
|
) -> Result<(Point<C, EccChip>, ScalarFixedShort<C, EccChip>), Error> {
|
2021-05-03 22:13:04 -07:00
|
|
|
self.chip
|
2021-07-10 08:56:24 -07:00
|
|
|
.mul_fixed_short(&mut layouter, magnitude_sign, &self.inner)
|
2021-07-09 22:19:42 -07:00
|
|
|
.map(|(point, scalar)| {
|
|
|
|
(
|
|
|
|
Point {
|
|
|
|
chip: self.chip.clone(),
|
|
|
|
inner: point,
|
|
|
|
},
|
|
|
|
ScalarFixedShort {
|
|
|
|
chip: self.chip.clone(),
|
|
|
|
inner: scalar,
|
|
|
|
},
|
|
|
|
)
|
2021-05-03 22:13:04 -07:00
|
|
|
})
|
|
|
|
}
|
2021-06-04 22:59:48 -07:00
|
|
|
|
|
|
|
/// Wraps the given fixed base (obtained directly from an instruction) in a gadget.
|
2021-08-18 23:59:39 -07:00
|
|
|
pub fn from_inner(
|
|
|
|
chip: EccChip,
|
|
|
|
inner: <EccChip::FixedPoints as FixedPoints<C>>::ShortScalar,
|
|
|
|
) -> Self {
|
|
|
|
Self { chip, inner }
|
2021-06-04 22:59:48 -07:00
|
|
|
}
|
2021-05-03 22:13:04 -07:00
|
|
|
}
|
2021-06-10 10:07:56 -07:00
|
|
|
|
|
|
|
#[cfg(test)]
|
2022-01-27 13:15:41 -08:00
|
|
|
pub(crate) mod tests {
|
|
|
|
use ff::PrimeField;
|
2021-09-28 13:00:29 -07:00
|
|
|
use group::{prime::PrimeCurveAffine, Curve, Group};
|
2021-06-11 15:29:05 -07:00
|
|
|
|
2022-01-27 15:28:02 -08:00
|
|
|
use halo2_proofs::{
|
2021-07-08 18:56:27 -07:00
|
|
|
circuit::{Layouter, SimpleFloorPlanner},
|
2021-06-10 10:07:56 -07:00
|
|
|
dev::MockProver,
|
2021-07-08 18:56:27 -07:00
|
|
|
plonk::{Circuit, ConstraintSystem, Error},
|
2021-06-10 10:07:56 -07:00
|
|
|
};
|
2022-01-27 13:15:41 -08:00
|
|
|
use lazy_static::lazy_static;
|
2021-06-11 15:29:05 -07:00
|
|
|
use pasta_curves::pallas;
|
2021-06-10 10:07:56 -07:00
|
|
|
|
2022-01-27 13:15:41 -08:00
|
|
|
use super::{
|
|
|
|
chip::{
|
|
|
|
find_zs_and_us, BaseFieldElem, EccChip, EccConfig, FixedPoint, FullScalar, ShortScalar,
|
|
|
|
H, NUM_WINDOWS, NUM_WINDOWS_SHORT,
|
|
|
|
},
|
|
|
|
FixedPoints,
|
|
|
|
};
|
2022-01-27 13:53:10 -08:00
|
|
|
use crate::utilities::lookup_range_check::LookupRangeCheckConfig;
|
2021-06-10 10:07:56 -07:00
|
|
|
|
2022-01-27 13:15:41 -08:00
|
|
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
|
|
|
pub(crate) struct TestFixedBases;
|
|
|
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
|
|
|
pub(crate) struct FullWidth(pallas::Affine, &'static [(u64, [pallas::Base; H])]);
|
|
|
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
|
|
|
pub(crate) struct BaseField;
|
|
|
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
|
|
|
pub(crate) struct Short;
|
|
|
|
|
|
|
|
lazy_static! {
|
|
|
|
static ref BASE: pallas::Affine = pallas::Point::generator().to_affine();
|
|
|
|
static ref ZS_AND_US: Vec<(u64, [pallas::Base; H])> =
|
|
|
|
find_zs_and_us(*BASE, NUM_WINDOWS).unwrap();
|
|
|
|
static ref ZS_AND_US_SHORT: Vec<(u64, [pallas::Base; H])> =
|
|
|
|
find_zs_and_us(*BASE, NUM_WINDOWS_SHORT).unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FullWidth {
|
|
|
|
pub(crate) fn from_pallas_generator() -> Self {
|
|
|
|
FullWidth(*BASE, &ZS_AND_US)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn from_parts(
|
|
|
|
base: pallas::Affine,
|
|
|
|
zs_and_us: &'static [(u64, [pallas::Base; H])],
|
|
|
|
) -> Self {
|
|
|
|
FullWidth(base, zs_and_us)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FixedPoint<pallas::Affine> for FullWidth {
|
2022-03-21 23:52:10 -07:00
|
|
|
type FixedScalarKind = FullScalar;
|
2022-01-27 13:15:41 -08:00
|
|
|
|
|
|
|
fn generator(&self) -> pallas::Affine {
|
|
|
|
self.0
|
|
|
|
}
|
|
|
|
|
|
|
|
fn u(&self) -> Vec<[[u8; 32]; H]> {
|
|
|
|
self.1
|
|
|
|
.iter()
|
|
|
|
.map(|(_, us)| {
|
|
|
|
[
|
|
|
|
us[0].to_repr(),
|
|
|
|
us[1].to_repr(),
|
|
|
|
us[2].to_repr(),
|
|
|
|
us[3].to_repr(),
|
|
|
|
us[4].to_repr(),
|
|
|
|
us[5].to_repr(),
|
|
|
|
us[6].to_repr(),
|
|
|
|
us[7].to_repr(),
|
|
|
|
]
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn z(&self) -> Vec<u64> {
|
|
|
|
self.1.iter().map(|(z, _)| *z).collect()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FixedPoint<pallas::Affine> for BaseField {
|
2022-03-21 23:52:10 -07:00
|
|
|
type FixedScalarKind = BaseFieldElem;
|
2022-01-27 13:15:41 -08:00
|
|
|
|
|
|
|
fn generator(&self) -> pallas::Affine {
|
|
|
|
*BASE
|
|
|
|
}
|
|
|
|
|
|
|
|
fn u(&self) -> Vec<[[u8; 32]; H]> {
|
|
|
|
ZS_AND_US
|
|
|
|
.iter()
|
|
|
|
.map(|(_, us)| {
|
|
|
|
[
|
|
|
|
us[0].to_repr(),
|
|
|
|
us[1].to_repr(),
|
|
|
|
us[2].to_repr(),
|
|
|
|
us[3].to_repr(),
|
|
|
|
us[4].to_repr(),
|
|
|
|
us[5].to_repr(),
|
|
|
|
us[6].to_repr(),
|
|
|
|
us[7].to_repr(),
|
|
|
|
]
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn z(&self) -> Vec<u64> {
|
|
|
|
ZS_AND_US.iter().map(|(z, _)| *z).collect()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FixedPoint<pallas::Affine> for Short {
|
2022-03-21 23:52:10 -07:00
|
|
|
type FixedScalarKind = ShortScalar;
|
2022-01-27 13:15:41 -08:00
|
|
|
|
|
|
|
fn generator(&self) -> pallas::Affine {
|
|
|
|
*BASE
|
|
|
|
}
|
|
|
|
|
|
|
|
fn u(&self) -> Vec<[[u8; 32]; H]> {
|
|
|
|
ZS_AND_US_SHORT
|
|
|
|
.iter()
|
|
|
|
.map(|(_, us)| {
|
|
|
|
[
|
|
|
|
us[0].to_repr(),
|
|
|
|
us[1].to_repr(),
|
|
|
|
us[2].to_repr(),
|
|
|
|
us[3].to_repr(),
|
|
|
|
us[4].to_repr(),
|
|
|
|
us[5].to_repr(),
|
|
|
|
us[6].to_repr(),
|
|
|
|
us[7].to_repr(),
|
|
|
|
]
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn z(&self) -> Vec<u64> {
|
|
|
|
ZS_AND_US_SHORT.iter().map(|(z, _)| *z).collect()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FixedPoints<pallas::Affine> for TestFixedBases {
|
|
|
|
type FullScalar = FullWidth;
|
|
|
|
type ShortScalar = Short;
|
|
|
|
type Base = BaseField;
|
|
|
|
}
|
|
|
|
|
2021-12-08 16:49:01 -08:00
|
|
|
struct MyCircuit {
|
|
|
|
test_errors: bool,
|
|
|
|
}
|
2021-06-10 10:07:56 -07:00
|
|
|
|
|
|
|
#[allow(non_snake_case)]
|
2021-06-11 15:29:05 -07:00
|
|
|
impl Circuit<pallas::Base> for MyCircuit {
|
2022-01-27 13:15:41 -08:00
|
|
|
type Config = EccConfig<TestFixedBases>;
|
2021-07-08 18:56:27 -07:00
|
|
|
type FloorPlanner = SimpleFloorPlanner;
|
|
|
|
|
|
|
|
fn without_witnesses(&self) -> Self {
|
2021-12-08 16:49:01 -08:00
|
|
|
MyCircuit { test_errors: false }
|
2021-07-08 18:56:27 -07:00
|
|
|
}
|
2021-06-10 10:07:56 -07:00
|
|
|
|
2021-06-11 15:29:05 -07:00
|
|
|
fn configure(meta: &mut ConstraintSystem<pallas::Base>) -> Self::Config {
|
2021-06-10 10:07:56 -07:00
|
|
|
let advices = [
|
|
|
|
meta.advice_column(),
|
|
|
|
meta.advice_column(),
|
|
|
|
meta.advice_column(),
|
|
|
|
meta.advice_column(),
|
|
|
|
meta.advice_column(),
|
|
|
|
meta.advice_column(),
|
|
|
|
meta.advice_column(),
|
|
|
|
meta.advice_column(),
|
|
|
|
meta.advice_column(),
|
|
|
|
meta.advice_column(),
|
|
|
|
];
|
2021-07-27 10:32:32 -07:00
|
|
|
let lookup_table = meta.lookup_table_column();
|
2021-07-21 04:13:47 -07:00
|
|
|
let lagrange_coeffs = [
|
|
|
|
meta.fixed_column(),
|
|
|
|
meta.fixed_column(),
|
|
|
|
meta.fixed_column(),
|
|
|
|
meta.fixed_column(),
|
|
|
|
meta.fixed_column(),
|
|
|
|
meta.fixed_column(),
|
|
|
|
meta.fixed_column(),
|
|
|
|
meta.fixed_column(),
|
|
|
|
];
|
2021-07-20 01:22:08 -07:00
|
|
|
// Shared fixed column for loading constants
|
|
|
|
let constants = meta.fixed_column();
|
|
|
|
meta.enable_constant(constants);
|
2021-07-15 04:52:15 -07:00
|
|
|
|
2021-07-21 07:59:08 -07:00
|
|
|
let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table);
|
2022-01-27 13:15:41 -08:00
|
|
|
EccChip::<TestFixedBases>::configure(meta, advices, lagrange_coeffs, range_check)
|
2021-06-10 10:07:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn synthesize(
|
|
|
|
&self,
|
|
|
|
config: Self::Config,
|
2021-07-08 18:56:27 -07:00
|
|
|
mut layouter: impl Layouter<pallas::Base>,
|
2021-06-10 10:07:56 -07:00
|
|
|
) -> Result<(), Error> {
|
2021-06-13 06:06:34 -07:00
|
|
|
let chip = EccChip::construct(config.clone());
|
|
|
|
|
|
|
|
// Load 10-bit lookup table. In the Action circuit, this will be
|
|
|
|
// provided by the Sinsemilla chip.
|
|
|
|
config.lookup_config.load(&mut layouter)?;
|
2021-06-10 10:07:56 -07:00
|
|
|
|
2021-09-27 01:33:13 -07:00
|
|
|
// Generate a random non-identity point P
|
2021-06-11 15:29:05 -07:00
|
|
|
let p_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); // P
|
2021-09-27 01:33:13 -07:00
|
|
|
let p = super::NonIdentityPoint::new(
|
|
|
|
chip.clone(),
|
|
|
|
layouter.namespace(|| "P"),
|
|
|
|
Some(p_val),
|
|
|
|
)?;
|
2021-06-10 10:07:56 -07:00
|
|
|
let p_neg = -p_val;
|
2021-09-27 01:33:13 -07:00
|
|
|
let p_neg = super::NonIdentityPoint::new(
|
|
|
|
chip.clone(),
|
|
|
|
layouter.namespace(|| "-P"),
|
|
|
|
Some(p_neg),
|
|
|
|
)?;
|
2021-06-10 10:07:56 -07:00
|
|
|
|
2021-09-27 01:33:13 -07:00
|
|
|
// Generate a random non-identity point Q
|
2021-06-11 15:29:05 -07:00
|
|
|
let q_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); // Q
|
2021-09-27 01:33:13 -07:00
|
|
|
let q = super::NonIdentityPoint::new(
|
|
|
|
chip.clone(),
|
|
|
|
layouter.namespace(|| "Q"),
|
|
|
|
Some(q_val),
|
|
|
|
)?;
|
2021-06-10 10:07:56 -07:00
|
|
|
|
|
|
|
// Make sure P and Q are not the same point.
|
|
|
|
assert_ne!(p_val, q_val);
|
|
|
|
|
2021-09-28 13:00:29 -07:00
|
|
|
// Test that we can witness the identity as a point, but not as a non-identity point.
|
|
|
|
{
|
|
|
|
let _ = super::Point::new(
|
|
|
|
chip.clone(),
|
|
|
|
layouter.namespace(|| "identity"),
|
|
|
|
Some(pallas::Affine::identity()),
|
|
|
|
)?;
|
|
|
|
|
|
|
|
super::NonIdentityPoint::new(
|
|
|
|
chip.clone(),
|
|
|
|
layouter.namespace(|| "identity"),
|
|
|
|
Some(pallas::Affine::identity()),
|
|
|
|
)
|
|
|
|
.expect_err("Trying to witness the identity should return an error");
|
|
|
|
}
|
|
|
|
|
2021-09-27 01:44:43 -07:00
|
|
|
// Test witness non-identity point
|
|
|
|
{
|
|
|
|
super::chip::witness_point::tests::test_witness_non_id(
|
|
|
|
chip.clone(),
|
|
|
|
layouter.namespace(|| "witness non-identity point"),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-06-10 10:07:56 -07:00
|
|
|
// Test complete addition
|
|
|
|
{
|
|
|
|
super::chip::add::tests::test_add(
|
2021-06-13 09:19:21 -07:00
|
|
|
chip.clone(),
|
2021-06-10 10:07:56 -07:00
|
|
|
layouter.namespace(|| "complete addition"),
|
|
|
|
p_val,
|
|
|
|
&p,
|
|
|
|
q_val,
|
|
|
|
&q,
|
|
|
|
&p_neg,
|
|
|
|
)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test incomplete addition
|
|
|
|
{
|
|
|
|
super::chip::add_incomplete::tests::test_add_incomplete(
|
2021-06-13 18:56:34 -07:00
|
|
|
chip.clone(),
|
2021-06-10 10:07:56 -07:00
|
|
|
layouter.namespace(|| "incomplete addition"),
|
2021-06-13 09:19:21 -07:00
|
|
|
p_val,
|
2021-06-10 10:07:56 -07:00
|
|
|
&p,
|
2021-06-13 09:19:21 -07:00
|
|
|
q_val,
|
2021-06-10 10:07:56 -07:00
|
|
|
&q,
|
|
|
|
&p_neg,
|
2021-12-08 16:49:01 -08:00
|
|
|
self.test_errors,
|
2021-06-10 10:07:56 -07:00
|
|
|
)?;
|
|
|
|
}
|
|
|
|
|
2021-06-13 18:56:34 -07:00
|
|
|
// Test variable-base scalar multiplication
|
|
|
|
{
|
|
|
|
super::chip::mul::tests::test_mul(
|
|
|
|
chip.clone(),
|
|
|
|
layouter.namespace(|| "variable-base scalar mul"),
|
|
|
|
&p,
|
2021-07-08 00:17:52 -07:00
|
|
|
p_val,
|
2021-06-13 18:56:34 -07:00
|
|
|
)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test full-width fixed-base scalar multiplication
|
|
|
|
{
|
|
|
|
super::chip::mul_fixed::full_width::tests::test_mul_fixed(
|
|
|
|
chip.clone(),
|
|
|
|
layouter.namespace(|| "full-width fixed-base scalar mul"),
|
|
|
|
)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test signed short fixed-base scalar multiplication
|
|
|
|
{
|
|
|
|
super::chip::mul_fixed::short::tests::test_mul_fixed_short(
|
2021-06-18 02:41:13 -07:00
|
|
|
chip.clone(),
|
2021-06-13 18:56:34 -07:00
|
|
|
layouter.namespace(|| "signed short fixed-base scalar mul"),
|
|
|
|
)?;
|
|
|
|
}
|
|
|
|
|
2021-06-18 02:41:13 -07:00
|
|
|
// Test fixed-base scalar multiplication with a base field element
|
|
|
|
{
|
|
|
|
super::chip::mul_fixed::base_field_elem::tests::test_mul_fixed_base_field(
|
|
|
|
chip,
|
|
|
|
layouter.namespace(|| "fixed-base scalar mul with base field element"),
|
|
|
|
)?;
|
|
|
|
}
|
|
|
|
|
2021-06-10 10:07:56 -07:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2021-07-26 05:54:27 -07:00
|
|
|
fn ecc_chip() {
|
2021-06-18 02:41:13 -07:00
|
|
|
let k = 13;
|
2021-12-08 16:49:01 -08:00
|
|
|
let circuit = MyCircuit { test_errors: true };
|
2021-06-10 10:07:56 -07:00
|
|
|
let prover = MockProver::run(k, &circuit, vec![]).unwrap();
|
|
|
|
assert_eq!(prover.verify(), Ok(()))
|
|
|
|
}
|
2021-07-02 09:30:22 -07:00
|
|
|
|
|
|
|
#[cfg(feature = "dev-graph")]
|
|
|
|
#[test]
|
|
|
|
fn print_ecc_chip() {
|
|
|
|
use plotters::prelude::*;
|
|
|
|
|
|
|
|
let root = BitMapBackend::new("ecc-chip-layout.png", (1024, 7680)).into_drawing_area();
|
|
|
|
root.fill(&WHITE).unwrap();
|
|
|
|
let root = root.titled("Ecc Chip Layout", ("sans-serif", 60)).unwrap();
|
|
|
|
|
2021-12-08 16:49:01 -08:00
|
|
|
let circuit = MyCircuit { test_errors: false };
|
2022-01-27 15:28:02 -08:00
|
|
|
halo2_proofs::dev::CircuitLayout::default()
|
2021-07-26 05:54:27 -07:00
|
|
|
.render(13, &circuit, &root)
|
2021-07-08 18:56:27 -07:00
|
|
|
.unwrap();
|
2021-07-02 09:30:22 -07:00
|
|
|
}
|
2021-06-10 10:07:56 -07:00
|
|
|
}
|