From 6627b2258f6c0df366c5b3dfd973d5993638070e Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Sat, 5 Jun 2021 14:05:58 +0800 Subject: [PATCH] ecc::chip.rs: Add ECC chip. Implement witness_scalar_var() and extract_p() instructions inline. --- src/circuit/gadget/ecc.rs | 2 + src/circuit/gadget/ecc/chip.rs | 280 +++++++++++++++++++++++++++++++++ 2 files changed, 282 insertions(+) create mode 100644 src/circuit/gadget/ecc/chip.rs diff --git a/src/circuit/gadget/ecc.rs b/src/circuit/gadget/ecc.rs index 07e6eff7..268e33c2 100644 --- a/src/circuit/gadget/ecc.rs +++ b/src/circuit/gadget/ecc.rs @@ -9,6 +9,8 @@ use halo2::{ plonk::Error, }; +pub mod chip; + /// 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 diff --git a/src/circuit/gadget/ecc/chip.rs b/src/circuit/gadget/ecc/chip.rs new file mode 100644 index 00000000..12cef95e --- /dev/null +++ b/src/circuit/gadget/ecc/chip.rs @@ -0,0 +1,280 @@ +use super::EccInstructions; +use crate::circuit::gadget::utilities::{copy, CellValue, Var}; +use crate::constants::{self, OrchardFixedBasesFull, ValueCommitV}; +use arrayvec::ArrayVec; +use ff::{Field, PrimeFieldBits}; +use halo2::{ + arithmetic::CurveAffine, + circuit::{Chip, Layouter}, + plonk::{Advice, Column, ConstraintSystem, Error, Fixed, Permutation, Selector}, +}; +use std::marker::PhantomData; + +// pub(super) mod add; +// pub(super) mod add_incomplete; +// pub(super) mod mul; +// pub(super) mod mul_fixed; +// pub(super) mod witness_point; +// pub(super) mod witness_scalar_fixed; + +/// A curve point represented in affine (x, y) coordinates. Each coordinate is +/// assigned to a cell. +#[derive(Clone, Debug)] +pub struct EccPoint { + /// x-coordinate + pub x: CellValue, + /// y-coordinate + pub y: CellValue, +} + +impl EccPoint { + /// Returns the value of this curve point, if known. + pub fn point(&self) -> Option { + match (self.x.value(), self.y.value()) { + (Some(x), Some(y)) => { + if x == C::Base::zero() && y == C::Base::zero() { + Some(C::identity()) + } else { + Some(C::from_xy(x, y).unwrap()) + } + } + _ => None, + } + } +} + +/// Configuration for the ECC chip +#[derive(Clone, Debug, Eq, PartialEq)] +#[allow(non_snake_case)] +pub struct EccConfig { + /// Advice columns needed by instructions in the ECC chip. + pub advices: [Column; 10], + + /// Coefficients of interpolation polynomials for x-coordinates (used in fixed-base scalar multiplication) + pub lagrange_coeffs: [Column; constants::H], + /// Fixed z such that y + z = u^2 some square, and -y + z is a non-square. (Used in fixed-base scalar multiplication) + pub fixed_z: Column, + + /// Incomplete addition + pub q_add_incomplete: Selector, + /// Complete addition + pub q_add: Selector, + /// Variable-base scalar multiplication (hi half) + pub q_mul_hi: Selector, + /// Variable-base scalar multiplication (lo half) + pub q_mul_lo: Selector, + /// Selector used in scalar decomposition for variable-base scalar mul + pub q_mul_decompose_var: Selector, + /// Variable-base scalar multiplication (final scalar) + pub q_mul_complete: Selector, + /// Fixed-base full-width scalar multiplication + pub q_mul_fixed: Selector, + /// Fixed-base signed short scalar multiplication + pub q_mul_fixed_short: Selector, + /// Witness point + pub q_point: Selector, + /// Witness full-width scalar for fixed-base scalar mul + pub q_scalar_fixed: Selector, + /// Witness signed short scalar for full-width fixed-base scalar mul + pub q_scalar_fixed_short: Selector, + /// Permutation + pub perm: Permutation, +} + +/// A chip implementing EccInstructions +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct EccChip { + config: EccConfig, + _marker: PhantomData, +} + +impl Chip for EccChip { + type Config = EccConfig; + type Loaded = (); + + fn config(&self) -> &Self::Config { + &self.config + } + + fn loaded(&self) -> &Self::Loaded { + &() + } +} + +impl EccChip +where + C::Scalar: PrimeFieldBits, +{ + pub fn construct(config: >::Config) -> Self { + Self { + config, + _marker: PhantomData, + } + } + + #[allow(non_snake_case)] + pub fn configure( + meta: &mut ConstraintSystem, + advices: [Column; 10], + perm: Permutation, + ) -> >::Config { + let config = EccConfig { + advices, + 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(), + ], + fixed_z: meta.fixed_column(), + q_add_incomplete: meta.selector(), + q_add: meta.selector(), + q_mul_hi: meta.selector(), + q_mul_lo: meta.selector(), + q_mul_decompose_var: meta.selector(), + q_mul_complete: meta.selector(), + q_mul_fixed: meta.selector(), + q_mul_fixed_short: meta.selector(), + q_point: meta.selector(), + q_scalar_fixed: meta.selector(), + q_scalar_fixed_short: meta.selector(), + perm, + }; + + // TODO: create gates + + config + } +} + +/// A full-width scalar used for fixed-base scalar multiplication. +/// This is decomposed in chunks of `window_width` bits in little-endian order. +/// For example, if `window_width` = 3, we will have [k_0, k_1, ..., k_n] +/// where `scalar = k_0 + k_1 * (2^3) + ... + k_n * (2^3)^n` and each `k_i` is +/// in the range [0..2^3). +#[derive(Clone, Debug)] +pub struct EccScalarFixed { + value: Option, + windows: ArrayVec, { constants::NUM_WINDOWS }>, +} + +/// A signed short scalar used for fixed-base scalar multiplication. +/// This is decomposed in chunks of `window_width` bits in little-endian order. +/// For example, if `window_width` = 3, we will have [k_0, k_1, ..., k_n] +/// where `scalar = k_0 + k_1 * (2^3) + ... + k_n * (2^3)^n` and each `k_i` is +/// in the range [0..2^3). +#[derive(Clone, Debug)] +pub struct EccScalarFixedShort { + magnitude: Option, + sign: CellValue, + windows: ArrayVec, { constants::NUM_WINDOWS_SHORT }>, +} + +impl EccInstructions for EccChip +where + C::Scalar: PrimeFieldBits, +{ + type ScalarFixed = EccScalarFixed; + type ScalarFixedShort = EccScalarFixedShort; + type ScalarVar = CellValue; + type Point = EccPoint; + type X = CellValue; + type FixedPoints = OrchardFixedBasesFull; + type FixedPointsShort = ValueCommitV; + + fn witness_scalar_var( + &self, + layouter: &mut impl Layouter, + value: Option, + ) -> Result { + layouter.assign_region( + || "Witness scalar for variable-base mul", + |mut region| { + let cell = region.assign_advice( + || "Scalar var", + self.config().advices[0], + 0, + || value.ok_or(Error::SynthesisError), + )?; + Ok(CellValue::new(cell, value)) + }, + ) + } + + fn witness_scalar_fixed( + &self, + layouter: &mut impl Layouter, + value: Option, + ) -> Result { + todo!() + } + + fn witness_scalar_fixed_short( + &self, + layouter: &mut impl Layouter, + value: Option, + ) -> Result { + todo!() + } + + fn witness_point( + &self, + layouter: &mut impl Layouter, + value: Option, + ) -> Result { + todo!() + } + + fn extract_p(point: &Self::Point) -> &Self::X { + &point.x + } + + fn add_incomplete( + &self, + layouter: &mut impl Layouter, + a: &Self::Point, + b: &Self::Point, + ) -> Result { + todo!() + } + + fn add( + &self, + layouter: &mut impl Layouter, + a: &Self::Point, + b: &Self::Point, + ) -> Result { + todo!() + } + + fn mul( + &self, + layouter: &mut impl Layouter, + scalar: &Self::ScalarVar, + base: &Self::Point, + ) -> Result { + todo!() + } + + fn mul_fixed( + &self, + layouter: &mut impl Layouter, + scalar: &Self::ScalarFixed, + base: &Self::FixedPoints, + ) -> Result { + todo!() + } + + fn mul_fixed_short( + &self, + layouter: &mut impl Layouter, + scalar: &Self::ScalarFixedShort, + base: &Self::FixedPointsShort, + ) -> Result { + todo!() + } +}