mirror of https://github.com/zcash/orchard.git
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:
parent
1681463856
commit
32f3068886
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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]>);
|
||||
|
|
Loading…
Reference in New Issue