ecc.rs: Add MulFixedBaseField type.

In the Orchard protocol, only the NullifierK fixed base in used in
scalar multiplication with a base field element.

The mul_fixed_base_field_elem() API does not have to accept fixed
bases other than NullifierK; conversely, NullifierK does not have
to work with the full-width mul_fixed() API.
This commit is contained in:
therealyingtong 2021-07-15 13:05:22 +08:00
parent 1681463856
commit 32f3068886
7 changed files with 97 additions and 79 deletions

View File

@ -39,8 +39,10 @@ pub trait EccInstructions<C: CurveAffine>: Chip<C::Base> + UtilitiesInstructions
/// Variable representing the affine short Weierstrass x-coordinate of an
/// elliptic curve point.
type X: Clone + Debug;
/// Enumeration of the set of fixed bases to be used in full-width scalar mul.
/// Enumeration of the set of fixed bases to be used in scalar mul with a full-width scalar.
type FixedPoints: Clone + Debug;
/// Enumeration of the set of fixed bases to be used in scalar mul with a base field element.
type FixedPointsBaseField: Clone + Debug;
/// Enumeration of the set of fixed bases to be used in short signed scalar mul.
type FixedPointsShort: Clone + Debug;
@ -113,7 +115,7 @@ pub trait EccInstructions<C: CurveAffine>: Chip<C::Base> + UtilitiesInstructions
&self,
layouter: &mut impl Layouter<C::Base>,
base_field_elem: Self::Var,
base: &Self::FixedPoints,
base: &Self::FixedPointsBaseField,
) -> Result<Self::Point, Error>;
}
@ -258,6 +260,8 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> X<C, EccC
/// A constant elliptic curve point over the given curve, for which window tables have
/// been provided to make scalar multiplication more efficient.
///
/// Used in scalar multiplication with full-width scalars.
#[derive(Clone, Debug)]
pub struct FixedPoint<C: CurveAffine, EccChip>
where
@ -294,9 +298,30 @@ where
})
}
/// Multiplies `self` using a value encoded in a base field element
/// as the scalar.
pub fn mul_base_field_elem(
/// Wraps the given fixed base (obtained directly from an instruction) in a gadget.
pub fn from_inner(chip: EccChip, inner: EccChip::FixedPoints) -> Self {
FixedPoint { chip, inner }
}
}
/// A constant elliptic curve point over the given curve, used in scalar multiplication
/// with a base field element
#[derive(Clone, Debug)]
pub struct FixedPointBaseField<C: CurveAffine, EccChip>
where
EccChip: EccInstructions<C> + Clone + Debug + Eq,
{
chip: EccChip,
inner: EccChip::FixedPointsBaseField,
}
impl<C: CurveAffine, EccChip> FixedPointBaseField<C, EccChip>
where
EccChip: EccInstructions<C> + Clone + Debug + Eq,
{
#[allow(clippy::type_complexity)]
/// Returns `[by] self`.
pub fn mul(
&self,
mut layouter: impl Layouter<C::Base>,
by: EccChip::Var,
@ -310,8 +335,8 @@ where
}
/// Wraps the given fixed base (obtained directly from an instruction) in a gadget.
pub fn from_inner(chip: EccChip, inner: EccChip::FixedPoints) -> Self {
FixedPoint { chip, inner }
pub fn from_inner(chip: EccChip, inner: EccChip::FixedPointsBaseField) -> Self {
FixedPointBaseField { chip, inner }
}
}

View File

@ -4,7 +4,7 @@ use crate::{
copy, decompose_running_sum::RunningSumConfig, lookup_range_check::LookupRangeCheckConfig,
CellValue, UtilitiesInstructions, Var,
},
constants::{self, OrchardFixedBasesFull, ValueCommitV},
constants::{self, NullifierK, OrchardFixedBasesFull, ValueCommitV},
primitives::sinsemilla,
};
use arrayvec::ArrayVec;
@ -327,6 +327,7 @@ impl EccInstructions<pallas::Affine> for EccChip {
type Point = EccPoint;
type X = CellValue<pallas::Base>;
type FixedPoints = OrchardFixedBasesFull;
type FixedPointsBaseField = NullifierK;
type FixedPointsShort = ValueCommitV;
fn constrain_equal(
@ -435,7 +436,7 @@ impl EccInstructions<pallas::Affine> for EccChip {
&self,
layouter: &mut impl Layouter<pallas::Base>,
base_field_elem: CellValue<pallas::Base>,
base: &Self::FixedPoints,
base: &Self::FixedPointsBaseField,
) -> Result<Self::Point, Error> {
let config: mul_fixed::base_field_elem::Config = self.config().into();
config.assign(

View File

@ -4,7 +4,7 @@ use super::{
};
use crate::constants::{
self,
load::{OrchardFixedBase, OrchardFixedBasesFull, ValueCommitV, WindowUs},
load::{NullifierK, OrchardFixedBase, OrchardFixedBasesFull, ValueCommitV, WindowUs},
util,
};
@ -37,6 +37,7 @@ lazy_static! {
#[derive(Copy, Clone, Debug)]
enum OrchardFixedBases {
Full(OrchardFixedBasesFull),
NullifierK,
ValueCommitV,
}
@ -52,10 +53,17 @@ impl From<ValueCommitV> for OrchardFixedBases {
}
}
impl From<NullifierK> for OrchardFixedBases {
fn from(_nullifier_k: NullifierK) -> Self {
Self::NullifierK
}
}
impl OrchardFixedBases {
pub fn generator(self) -> pallas::Affine {
match self {
Self::ValueCommitV => constants::value_commit_v::generator(),
Self::NullifierK => constants::nullifier_k::generator(),
Self::Full(base) => base.generator(),
}
}
@ -63,6 +71,7 @@ impl OrchardFixedBases {
pub fn u(self) -> Vec<WindowUs> {
match self {
Self::ValueCommitV => ValueCommitV::get().u_short.0.as_ref().to_vec(),
Self::NullifierK => NullifierK.u().0.as_ref().to_vec(),
Self::Full(base) => base.u().0.as_ref().to_vec(),
}
}
@ -236,6 +245,14 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
base.z.0.as_ref().to_vec(),
)
}
OrchardFixedBases::NullifierK => {
assert_eq!(NUM_WINDOWS, constants::NUM_WINDOWS);
let base: OrchardFixedBase = NullifierK.into();
(
base.lagrange_coeffs.0.as_ref().to_vec(),
base.z.0.as_ref().to_vec(),
)
}
};
// Assign fixed columns for given fixed base

View File

@ -1,4 +1,4 @@
use super::super::{EccBaseFieldElemFixed, EccConfig, EccPoint, OrchardFixedBasesFull};
use super::super::{EccBaseFieldElemFixed, EccConfig, EccPoint, NullifierK};
use super::H_BASE;
use crate::{
@ -181,7 +181,7 @@ impl Config {
&self,
mut layouter: impl Layouter<pallas::Base>,
scalar: CellValue<pallas::Base>,
base: OrchardFixedBasesFull,
base: NullifierK,
) -> Result<EccPoint, Error> {
let (scalar, acc, mul_b) = layouter.assign_region(
|| "Base-field elem fixed-base mul (incomplete addition)",
@ -423,8 +423,8 @@ pub mod tests {
use crate::circuit::gadget::{
ecc::{
chip::{EccChip, OrchardFixedBasesFull},
FixedPoint, Point,
chip::{EccChip, NullifierK},
FixedPointBaseField, Point,
},
utilities::UtilitiesInstructions,
};
@ -434,59 +434,21 @@ pub mod tests {
chip: EccChip,
mut layouter: impl Layouter<pallas::Base>,
) -> Result<(), Error> {
// commit_ivk_r
let commit_ivk_r = OrchardFixedBasesFull::CommitIvkR;
test_single_base(
chip.clone(),
layouter.namespace(|| "commit_ivk_r"),
FixedPoint::from_inner(chip.clone(), commit_ivk_r),
commit_ivk_r.generator(),
)?;
// note_commit_r
let note_commit_r = OrchardFixedBasesFull::NoteCommitR;
test_single_base(
chip.clone(),
layouter.namespace(|| "note_commit_r"),
FixedPoint::from_inner(chip.clone(), note_commit_r),
note_commit_r.generator(),
)?;
// nullifier_k
let nullifier_k = OrchardFixedBasesFull::NullifierK;
let nullifier_k = NullifierK;
test_single_base(
chip.clone(),
layouter.namespace(|| "nullifier_k"),
FixedPoint::from_inner(chip.clone(), nullifier_k),
FixedPointBaseField::from_inner(chip, nullifier_k),
nullifier_k.generator(),
)?;
// value_commit_r
let value_commit_r = OrchardFixedBasesFull::ValueCommitR;
test_single_base(
chip.clone(),
layouter.namespace(|| "value_commit_r"),
FixedPoint::from_inner(chip.clone(), value_commit_r),
value_commit_r.generator(),
)?;
// spend_auth_g
let spend_auth_g = OrchardFixedBasesFull::SpendAuthG;
test_single_base(
chip.clone(),
layouter.namespace(|| "spend_auth_g"),
FixedPoint::from_inner(chip, spend_auth_g),
spend_auth_g.generator(),
)?;
Ok(())
)
}
#[allow(clippy::op_ref)]
fn test_single_base(
chip: EccChip,
mut layouter: impl Layouter<pallas::Base>,
base: FixedPoint<pallas::Affine, EccChip>,
base: FixedPointBaseField<pallas::Affine, EccChip>,
base_val: pallas::Affine,
) -> Result<(), Error> {
let column = chip.config().advices[0];
@ -517,7 +479,7 @@ pub mod tests {
column,
Some(scalar_fixed),
)?;
base.mul_base_field_elem(layouter.namespace(|| "random [a]B"), scalar_fixed)?
base.mul(layouter.namespace(|| "random [a]B"), scalar_fixed)?
};
constrain_equal(
chip.clone(),
@ -545,7 +507,7 @@ pub mod tests {
column,
Some(scalar_fixed),
)?;
base.mul_base_field_elem(layouter.namespace(|| "mul with double"), scalar_fixed)?
base.mul(layouter.namespace(|| "mul with double"), scalar_fixed)?
};
constrain_equal(
chip.clone(),
@ -563,7 +525,7 @@ pub mod tests {
let result = {
let scalar_fixed =
chip.load_private(layouter.namespace(|| "zero"), column, Some(scalar_fixed))?;
base.mul_base_field_elem(layouter.namespace(|| "mul by zero"), scalar_fixed)?
base.mul(layouter.namespace(|| "mul by zero"), scalar_fixed)?
};
constrain_equal(
chip.clone(),
@ -580,7 +542,7 @@ pub mod tests {
let result = {
let scalar_fixed =
chip.load_private(layouter.namespace(|| "-1"), column, Some(scalar_fixed))?;
base.mul_base_field_elem(layouter.namespace(|| "mul by -1"), scalar_fixed)?
base.mul(layouter.namespace(|| "mul by -1"), scalar_fixed)?
};
constrain_equal(
chip,

View File

@ -150,15 +150,6 @@ pub mod tests {
note_commit_r.generator(),
)?;
// nullifier_k
let nullifier_k = OrchardFixedBasesFull::NullifierK;
test_single_base(
chip.clone(),
layouter.namespace(|| "nullifier_k"),
FixedPoint::from_inner(chip.clone(), nullifier_k),
nullifier_k.generator(),
)?;
// value_commit_r
let value_commit_r = OrchardFixedBasesFull::ValueCommitR;
test_single_base(

View File

@ -18,7 +18,7 @@ pub mod value_commit_v;
pub mod load;
pub mod util;
pub use load::{OrchardFixedBase, OrchardFixedBasesFull, ValueCommitV};
pub use load::{NullifierK, OrchardFixedBase, OrchardFixedBasesFull, ValueCommitV};
/// The Pallas scalar field modulus is $q = 2^{254} + \mathsf{t_q}$.
/// <https://github.com/zcash/pasta>

View File

@ -7,7 +7,6 @@ use pasta_curves::{arithmetic::FieldExt, pallas};
pub enum OrchardFixedBasesFull {
CommitIvkR,
NoteCommitR,
NullifierK,
ValueCommitR,
SpendAuthG,
}
@ -17,7 +16,6 @@ impl OrchardFixedBasesFull {
match self {
OrchardFixedBasesFull::CommitIvkR => super::commit_ivk_r::generator(),
OrchardFixedBasesFull::NoteCommitR => super::note_commit_r::generator(),
OrchardFixedBasesFull::NullifierK => super::nullifier_k::generator(),
OrchardFixedBasesFull::ValueCommitR => super::value_commit_r::generator(),
OrchardFixedBasesFull::SpendAuthG => super::spend_auth_g::generator(),
}
@ -27,7 +25,6 @@ impl OrchardFixedBasesFull {
match self {
OrchardFixedBasesFull::CommitIvkR => super::commit_ivk_r::U.into(),
OrchardFixedBasesFull::NoteCommitR => super::note_commit_r::U.into(),
OrchardFixedBasesFull::NullifierK => super::nullifier_k::U.into(),
OrchardFixedBasesFull::ValueCommitR => super::value_commit_r::U.into(),
OrchardFixedBasesFull::SpendAuthG => super::spend_auth_g::U.into(),
}
@ -56,11 +53,6 @@ impl From<OrchardFixedBasesFull> for OrchardFixedBase {
super::note_commit_r::Z.into(),
super::note_commit_r::U.into(),
),
OrchardFixedBasesFull::NullifierK => (
super::nullifier_k::generator(),
super::nullifier_k::Z.into(),
super::nullifier_k::U.into(),
),
OrchardFixedBasesFull::ValueCommitR => (
super::value_commit_r::generator(),
super::value_commit_r::Z.into(),
@ -82,7 +74,7 @@ impl From<OrchardFixedBasesFull> for OrchardFixedBase {
}
}
/// A fixed base to be used in scalar multiplication with a short signed exponent.
/// A fixed base to be used in scalar multiplication with a base field element.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ValueCommitV {
pub generator: pallas::Affine,
@ -103,6 +95,36 @@ impl ValueCommitV {
}
}
/// A fixed base to be used in scalar multiplication with a short signed exponent.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct NullifierK;
impl From<NullifierK> for OrchardFixedBase {
fn from(_nullifier_k: NullifierK) -> Self {
let (generator, z, u) = (
super::nullifier_k::generator(),
super::nullifier_k::Z.into(),
super::nullifier_k::U.into(),
);
Self {
generator,
lagrange_coeffs: compute_lagrange_coeffs(generator, NUM_WINDOWS).into(),
z,
u,
}
}
}
impl NullifierK {
pub fn generator(&self) -> pallas::Affine {
super::nullifier_k::generator()
}
pub fn u(&self) -> U {
super::nullifier_k::U.into()
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
// 8 coefficients per window
pub struct WindowLagrangeCoeffs(pub Box<[pallas::Base; H]>);