2021-06-04 23:05:58 -07:00
|
|
|
|
use super::EccInstructions;
|
2021-06-13 06:06:34 -07:00
|
|
|
|
use crate::{
|
|
|
|
|
circuit::gadget::utilities::{
|
2021-07-09 17:50:07 -07:00
|
|
|
|
copy, decompose_running_sum::RunningSumConfig, lookup_range_check::LookupRangeCheckConfig,
|
2021-07-09 18:09:26 -07:00
|
|
|
|
CellValue, UtilitiesInstructions, Var,
|
2021-06-13 06:06:34 -07:00
|
|
|
|
},
|
|
|
|
|
constants::{self, OrchardFixedBasesFull, ValueCommitV},
|
|
|
|
|
primitives::sinsemilla,
|
|
|
|
|
};
|
2021-06-11 21:32:31 -07:00
|
|
|
|
use arrayvec::ArrayVec;
|
2021-06-11 15:29:05 -07:00
|
|
|
|
|
|
|
|
|
use group::prime::PrimeCurveAffine;
|
2021-06-04 23:05:58 -07:00
|
|
|
|
use halo2::{
|
|
|
|
|
circuit::{Chip, Layouter},
|
|
|
|
|
plonk::{Advice, Column, ConstraintSystem, Error, Fixed, Permutation, Selector},
|
|
|
|
|
};
|
2021-06-11 15:29:05 -07:00
|
|
|
|
use pasta_curves::{arithmetic::CurveAffine, pallas};
|
2021-06-04 23:05:58 -07:00
|
|
|
|
|
2021-06-04 23:13:56 -07:00
|
|
|
|
pub(super) mod add;
|
2021-06-04 23:11:40 -07:00
|
|
|
|
pub(super) mod add_incomplete;
|
2021-06-04 23:17:43 -07:00
|
|
|
|
pub(super) mod mul;
|
2021-06-04 23:34:44 -07:00
|
|
|
|
pub(super) mod mul_fixed;
|
2021-06-04 23:08:51 -07:00
|
|
|
|
pub(super) mod witness_point;
|
2021-06-04 23:23:56 -07:00
|
|
|
|
pub(super) mod witness_scalar_fixed;
|
2021-06-04 23:05:58 -07:00
|
|
|
|
|
|
|
|
|
/// A curve point represented in affine (x, y) coordinates. Each coordinate is
|
|
|
|
|
/// assigned to a cell.
|
|
|
|
|
#[derive(Clone, Debug)]
|
2021-06-11 15:29:05 -07:00
|
|
|
|
pub struct EccPoint {
|
2021-06-04 23:05:58 -07:00
|
|
|
|
/// x-coordinate
|
2021-06-11 15:29:05 -07:00
|
|
|
|
x: CellValue<pallas::Base>,
|
2021-06-04 23:05:58 -07:00
|
|
|
|
/// y-coordinate
|
2021-06-11 15:29:05 -07:00
|
|
|
|
y: CellValue<pallas::Base>,
|
2021-06-04 23:05:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-11 15:29:05 -07:00
|
|
|
|
impl EccPoint {
|
2021-06-18 23:59:09 -07:00
|
|
|
|
/// Constructs a point from its coordinates, without checking they are on the curve.
|
|
|
|
|
///
|
|
|
|
|
/// This is an internal API that we only use where we know we have a valid curve point
|
|
|
|
|
/// (specifically inside Sinsemilla).
|
|
|
|
|
pub(in crate::circuit::gadget) fn from_coordinates_unchecked(
|
|
|
|
|
x: CellValue<pallas::Base>,
|
|
|
|
|
y: CellValue<pallas::Base>,
|
|
|
|
|
) -> Self {
|
|
|
|
|
EccPoint { x, y }
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-04 23:05:58 -07:00
|
|
|
|
/// Returns the value of this curve point, if known.
|
2021-06-11 15:29:05 -07:00
|
|
|
|
pub fn point(&self) -> Option<pallas::Affine> {
|
2021-06-04 23:05:58 -07:00
|
|
|
|
match (self.x.value(), self.y.value()) {
|
|
|
|
|
(Some(x), Some(y)) => {
|
2021-06-11 15:29:05 -07:00
|
|
|
|
if x == pallas::Base::zero() && y == pallas::Base::zero() {
|
|
|
|
|
Some(pallas::Affine::identity())
|
2021-06-04 23:05:58 -07:00
|
|
|
|
} else {
|
2021-06-11 15:29:05 -07:00
|
|
|
|
Some(pallas::Affine::from_xy(x, y).unwrap())
|
2021-06-04 23:05:58 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-10 20:24:12 -07:00
|
|
|
|
/// The cell containing the affine short-Weierstrass x-coordinate,
|
|
|
|
|
/// or 0 for the zero point.
|
2021-06-11 15:29:05 -07:00
|
|
|
|
pub fn x(&self) -> CellValue<pallas::Base> {
|
2021-06-10 20:24:12 -07:00
|
|
|
|
self.x
|
|
|
|
|
}
|
|
|
|
|
/// The cell containing the affine short-Weierstrass y-coordinate,
|
|
|
|
|
/// or 0 for the zero point.
|
2021-06-11 15:29:05 -07:00
|
|
|
|
pub fn y(&self) -> CellValue<pallas::Base> {
|
2021-06-10 20:24:12 -07:00
|
|
|
|
self.y
|
|
|
|
|
}
|
2021-06-04 23:05:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Configuration for the ECC chip
|
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
|
|
|
#[allow(non_snake_case)]
|
2021-06-11 15:29:05 -07:00
|
|
|
|
pub struct EccConfig {
|
2021-06-04 23:05:58 -07:00
|
|
|
|
/// Advice columns needed by instructions in the ECC chip.
|
|
|
|
|
pub advices: [Column<Advice>; 10],
|
|
|
|
|
|
|
|
|
|
/// Coefficients of interpolation polynomials for x-coordinates (used in fixed-base scalar multiplication)
|
|
|
|
|
pub lagrange_coeffs: [Column<Fixed>; 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<Fixed>,
|
|
|
|
|
|
|
|
|
|
/// Incomplete addition
|
|
|
|
|
pub q_add_incomplete: Selector,
|
2021-06-13 06:06:34 -07:00
|
|
|
|
|
2021-06-04 23:05:58 -07:00
|
|
|
|
/// Complete addition
|
|
|
|
|
pub q_add: Selector,
|
2021-06-13 06:06:34 -07:00
|
|
|
|
|
2021-06-04 23:05:58 -07:00
|
|
|
|
/// Variable-base scalar multiplication (hi half)
|
2021-07-02 01:41:18 -07:00
|
|
|
|
pub q_mul_hi: Column<Fixed>,
|
2021-06-04 23:05:58 -07:00
|
|
|
|
/// Variable-base scalar multiplication (lo half)
|
2021-07-02 01:41:18 -07:00
|
|
|
|
pub q_mul_lo: Column<Fixed>,
|
2021-06-18 11:11:47 -07:00
|
|
|
|
/// Selector used to enforce boolean decomposition in variable-base scalar mul
|
|
|
|
|
pub q_mul_decompose_var: Selector,
|
|
|
|
|
/// Selector used to enforce switching logic on LSB in variable-base scalar mul
|
|
|
|
|
pub q_mul_lsb: Selector,
|
2021-06-13 06:06:34 -07:00
|
|
|
|
/// Variable-base scalar multiplication (overflow check)
|
|
|
|
|
pub q_mul_overflow: Selector,
|
|
|
|
|
|
2021-06-04 23:05:58 -07:00
|
|
|
|
/// Fixed-base full-width scalar multiplication
|
2021-07-07 00:52:31 -07:00
|
|
|
|
pub q_mul_fixed: Selector,
|
2021-06-04 23:05:58 -07:00
|
|
|
|
/// Fixed-base signed short scalar multiplication
|
|
|
|
|
pub q_mul_fixed_short: Selector,
|
2021-06-18 02:41:13 -07:00
|
|
|
|
/// Fixed-base multiplication using a base field element as the scalar
|
2021-07-09 17:50:07 -07:00
|
|
|
|
pub q_mul_fixed_running_sum: Selector,
|
2021-07-07 00:52:31 -07:00
|
|
|
|
/// Canonicity checks on base field element used as scalar in fixed-base mul
|
|
|
|
|
pub base_field_fixed_canon: Selector,
|
2021-06-13 06:06:34 -07:00
|
|
|
|
|
2021-06-04 23:05:58 -07:00
|
|
|
|
/// Witness point
|
|
|
|
|
pub q_point: Selector,
|
2021-06-19 04:08:46 -07:00
|
|
|
|
|
2021-06-04 23:05:58 -07:00
|
|
|
|
/// 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,
|
2021-06-13 06:06:34 -07:00
|
|
|
|
|
2021-06-19 04:08:46 -07:00
|
|
|
|
/// Shared fixed column used for loading constants. This is included in
|
|
|
|
|
/// the permutation so that cells in advice columns can be constrained to
|
|
|
|
|
/// equal cells in this fixed column.
|
|
|
|
|
pub constants: Column<Fixed>,
|
|
|
|
|
/// Permutation over all advice columns and the `constants` fixed column.
|
2021-06-04 23:05:58 -07:00
|
|
|
|
pub perm: Permutation,
|
2021-07-09 17:50:07 -07:00
|
|
|
|
/// Lookup range check using 10-bit lookup table
|
2021-06-13 06:06:34 -07:00
|
|
|
|
pub lookup_config: LookupRangeCheckConfig<pallas::Base, { sinsemilla::K }>,
|
2021-07-09 17:50:07 -07:00
|
|
|
|
/// Running sum decomposition for full-width base field element
|
|
|
|
|
pub running_sum_full_config: RunningSumConfig<
|
|
|
|
|
pallas::Base,
|
|
|
|
|
{ constants::L_ORCHARD_BASE },
|
|
|
|
|
{ constants::FIXED_BASE_WINDOW_SIZE },
|
|
|
|
|
{ constants::NUM_WINDOWS },
|
|
|
|
|
>,
|
|
|
|
|
/// Running sum decomposition for 64-bit word
|
|
|
|
|
pub running_sum_short_config: RunningSumConfig<
|
|
|
|
|
pallas::Base,
|
|
|
|
|
{ constants::L_VALUE },
|
|
|
|
|
{ constants::FIXED_BASE_WINDOW_SIZE },
|
|
|
|
|
{ constants::NUM_WINDOWS_SHORT },
|
|
|
|
|
>,
|
2021-06-04 23:05:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A chip implementing EccInstructions
|
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
2021-06-11 15:29:05 -07:00
|
|
|
|
pub struct EccChip {
|
|
|
|
|
config: EccConfig,
|
2021-06-04 23:05:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-11 15:29:05 -07:00
|
|
|
|
impl Chip<pallas::Base> for EccChip {
|
|
|
|
|
type Config = EccConfig;
|
2021-06-04 23:05:58 -07:00
|
|
|
|
type Loaded = ();
|
|
|
|
|
|
|
|
|
|
fn config(&self) -> &Self::Config {
|
|
|
|
|
&self.config
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn loaded(&self) -> &Self::Loaded {
|
|
|
|
|
&()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-09 18:09:26 -07:00
|
|
|
|
impl UtilitiesInstructions<pallas::Base> for EccChip {
|
|
|
|
|
type Var = CellValue<pallas::Base>;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-11 15:29:05 -07:00
|
|
|
|
impl EccChip {
|
|
|
|
|
pub fn construct(config: <Self as Chip<pallas::Base>>::Config) -> Self {
|
2021-06-10 10:09:04 -07:00
|
|
|
|
Self { config }
|
2021-06-04 23:05:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
|
pub fn configure(
|
2021-06-11 15:29:05 -07:00
|
|
|
|
meta: &mut ConstraintSystem<pallas::Base>,
|
2021-06-04 23:05:58 -07:00
|
|
|
|
advices: [Column<Advice>; 10],
|
2021-06-13 06:06:34 -07:00
|
|
|
|
lookup_table: Column<Fixed>,
|
2021-06-19 04:08:46 -07:00
|
|
|
|
// TODO: Replace with public inputs API
|
|
|
|
|
constants: [Column<Fixed>; 2],
|
2021-06-04 23:05:58 -07:00
|
|
|
|
perm: Permutation,
|
2021-06-11 15:29:05 -07:00
|
|
|
|
) -> <Self as Chip<pallas::Base>>::Config {
|
2021-06-19 04:08:46 -07:00
|
|
|
|
let lookup_config = LookupRangeCheckConfig::configure(
|
|
|
|
|
meta,
|
|
|
|
|
advices[9],
|
|
|
|
|
constants[0],
|
|
|
|
|
lookup_table,
|
|
|
|
|
perm.clone(),
|
|
|
|
|
);
|
2021-07-09 17:50:07 -07:00
|
|
|
|
let q_mul_fixed_running_sum = meta.selector();
|
|
|
|
|
let running_sum_full_config =
|
|
|
|
|
RunningSumConfig::configure(meta, q_mul_fixed_running_sum, advices[4], perm.clone());
|
|
|
|
|
let running_sum_short_config =
|
|
|
|
|
RunningSumConfig::configure(meta, q_mul_fixed_running_sum, advices[4], perm.clone());
|
2021-06-13 06:06:34 -07:00
|
|
|
|
|
2021-06-11 15:29:05 -07:00
|
|
|
|
let config = EccConfig {
|
2021-06-04 23:05:58 -07:00
|
|
|
|
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(),
|
2021-07-02 01:41:18 -07:00
|
|
|
|
q_mul_hi: meta.fixed_column(),
|
|
|
|
|
q_mul_lo: meta.fixed_column(),
|
2021-06-18 11:11:47 -07:00
|
|
|
|
q_mul_decompose_var: meta.selector(),
|
2021-06-13 06:06:34 -07:00
|
|
|
|
q_mul_overflow: meta.selector(),
|
2021-06-18 11:11:47 -07:00
|
|
|
|
q_mul_lsb: meta.selector(),
|
2021-07-07 00:52:31 -07:00
|
|
|
|
q_mul_fixed: meta.selector(),
|
2021-06-04 23:05:58 -07:00
|
|
|
|
q_mul_fixed_short: meta.selector(),
|
2021-07-09 17:50:07 -07:00
|
|
|
|
q_mul_fixed_running_sum,
|
2021-07-07 00:52:31 -07:00
|
|
|
|
base_field_fixed_canon: meta.selector(),
|
2021-06-04 23:05:58 -07:00
|
|
|
|
q_point: meta.selector(),
|
|
|
|
|
q_scalar_fixed: meta.selector(),
|
|
|
|
|
q_scalar_fixed_short: meta.selector(),
|
2021-06-19 04:08:46 -07:00
|
|
|
|
constants: constants[1],
|
2021-06-04 23:05:58 -07:00
|
|
|
|
perm,
|
2021-06-13 06:06:34 -07:00
|
|
|
|
lookup_config,
|
2021-07-09 17:50:07 -07:00
|
|
|
|
running_sum_full_config,
|
|
|
|
|
running_sum_short_config,
|
2021-06-04 23:05:58 -07:00
|
|
|
|
};
|
|
|
|
|
|
2021-06-04 23:08:51 -07:00
|
|
|
|
// Create witness point gate
|
|
|
|
|
{
|
2021-06-11 15:29:05 -07:00
|
|
|
|
let config: witness_point::Config = (&config).into();
|
2021-06-10 10:09:04 -07:00
|
|
|
|
config.create_gate(meta);
|
2021-06-04 23:08:51 -07:00
|
|
|
|
}
|
2021-06-04 23:05:58 -07:00
|
|
|
|
|
2021-06-04 23:11:40 -07:00
|
|
|
|
// Create incomplete point addition gate
|
|
|
|
|
{
|
2021-06-11 15:29:05 -07:00
|
|
|
|
let config: add_incomplete::Config = (&config).into();
|
2021-06-04 23:11:40 -07:00
|
|
|
|
config.create_gate(meta);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-04 23:13:56 -07:00
|
|
|
|
// Create complete point addition gate
|
|
|
|
|
{
|
2021-06-11 15:29:05 -07:00
|
|
|
|
let add_config: add::Config = (&config).into();
|
2021-06-04 23:13:56 -07:00
|
|
|
|
add_config.create_gate(meta);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-04 23:17:43 -07:00
|
|
|
|
// Create variable-base scalar mul gates
|
|
|
|
|
{
|
|
|
|
|
let mul_config: mul::Config = (&config).into();
|
|
|
|
|
mul_config.create_gate(meta);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-04 23:23:56 -07:00
|
|
|
|
// Create witness scalar_fixed gate that applies to both full-width and
|
|
|
|
|
// short scalars
|
|
|
|
|
{
|
|
|
|
|
let config: witness_scalar_fixed::Config = (&config).into();
|
|
|
|
|
config.create_gate(meta);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-13 06:06:34 -07:00
|
|
|
|
// Create witness scalar_fixed gate that only applies to short scalars
|
2021-06-04 23:23:56 -07:00
|
|
|
|
{
|
|
|
|
|
let config: witness_scalar_fixed::short::Config = (&config).into();
|
|
|
|
|
config.create_gate(meta);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-13 06:06:34 -07:00
|
|
|
|
// Create fixed-base scalar mul gate that is used in both full-width
|
2021-06-04 23:34:44 -07:00
|
|
|
|
// and short multiplication.
|
|
|
|
|
{
|
|
|
|
|
let mul_fixed_config: mul_fixed::Config<{ constants::NUM_WINDOWS }> = (&config).into();
|
2021-06-18 02:41:13 -07:00
|
|
|
|
mul_fixed_config.create_gate_scalar(meta);
|
2021-06-04 23:34:44 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create gate that is only used in short fixed-base scalar mul.
|
|
|
|
|
{
|
|
|
|
|
let short_config: mul_fixed::short::Config<{ constants::NUM_WINDOWS_SHORT }> =
|
|
|
|
|
(&config).into();
|
|
|
|
|
short_config.create_gate(meta);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-03 01:49:15 -07:00
|
|
|
|
// Create gate that is only used in fixed-base mul using a base field element.
|
2021-06-18 02:41:13 -07:00
|
|
|
|
{
|
|
|
|
|
let base_field_config: mul_fixed::base_field_elem::Config = (&config).into();
|
|
|
|
|
base_field_config.create_gate(meta);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-04 23:05:58 -07:00
|
|
|
|
config
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-13 06:06:34 -07:00
|
|
|
|
/// A base-field element used as the scalar in variable-base scalar multiplication.
|
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
|
|
|
pub struct EccScalarVar(CellValue<pallas::Base>);
|
|
|
|
|
impl std::ops::Deref for EccScalarVar {
|
|
|
|
|
type Target = CellValue<pallas::Base>;
|
|
|
|
|
|
|
|
|
|
fn deref(&self) -> &CellValue<pallas::Base> {
|
|
|
|
|
&self.0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-11 21:32:31 -07:00
|
|
|
|
/// A full-width scalar used for fixed-base scalar multiplication.
|
2021-06-18 02:41:13 -07:00
|
|
|
|
/// This is decomposed into 85 3-bit windows in little-endian order,
|
|
|
|
|
/// i.e. `windows` = [k_0, k_1, ..., k_84] (for a 255-bit scalar)
|
|
|
|
|
/// where `scalar = k_0 + k_1 * (2^3) + ... + k_84 * (2^3)^84` and
|
|
|
|
|
/// each `k_i` is in the range [0..2^3).
|
2021-06-11 21:32:31 -07:00
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
|
pub struct EccScalarFixed {
|
|
|
|
|
value: Option<pallas::Scalar>,
|
|
|
|
|
windows: ArrayVec<CellValue<pallas::Base>, { constants::NUM_WINDOWS }>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A signed short scalar used for fixed-base scalar multiplication.
|
2021-06-18 02:41:13 -07:00
|
|
|
|
/// A short scalar must have magnitude in the range [0..2^64), with
|
|
|
|
|
/// a sign of either 1 or -1.
|
2021-07-07 22:14:53 -07:00
|
|
|
|
/// This is decomposed into 3-bit windows in little-endian order
|
|
|
|
|
/// using a running sum `z`, where z_{i+1} = (z_i - a_i) / (2^3)
|
|
|
|
|
/// for element α = a_0 + (2^3) a_1 + ... + (2^{3(n-1)}) a_{n-1}.
|
|
|
|
|
/// Each `a_i` is in the range [0..2^3).
|
|
|
|
|
///
|
|
|
|
|
/// `windows` = [k_0, k_1, ..., k_21] (for a 64-bit magnitude)
|
2021-06-18 02:41:13 -07:00
|
|
|
|
/// where `scalar = k_0 + k_1 * (2^3) + ... + k_84 * (2^3)^84` and
|
|
|
|
|
/// each `k_i` is in the range [0..2^3).
|
|
|
|
|
/// k_21 must be a single bit, i.e. 0 or 1.
|
2021-06-11 21:32:31 -07:00
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
|
pub struct EccScalarFixedShort {
|
|
|
|
|
magnitude: Option<pallas::Scalar>,
|
|
|
|
|
sign: CellValue<pallas::Base>,
|
|
|
|
|
windows: ArrayVec<CellValue<pallas::Base>, { constants::NUM_WINDOWS_SHORT }>,
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-18 02:41:13 -07:00
|
|
|
|
/// A base field element used for fixed-base scalar multiplication.
|
|
|
|
|
/// This is decomposed into 3-bit windows in little-endian order
|
|
|
|
|
/// using a running sum `z`, where z_{i+1} = (z_i - a_i) / (2^3)
|
|
|
|
|
/// for element α = a_0 + (2^3) a_1 + ... + (2^{3(n-1)}) a_{n-1}.
|
|
|
|
|
/// Each `a_i` is in the range [0..2^3).
|
|
|
|
|
///
|
|
|
|
|
/// `windows` = [z_1, ..., z_85], where we expect z_85 = 0.
|
2021-07-03 01:49:15 -07:00
|
|
|
|
/// Since z_0 is initialized as the scalar α, we store it as
|
|
|
|
|
/// `base_field_elem`.
|
2021-06-18 02:41:13 -07:00
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
|
struct EccBaseFieldElemFixed {
|
|
|
|
|
base_field_elem: CellValue<pallas::Base>,
|
|
|
|
|
running_sum: ArrayVec<CellValue<pallas::Base>, { constants::NUM_WINDOWS }>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl EccBaseFieldElemFixed {
|
|
|
|
|
fn base_field_elem(&self) -> CellValue<pallas::Base> {
|
|
|
|
|
self.base_field_elem
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-11 15:29:05 -07:00
|
|
|
|
impl EccInstructions<pallas::Affine> for EccChip {
|
2021-06-11 21:32:31 -07:00
|
|
|
|
type ScalarFixed = EccScalarFixed;
|
|
|
|
|
type ScalarFixedShort = EccScalarFixedShort;
|
2021-06-13 06:06:34 -07:00
|
|
|
|
type ScalarVar = EccScalarVar;
|
2021-06-11 15:29:05 -07:00
|
|
|
|
type Point = EccPoint;
|
|
|
|
|
type X = CellValue<pallas::Base>;
|
2021-06-11 21:32:31 -07:00
|
|
|
|
type FixedPoints = OrchardFixedBasesFull;
|
|
|
|
|
type FixedPointsShort = ValueCommitV;
|
2021-06-04 23:05:58 -07:00
|
|
|
|
|
2021-06-13 06:26:30 -07:00
|
|
|
|
fn constrain_equal(
|
|
|
|
|
&self,
|
|
|
|
|
layouter: &mut impl Layouter<pallas::Base>,
|
|
|
|
|
a: &Self::Point,
|
|
|
|
|
b: &Self::Point,
|
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
|
let config = self.config().clone();
|
|
|
|
|
layouter.assign_region(
|
|
|
|
|
|| "constrain equal",
|
|
|
|
|
|mut region| {
|
|
|
|
|
// Constrain x-coordinates
|
|
|
|
|
region.constrain_equal(&config.perm, a.x().cell(), b.x().cell())?;
|
|
|
|
|
// Constrain x-coordinates
|
|
|
|
|
region.constrain_equal(&config.perm, a.y().cell(), b.y().cell())
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-04 23:05:58 -07:00
|
|
|
|
fn witness_scalar_var(
|
|
|
|
|
&self,
|
2021-06-12 05:32:11 -07:00
|
|
|
|
layouter: &mut impl Layouter<pallas::Base>,
|
|
|
|
|
value: Option<pallas::Base>,
|
2021-06-04 23:05:58 -07:00
|
|
|
|
) -> Result<Self::ScalarVar, Error> {
|
2021-06-12 05:32:11 -07:00
|
|
|
|
let config = self.config().clone();
|
|
|
|
|
layouter.assign_region(
|
|
|
|
|
|| "Witness scalar for variable-base mul",
|
|
|
|
|
|mut region| {
|
|
|
|
|
let cell = region.assign_advice(
|
2021-06-13 06:06:34 -07:00
|
|
|
|
|| "witness scalar var",
|
2021-06-12 05:32:11 -07:00
|
|
|
|
config.advices[0],
|
|
|
|
|
0,
|
|
|
|
|
|| value.ok_or(Error::SynthesisError),
|
|
|
|
|
)?;
|
2021-06-13 06:06:34 -07:00
|
|
|
|
Ok(EccScalarVar(CellValue::new(cell, value)))
|
2021-06-12 05:32:11 -07:00
|
|
|
|
},
|
|
|
|
|
)
|
2021-06-04 23:05:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn witness_scalar_fixed(
|
|
|
|
|
&self,
|
2021-06-04 23:23:56 -07:00
|
|
|
|
layouter: &mut impl Layouter<pallas::Base>,
|
|
|
|
|
value: Option<pallas::Scalar>,
|
2021-06-04 23:05:58 -07:00
|
|
|
|
) -> Result<Self::ScalarFixed, Error> {
|
2021-06-04 23:23:56 -07:00
|
|
|
|
let config: witness_scalar_fixed::full_width::Config = self.config().into();
|
|
|
|
|
layouter.assign_region(
|
|
|
|
|
|| "witness scalar for fixed-base mul",
|
|
|
|
|
|mut region| config.assign_region(value, 0, &mut region),
|
|
|
|
|
)
|
2021-06-04 23:05:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn witness_scalar_fixed_short(
|
|
|
|
|
&self,
|
2021-06-04 23:23:56 -07:00
|
|
|
|
layouter: &mut impl Layouter<pallas::Base>,
|
|
|
|
|
value: Option<pallas::Scalar>,
|
2021-06-04 23:05:58 -07:00
|
|
|
|
) -> Result<Self::ScalarFixedShort, Error> {
|
2021-06-04 23:23:56 -07:00
|
|
|
|
let config: witness_scalar_fixed::short::Config = self.config().into();
|
|
|
|
|
layouter.assign_region(
|
|
|
|
|
|| "witness short scalar for fixed-base mul",
|
|
|
|
|
|mut region| config.assign_region(value, 0, &mut region),
|
|
|
|
|
)
|
2021-06-04 23:05:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn witness_point(
|
|
|
|
|
&self,
|
2021-06-11 15:29:05 -07:00
|
|
|
|
layouter: &mut impl Layouter<pallas::Base>,
|
|
|
|
|
value: Option<pallas::Affine>,
|
2021-06-04 23:05:58 -07:00
|
|
|
|
) -> Result<Self::Point, Error> {
|
2021-06-11 15:29:05 -07:00
|
|
|
|
let config: witness_point::Config = self.config().into();
|
2021-06-04 23:08:51 -07:00
|
|
|
|
layouter.assign_region(
|
|
|
|
|
|| "witness point",
|
|
|
|
|
|mut region| config.assign_region(value, 0, &mut region),
|
|
|
|
|
)
|
2021-06-04 23:05:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn extract_p(point: &Self::Point) -> &Self::X {
|
|
|
|
|
&point.x
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn add_incomplete(
|
|
|
|
|
&self,
|
2021-06-11 15:29:05 -07:00
|
|
|
|
layouter: &mut impl Layouter<pallas::Base>,
|
2021-06-04 23:05:58 -07:00
|
|
|
|
a: &Self::Point,
|
|
|
|
|
b: &Self::Point,
|
|
|
|
|
) -> Result<Self::Point, Error> {
|
2021-06-11 15:29:05 -07:00
|
|
|
|
let config: add_incomplete::Config = self.config().into();
|
2021-06-04 23:11:40 -07:00
|
|
|
|
layouter.assign_region(
|
|
|
|
|
|| "incomplete point addition",
|
|
|
|
|
|mut region| config.assign_region(a, b, 0, &mut region),
|
|
|
|
|
)
|
2021-06-04 23:05:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn add(
|
|
|
|
|
&self,
|
2021-06-11 15:29:05 -07:00
|
|
|
|
layouter: &mut impl Layouter<pallas::Base>,
|
2021-06-04 23:05:58 -07:00
|
|
|
|
a: &Self::Point,
|
|
|
|
|
b: &Self::Point,
|
|
|
|
|
) -> Result<Self::Point, Error> {
|
2021-06-11 15:29:05 -07:00
|
|
|
|
let config: add::Config = self.config().into();
|
2021-06-04 23:13:56 -07:00
|
|
|
|
layouter.assign_region(
|
|
|
|
|
|| "complete point addition",
|
|
|
|
|
|mut region| config.assign_region(a, b, 0, &mut region),
|
|
|
|
|
)
|
2021-06-04 23:05:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn mul(
|
|
|
|
|
&self,
|
2021-06-04 23:17:43 -07:00
|
|
|
|
layouter: &mut impl Layouter<pallas::Base>,
|
|
|
|
|
scalar: &Self::ScalarVar,
|
|
|
|
|
base: &Self::Point,
|
2021-06-04 23:05:58 -07:00
|
|
|
|
) -> Result<Self::Point, Error> {
|
2021-06-04 23:17:43 -07:00
|
|
|
|
let config: mul::Config = self.config().into();
|
2021-06-13 06:06:34 -07:00
|
|
|
|
config.assign(
|
|
|
|
|
layouter.namespace(|| "variable-base scalar mul"),
|
|
|
|
|
*scalar,
|
|
|
|
|
base,
|
2021-06-04 23:17:43 -07:00
|
|
|
|
)
|
2021-06-04 23:05:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn mul_fixed(
|
|
|
|
|
&self,
|
2021-06-04 23:34:44 -07:00
|
|
|
|
layouter: &mut impl Layouter<pallas::Base>,
|
|
|
|
|
scalar: &Self::ScalarFixed,
|
|
|
|
|
base: &Self::FixedPoints,
|
2021-06-04 23:05:58 -07:00
|
|
|
|
) -> Result<Self::Point, Error> {
|
2021-06-04 23:34:44 -07:00
|
|
|
|
let config: mul_fixed::full_width::Config<{ constants::NUM_WINDOWS }> =
|
|
|
|
|
self.config().into();
|
2021-07-06 20:26:32 -07:00
|
|
|
|
config.assign(
|
|
|
|
|
layouter.namespace(|| format!("fixed-base mul of {:?}", base)),
|
|
|
|
|
scalar,
|
|
|
|
|
*base,
|
2021-06-04 23:34:44 -07:00
|
|
|
|
)
|
2021-06-04 23:05:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn mul_fixed_short(
|
|
|
|
|
&self,
|
2021-06-04 23:34:44 -07:00
|
|
|
|
layouter: &mut impl Layouter<pallas::Base>,
|
|
|
|
|
scalar: &Self::ScalarFixedShort,
|
|
|
|
|
base: &Self::FixedPointsShort,
|
2021-06-04 23:05:58 -07:00
|
|
|
|
) -> Result<Self::Point, Error> {
|
2021-06-04 23:34:44 -07:00
|
|
|
|
let config: mul_fixed::short::Config<{ constants::NUM_WINDOWS_SHORT }> =
|
|
|
|
|
self.config().into();
|
2021-07-06 20:26:32 -07:00
|
|
|
|
config.assign(
|
|
|
|
|
layouter.namespace(|| format!("short fixed-base mul of {:?}", base)),
|
|
|
|
|
scalar,
|
|
|
|
|
base,
|
2021-06-04 23:34:44 -07:00
|
|
|
|
)
|
2021-06-04 23:05:58 -07:00
|
|
|
|
}
|
2021-06-18 02:41:13 -07:00
|
|
|
|
|
|
|
|
|
fn mul_fixed_base_field_elem(
|
|
|
|
|
&self,
|
|
|
|
|
layouter: &mut impl Layouter<pallas::Base>,
|
|
|
|
|
base_field_elem: CellValue<pallas::Base>,
|
|
|
|
|
base: &Self::FixedPoints,
|
|
|
|
|
) -> Result<Self::Point, Error> {
|
|
|
|
|
let config: mul_fixed::base_field_elem::Config = self.config().into();
|
2021-07-06 20:26:32 -07:00
|
|
|
|
config.assign(
|
|
|
|
|
layouter.namespace(|| format!("base-field elem fixed-base mul of {:?}", base)),
|
|
|
|
|
base_field_elem,
|
|
|
|
|
*base,
|
2021-06-18 02:41:13 -07:00
|
|
|
|
)
|
|
|
|
|
}
|
2021-06-04 23:05:58 -07:00
|
|
|
|
}
|