mirror of https://github.com/zcash/orchard.git
ecc: Merge FixedPoints, FixedPointsBaseField, FixedPointsShort types.
This API change defines a FixedPoints trait that is implemented for all OrchardFixedBases. This makes EccChip, SinsemillaChip, and MerkleChip generic over the fixed bases used.
This commit is contained in:
parent
951dd0a108
commit
e3aad46785
|
@ -15,8 +15,7 @@ use pasta_curves::{
|
|||
|
||||
use crate::{
|
||||
constants::{
|
||||
load::{NullifierK, OrchardFixedBasesFull, ValueCommitV},
|
||||
util::gen_const_array,
|
||||
util::gen_const_array, OrchardCommitDomains, OrchardFixedBases, OrchardHashDomains,
|
||||
MERKLE_DEPTH_ORCHARD,
|
||||
},
|
||||
keys::{
|
||||
|
@ -38,14 +37,14 @@ use crate::{
|
|||
use gadget::{
|
||||
ecc::{
|
||||
chip::{EccChip, EccConfig},
|
||||
FixedPoint, FixedPointBaseField, FixedPointShort, NonIdentityPoint, Point,
|
||||
FixedPoint, NonIdentityPoint, Point,
|
||||
},
|
||||
poseidon::{
|
||||
Hash as PoseidonHash, Pow5T3Chip as PoseidonChip, Pow5T3Config as PoseidonConfig,
|
||||
StateWord, Word,
|
||||
},
|
||||
sinsemilla::{
|
||||
chip::{SinsemillaChip, SinsemillaConfig, SinsemillaHashDomains},
|
||||
chip::{SinsemillaChip, SinsemillaConfig},
|
||||
merkle::{
|
||||
chip::{MerkleChip, MerkleConfig},
|
||||
MerklePath,
|
||||
|
@ -88,10 +87,12 @@ pub struct Config {
|
|||
advices: [Column<Advice>; 10],
|
||||
ecc_config: EccConfig,
|
||||
poseidon_config: PoseidonConfig<pallas::Base>,
|
||||
merkle_config_1: MerkleConfig,
|
||||
merkle_config_2: MerkleConfig,
|
||||
sinsemilla_config_1: SinsemillaConfig,
|
||||
sinsemilla_config_2: SinsemillaConfig,
|
||||
merkle_config_1: MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
|
||||
merkle_config_2: MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
|
||||
sinsemilla_config_1:
|
||||
SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
|
||||
sinsemilla_config_2:
|
||||
SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
|
||||
commit_ivk_config: CommitIvkConfig,
|
||||
old_note_commit_config: NoteCommitConfig,
|
||||
new_note_commit_config: NoteCommitConfig,
|
||||
|
@ -241,7 +242,12 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
|||
|
||||
// Configuration for curve point operations.
|
||||
// This uses 10 advice columns and spans the whole circuit.
|
||||
let ecc_config = EccChip::configure(meta, advices, lagrange_coeffs, range_check.clone());
|
||||
let ecc_config = EccChip::<OrchardFixedBases>::configure(
|
||||
meta,
|
||||
advices,
|
||||
lagrange_coeffs,
|
||||
range_check.clone(),
|
||||
);
|
||||
|
||||
// Configuration for the Poseidon hash.
|
||||
let poseidon_config = PoseidonChip::configure(
|
||||
|
@ -407,7 +413,7 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
|||
let merkle_inputs = MerklePath {
|
||||
chip_1: config.merkle_chip_1(),
|
||||
chip_2: config.merkle_chip_2(),
|
||||
domain: SinsemillaHashDomains::MerkleCrh,
|
||||
domain: OrchardHashDomains::MerkleCrh,
|
||||
leaf_pos: self.pos,
|
||||
path,
|
||||
};
|
||||
|
@ -458,15 +464,15 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
|||
|
||||
// commitment = [v_net] ValueCommitV
|
||||
let (commitment, _) = {
|
||||
let value_commit_v = ValueCommitV::get();
|
||||
let value_commit_v = FixedPointShort::from_inner(ecc_chip.clone(), value_commit_v);
|
||||
value_commit_v.mul(layouter.namespace(|| "[v_net] ValueCommitV"), v_net)?
|
||||
let value_commit_v = OrchardFixedBases::ValueCommitV;
|
||||
let value_commit_v = FixedPoint::from_inner(ecc_chip.clone(), value_commit_v);
|
||||
value_commit_v.mul_short(layouter.namespace(|| "[v_net] ValueCommitV"), v_net)?
|
||||
};
|
||||
|
||||
// blind = [rcv] ValueCommitR
|
||||
let (blind, _rcv) = {
|
||||
let rcv = self.rcv.as_ref().map(|rcv| rcv.inner());
|
||||
let value_commit_r = OrchardFixedBasesFull::ValueCommitR;
|
||||
let value_commit_r = OrchardFixedBases::ValueCommitR;
|
||||
let value_commit_r = FixedPoint::from_inner(ecc_chip.clone(), value_commit_r);
|
||||
|
||||
// [rcv] ValueCommitR
|
||||
|
@ -564,8 +570,9 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
|||
// `product` = [poseidon_hash(nk, rho_old) + psi_old] NullifierK.
|
||||
//
|
||||
let product = {
|
||||
let nullifier_k = FixedPointBaseField::from_inner(ecc_chip.clone(), NullifierK);
|
||||
nullifier_k.mul(
|
||||
let nullifier_k =
|
||||
FixedPoint::from_inner(ecc_chip.clone(), OrchardFixedBases::NullifierK);
|
||||
nullifier_k.mul_base_field(
|
||||
layouter.namespace(|| "[poseidon_output + psi_old] NullifierK"),
|
||||
scalar,
|
||||
)?
|
||||
|
@ -587,7 +594,7 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
|||
{
|
||||
// alpha_commitment = [alpha] SpendAuthG
|
||||
let (alpha_commitment, _) = {
|
||||
let spend_auth_g = OrchardFixedBasesFull::SpendAuthG;
|
||||
let spend_auth_g = OrchardFixedBases::SpendAuthG;
|
||||
let spend_auth_g = FixedPoint::from_inner(ecc_chip.clone(), spend_auth_g);
|
||||
spend_auth_g.mul(layouter.namespace(|| "[alpha] SpendAuthG"), self.alpha)?
|
||||
};
|
||||
|
|
|
@ -9,26 +9,31 @@ use crate::{
|
|||
circuit::gadget::{
|
||||
ecc::{chip::EccChip, X},
|
||||
sinsemilla::{
|
||||
chip::{SinsemillaChip, SinsemillaCommitDomains, SinsemillaConfig},
|
||||
chip::{SinsemillaChip, SinsemillaConfig},
|
||||
CommitDomain, Message, MessagePiece,
|
||||
},
|
||||
utilities::{bitrange_subset, bool_check, copy, CellValue, Var},
|
||||
},
|
||||
constants::T_P,
|
||||
constants::{OrchardCommitDomains, OrchardFixedBases, OrchardHashDomains, T_P},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CommitIvkConfig {
|
||||
q_commit_ivk: Selector,
|
||||
advices: [Column<Advice>; 10],
|
||||
sinsemilla_config: SinsemillaConfig,
|
||||
sinsemilla_config:
|
||||
SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
|
||||
}
|
||||
|
||||
impl CommitIvkConfig {
|
||||
pub(in crate::circuit) fn configure(
|
||||
meta: &mut ConstraintSystem<pallas::Base>,
|
||||
advices: [Column<Advice>; 10],
|
||||
sinsemilla_config: SinsemillaConfig,
|
||||
sinsemilla_config: SinsemillaConfig<
|
||||
OrchardHashDomains,
|
||||
OrchardCommitDomains,
|
||||
OrchardFixedBases,
|
||||
>,
|
||||
) -> Self {
|
||||
let q_commit_ivk = meta.selector();
|
||||
|
||||
|
@ -221,13 +226,17 @@ impl CommitIvkConfig {
|
|||
#[allow(clippy::type_complexity)]
|
||||
pub(in crate::circuit) fn assign_region(
|
||||
&self,
|
||||
sinsemilla_chip: SinsemillaChip,
|
||||
ecc_chip: EccChip,
|
||||
sinsemilla_chip: SinsemillaChip<
|
||||
OrchardHashDomains,
|
||||
OrchardCommitDomains,
|
||||
OrchardFixedBases,
|
||||
>,
|
||||
ecc_chip: EccChip<OrchardFixedBases>,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
ak: CellValue<pallas::Base>,
|
||||
nk: CellValue<pallas::Base>,
|
||||
rivk: Option<pallas::Scalar>,
|
||||
) -> Result<X<pallas::Affine, EccChip>, Error> {
|
||||
) -> Result<X<pallas::Affine, EccChip<OrchardFixedBases>>, Error> {
|
||||
// <https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit>
|
||||
// We need to hash `ak || nk` where each of `ak`, `nk` is a field element (255 bits).
|
||||
//
|
||||
|
@ -328,11 +337,8 @@ impl CommitIvkConfig {
|
|||
sinsemilla_chip.clone(),
|
||||
vec![a.clone(), b.clone(), c.clone(), d.clone()],
|
||||
);
|
||||
let domain = CommitDomain::new(
|
||||
sinsemilla_chip,
|
||||
ecc_chip,
|
||||
&SinsemillaCommitDomains::CommitIvk,
|
||||
);
|
||||
let domain =
|
||||
CommitDomain::new(sinsemilla_chip, ecc_chip, &OrchardCommitDomains::CommitIvk);
|
||||
domain.short_commit(layouter.namespace(|| "Hash ak||nk"), message, rivk)?
|
||||
};
|
||||
|
||||
|
@ -643,7 +649,10 @@ mod tests {
|
|||
lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions, Var,
|
||||
},
|
||||
},
|
||||
constants::{COMMIT_IVK_PERSONALIZATION, L_ORCHARD_BASE, T_Q},
|
||||
constants::{
|
||||
OrchardCommitDomains, OrchardFixedBases, OrchardHashDomains,
|
||||
COMMIT_IVK_PERSONALIZATION, L_ORCHARD_BASE, T_Q,
|
||||
},
|
||||
primitives::sinsemilla::CommitDomain,
|
||||
};
|
||||
use ff::PrimeFieldBits;
|
||||
|
@ -715,7 +724,11 @@ mod tests {
|
|||
];
|
||||
|
||||
let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx);
|
||||
let sinsemilla_config = SinsemillaChip::configure(
|
||||
let sinsemilla_config = SinsemillaChip::<
|
||||
OrchardHashDomains,
|
||||
OrchardCommitDomains,
|
||||
OrchardFixedBases,
|
||||
>::configure(
|
||||
meta,
|
||||
advices[..5].try_into().unwrap(),
|
||||
advices[2],
|
||||
|
@ -727,7 +740,12 @@ mod tests {
|
|||
let commit_ivk_config =
|
||||
CommitIvkConfig::configure(meta, advices, sinsemilla_config);
|
||||
|
||||
let ecc_config = EccChip::configure(meta, advices, lagrange_coeffs, range_check);
|
||||
let ecc_config = EccChip::<OrchardFixedBases>::configure(
|
||||
meta,
|
||||
advices,
|
||||
lagrange_coeffs,
|
||||
range_check,
|
||||
);
|
||||
|
||||
(commit_ivk_config, ecc_config)
|
||||
}
|
||||
|
@ -740,7 +758,7 @@ mod tests {
|
|||
let (commit_ivk_config, ecc_config) = config;
|
||||
|
||||
// Load the Sinsemilla generator lookup table used by the whole circuit.
|
||||
SinsemillaChip::load(commit_ivk_config.sinsemilla_config.clone(), &mut layouter)?;
|
||||
SinsemillaChip::<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>::load(commit_ivk_config.sinsemilla_config.clone(), &mut layouter)?;
|
||||
|
||||
// Construct a Sinsemilla chip
|
||||
let sinsemilla_chip =
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use pasta_curves::pallas;
|
||||
|
||||
use crate::constants::{OrchardCommitDomains, OrchardFixedBases, OrchardHashDomains};
|
||||
use ecc::chip::EccChip;
|
||||
use poseidon::Pow5T3Chip as PoseidonChip;
|
||||
use sinsemilla::{chip::SinsemillaChip, merkle::chip::MerkleChip};
|
||||
|
@ -10,23 +11,31 @@ pub(crate) mod sinsemilla;
|
|||
pub(crate) mod utilities;
|
||||
|
||||
impl super::Config {
|
||||
pub(super) fn ecc_chip(&self) -> EccChip {
|
||||
pub(super) fn ecc_chip(&self) -> EccChip<OrchardFixedBases> {
|
||||
EccChip::construct(self.ecc_config.clone())
|
||||
}
|
||||
|
||||
pub(super) fn sinsemilla_chip_1(&self) -> SinsemillaChip {
|
||||
pub(super) fn sinsemilla_chip_1(
|
||||
&self,
|
||||
) -> SinsemillaChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
|
||||
SinsemillaChip::construct(self.sinsemilla_config_1.clone())
|
||||
}
|
||||
|
||||
pub(super) fn sinsemilla_chip_2(&self) -> SinsemillaChip {
|
||||
pub(super) fn sinsemilla_chip_2(
|
||||
&self,
|
||||
) -> SinsemillaChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
|
||||
SinsemillaChip::construct(self.sinsemilla_config_2.clone())
|
||||
}
|
||||
|
||||
pub(super) fn merkle_chip_1(&self) -> MerkleChip {
|
||||
pub(super) fn merkle_chip_1(
|
||||
&self,
|
||||
) -> MerkleChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
|
||||
MerkleChip::construct(self.merkle_config_1.clone())
|
||||
}
|
||||
|
||||
pub(super) fn merkle_chip_2(&self) -> MerkleChip {
|
||||
pub(super) fn merkle_chip_2(
|
||||
&self,
|
||||
) -> MerkleChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
|
||||
MerkleChip::construct(self.merkle_config_2.clone())
|
||||
}
|
||||
|
||||
|
|
|
@ -9,11 +9,14 @@ use halo2::{
|
|||
};
|
||||
|
||||
use crate::circuit::gadget::utilities::UtilitiesInstructions;
|
||||
use crate::constants;
|
||||
|
||||
pub mod chip;
|
||||
|
||||
/// The set of circuit instructions required to use the ECC gadgets.
|
||||
pub trait EccInstructions<C: CurveAffine>: Chip<C::Base> + UtilitiesInstructions<C::Base> {
|
||||
pub trait EccInstructions<C: CurveAffine>:
|
||||
Chip<C::Base> + UtilitiesInstructions<C::Base> + Clone + Debug + Eq
|
||||
{
|
||||
/// Variable representing an element of the elliptic curve's base field, that
|
||||
/// is used as a scalar in variable-base scalar mul.
|
||||
///
|
||||
|
@ -42,11 +45,7 @@ pub trait EccInstructions<C: CurveAffine>: Chip<C::Base> + UtilitiesInstructions
|
|||
/// elliptic curve point.
|
||||
type X: Clone + Debug;
|
||||
/// 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;
|
||||
type FixedPoints: FixedPoints<C>;
|
||||
|
||||
/// Constrains point `a` to be equal in value to point `b`.
|
||||
fn constrain_equal(
|
||||
|
@ -116,7 +115,7 @@ pub trait EccInstructions<C: CurveAffine>: Chip<C::Base> + UtilitiesInstructions
|
|||
&self,
|
||||
layouter: &mut impl Layouter<C::Base>,
|
||||
magnitude_sign: (Self::Var, Self::Var),
|
||||
base: &Self::FixedPointsShort,
|
||||
base: &Self::FixedPoints,
|
||||
) -> Result<(Self::Point, Self::ScalarFixedShort), Error>;
|
||||
|
||||
/// Performs fixed-base scalar multiplication using a base field element as the scalar.
|
||||
|
@ -126,10 +125,18 @@ pub trait EccInstructions<C: CurveAffine>: Chip<C::Base> + UtilitiesInstructions
|
|||
&self,
|
||||
layouter: &mut impl Layouter<C::Base>,
|
||||
base_field_elem: Self::Var,
|
||||
base: &Self::FixedPointsBaseField,
|
||||
base: &Self::FixedPoints,
|
||||
) -> Result<Self::Point, Error>;
|
||||
}
|
||||
|
||||
/// Returns information about a fixed point.
|
||||
pub trait FixedPoints<C: CurveAffine>: Debug + Eq + Clone {
|
||||
fn generator(&self) -> C;
|
||||
fn u(&self) -> Vec<[[u8; 32]; constants::H]>;
|
||||
fn z(&self) -> Vec<u64>;
|
||||
fn lagrange_coeffs(&self) -> Vec<[C::Base; constants::H]>;
|
||||
}
|
||||
|
||||
/// An element of the given elliptic curve's base field, that is used as a scalar
|
||||
/// in variable-base scalar mul.
|
||||
///
|
||||
|
@ -142,41 +149,33 @@ pub trait EccInstructions<C: CurveAffine>: Chip<C::Base> + UtilitiesInstructions
|
|||
/// to be in the base field of the curve. (See non-normative notes in
|
||||
/// https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents.)
|
||||
#[derive(Debug)]
|
||||
pub struct ScalarVar<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> {
|
||||
pub struct ScalarVar<C: CurveAffine, EccChip: EccInstructions<C>> {
|
||||
chip: EccChip,
|
||||
inner: EccChip::ScalarVar,
|
||||
}
|
||||
|
||||
/// A full-width element of the given elliptic curve's scalar field, to be used for fixed-base scalar mul.
|
||||
#[derive(Debug)]
|
||||
pub struct ScalarFixed<C: CurveAffine, EccChip>
|
||||
where
|
||||
EccChip: EccInstructions<C> + Clone + Debug + Eq,
|
||||
{
|
||||
pub struct ScalarFixed<C: CurveAffine, EccChip: EccInstructions<C>> {
|
||||
chip: EccChip,
|
||||
inner: EccChip::ScalarFixed,
|
||||
}
|
||||
|
||||
/// A signed short element of the given elliptic curve's scalar field, to be used for fixed-base scalar mul.
|
||||
#[derive(Debug)]
|
||||
pub struct ScalarFixedShort<C: CurveAffine, EccChip>
|
||||
where
|
||||
EccChip: EccInstructions<C> + Clone + Debug + Eq,
|
||||
{
|
||||
pub struct ScalarFixedShort<C: CurveAffine, EccChip: EccInstructions<C>> {
|
||||
chip: EccChip,
|
||||
inner: EccChip::ScalarFixedShort,
|
||||
}
|
||||
|
||||
/// A non-identity elliptic curve point over the given curve.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct NonIdentityPoint<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> {
|
||||
pub struct NonIdentityPoint<C: CurveAffine, EccChip: EccInstructions<C>> {
|
||||
chip: EccChip,
|
||||
inner: EccChip::NonIdentityPoint,
|
||||
}
|
||||
|
||||
impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq>
|
||||
NonIdentityPoint<C, EccChip>
|
||||
{
|
||||
impl<C: CurveAffine, EccChip: EccInstructions<C>> NonIdentityPoint<C, EccChip> {
|
||||
/// Constructs a new point with the given value.
|
||||
pub fn new(
|
||||
chip: EccChip,
|
||||
|
@ -351,12 +350,12 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> Point<C,
|
|||
/// The affine short Weierstrass x-coordinate of an elliptic curve point over the
|
||||
/// given curve.
|
||||
#[derive(Debug)]
|
||||
pub struct X<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> {
|
||||
pub struct X<C: CurveAffine, EccChip: EccInstructions<C>> {
|
||||
chip: EccChip,
|
||||
inner: EccChip::X,
|
||||
}
|
||||
|
||||
impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> X<C, EccChip> {
|
||||
impl<C: CurveAffine, EccChip: EccInstructions<C>> X<C, EccChip> {
|
||||
/// 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 }
|
||||
|
@ -373,18 +372,12 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> X<C, EccC
|
|||
///
|
||||
/// Used in scalar multiplication with full-width scalars.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FixedPoint<C: CurveAffine, EccChip>
|
||||
where
|
||||
EccChip: EccInstructions<C> + Clone + Debug + Eq,
|
||||
{
|
||||
pub struct FixedPoint<C: CurveAffine, EccChip: EccInstructions<C>> {
|
||||
chip: EccChip,
|
||||
inner: EccChip::FixedPoints,
|
||||
}
|
||||
|
||||
impl<C: CurveAffine, EccChip> FixedPoint<C, EccChip>
|
||||
where
|
||||
EccChip: EccInstructions<C> + Clone + Debug + Eq,
|
||||
{
|
||||
impl<C: CurveAffine, EccChip: EccInstructions<C>> FixedPoint<C, EccChip> {
|
||||
#[allow(clippy::type_complexity)]
|
||||
/// Returns `[by] self`.
|
||||
pub fn mul(
|
||||
|
@ -408,30 +401,9 @@ 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 }
|
||||
}
|
||||
}
|
||||
|
||||
/// 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(
|
||||
pub fn mul_base_field(
|
||||
&self,
|
||||
mut layouter: impl Layouter<C::Base>,
|
||||
by: EccChip::Var,
|
||||
|
@ -444,30 +416,9 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
/// Wraps the given fixed base (obtained directly from an instruction) in a gadget.
|
||||
pub fn from_inner(chip: EccChip, inner: EccChip::FixedPointsBaseField) -> Self {
|
||||
FixedPointBaseField { chip, inner }
|
||||
}
|
||||
}
|
||||
|
||||
/// A constant elliptic curve point over the given curve, used in scalar multiplication
|
||||
/// with a short signed exponent
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FixedPointShort<C: CurveAffine, EccChip>
|
||||
where
|
||||
EccChip: EccInstructions<C> + Clone + Debug + Eq,
|
||||
{
|
||||
chip: EccChip,
|
||||
inner: EccChip::FixedPointsShort,
|
||||
}
|
||||
|
||||
impl<C: CurveAffine, EccChip> FixedPointShort<C, EccChip>
|
||||
where
|
||||
EccChip: EccInstructions<C> + Clone + Debug + Eq,
|
||||
{
|
||||
#[allow(clippy::type_complexity)]
|
||||
/// Returns `[by] self`.
|
||||
pub fn mul(
|
||||
pub fn mul_short(
|
||||
&self,
|
||||
mut layouter: impl Layouter<C::Base>,
|
||||
magnitude_sign: (EccChip::Var, EccChip::Var),
|
||||
|
@ -489,8 +440,8 @@ where
|
|||
}
|
||||
|
||||
/// Wraps the given fixed base (obtained directly from an instruction) in a gadget.
|
||||
pub fn from_inner(chip: EccChip, inner: EccChip::FixedPointsShort) -> Self {
|
||||
FixedPointShort { chip, inner }
|
||||
pub fn from_inner(chip: EccChip, inner: EccChip::FixedPoints) -> Self {
|
||||
FixedPoint { chip, inner }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -507,6 +458,7 @@ mod tests {
|
|||
|
||||
use super::chip::{EccChip, EccConfig};
|
||||
use crate::circuit::gadget::utilities::lookup_range_check::LookupRangeCheckConfig;
|
||||
use crate::constants::OrchardFixedBases;
|
||||
|
||||
struct MyCircuit {}
|
||||
|
||||
|
@ -548,7 +500,7 @@ mod tests {
|
|||
meta.enable_constant(constants);
|
||||
|
||||
let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table);
|
||||
EccChip::configure(meta, advices, lagrange_coeffs, range_check)
|
||||
EccChip::<OrchardFixedBases>::configure(meta, advices, lagrange_coeffs, range_check)
|
||||
}
|
||||
|
||||
fn synthesize(
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
use super::EccInstructions;
|
||||
use super::{EccInstructions, FixedPoints};
|
||||
use crate::{
|
||||
circuit::gadget::utilities::{
|
||||
copy, decompose_running_sum::RunningSumConfig, lookup_range_check::LookupRangeCheckConfig,
|
||||
CellValue, UtilitiesInstructions, Var,
|
||||
},
|
||||
constants::{self, NullifierK, OrchardFixedBasesFull, ValueCommitV},
|
||||
constants,
|
||||
primitives::sinsemilla,
|
||||
};
|
||||
use arrayvec::ArrayVec;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use group::prime::PrimeCurveAffine;
|
||||
use halo2::{
|
||||
|
@ -178,11 +179,12 @@ pub struct EccConfig {
|
|||
|
||||
/// A chip implementing EccInstructions
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct EccChip {
|
||||
pub struct EccChip<Fixed: super::FixedPoints<pallas::Affine>> {
|
||||
config: EccConfig,
|
||||
_marker: PhantomData<Fixed>,
|
||||
}
|
||||
|
||||
impl Chip<pallas::Base> for EccChip {
|
||||
impl<Fixed: super::FixedPoints<pallas::Affine>> Chip<pallas::Base> for EccChip<Fixed> {
|
||||
type Config = EccConfig;
|
||||
type Loaded = ();
|
||||
|
||||
|
@ -195,13 +197,18 @@ impl Chip<pallas::Base> for EccChip {
|
|||
}
|
||||
}
|
||||
|
||||
impl UtilitiesInstructions<pallas::Base> for EccChip {
|
||||
impl<Fixed: super::FixedPoints<pallas::Affine>> UtilitiesInstructions<pallas::Base>
|
||||
for EccChip<Fixed>
|
||||
{
|
||||
type Var = CellValue<pallas::Base>;
|
||||
}
|
||||
|
||||
impl EccChip {
|
||||
impl<FixedPoints: super::FixedPoints<pallas::Affine>> EccChip<FixedPoints> {
|
||||
pub fn construct(config: <Self as Chip<pallas::Base>>::Config) -> Self {
|
||||
Self { config }
|
||||
Self {
|
||||
config,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// # Side effects
|
||||
|
@ -298,25 +305,28 @@ impl EccChip {
|
|||
// and fixed-base mul using a base field element.
|
||||
{
|
||||
// The const generic does not matter when creating gates.
|
||||
let mul_fixed_config: mul_fixed::Config<{ constants::NUM_WINDOWS }> = (&config).into();
|
||||
let mul_fixed_config: mul_fixed::Config<FixedPoints, { constants::NUM_WINDOWS }> =
|
||||
(&config).into();
|
||||
mul_fixed_config.running_sum_coords_gate(meta);
|
||||
}
|
||||
|
||||
// Create gate that is only used in full-width fixed-base scalar mul.
|
||||
{
|
||||
let mul_fixed_full_config: mul_fixed::full_width::Config = (&config).into();
|
||||
let mul_fixed_full_config: mul_fixed::full_width::Config<FixedPoints> =
|
||||
(&config).into();
|
||||
mul_fixed_full_config.create_gate(meta);
|
||||
}
|
||||
|
||||
// Create gate that is only used in short fixed-base scalar mul.
|
||||
{
|
||||
let short_config: mul_fixed::short::Config = (&config).into();
|
||||
let short_config: mul_fixed::short::Config<FixedPoints> = (&config).into();
|
||||
short_config.create_gate(meta);
|
||||
}
|
||||
|
||||
// Create gate that is only used in fixed-base mul using a base field element.
|
||||
{
|
||||
let base_field_config: mul_fixed::base_field_elem::Config = (&config).into();
|
||||
let base_field_config: mul_fixed::base_field_elem::Config<FixedPoints> =
|
||||
(&config).into();
|
||||
base_field_config.create_gate(meta);
|
||||
}
|
||||
|
||||
|
@ -375,16 +385,14 @@ impl EccBaseFieldElemFixed {
|
|||
}
|
||||
}
|
||||
|
||||
impl EccInstructions<pallas::Affine> for EccChip {
|
||||
impl<Fixed: super::FixedPoints<pallas::Affine>> EccInstructions<pallas::Affine> for EccChip<Fixed> {
|
||||
type ScalarFixed = EccScalarFixed;
|
||||
type ScalarFixedShort = EccScalarFixedShort;
|
||||
type ScalarVar = CellValue<pallas::Base>;
|
||||
type Point = EccPoint;
|
||||
type NonIdentityPoint = NonIdentityEccPoint;
|
||||
type X = CellValue<pallas::Base>;
|
||||
type FixedPoints = OrchardFixedBasesFull;
|
||||
type FixedPointsBaseField = NullifierK;
|
||||
type FixedPointsShort = ValueCommitV;
|
||||
type FixedPoints = Fixed;
|
||||
|
||||
fn constrain_equal(
|
||||
&self,
|
||||
|
@ -480,11 +488,11 @@ impl EccInstructions<pallas::Affine> for EccChip {
|
|||
scalar: Option<pallas::Scalar>,
|
||||
base: &Self::FixedPoints,
|
||||
) -> Result<(Self::Point, Self::ScalarFixed), Error> {
|
||||
let config: mul_fixed::full_width::Config = self.config().into();
|
||||
let config: mul_fixed::full_width::Config<Fixed> = self.config().into();
|
||||
config.assign(
|
||||
layouter.namespace(|| format!("fixed-base mul of {:?}", base)),
|
||||
scalar,
|
||||
*base,
|
||||
base,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -492,9 +500,9 @@ impl EccInstructions<pallas::Affine> for EccChip {
|
|||
&self,
|
||||
layouter: &mut impl Layouter<pallas::Base>,
|
||||
magnitude_sign: (CellValue<pallas::Base>, CellValue<pallas::Base>),
|
||||
base: &Self::FixedPointsShort,
|
||||
base: &Self::FixedPoints,
|
||||
) -> Result<(Self::Point, Self::ScalarFixedShort), Error> {
|
||||
let config: mul_fixed::short::Config = self.config().into();
|
||||
let config: mul_fixed::short::Config<Fixed> = self.config().into();
|
||||
config.assign(
|
||||
layouter.namespace(|| format!("short fixed-base mul of {:?}", base)),
|
||||
magnitude_sign,
|
||||
|
@ -506,13 +514,13 @@ impl EccInstructions<pallas::Affine> for EccChip {
|
|||
&self,
|
||||
layouter: &mut impl Layouter<pallas::Base>,
|
||||
base_field_elem: CellValue<pallas::Base>,
|
||||
base: &Self::FixedPointsBaseField,
|
||||
base: &Self::FixedPoints,
|
||||
) -> Result<Self::Point, Error> {
|
||||
let config: mul_fixed::base_field_elem::Config = self.config().into();
|
||||
let config: mul_fixed::base_field_elem::Config<Fixed> = self.config().into();
|
||||
config.assign(
|
||||
layouter.namespace(|| format!("base-field elem fixed-base mul of {:?}", base)),
|
||||
base_field_elem,
|
||||
*base,
|
||||
base,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -459,11 +459,12 @@ pub mod tests {
|
|||
},
|
||||
utilities::UtilitiesInstructions,
|
||||
};
|
||||
use crate::constants::OrchardFixedBases;
|
||||
|
||||
pub fn test_mul(
|
||||
chip: EccChip,
|
||||
chip: EccChip<OrchardFixedBases>,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
p: &NonIdentityPoint<pallas::Affine, EccChip>,
|
||||
p: &NonIdentityPoint<pallas::Affine, EccChip<OrchardFixedBases>>,
|
||||
p_val: pallas::Affine,
|
||||
) -> Result<(), Error> {
|
||||
let column = chip.config().advices[0];
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
use super::{
|
||||
add, add_incomplete, CellValue, EccBaseFieldElemFixed, EccConfig, EccScalarFixed,
|
||||
EccScalarFixedShort, NonIdentityEccPoint, Var,
|
||||
};
|
||||
use crate::constants::{
|
||||
self,
|
||||
load::{NullifierK, OrchardFixedBase, OrchardFixedBasesFull, ValueCommitV, WindowUs},
|
||||
EccScalarFixedShort, FixedPoints, NonIdentityEccPoint, Var,
|
||||
};
|
||||
use crate::constants;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use group::Curve;
|
||||
use halo2::{
|
||||
|
@ -30,53 +28,8 @@ lazy_static! {
|
|||
static ref H_BASE: pallas::Base = pallas::Base::from_u64(constants::H as u64);
|
||||
}
|
||||
|
||||
// A sum type for both full-width and short bases. This enables us to use the
|
||||
// shared functionality of full-width and short fixed-base scalar multiplication.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum OrchardFixedBases {
|
||||
Full(OrchardFixedBasesFull),
|
||||
NullifierK,
|
||||
ValueCommitV,
|
||||
}
|
||||
|
||||
impl From<OrchardFixedBasesFull> for OrchardFixedBases {
|
||||
fn from(full_width_base: OrchardFixedBasesFull) -> Self {
|
||||
Self::Full(full_width_base)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ValueCommitV> for OrchardFixedBases {
|
||||
fn from(_value_commit_v: ValueCommitV) -> Self {
|
||||
Self::ValueCommitV
|
||||
}
|
||||
}
|
||||
|
||||
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(),
|
||||
}
|
||||
}
|
||||
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Config<const NUM_WINDOWS: usize> {
|
||||
pub struct Config<F: FixedPoints<pallas::Affine>, const NUM_WINDOWS: usize> {
|
||||
q_mul_fixed_running_sum: Selector,
|
||||
// The fixed Lagrange interpolation coefficients for `x_p`.
|
||||
lagrange_coeffs: [Column<Fixed>; constants::H],
|
||||
|
@ -95,9 +48,12 @@ pub struct Config<const NUM_WINDOWS: usize> {
|
|||
add_config: add::Config,
|
||||
// Configuration for `add_incomplete`
|
||||
add_incomplete_config: add_incomplete::Config,
|
||||
_marker: PhantomData<F>,
|
||||
}
|
||||
|
||||
impl<const NUM_WINDOWS: usize> From<&EccConfig> for Config<NUM_WINDOWS> {
|
||||
impl<Fixed: FixedPoints<pallas::Affine>, const NUM_WINDOWS: usize> From<&EccConfig>
|
||||
for Config<Fixed, NUM_WINDOWS>
|
||||
{
|
||||
fn from(ecc_config: &EccConfig) -> Self {
|
||||
let config = Self {
|
||||
q_mul_fixed_running_sum: ecc_config.q_mul_fixed_running_sum,
|
||||
|
@ -109,6 +65,7 @@ impl<const NUM_WINDOWS: usize> From<&EccConfig> for Config<NUM_WINDOWS> {
|
|||
u: ecc_config.advices[5],
|
||||
add_config: ecc_config.into(),
|
||||
add_incomplete_config: ecc_config.into(),
|
||||
_marker: PhantomData,
|
||||
};
|
||||
|
||||
// Check relationships between this config and `add_config`.
|
||||
|
@ -145,7 +102,7 @@ impl<const NUM_WINDOWS: usize> From<&EccConfig> for Config<NUM_WINDOWS> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
|
||||
impl<Fixed: FixedPoints<pallas::Affine>, const NUM_WINDOWS: usize> Config<Fixed, NUM_WINDOWS> {
|
||||
/// Check that each window in the running sum decomposition uses the correct y_p
|
||||
/// and interpolated x_p.
|
||||
///
|
||||
|
@ -218,7 +175,7 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
|
|||
region: &mut Region<'_, pallas::Base>,
|
||||
offset: usize,
|
||||
scalar: &ScalarFixed,
|
||||
base: OrchardFixedBases,
|
||||
base: &Fixed,
|
||||
coords_check_toggle: Selector,
|
||||
) -> Result<(NonIdentityEccPoint, NonIdentityEccPoint), Error> {
|
||||
// Assign fixed columns for given fixed base
|
||||
|
@ -240,37 +197,11 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
|
|||
&self,
|
||||
region: &mut Region<'_, pallas::Base>,
|
||||
offset: usize,
|
||||
base: OrchardFixedBases,
|
||||
base: &Fixed,
|
||||
coords_check_toggle: Selector,
|
||||
) -> Result<(), Error> {
|
||||
let mut constants = None;
|
||||
|
||||
let build_constants = || match base {
|
||||
OrchardFixedBases::ValueCommitV => {
|
||||
assert_eq!(NUM_WINDOWS, constants::NUM_WINDOWS_SHORT);
|
||||
let base = ValueCommitV::get();
|
||||
(
|
||||
base.lagrange_coeffs_short.0.as_ref().to_vec(),
|
||||
base.z_short.0.as_ref().to_vec(),
|
||||
)
|
||||
}
|
||||
OrchardFixedBases::Full(base) => {
|
||||
assert_eq!(NUM_WINDOWS, constants::NUM_WINDOWS);
|
||||
let base: OrchardFixedBase = base.into();
|
||||
(
|
||||
base.lagrange_coeffs.0.as_ref().to_vec(),
|
||||
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(),
|
||||
)
|
||||
}
|
||||
};
|
||||
let lagrange_coeffs = base.lagrange_coeffs();
|
||||
let z = base.z();
|
||||
|
||||
// Assign fixed columns for given fixed base
|
||||
for window in 0..NUM_WINDOWS {
|
||||
|
@ -287,13 +218,7 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
|
|||
},
|
||||
self.lagrange_coeffs[k],
|
||||
window + offset,
|
||||
|| {
|
||||
if constants.as_ref().is_none() {
|
||||
constants = Some(build_constants());
|
||||
}
|
||||
let lagrange_coeffs = &constants.as_ref().unwrap().0;
|
||||
Ok(lagrange_coeffs[window].0[k])
|
||||
},
|
||||
|| Ok(lagrange_coeffs[window][k]),
|
||||
)?;
|
||||
}
|
||||
|
||||
|
@ -302,10 +227,7 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
|
|||
|| format!("z-value for window: {:?}", window),
|
||||
self.fixed_z,
|
||||
window + offset,
|
||||
|| {
|
||||
let z = &constants.as_ref().unwrap().1;
|
||||
Ok(z[window])
|
||||
},
|
||||
|| Ok(pallas::Base::from_u64(z[window])),
|
||||
)?;
|
||||
}
|
||||
|
||||
|
@ -319,7 +241,7 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
|
|||
w: usize,
|
||||
k: Option<pallas::Scalar>,
|
||||
k_usize: Option<usize>,
|
||||
base: OrchardFixedBases,
|
||||
base: &Fixed,
|
||||
) -> Result<NonIdentityEccPoint, Error> {
|
||||
let base_value = base.generator();
|
||||
let base_u = base.u();
|
||||
|
@ -360,7 +282,7 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
|
|||
};
|
||||
|
||||
// Assign u = (y_p + z_w).sqrt()
|
||||
let u_val = k_usize.map(|k| base_u[w].0[k]);
|
||||
let u_val = k_usize.map(|k| pallas::Base::from_bytes(&base_u[w][k]).unwrap());
|
||||
region.assign_advice(
|
||||
|| "u",
|
||||
self.u,
|
||||
|
@ -375,7 +297,7 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
|
|||
&self,
|
||||
region: &mut Region<'_, pallas::Base>,
|
||||
offset: usize,
|
||||
base: OrchardFixedBases,
|
||||
base: &Fixed,
|
||||
scalar: &ScalarFixed,
|
||||
) -> Result<NonIdentityEccPoint, Error> {
|
||||
// Recall that the message at each window `w` is represented as
|
||||
|
@ -392,7 +314,7 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
|
|||
region: &mut Region<'_, pallas::Base>,
|
||||
offset: usize,
|
||||
mut acc: NonIdentityEccPoint,
|
||||
base: OrchardFixedBases,
|
||||
base: &Fixed,
|
||||
scalar: &ScalarFixed,
|
||||
) -> Result<NonIdentityEccPoint, Error> {
|
||||
let scalar_windows_field = scalar.windows_field();
|
||||
|
@ -420,13 +342,13 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
|
|||
&self,
|
||||
region: &mut Region<'_, pallas::Base>,
|
||||
offset: usize,
|
||||
base: OrchardFixedBases,
|
||||
base: &Fixed,
|
||||
scalar: &ScalarFixed,
|
||||
) -> Result<NonIdentityEccPoint, Error> {
|
||||
// Assign u = (y_p + z_w).sqrt() for the most significant window
|
||||
{
|
||||
let u_val =
|
||||
scalar.windows_usize()[NUM_WINDOWS - 1].map(|k| base.u()[NUM_WINDOWS - 1].0[k]);
|
||||
let u_val = scalar.windows_usize()[NUM_WINDOWS - 1]
|
||||
.map(|k| pallas::Base::from_bytes(&base.u()[NUM_WINDOWS - 1][k]).unwrap());
|
||||
region.assign_advice(
|
||||
|| "u",
|
||||
self.u,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::super::{EccBaseFieldElemFixed, EccConfig, EccPoint, NullifierK};
|
||||
use super::super::{EccBaseFieldElemFixed, EccConfig, EccPoint, FixedPoints};
|
||||
use super::H_BASE;
|
||||
|
||||
use crate::{
|
||||
|
@ -18,16 +18,16 @@ use pasta_curves::{arithmetic::FieldExt, pallas};
|
|||
|
||||
use std::convert::TryInto;
|
||||
|
||||
pub struct Config {
|
||||
pub struct Config<Fixed: FixedPoints<pallas::Affine>> {
|
||||
q_mul_fixed_running_sum: Selector,
|
||||
q_mul_fixed_base_field: Selector,
|
||||
canon_advices: [Column<Advice>; 3],
|
||||
lookup_config: LookupRangeCheckConfig<pallas::Base, { sinsemilla::K }>,
|
||||
running_sum_config: RunningSumConfig<pallas::Base, { constants::FIXED_BASE_WINDOW_SIZE }>,
|
||||
super_config: super::Config<{ constants::NUM_WINDOWS }>,
|
||||
super_config: super::Config<Fixed, { constants::NUM_WINDOWS }>,
|
||||
}
|
||||
|
||||
impl From<&EccConfig> for Config {
|
||||
impl<Fixed: FixedPoints<pallas::Affine>> From<&EccConfig> for Config<Fixed> {
|
||||
fn from(config: &EccConfig) -> Self {
|
||||
let config = Self {
|
||||
q_mul_fixed_running_sum: config.q_mul_fixed_running_sum,
|
||||
|
@ -52,7 +52,7 @@ impl From<&EccConfig> for Config {
|
|||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
impl<Fixed: FixedPoints<pallas::Affine>> Config<Fixed> {
|
||||
pub fn create_gate(&self, meta: &mut ConstraintSystem<pallas::Base>) {
|
||||
// Check that the base field element is canonical.
|
||||
meta.create_gate("Canonicity checks", |meta| {
|
||||
|
@ -157,7 +157,7 @@ impl Config {
|
|||
&self,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
scalar: CellValue<pallas::Base>,
|
||||
base: NullifierK,
|
||||
base: &Fixed,
|
||||
) -> Result<EccPoint, Error> {
|
||||
let (scalar, acc, mul_b) = layouter.assign_region(
|
||||
|| "Base-field elem fixed-base mul (incomplete addition)",
|
||||
|
@ -184,7 +184,7 @@ impl Config {
|
|||
&mut region,
|
||||
offset,
|
||||
&(&scalar).into(),
|
||||
base.into(),
|
||||
base,
|
||||
self.q_mul_fixed_running_sum,
|
||||
)?;
|
||||
|
||||
|
@ -210,7 +210,6 @@ impl Config {
|
|||
{
|
||||
use group::Curve;
|
||||
|
||||
let base: super::OrchardFixedBases = base.into();
|
||||
let scalar = &scalar
|
||||
.base_field_elem()
|
||||
.value()
|
||||
|
@ -387,43 +386,40 @@ pub mod tests {
|
|||
use pasta_curves::{arithmetic::FieldExt, pallas};
|
||||
|
||||
use crate::circuit::gadget::{
|
||||
ecc::{
|
||||
chip::{EccChip, NullifierK},
|
||||
FixedPointBaseField, NonIdentityPoint, Point,
|
||||
},
|
||||
ecc::{chip::EccChip, FixedPoint, FixedPoints, NonIdentityPoint, Point},
|
||||
utilities::UtilitiesInstructions,
|
||||
};
|
||||
use crate::constants;
|
||||
use crate::constants::{self, OrchardFixedBases};
|
||||
|
||||
pub fn test_mul_fixed_base_field(
|
||||
chip: EccChip,
|
||||
chip: EccChip<OrchardFixedBases>,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
) -> Result<(), Error> {
|
||||
// nullifier_k
|
||||
let nullifier_k = NullifierK;
|
||||
let nullifier_k = OrchardFixedBases::NullifierK;
|
||||
test_single_base(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "nullifier_k"),
|
||||
FixedPointBaseField::from_inner(chip, nullifier_k),
|
||||
FixedPoint::from_inner(chip, nullifier_k),
|
||||
nullifier_k.generator(),
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::op_ref)]
|
||||
fn test_single_base(
|
||||
chip: EccChip,
|
||||
chip: EccChip<OrchardFixedBases>,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
base: FixedPointBaseField<pallas::Affine, EccChip>,
|
||||
base: FixedPoint<pallas::Affine, EccChip<OrchardFixedBases>>,
|
||||
base_val: pallas::Affine,
|
||||
) -> Result<(), Error> {
|
||||
let column = chip.config().advices[0];
|
||||
|
||||
fn constrain_equal_non_id(
|
||||
chip: EccChip,
|
||||
chip: EccChip<OrchardFixedBases>,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
base_val: pallas::Affine,
|
||||
scalar_val: pallas::Base,
|
||||
result: Point<pallas::Affine, EccChip>,
|
||||
result: Point<pallas::Affine, EccChip<OrchardFixedBases>>,
|
||||
) -> Result<(), Error> {
|
||||
// Move scalar from base field into scalar field (which always fits for Pallas).
|
||||
let scalar = pallas::Scalar::from_bytes(&scalar_val.to_bytes()).unwrap();
|
||||
|
@ -444,7 +440,7 @@ pub mod tests {
|
|||
column,
|
||||
Some(scalar_fixed),
|
||||
)?;
|
||||
base.mul(layouter.namespace(|| "random [a]B"), scalar_fixed)?
|
||||
base.mul_base_field(layouter.namespace(|| "random [a]B"), scalar_fixed)?
|
||||
};
|
||||
constrain_equal_non_id(
|
||||
chip.clone(),
|
||||
|
@ -472,7 +468,7 @@ pub mod tests {
|
|||
column,
|
||||
Some(scalar_fixed),
|
||||
)?;
|
||||
base.mul(layouter.namespace(|| "mul with double"), scalar_fixed)?
|
||||
base.mul_base_field(layouter.namespace(|| "mul with double"), scalar_fixed)?
|
||||
};
|
||||
constrain_equal_non_id(
|
||||
chip.clone(),
|
||||
|
@ -490,7 +486,7 @@ pub mod tests {
|
|||
let result = {
|
||||
let scalar_fixed =
|
||||
chip.load_private(layouter.namespace(|| "zero"), column, Some(scalar_fixed))?;
|
||||
base.mul(layouter.namespace(|| "mul by zero"), scalar_fixed)?
|
||||
base.mul_base_field(layouter.namespace(|| "mul by zero"), scalar_fixed)?
|
||||
};
|
||||
assert!(result.inner().is_identity().unwrap());
|
||||
}
|
||||
|
@ -501,7 +497,7 @@ pub mod tests {
|
|||
let result = {
|
||||
let scalar_fixed =
|
||||
chip.load_private(layouter.namespace(|| "-1"), column, Some(scalar_fixed))?;
|
||||
base.mul(layouter.namespace(|| "mul by -1"), scalar_fixed)?
|
||||
base.mul_base_field(layouter.namespace(|| "mul by -1"), scalar_fixed)?
|
||||
};
|
||||
constrain_equal_non_id(
|
||||
chip,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::super::{EccConfig, EccPoint, EccScalarFixed, OrchardFixedBasesFull};
|
||||
use super::super::{EccConfig, EccPoint, EccScalarFixed, FixedPoints};
|
||||
|
||||
use crate::{
|
||||
circuit::gadget::utilities::{range_check, CellValue, Var},
|
||||
|
@ -12,12 +12,12 @@ use halo2::{
|
|||
};
|
||||
use pasta_curves::{arithmetic::FieldExt, pallas};
|
||||
|
||||
pub struct Config {
|
||||
pub struct Config<Fixed: FixedPoints<pallas::Affine>> {
|
||||
q_mul_fixed_full: Selector,
|
||||
super_config: super::Config<NUM_WINDOWS>,
|
||||
super_config: super::Config<Fixed, NUM_WINDOWS>,
|
||||
}
|
||||
|
||||
impl From<&EccConfig> for Config {
|
||||
impl<Fixed: FixedPoints<pallas::Affine>> From<&EccConfig> for Config<Fixed> {
|
||||
fn from(config: &EccConfig) -> Self {
|
||||
Self {
|
||||
q_mul_fixed_full: config.q_mul_fixed_full,
|
||||
|
@ -26,7 +26,7 @@ impl From<&EccConfig> for Config {
|
|||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
impl<Fixed: FixedPoints<pallas::Affine>> Config<Fixed> {
|
||||
pub fn create_gate(&self, meta: &mut ConstraintSystem<pallas::Base>) {
|
||||
// Check that each window `k` is within 3 bits
|
||||
meta.create_gate("Full-width fixed-base scalar mul", |meta| {
|
||||
|
@ -115,7 +115,7 @@ impl Config {
|
|||
&self,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
scalar: Option<pallas::Scalar>,
|
||||
base: OrchardFixedBasesFull,
|
||||
base: &Fixed,
|
||||
) -> Result<(EccPoint, EccScalarFixed), Error> {
|
||||
let (scalar, acc, mul_b) = layouter.assign_region(
|
||||
|| "Full-width fixed-base mul (incomplete addition)",
|
||||
|
@ -128,7 +128,7 @@ impl Config {
|
|||
&mut region,
|
||||
offset,
|
||||
&(&scalar).into(),
|
||||
base.into(),
|
||||
base,
|
||||
self.q_mul_fixed_full,
|
||||
)?;
|
||||
|
||||
|
@ -154,7 +154,6 @@ impl Config {
|
|||
{
|
||||
use group::Curve;
|
||||
|
||||
let base: super::OrchardFixedBases = base.into();
|
||||
let real_mul = scalar.value.map(|scalar| base.generator() * scalar);
|
||||
let result = result.point();
|
||||
|
||||
|
@ -174,17 +173,16 @@ pub mod tests {
|
|||
use pasta_curves::{arithmetic::FieldExt, pallas};
|
||||
|
||||
use crate::circuit::gadget::ecc::{
|
||||
chip::{EccChip, OrchardFixedBasesFull},
|
||||
FixedPoint, NonIdentityPoint, Point,
|
||||
chip::EccChip, FixedPoint, FixedPoints, NonIdentityPoint, Point,
|
||||
};
|
||||
use crate::constants;
|
||||
use crate::constants::{self, OrchardFixedBases};
|
||||
|
||||
pub fn test_mul_fixed(
|
||||
chip: EccChip,
|
||||
chip: EccChip<OrchardFixedBases>,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
) -> Result<(), Error> {
|
||||
// commit_ivk_r
|
||||
let commit_ivk_r = OrchardFixedBasesFull::CommitIvkR;
|
||||
let commit_ivk_r = OrchardFixedBases::CommitIvkR;
|
||||
test_single_base(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "commit_ivk_r"),
|
||||
|
@ -193,7 +191,7 @@ pub mod tests {
|
|||
)?;
|
||||
|
||||
// note_commit_r
|
||||
let note_commit_r = OrchardFixedBasesFull::NoteCommitR;
|
||||
let note_commit_r = OrchardFixedBases::NoteCommitR;
|
||||
test_single_base(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "note_commit_r"),
|
||||
|
@ -202,7 +200,7 @@ pub mod tests {
|
|||
)?;
|
||||
|
||||
// value_commit_r
|
||||
let value_commit_r = OrchardFixedBasesFull::ValueCommitR;
|
||||
let value_commit_r = OrchardFixedBases::ValueCommitR;
|
||||
test_single_base(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "value_commit_r"),
|
||||
|
@ -211,7 +209,7 @@ pub mod tests {
|
|||
)?;
|
||||
|
||||
// spend_auth_g
|
||||
let spend_auth_g = OrchardFixedBasesFull::SpendAuthG;
|
||||
let spend_auth_g = OrchardFixedBases::SpendAuthG;
|
||||
test_single_base(
|
||||
chip.clone(),
|
||||
layouter.namespace(|| "spend_auth_g"),
|
||||
|
@ -224,17 +222,17 @@ pub mod tests {
|
|||
|
||||
#[allow(clippy::op_ref)]
|
||||
fn test_single_base(
|
||||
chip: EccChip,
|
||||
chip: EccChip<OrchardFixedBases>,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
base: FixedPoint<pallas::Affine, EccChip>,
|
||||
base: FixedPoint<pallas::Affine, EccChip<OrchardFixedBases>>,
|
||||
base_val: pallas::Affine,
|
||||
) -> Result<(), Error> {
|
||||
fn constrain_equal_non_id(
|
||||
chip: EccChip,
|
||||
chip: EccChip<OrchardFixedBases>,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
base_val: pallas::Affine,
|
||||
scalar_val: pallas::Scalar,
|
||||
result: Point<pallas::Affine, EccChip>,
|
||||
result: Point<pallas::Affine, EccChip<OrchardFixedBases>>,
|
||||
) -> Result<(), Error> {
|
||||
let expected = NonIdentityPoint::new(
|
||||
chip,
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use std::{array, convert::TryInto};
|
||||
|
||||
use super::super::{EccConfig, EccPoint, EccScalarFixedShort};
|
||||
use super::super::{EccConfig, EccPoint, EccScalarFixedShort, FixedPoints};
|
||||
use crate::{
|
||||
circuit::gadget::utilities::{copy, decompose_running_sum::RunningSumConfig, CellValue, Var},
|
||||
constants::{ValueCommitV, FIXED_BASE_WINDOW_SIZE, L_VALUE, NUM_WINDOWS_SHORT},
|
||||
constants::{FIXED_BASE_WINDOW_SIZE, L_VALUE, NUM_WINDOWS_SHORT},
|
||||
};
|
||||
|
||||
use halo2::{
|
||||
|
@ -14,15 +14,15 @@ use halo2::{
|
|||
use pasta_curves::pallas;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Config {
|
||||
pub struct Config<Fixed: FixedPoints<pallas::Affine>> {
|
||||
// Selector used for fixed-base scalar mul with short signed exponent.
|
||||
q_mul_fixed_short: Selector,
|
||||
q_mul_fixed_running_sum: Selector,
|
||||
running_sum_config: RunningSumConfig<pallas::Base, { FIXED_BASE_WINDOW_SIZE }>,
|
||||
super_config: super::Config<NUM_WINDOWS_SHORT>,
|
||||
super_config: super::Config<Fixed, NUM_WINDOWS_SHORT>,
|
||||
}
|
||||
|
||||
impl From<&EccConfig> for Config {
|
||||
impl<Fixed: FixedPoints<pallas::Affine>> From<&EccConfig> for Config<Fixed> {
|
||||
fn from(config: &EccConfig) -> Self {
|
||||
Self {
|
||||
q_mul_fixed_short: config.q_mul_fixed_short,
|
||||
|
@ -33,7 +33,7 @@ impl From<&EccConfig> for Config {
|
|||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
impl<Fixed: FixedPoints<pallas::Affine>> Config<Fixed> {
|
||||
pub(crate) fn create_gate(&self, meta: &mut ConstraintSystem<pallas::Base>) {
|
||||
meta.create_gate("Short fixed-base mul gate", |meta| {
|
||||
let q_mul_fixed_short = meta.query_selector(self.q_mul_fixed_short);
|
||||
|
@ -98,7 +98,7 @@ impl Config {
|
|||
&self,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
magnitude_sign: (CellValue<pallas::Base>, CellValue<pallas::Base>),
|
||||
base: &ValueCommitV,
|
||||
base: &Fixed,
|
||||
) -> Result<(EccPoint, EccScalarFixedShort), Error> {
|
||||
let (scalar, acc, mul_b) = layouter.assign_region(
|
||||
|| "Short fixed-base mul (incomplete addition)",
|
||||
|
@ -112,7 +112,7 @@ impl Config {
|
|||
&mut region,
|
||||
offset,
|
||||
&(&scalar).into(),
|
||||
base.clone().into(),
|
||||
base,
|
||||
self.q_mul_fixed_running_sum,
|
||||
)?;
|
||||
|
||||
|
@ -201,8 +201,6 @@ impl Config {
|
|||
magnitude <= pallas::Base::from_u64(0xFFFF_FFFF_FFFF_FFFFu64);
|
||||
let sign_is_valid = sign * sign == pallas::Base::one();
|
||||
if magnitude_is_valid && sign_is_valid {
|
||||
let base: super::OrchardFixedBases = base.clone().into();
|
||||
|
||||
let scalar = scalar.magnitude.value().zip(scalar.sign.value()).map(
|
||||
|(magnitude, sign)| {
|
||||
// Move magnitude from base field into scalar field (which always fits
|
||||
|
@ -244,23 +242,23 @@ pub mod tests {
|
|||
use pasta_curves::{arithmetic::FieldExt, pallas};
|
||||
|
||||
use crate::circuit::gadget::{
|
||||
ecc::{chip::EccChip, FixedPointShort, NonIdentityPoint, Point},
|
||||
ecc::{chip::EccChip, FixedPoint, FixedPoints, NonIdentityPoint, Point},
|
||||
utilities::{lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions},
|
||||
};
|
||||
use crate::constants::load::ValueCommitV;
|
||||
use crate::constants::OrchardFixedBases;
|
||||
|
||||
#[allow(clippy::op_ref)]
|
||||
pub fn test_mul_fixed_short(
|
||||
chip: EccChip,
|
||||
chip: EccChip<OrchardFixedBases>,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
) -> Result<(), Error> {
|
||||
// value_commit_v
|
||||
let value_commit_v = ValueCommitV::get();
|
||||
let base_val = value_commit_v.generator;
|
||||
let value_commit_v = FixedPointShort::from_inner(chip.clone(), value_commit_v);
|
||||
let value_commit_v = OrchardFixedBases::ValueCommitV;
|
||||
let base_val = value_commit_v.generator();
|
||||
let value_commit_v = FixedPoint::from_inner(chip.clone(), value_commit_v);
|
||||
|
||||
fn load_magnitude_sign(
|
||||
chip: EccChip,
|
||||
chip: EccChip<OrchardFixedBases>,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
magnitude: pallas::Base,
|
||||
sign: pallas::Base,
|
||||
|
@ -274,11 +272,11 @@ pub mod tests {
|
|||
}
|
||||
|
||||
fn constrain_equal_non_id(
|
||||
chip: EccChip,
|
||||
chip: EccChip<OrchardFixedBases>,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
base_val: pallas::Affine,
|
||||
scalar_val: pallas::Scalar,
|
||||
result: Point<pallas::Affine, EccChip>,
|
||||
result: Point<pallas::Affine, EccChip<OrchardFixedBases>>,
|
||||
) -> Result<(), Error> {
|
||||
let expected = NonIdentityPoint::new(
|
||||
chip,
|
||||
|
@ -333,7 +331,7 @@ pub mod tests {
|
|||
*magnitude,
|
||||
*sign,
|
||||
)?;
|
||||
value_commit_v.mul(layouter.namespace(|| *name), magnitude_sign)?
|
||||
value_commit_v.mul_short(layouter.namespace(|| *name), magnitude_sign)?
|
||||
};
|
||||
// Move from base field into scalar field
|
||||
let scalar = {
|
||||
|
@ -367,7 +365,7 @@ pub mod tests {
|
|||
*magnitude,
|
||||
*sign,
|
||||
)?;
|
||||
value_commit_v.mul(layouter.namespace(|| *name), magnitude_sign)?
|
||||
value_commit_v.mul_short(layouter.namespace(|| *name), magnitude_sign)?
|
||||
};
|
||||
assert!(result.inner().is_identity().unwrap());
|
||||
}
|
||||
|
@ -435,7 +433,7 @@ pub mod tests {
|
|||
meta.enable_constant(constants);
|
||||
|
||||
let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table);
|
||||
EccChip::configure(meta, advices, lagrange_coeffs, range_check)
|
||||
EccChip::<OrchardFixedBases>::configure(meta, advices, lagrange_coeffs, range_check)
|
||||
}
|
||||
|
||||
fn synthesize(
|
||||
|
@ -445,7 +443,7 @@ pub mod tests {
|
|||
) -> Result<(), Error> {
|
||||
let column = config.advices[0];
|
||||
|
||||
let short_config: super::Config = (&config).into();
|
||||
let short_config: super::Config<OrchardFixedBases> = (&config).into();
|
||||
let magnitude_sign = {
|
||||
let magnitude = self.load_private(
|
||||
layouter.namespace(|| "load magnitude"),
|
||||
|
@ -457,7 +455,7 @@ pub mod tests {
|
|||
(magnitude, sign)
|
||||
};
|
||||
|
||||
short_config.assign(layouter, magnitude_sign, &ValueCommitV::get())?;
|
||||
short_config.assign(layouter, magnitude_sign, &OrchardFixedBases::ValueCommitV)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -360,6 +360,7 @@ where
|
|||
pub fn new(
|
||||
sinsemilla_chip: SinsemillaChip,
|
||||
ecc_chip: EccChip,
|
||||
// Instead of using SinsemilllaChip::CommitDomains, just use something that implements a CommitDomains trait
|
||||
domain: &SinsemillaChip::CommitDomains,
|
||||
) -> Self {
|
||||
CommitDomain {
|
||||
|
@ -416,7 +417,7 @@ mod tests {
|
|||
};
|
||||
|
||||
use super::{
|
||||
chip::{SinsemillaChip, SinsemillaCommitDomains, SinsemillaConfig, SinsemillaHashDomains},
|
||||
chip::{SinsemillaChip, SinsemillaConfig},
|
||||
CommitDomain, HashDomain, Message, MessagePiece,
|
||||
};
|
||||
|
||||
|
@ -428,7 +429,10 @@ mod tests {
|
|||
},
|
||||
utilities::lookup_range_check::LookupRangeCheckConfig,
|
||||
},
|
||||
constants::{COMMIT_IVK_PERSONALIZATION, MERKLE_CRH_PERSONALIZATION},
|
||||
constants::{
|
||||
OrchardCommitDomains, OrchardFixedBases, OrchardHashDomains,
|
||||
COMMIT_IVK_PERSONALIZATION, MERKLE_CRH_PERSONALIZATION,
|
||||
},
|
||||
primitives::sinsemilla::{self, K},
|
||||
};
|
||||
|
||||
|
@ -440,7 +444,11 @@ mod tests {
|
|||
struct MyCircuit {}
|
||||
|
||||
impl Circuit<pallas::Base> for MyCircuit {
|
||||
type Config = (EccConfig, SinsemillaConfig, SinsemillaConfig);
|
||||
type Config = (
|
||||
EccConfig,
|
||||
SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
|
||||
SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
|
||||
);
|
||||
type FloorPlanner = SimpleFloorPlanner;
|
||||
|
||||
fn without_witnesses(&self) -> Self {
|
||||
|
@ -487,8 +495,12 @@ mod tests {
|
|||
|
||||
let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx);
|
||||
|
||||
let ecc_config =
|
||||
EccChip::configure(meta, advices, lagrange_coeffs, range_check.clone());
|
||||
let ecc_config = EccChip::<OrchardFixedBases>::configure(
|
||||
meta,
|
||||
advices,
|
||||
lagrange_coeffs,
|
||||
range_check.clone(),
|
||||
);
|
||||
|
||||
let config1 = SinsemillaChip::configure(
|
||||
meta,
|
||||
|
@ -517,7 +529,10 @@ mod tests {
|
|||
let ecc_chip = EccChip::construct(config.0);
|
||||
|
||||
// The two `SinsemillaChip`s share the same lookup table.
|
||||
SinsemillaChip::load(config.1.clone(), &mut layouter)?;
|
||||
SinsemillaChip::<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>::load(
|
||||
config.1.clone(),
|
||||
&mut layouter,
|
||||
)?;
|
||||
|
||||
// This MerkleCRH example is purely for illustrative purposes.
|
||||
// It is not an implementation of the Orchard protocol spec.
|
||||
|
@ -527,7 +542,7 @@ mod tests {
|
|||
let merkle_crh = HashDomain::new(
|
||||
chip1.clone(),
|
||||
ecc_chip.clone(),
|
||||
&SinsemillaHashDomains::MerkleCrh,
|
||||
&OrchardHashDomains::MerkleCrh,
|
||||
);
|
||||
|
||||
// Layer 31, l = MERKLE_DEPTH_ORCHARD - 1 - layer = 0
|
||||
|
@ -603,7 +618,7 @@ mod tests {
|
|||
let commit_ivk = CommitDomain::new(
|
||||
chip2.clone(),
|
||||
ecc_chip.clone(),
|
||||
&SinsemillaCommitDomains::CommitIvk,
|
||||
&OrchardCommitDomains::CommitIvk,
|
||||
);
|
||||
let r_val = pallas::Scalar::rand();
|
||||
let message: Vec<Option<bool>> =
|
||||
|
|
|
@ -4,17 +4,14 @@ use super::{
|
|||
};
|
||||
use crate::{
|
||||
circuit::gadget::{
|
||||
ecc::chip::NonIdentityEccPoint,
|
||||
ecc::{chip::NonIdentityEccPoint, FixedPoints},
|
||||
utilities::{lookup_range_check::LookupRangeCheckConfig, CellValue, Var},
|
||||
},
|
||||
constants::OrchardFixedBasesFull,
|
||||
primitives::sinsemilla::{
|
||||
self, Q_COMMIT_IVK_M_GENERATOR, Q_MERKLE_CRH, Q_NOTE_COMMITMENT_M_GENERATOR,
|
||||
},
|
||||
primitives::sinsemilla,
|
||||
};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use halo2::{
|
||||
arithmetic::{CurveAffine, FieldExt},
|
||||
circuit::{Chip, Layouter},
|
||||
plonk::{
|
||||
Advice, Column, ConstraintSystem, Error, Expression, Fixed, Selector, TableColumn,
|
||||
|
@ -22,7 +19,7 @@ use halo2::{
|
|||
},
|
||||
poly::Rotation,
|
||||
};
|
||||
use pasta_curves::pallas;
|
||||
use pasta_curves::{arithmetic::FieldExt, pallas};
|
||||
|
||||
mod generator_table;
|
||||
use generator_table::GeneratorTableConfig;
|
||||
|
@ -31,7 +28,12 @@ mod hash_to_point;
|
|||
|
||||
/// Configuration for the Sinsemilla hash chip
|
||||
#[derive(Eq, PartialEq, Clone, Debug)]
|
||||
pub struct SinsemillaConfig {
|
||||
pub struct SinsemillaConfig<Hash, Commit, F>
|
||||
where
|
||||
Hash: HashDomains<pallas::Affine>,
|
||||
F: FixedPoints<pallas::Affine>,
|
||||
Commit: CommitDomains<pallas::Affine, F, Hash>,
|
||||
{
|
||||
/// Binary selector used in lookup argument and in the body of the Sinsemilla hash.
|
||||
q_sinsemilla1: Selector,
|
||||
/// Non-binary selector used in lookup argument and in the body of the Sinsemilla hash.
|
||||
|
@ -66,9 +68,15 @@ pub struct SinsemillaConfig {
|
|||
generator_table: GeneratorTableConfig,
|
||||
/// An advice column configured to perform lookup range checks.
|
||||
lookup_config: LookupRangeCheckConfig<pallas::Base, { sinsemilla::K }>,
|
||||
_marker: PhantomData<(Hash, Commit, F)>,
|
||||
}
|
||||
|
||||
impl SinsemillaConfig {
|
||||
impl<Hash, Commit, F> SinsemillaConfig<Hash, Commit, F>
|
||||
where
|
||||
Hash: HashDomains<pallas::Affine>,
|
||||
F: FixedPoints<pallas::Affine>,
|
||||
Commit: CommitDomains<pallas::Affine, F, Hash>,
|
||||
{
|
||||
/// Returns an array of all advice columns in this config, in arbitrary order.
|
||||
pub fn advices(&self) -> [Column<Advice>; 5] {
|
||||
[self.x_a, self.x_p, self.bits, self.lambda_1, self.lambda_2]
|
||||
|
@ -81,12 +89,22 @@ impl SinsemillaConfig {
|
|||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Clone, Debug)]
|
||||
pub struct SinsemillaChip {
|
||||
config: SinsemillaConfig,
|
||||
pub struct SinsemillaChip<Hash, Commit, Fixed>
|
||||
where
|
||||
Hash: HashDomains<pallas::Affine>,
|
||||
Fixed: FixedPoints<pallas::Affine>,
|
||||
Commit: CommitDomains<pallas::Affine, Fixed, Hash>,
|
||||
{
|
||||
config: SinsemillaConfig<Hash, Commit, Fixed>,
|
||||
}
|
||||
|
||||
impl Chip<pallas::Base> for SinsemillaChip {
|
||||
type Config = SinsemillaConfig;
|
||||
impl<Hash, Commit, Fixed> Chip<pallas::Base> for SinsemillaChip<Hash, Commit, Fixed>
|
||||
where
|
||||
Hash: HashDomains<pallas::Affine>,
|
||||
Fixed: FixedPoints<pallas::Affine>,
|
||||
Commit: CommitDomains<pallas::Affine, Fixed, Hash>,
|
||||
{
|
||||
type Config = SinsemillaConfig<Hash, Commit, Fixed>;
|
||||
type Loaded = ();
|
||||
|
||||
fn config(&self) -> &Self::Config {
|
||||
|
@ -98,13 +116,18 @@ impl Chip<pallas::Base> for SinsemillaChip {
|
|||
}
|
||||
}
|
||||
|
||||
impl SinsemillaChip {
|
||||
impl<Hash, Commit, F> SinsemillaChip<Hash, Commit, F>
|
||||
where
|
||||
Hash: HashDomains<pallas::Affine>,
|
||||
F: FixedPoints<pallas::Affine>,
|
||||
Commit: CommitDomains<pallas::Affine, F, Hash>,
|
||||
{
|
||||
pub fn construct(config: <Self as Chip<pallas::Base>>::Config) -> Self {
|
||||
Self { config }
|
||||
}
|
||||
|
||||
pub fn load(
|
||||
config: SinsemillaConfig,
|
||||
config: SinsemillaConfig<Hash, Commit, F>,
|
||||
layouter: &mut impl Layouter<pallas::Base>,
|
||||
) -> Result<<Self as Chip<pallas::Base>>::Loaded, Error> {
|
||||
// Load the lookup table.
|
||||
|
@ -129,7 +152,7 @@ impl SinsemillaChip {
|
|||
meta.enable_equality((*advice).into())
|
||||
}
|
||||
|
||||
let config = SinsemillaConfig {
|
||||
let config = SinsemillaConfig::<Hash, Commit, F> {
|
||||
q_sinsemilla1: meta.complex_selector(),
|
||||
q_sinsemilla2: meta.fixed_column(),
|
||||
q_sinsemilla4: meta.selector(),
|
||||
|
@ -146,6 +169,7 @@ impl SinsemillaChip {
|
|||
table_y: lookup.2,
|
||||
},
|
||||
lookup_config: range_check,
|
||||
_marker: PhantomData,
|
||||
};
|
||||
|
||||
// Set up lookup argument
|
||||
|
@ -241,8 +265,12 @@ impl SinsemillaChip {
|
|||
}
|
||||
|
||||
// Implement `SinsemillaInstructions` for `SinsemillaChip`
|
||||
impl SinsemillaInstructions<pallas::Affine, { sinsemilla::K }, { sinsemilla::C }>
|
||||
for SinsemillaChip
|
||||
impl<Hash, Commit, F> SinsemillaInstructions<pallas::Affine, { sinsemilla::K }, { sinsemilla::C }>
|
||||
for SinsemillaChip<Hash, Commit, F>
|
||||
where
|
||||
Hash: HashDomains<pallas::Affine>,
|
||||
F: FixedPoints<pallas::Affine>,
|
||||
Commit: CommitDomains<pallas::Affine, F, Hash>,
|
||||
{
|
||||
type CellValue = CellValue<pallas::Base>;
|
||||
|
||||
|
@ -253,10 +281,10 @@ impl SinsemillaInstructions<pallas::Affine, { sinsemilla::K }, { sinsemilla::C }
|
|||
|
||||
type X = CellValue<pallas::Base>;
|
||||
type NonIdentityPoint = NonIdentityEccPoint;
|
||||
type FixedPoints = OrchardFixedBasesFull;
|
||||
type FixedPoints = F;
|
||||
|
||||
type HashDomains = SinsemillaHashDomains;
|
||||
type CommitDomains = SinsemillaCommitDomains;
|
||||
type HashDomains = Hash;
|
||||
type CommitDomains = Commit;
|
||||
|
||||
fn witness_message_piece(
|
||||
&self,
|
||||
|
@ -298,57 +326,3 @@ impl SinsemillaInstructions<pallas::Affine, { sinsemilla::K }, { sinsemilla::C }
|
|||
point.x()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum SinsemillaHashDomains {
|
||||
NoteCommit,
|
||||
CommitIvk,
|
||||
MerkleCrh,
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
impl HashDomains<pallas::Affine> for SinsemillaHashDomains {
|
||||
fn Q(&self) -> pallas::Affine {
|
||||
match self {
|
||||
SinsemillaHashDomains::CommitIvk => pallas::Affine::from_xy(
|
||||
pallas::Base::from_bytes(&Q_COMMIT_IVK_M_GENERATOR.0).unwrap(),
|
||||
pallas::Base::from_bytes(&Q_COMMIT_IVK_M_GENERATOR.1).unwrap(),
|
||||
)
|
||||
.unwrap(),
|
||||
SinsemillaHashDomains::NoteCommit => pallas::Affine::from_xy(
|
||||
pallas::Base::from_bytes(&Q_NOTE_COMMITMENT_M_GENERATOR.0).unwrap(),
|
||||
pallas::Base::from_bytes(&Q_NOTE_COMMITMENT_M_GENERATOR.1).unwrap(),
|
||||
)
|
||||
.unwrap(),
|
||||
SinsemillaHashDomains::MerkleCrh => pallas::Affine::from_xy(
|
||||
pallas::Base::from_bytes(&Q_MERKLE_CRH.0).unwrap(),
|
||||
pallas::Base::from_bytes(&Q_MERKLE_CRH.1).unwrap(),
|
||||
)
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum SinsemillaCommitDomains {
|
||||
NoteCommit,
|
||||
CommitIvk,
|
||||
}
|
||||
|
||||
impl CommitDomains<pallas::Affine, OrchardFixedBasesFull, SinsemillaHashDomains>
|
||||
for SinsemillaCommitDomains
|
||||
{
|
||||
fn r(&self) -> OrchardFixedBasesFull {
|
||||
match self {
|
||||
Self::NoteCommit => OrchardFixedBasesFull::NoteCommitR,
|
||||
Self::CommitIvk => OrchardFixedBasesFull::CommitIvkR,
|
||||
}
|
||||
}
|
||||
|
||||
fn hash_domain(&self) -> SinsemillaHashDomains {
|
||||
match self {
|
||||
Self::NoteCommit => SinsemillaHashDomains::NoteCommit,
|
||||
Self::CommitIvk => SinsemillaHashDomains::CommitIvk,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ use halo2::{
|
|||
poly::Rotation,
|
||||
};
|
||||
|
||||
use super::{CommitDomains, FixedPoints, HashDomains};
|
||||
use pasta_curves::{arithmetic::FieldExt, pallas};
|
||||
|
||||
/// Table containing independent generators S[0..2^k]
|
||||
|
@ -21,7 +22,14 @@ impl GeneratorTableConfig {
|
|||
/// Even though the lookup table can be used in other parts of the circuit,
|
||||
/// this specific configuration sets up Sinsemilla-specific constraints
|
||||
/// controlled by `q_sinsemilla`, and would likely not apply to other chips.
|
||||
pub fn configure(meta: &mut ConstraintSystem<pallas::Base>, config: super::SinsemillaConfig) {
|
||||
pub fn configure<Hash, Commit, F>(
|
||||
meta: &mut ConstraintSystem<pallas::Base>,
|
||||
config: super::SinsemillaConfig<Hash, Commit, F>,
|
||||
) where
|
||||
Hash: HashDomains<pallas::Affine>,
|
||||
F: FixedPoints<pallas::Affine>,
|
||||
Commit: CommitDomains<pallas::Affine, F, Hash>,
|
||||
{
|
||||
let (table_idx, table_x, table_y) = (
|
||||
config.generator_table.table_idx,
|
||||
config.generator_table.table_x,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use super::super::SinsemillaInstructions;
|
||||
use super::super::{CommitDomains, HashDomains, SinsemillaInstructions};
|
||||
use super::{CellValue, NonIdentityEccPoint, SinsemillaChip, Var};
|
||||
|
||||
use crate::circuit::gadget::ecc::FixedPoints;
|
||||
use crate::primitives::sinsemilla::{self, lebs2ip_k, INV_TWO_POW_K, SINSEMILLA_S};
|
||||
use halo2::{
|
||||
circuit::{Chip, Region},
|
||||
|
@ -14,7 +16,12 @@ use pasta_curves::{
|
|||
|
||||
use std::ops::Deref;
|
||||
|
||||
impl SinsemillaChip {
|
||||
impl<Hash, Commit, Fixed> SinsemillaChip<Hash, Commit, Fixed>
|
||||
where
|
||||
Hash: HashDomains<pallas::Affine>,
|
||||
Fixed: FixedPoints<pallas::Affine>,
|
||||
Commit: CommitDomains<pallas::Affine, Fixed, Hash>,
|
||||
{
|
||||
#[allow(non_snake_case)]
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub(super) fn hash_message(
|
||||
|
|
|
@ -139,10 +139,12 @@ pub mod tests {
|
|||
|
||||
use crate::{
|
||||
circuit::gadget::{
|
||||
sinsemilla::chip::{SinsemillaChip, SinsemillaHashDomains},
|
||||
sinsemilla::chip::SinsemillaChip,
|
||||
utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions, Var},
|
||||
},
|
||||
constants::MERKLE_DEPTH_ORCHARD,
|
||||
constants::{
|
||||
OrchardCommitDomains, OrchardFixedBases, OrchardHashDomains, MERKLE_DEPTH_ORCHARD,
|
||||
},
|
||||
note::commitment::ExtractedNoteCommitment,
|
||||
tree,
|
||||
};
|
||||
|
@ -166,7 +168,10 @@ pub mod tests {
|
|||
}
|
||||
|
||||
impl Circuit<pallas::Base> for MyCircuit {
|
||||
type Config = (MerkleConfig, MerkleConfig);
|
||||
type Config = (
|
||||
MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
|
||||
MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
|
||||
);
|
||||
type FloorPlanner = SimpleFloorPlanner;
|
||||
|
||||
fn without_witnesses(&self) -> Self {
|
||||
|
@ -234,7 +239,10 @@ pub mod tests {
|
|||
mut layouter: impl Layouter<pallas::Base>,
|
||||
) -> Result<(), Error> {
|
||||
// Load generator table (shared across both configs)
|
||||
SinsemillaChip::load(config.0.sinsemilla_config.clone(), &mut layouter)?;
|
||||
SinsemillaChip::<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>::load(
|
||||
config.0.sinsemilla_config.clone(),
|
||||
&mut layouter,
|
||||
)?;
|
||||
|
||||
// Construct Merkle chips which will be placed side-by-side in the circuit.
|
||||
let chip_1 = MerkleChip::construct(config.0.clone());
|
||||
|
@ -249,7 +257,7 @@ pub mod tests {
|
|||
let path = MerklePath {
|
||||
chip_1,
|
||||
chip_2,
|
||||
domain: SinsemillaHashDomains::MerkleCrh,
|
||||
domain: OrchardHashDomains::MerkleCrh,
|
||||
leaf_pos: self.leaf_pos,
|
||||
path: self.merkle_path,
|
||||
};
|
||||
|
|
|
@ -9,9 +9,10 @@ use super::MerkleInstructions;
|
|||
|
||||
use crate::{
|
||||
circuit::gadget::{
|
||||
ecc::FixedPoints,
|
||||
sinsemilla::{
|
||||
chip::{SinsemillaChip, SinsemillaConfig},
|
||||
SinsemillaInstructions,
|
||||
CommitDomains, HashDomains, SinsemillaInstructions,
|
||||
},
|
||||
utilities::{
|
||||
bitrange_subset,
|
||||
|
@ -25,20 +26,35 @@ use crate::{
|
|||
use std::array;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MerkleConfig {
|
||||
pub struct MerkleConfig<Hash, Commit, Fixed>
|
||||
where
|
||||
Hash: HashDomains<pallas::Affine>,
|
||||
Fixed: FixedPoints<pallas::Affine>,
|
||||
Commit: CommitDomains<pallas::Affine, Fixed, Hash>,
|
||||
{
|
||||
advices: [Column<Advice>; 5],
|
||||
q_decompose: Selector,
|
||||
pub(super) cond_swap_config: CondSwapConfig,
|
||||
pub(super) sinsemilla_config: SinsemillaConfig,
|
||||
pub(super) sinsemilla_config: SinsemillaConfig<Hash, Commit, Fixed>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MerkleChip {
|
||||
config: MerkleConfig,
|
||||
pub struct MerkleChip<Hash, Commit, Fixed>
|
||||
where
|
||||
Hash: HashDomains<pallas::Affine>,
|
||||
Fixed: FixedPoints<pallas::Affine>,
|
||||
Commit: CommitDomains<pallas::Affine, Fixed, Hash>,
|
||||
{
|
||||
config: MerkleConfig<Hash, Commit, Fixed>,
|
||||
}
|
||||
|
||||
impl Chip<pallas::Base> for MerkleChip {
|
||||
type Config = MerkleConfig;
|
||||
impl<Hash, Commit, Fixed> Chip<pallas::Base> for MerkleChip<Hash, Commit, Fixed>
|
||||
where
|
||||
Hash: HashDomains<pallas::Affine>,
|
||||
Fixed: FixedPoints<pallas::Affine>,
|
||||
Commit: CommitDomains<pallas::Affine, Fixed, Hash>,
|
||||
{
|
||||
type Config = MerkleConfig<Hash, Commit, Fixed>;
|
||||
type Loaded = ();
|
||||
|
||||
fn config(&self) -> &Self::Config {
|
||||
|
@ -50,11 +66,16 @@ impl Chip<pallas::Base> for MerkleChip {
|
|||
}
|
||||
}
|
||||
|
||||
impl MerkleChip {
|
||||
impl<Hash, Commit, F> MerkleChip<Hash, Commit, F>
|
||||
where
|
||||
Hash: HashDomains<pallas::Affine>,
|
||||
F: FixedPoints<pallas::Affine>,
|
||||
Commit: CommitDomains<pallas::Affine, F, Hash>,
|
||||
{
|
||||
pub fn configure(
|
||||
meta: &mut ConstraintSystem<pallas::Base>,
|
||||
sinsemilla_config: SinsemillaConfig,
|
||||
) -> MerkleConfig {
|
||||
sinsemilla_config: SinsemillaConfig<Hash, Commit, F>,
|
||||
) -> MerkleConfig<Hash, Commit, F> {
|
||||
// All five advice columns are equality-enabled by SinsemillaConfig.
|
||||
let advices = sinsemilla_config.advices();
|
||||
let cond_swap_config = CondSwapChip::configure(meta, advices);
|
||||
|
@ -154,13 +175,18 @@ impl MerkleChip {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn construct(config: MerkleConfig) -> Self {
|
||||
pub fn construct(config: MerkleConfig<Hash, Commit, F>) -> Self {
|
||||
MerkleChip { config }
|
||||
}
|
||||
}
|
||||
|
||||
impl MerkleInstructions<pallas::Affine, MERKLE_DEPTH_ORCHARD, { sinsemilla::K }, { sinsemilla::C }>
|
||||
for MerkleChip
|
||||
impl<Hash, Commit, F>
|
||||
MerkleInstructions<pallas::Affine, MERKLE_DEPTH_ORCHARD, { sinsemilla::K }, { sinsemilla::C }>
|
||||
for MerkleChip<Hash, Commit, F>
|
||||
where
|
||||
Hash: HashDomains<pallas::Affine>,
|
||||
F: FixedPoints<pallas::Affine>,
|
||||
Commit: CommitDomains<pallas::Affine, F, Hash>,
|
||||
{
|
||||
#[allow(non_snake_case)]
|
||||
fn hash_layer(
|
||||
|
@ -371,11 +397,21 @@ impl MerkleInstructions<pallas::Affine, MERKLE_DEPTH_ORCHARD, { sinsemilla::K },
|
|||
}
|
||||
}
|
||||
|
||||
impl UtilitiesInstructions<pallas::Base> for MerkleChip {
|
||||
impl<Hash, Commit, F> UtilitiesInstructions<pallas::Base> for MerkleChip<Hash, Commit, F>
|
||||
where
|
||||
Hash: HashDomains<pallas::Affine>,
|
||||
F: FixedPoints<pallas::Affine>,
|
||||
Commit: CommitDomains<pallas::Affine, F, Hash>,
|
||||
{
|
||||
type Var = CellValue<pallas::Base>;
|
||||
}
|
||||
|
||||
impl CondSwapInstructions<pallas::Base> for MerkleChip {
|
||||
impl<Hash, Commit, F> CondSwapInstructions<pallas::Base> for MerkleChip<Hash, Commit, F>
|
||||
where
|
||||
Hash: HashDomains<pallas::Affine>,
|
||||
F: FixedPoints<pallas::Affine>,
|
||||
Commit: CommitDomains<pallas::Affine, F, Hash>,
|
||||
{
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn swap(
|
||||
&self,
|
||||
|
@ -389,51 +425,57 @@ impl CondSwapInstructions<pallas::Base> for MerkleChip {
|
|||
}
|
||||
}
|
||||
|
||||
impl SinsemillaInstructions<pallas::Affine, { sinsemilla::K }, { sinsemilla::C }> for MerkleChip {
|
||||
type CellValue = <SinsemillaChip as SinsemillaInstructions<
|
||||
impl<Hash, Commit, F> SinsemillaInstructions<pallas::Affine, { sinsemilla::K }, { sinsemilla::C }>
|
||||
for MerkleChip<Hash, Commit, F>
|
||||
where
|
||||
Hash: HashDomains<pallas::Affine>,
|
||||
F: FixedPoints<pallas::Affine>,
|
||||
Commit: CommitDomains<pallas::Affine, F, Hash>,
|
||||
{
|
||||
type CellValue = <SinsemillaChip<Hash, Commit, F> as SinsemillaInstructions<
|
||||
pallas::Affine,
|
||||
{ sinsemilla::K },
|
||||
{ sinsemilla::C },
|
||||
>>::CellValue;
|
||||
|
||||
type Message = <SinsemillaChip as SinsemillaInstructions<
|
||||
type Message = <SinsemillaChip<Hash, Commit, F> as SinsemillaInstructions<
|
||||
pallas::Affine,
|
||||
{ sinsemilla::K },
|
||||
{ sinsemilla::C },
|
||||
>>::Message;
|
||||
type MessagePiece = <SinsemillaChip as SinsemillaInstructions<
|
||||
type MessagePiece = <SinsemillaChip<Hash, Commit, F> as SinsemillaInstructions<
|
||||
pallas::Affine,
|
||||
{ sinsemilla::K },
|
||||
{ sinsemilla::C },
|
||||
>>::MessagePiece;
|
||||
type RunningSum = <SinsemillaChip as SinsemillaInstructions<
|
||||
type RunningSum = <SinsemillaChip<Hash, Commit, F> as SinsemillaInstructions<
|
||||
pallas::Affine,
|
||||
{ sinsemilla::K },
|
||||
{ sinsemilla::C },
|
||||
>>::RunningSum;
|
||||
|
||||
type X = <SinsemillaChip as SinsemillaInstructions<
|
||||
type X = <SinsemillaChip<Hash, Commit, F> as SinsemillaInstructions<
|
||||
pallas::Affine,
|
||||
{ sinsemilla::K },
|
||||
{ sinsemilla::C },
|
||||
>>::X;
|
||||
type NonIdentityPoint = <SinsemillaChip as SinsemillaInstructions<
|
||||
type NonIdentityPoint = <SinsemillaChip<Hash, Commit, F> as SinsemillaInstructions<
|
||||
pallas::Affine,
|
||||
{ sinsemilla::K },
|
||||
{ sinsemilla::C },
|
||||
>>::NonIdentityPoint;
|
||||
type FixedPoints = <SinsemillaChip as SinsemillaInstructions<
|
||||
type FixedPoints = <SinsemillaChip<Hash, Commit, F> as SinsemillaInstructions<
|
||||
pallas::Affine,
|
||||
{ sinsemilla::K },
|
||||
{ sinsemilla::C },
|
||||
>>::FixedPoints;
|
||||
|
||||
type HashDomains = <SinsemillaChip as SinsemillaInstructions<
|
||||
type HashDomains = <SinsemillaChip<Hash, Commit, F> as SinsemillaInstructions<
|
||||
pallas::Affine,
|
||||
{ sinsemilla::K },
|
||||
{ sinsemilla::C },
|
||||
>>::HashDomains;
|
||||
type CommitDomains = <SinsemillaChip as SinsemillaInstructions<
|
||||
type CommitDomains = <SinsemillaChip<Hash, Commit, F> as SinsemillaInstructions<
|
||||
pallas::Affine,
|
||||
{ sinsemilla::K },
|
||||
{ sinsemilla::C },
|
||||
|
@ -446,7 +488,7 @@ impl SinsemillaInstructions<pallas::Affine, { sinsemilla::K }, { sinsemilla::C }
|
|||
num_words: usize,
|
||||
) -> Result<Self::MessagePiece, Error> {
|
||||
let config = self.config().sinsemilla_config.clone();
|
||||
let chip = SinsemillaChip::construct(config);
|
||||
let chip = SinsemillaChip::<Hash, Commit, F>::construct(config);
|
||||
chip.witness_message_piece(layouter, value, num_words)
|
||||
}
|
||||
|
||||
|
@ -459,11 +501,11 @@ impl SinsemillaInstructions<pallas::Affine, { sinsemilla::K }, { sinsemilla::C }
|
|||
message: Self::Message,
|
||||
) -> Result<(Self::NonIdentityPoint, Vec<Vec<Self::CellValue>>), Error> {
|
||||
let config = self.config().sinsemilla_config.clone();
|
||||
let chip = SinsemillaChip::construct(config);
|
||||
let chip = SinsemillaChip::<Hash, Commit, F>::construct(config);
|
||||
chip.hash_to_point(layouter, Q, message)
|
||||
}
|
||||
|
||||
fn extract(point: &Self::NonIdentityPoint) -> Self::X {
|
||||
SinsemillaChip::extract(point)
|
||||
SinsemillaChip::<Hash, Commit, F>::extract(point)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,12 +12,12 @@ use crate::{
|
|||
Point,
|
||||
},
|
||||
sinsemilla::{
|
||||
chip::{SinsemillaChip, SinsemillaCommitDomains, SinsemillaConfig},
|
||||
chip::{SinsemillaChip, SinsemillaConfig},
|
||||
CommitDomain, Message, MessagePiece,
|
||||
},
|
||||
utilities::{bitrange_subset, bool_check, copy, CellValue, Var},
|
||||
},
|
||||
constants::T_P,
|
||||
constants::{OrchardCommitDomains, OrchardFixedBases, OrchardHashDomains, T_P},
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -48,7 +48,8 @@ pub struct NoteCommitConfig {
|
|||
q_notecommit_psi: Selector,
|
||||
q_y_canon: Selector,
|
||||
advices: [Column<Advice>; 10],
|
||||
sinsemilla_config: SinsemillaConfig,
|
||||
sinsemilla_config:
|
||||
SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
|
||||
}
|
||||
|
||||
impl NoteCommitConfig {
|
||||
|
@ -57,7 +58,11 @@ impl NoteCommitConfig {
|
|||
pub(in crate::circuit) fn configure(
|
||||
meta: &mut ConstraintSystem<pallas::Base>,
|
||||
advices: [Column<Advice>; 10],
|
||||
sinsemilla_config: SinsemillaConfig,
|
||||
sinsemilla_config: SinsemillaConfig<
|
||||
OrchardHashDomains,
|
||||
OrchardCommitDomains,
|
||||
OrchardFixedBases,
|
||||
>,
|
||||
) -> Self {
|
||||
let q_notecommit_b = meta.selector();
|
||||
let q_notecommit_d = meta.selector();
|
||||
|
@ -520,15 +525,15 @@ impl NoteCommitConfig {
|
|||
pub(in crate::circuit) fn assign_region(
|
||||
&self,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
chip: SinsemillaChip,
|
||||
ecc_chip: EccChip,
|
||||
chip: SinsemillaChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
|
||||
ecc_chip: EccChip<OrchardFixedBases>,
|
||||
g_d: &NonIdentityEccPoint,
|
||||
pk_d: &NonIdentityEccPoint,
|
||||
value: CellValue<pallas::Base>,
|
||||
rho: CellValue<pallas::Base>,
|
||||
psi: CellValue<pallas::Base>,
|
||||
rcm: Option<pallas::Scalar>,
|
||||
) -> Result<Point<pallas::Affine, EccChip>, Error> {
|
||||
) -> Result<Point<pallas::Affine, EccChip<OrchardFixedBases>>, Error> {
|
||||
let (gd_x, gd_y) = (g_d.x().value(), g_d.y().value());
|
||||
let (pkd_x, pkd_y) = (pk_d.x().value(), pk_d.y().value());
|
||||
let value_val = value.value();
|
||||
|
@ -729,7 +734,7 @@ impl NoteCommitConfig {
|
|||
h.clone(),
|
||||
],
|
||||
);
|
||||
let domain = CommitDomain::new(chip, ecc_chip, &SinsemillaCommitDomains::NoteCommit);
|
||||
let domain = CommitDomain::new(chip, ecc_chip, &OrchardCommitDomains::NoteCommit);
|
||||
domain.commit(
|
||||
layouter.namespace(|| "Process NoteCommit inputs"),
|
||||
message,
|
||||
|
@ -1438,7 +1443,10 @@ mod tests {
|
|||
lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions,
|
||||
},
|
||||
},
|
||||
constants::{L_ORCHARD_BASE, L_VALUE, NOTE_COMMITMENT_PERSONALIZATION, T_Q},
|
||||
constants::{
|
||||
OrchardCommitDomains, OrchardFixedBases, OrchardHashDomains, L_ORCHARD_BASE, L_VALUE,
|
||||
NOTE_COMMITMENT_PERSONALIZATION, T_Q,
|
||||
},
|
||||
primitives::sinsemilla::CommitDomain,
|
||||
};
|
||||
|
||||
|
@ -1521,7 +1529,11 @@ mod tests {
|
|||
];
|
||||
|
||||
let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx);
|
||||
let sinsemilla_config = SinsemillaChip::configure(
|
||||
let sinsemilla_config = SinsemillaChip::<
|
||||
OrchardHashDomains,
|
||||
OrchardCommitDomains,
|
||||
OrchardFixedBases,
|
||||
>::configure(
|
||||
meta,
|
||||
advices[..5].try_into().unwrap(),
|
||||
advices[2],
|
||||
|
@ -1532,7 +1544,12 @@ mod tests {
|
|||
let note_commit_config =
|
||||
NoteCommitConfig::configure(meta, advices, sinsemilla_config);
|
||||
|
||||
let ecc_config = EccChip::configure(meta, advices, lagrange_coeffs, range_check);
|
||||
let ecc_config = EccChip::<OrchardFixedBases>::configure(
|
||||
meta,
|
||||
advices,
|
||||
lagrange_coeffs,
|
||||
range_check,
|
||||
);
|
||||
|
||||
(note_commit_config, ecc_config)
|
||||
}
|
||||
|
@ -1545,7 +1562,11 @@ mod tests {
|
|||
let (note_commit_config, ecc_config) = config;
|
||||
|
||||
// Load the Sinsemilla generator lookup table used by the whole circuit.
|
||||
SinsemillaChip::load(note_commit_config.sinsemilla_config.clone(), &mut layouter)?;
|
||||
SinsemillaChip::<
|
||||
OrchardHashDomains,
|
||||
OrchardCommitDomains,
|
||||
OrchardFixedBases,
|
||||
>::load(note_commit_config.sinsemilla_config.clone(), &mut layouter)?;
|
||||
|
||||
// Construct a Sinsemilla chip
|
||||
let sinsemilla_chip =
|
||||
|
|
117
src/constants.rs
117
src/constants.rs
|
@ -1,4 +1,12 @@
|
|||
//! Constants used in the Orchard protocol.
|
||||
use crate::circuit::gadget::{
|
||||
ecc::FixedPoints,
|
||||
sinsemilla::{CommitDomains, HashDomains},
|
||||
};
|
||||
use crate::primitives::sinsemilla::{
|
||||
Q_COMMIT_IVK_M_GENERATOR, Q_MERKLE_CRH, Q_NOTE_COMMITMENT_M_GENERATOR,
|
||||
};
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
use ff::{Field, PrimeField};
|
||||
use group::Curve;
|
||||
|
@ -15,11 +23,8 @@ pub mod spend_auth_g;
|
|||
pub mod value_commit_r;
|
||||
pub mod value_commit_v;
|
||||
|
||||
pub mod load;
|
||||
pub mod util;
|
||||
|
||||
pub use load::{NullifierK, OrchardFixedBase, OrchardFixedBasesFull, ValueCommitV};
|
||||
|
||||
/// The Pallas scalar field modulus is $q = 2^{254} + \mathsf{t_q}$.
|
||||
/// <https://github.com/zcash/pasta>
|
||||
pub(crate) const T_Q: u128 = 45560315531506369815346746415080538113;
|
||||
|
@ -201,6 +206,112 @@ fn find_zs_and_us<C: CurveAffine>(base: C, num_windows: usize) -> Option<Vec<(u6
|
|||
.collect()
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum OrchardFixedBases {
|
||||
CommitIvkR,
|
||||
NoteCommitR,
|
||||
ValueCommitR,
|
||||
SpendAuthG,
|
||||
NullifierK,
|
||||
ValueCommitV,
|
||||
}
|
||||
|
||||
impl FixedPoints<pallas::Affine> for OrchardFixedBases {
|
||||
fn generator(&self) -> pallas::Affine {
|
||||
match self {
|
||||
OrchardFixedBases::CommitIvkR => commit_ivk_r::generator(),
|
||||
OrchardFixedBases::NoteCommitR => note_commit_r::generator(),
|
||||
OrchardFixedBases::ValueCommitR => value_commit_r::generator(),
|
||||
OrchardFixedBases::SpendAuthG => spend_auth_g::generator(),
|
||||
OrchardFixedBases::NullifierK => nullifier_k::generator(),
|
||||
OrchardFixedBases::ValueCommitV => value_commit_v::generator(),
|
||||
}
|
||||
}
|
||||
|
||||
fn u(&self) -> Vec<[[u8; 32]; H]> {
|
||||
match self {
|
||||
OrchardFixedBases::CommitIvkR => commit_ivk_r::U.to_vec(),
|
||||
OrchardFixedBases::NoteCommitR => note_commit_r::U.to_vec(),
|
||||
OrchardFixedBases::ValueCommitR => value_commit_r::U.to_vec(),
|
||||
OrchardFixedBases::SpendAuthG => spend_auth_g::U.to_vec(),
|
||||
OrchardFixedBases::NullifierK => nullifier_k::U.to_vec(),
|
||||
OrchardFixedBases::ValueCommitV => value_commit_v::U_SHORT.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
fn z(&self) -> Vec<u64> {
|
||||
match self {
|
||||
OrchardFixedBases::CommitIvkR => commit_ivk_r::Z.to_vec(),
|
||||
OrchardFixedBases::NoteCommitR => note_commit_r::Z.to_vec(),
|
||||
OrchardFixedBases::ValueCommitR => value_commit_r::Z.to_vec(),
|
||||
OrchardFixedBases::SpendAuthG => spend_auth_g::Z.to_vec(),
|
||||
OrchardFixedBases::NullifierK => nullifier_k::Z.to_vec(),
|
||||
OrchardFixedBases::ValueCommitV => value_commit_v::Z_SHORT.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
fn lagrange_coeffs(&self) -> Vec<[pallas::Base; H]> {
|
||||
match self {
|
||||
OrchardFixedBases::ValueCommitV => {
|
||||
compute_lagrange_coeffs(self.generator(), NUM_WINDOWS_SHORT)
|
||||
}
|
||||
_ => compute_lagrange_coeffs(self.generator(), NUM_WINDOWS),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum OrchardHashDomains {
|
||||
NoteCommit,
|
||||
CommitIvk,
|
||||
MerkleCrh,
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
impl HashDomains<pallas::Affine> for OrchardHashDomains {
|
||||
fn Q(&self) -> pallas::Affine {
|
||||
match self {
|
||||
OrchardHashDomains::CommitIvk => pallas::Affine::from_xy(
|
||||
pallas::Base::from_bytes(&Q_COMMIT_IVK_M_GENERATOR.0).unwrap(),
|
||||
pallas::Base::from_bytes(&Q_COMMIT_IVK_M_GENERATOR.1).unwrap(),
|
||||
)
|
||||
.unwrap(),
|
||||
OrchardHashDomains::NoteCommit => pallas::Affine::from_xy(
|
||||
pallas::Base::from_bytes(&Q_NOTE_COMMITMENT_M_GENERATOR.0).unwrap(),
|
||||
pallas::Base::from_bytes(&Q_NOTE_COMMITMENT_M_GENERATOR.1).unwrap(),
|
||||
)
|
||||
.unwrap(),
|
||||
OrchardHashDomains::MerkleCrh => pallas::Affine::from_xy(
|
||||
pallas::Base::from_bytes(&Q_MERKLE_CRH.0).unwrap(),
|
||||
pallas::Base::from_bytes(&Q_MERKLE_CRH.1).unwrap(),
|
||||
)
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum OrchardCommitDomains {
|
||||
NoteCommit,
|
||||
CommitIvk,
|
||||
}
|
||||
|
||||
impl CommitDomains<pallas::Affine, OrchardFixedBases, OrchardHashDomains> for OrchardCommitDomains {
|
||||
fn r(&self) -> OrchardFixedBases {
|
||||
match self {
|
||||
Self::NoteCommit => OrchardFixedBases::NoteCommitR,
|
||||
Self::CommitIvk => OrchardFixedBases::CommitIvkR,
|
||||
}
|
||||
}
|
||||
|
||||
fn hash_domain(&self) -> OrchardHashDomains {
|
||||
match self {
|
||||
Self::NoteCommit => OrchardHashDomains::NoteCommit,
|
||||
Self::CommitIvk => OrchardHashDomains::CommitIvk,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
// Test that Lagrange interpolation coefficients reproduce the correct x-coordinate
|
||||
// for each fixed-base multiple in each window.
|
||||
|
|
|
@ -1,256 +0,0 @@
|
|||
use std::convert::TryInto;
|
||||
|
||||
use crate::constants::{self, compute_lagrange_coeffs, H, NUM_WINDOWS, NUM_WINDOWS_SHORT};
|
||||
use pasta_curves::{arithmetic::FieldExt, pallas};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum OrchardFixedBasesFull {
|
||||
CommitIvkR,
|
||||
NoteCommitR,
|
||||
ValueCommitR,
|
||||
SpendAuthG,
|
||||
}
|
||||
|
||||
impl OrchardFixedBasesFull {
|
||||
pub fn generator(&self) -> pallas::Affine {
|
||||
match self {
|
||||
OrchardFixedBasesFull::CommitIvkR => super::commit_ivk_r::generator(),
|
||||
OrchardFixedBasesFull::NoteCommitR => super::note_commit_r::generator(),
|
||||
OrchardFixedBasesFull::ValueCommitR => super::value_commit_r::generator(),
|
||||
OrchardFixedBasesFull::SpendAuthG => super::spend_auth_g::generator(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn u(&self) -> U {
|
||||
match self {
|
||||
OrchardFixedBasesFull::CommitIvkR => super::commit_ivk_r::U.into(),
|
||||
OrchardFixedBasesFull::NoteCommitR => super::note_commit_r::U.into(),
|
||||
OrchardFixedBasesFull::ValueCommitR => super::value_commit_r::U.into(),
|
||||
OrchardFixedBasesFull::SpendAuthG => super::spend_auth_g::U.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A fixed base to be used in scalar multiplication with a full-width scalar.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct OrchardFixedBase {
|
||||
pub generator: pallas::Affine,
|
||||
pub lagrange_coeffs: LagrangeCoeffs,
|
||||
pub z: Z,
|
||||
pub u: U,
|
||||
}
|
||||
|
||||
impl From<OrchardFixedBasesFull> for OrchardFixedBase {
|
||||
fn from(base: OrchardFixedBasesFull) -> Self {
|
||||
let (generator, z, u) = match base {
|
||||
OrchardFixedBasesFull::CommitIvkR => (
|
||||
super::commit_ivk_r::generator(),
|
||||
super::commit_ivk_r::Z.into(),
|
||||
super::commit_ivk_r::U.into(),
|
||||
),
|
||||
OrchardFixedBasesFull::NoteCommitR => (
|
||||
super::note_commit_r::generator(),
|
||||
super::note_commit_r::Z.into(),
|
||||
super::note_commit_r::U.into(),
|
||||
),
|
||||
OrchardFixedBasesFull::ValueCommitR => (
|
||||
super::value_commit_r::generator(),
|
||||
super::value_commit_r::Z.into(),
|
||||
super::value_commit_r::U.into(),
|
||||
),
|
||||
OrchardFixedBasesFull::SpendAuthG => (
|
||||
super::spend_auth_g::generator(),
|
||||
super::spend_auth_g::Z.into(),
|
||||
super::spend_auth_g::U.into(),
|
||||
),
|
||||
};
|
||||
|
||||
Self {
|
||||
generator,
|
||||
lagrange_coeffs: compute_lagrange_coeffs(generator, NUM_WINDOWS).into(),
|
||||
z,
|
||||
u,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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,
|
||||
pub lagrange_coeffs_short: LagrangeCoeffsShort,
|
||||
pub z_short: ZShort,
|
||||
pub u_short: UShort,
|
||||
}
|
||||
|
||||
impl ValueCommitV {
|
||||
pub fn get() -> Self {
|
||||
let generator = super::value_commit_v::generator();
|
||||
Self {
|
||||
generator,
|
||||
lagrange_coeffs_short: compute_lagrange_coeffs(generator, NUM_WINDOWS_SHORT).into(),
|
||||
z_short: super::value_commit_v::Z_SHORT.into(),
|
||||
u_short: super::value_commit_v::U_SHORT.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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]>);
|
||||
|
||||
impl From<&[pallas::Base; H]> for WindowLagrangeCoeffs {
|
||||
fn from(array: &[pallas::Base; H]) -> Self {
|
||||
Self(Box::new(*array))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
// 85 windows per base (with the exception of ValueCommitV)
|
||||
pub struct LagrangeCoeffs(pub Box<[WindowLagrangeCoeffs; constants::NUM_WINDOWS]>);
|
||||
|
||||
impl From<Vec<WindowLagrangeCoeffs>> for LagrangeCoeffs {
|
||||
fn from(windows: Vec<WindowLagrangeCoeffs>) -> Self {
|
||||
Self(windows.into_boxed_slice().try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<[pallas::Base; H]>> for LagrangeCoeffs {
|
||||
fn from(arrays: Vec<[pallas::Base; H]>) -> Self {
|
||||
let windows: Vec<WindowLagrangeCoeffs> = arrays.iter().map(|array| array.into()).collect();
|
||||
windows.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
// 22 windows for ValueCommitV
|
||||
pub struct LagrangeCoeffsShort(pub Box<[WindowLagrangeCoeffs; NUM_WINDOWS_SHORT]>);
|
||||
|
||||
impl From<Vec<WindowLagrangeCoeffs>> for LagrangeCoeffsShort {
|
||||
fn from(windows: Vec<WindowLagrangeCoeffs>) -> Self {
|
||||
Self(windows.into_boxed_slice().try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<[pallas::Base; H]>> for LagrangeCoeffsShort {
|
||||
fn from(arrays: Vec<[pallas::Base; H]>) -> Self {
|
||||
let windows: Vec<WindowLagrangeCoeffs> = arrays.iter().map(|array| array.into()).collect();
|
||||
windows.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
// 85 Z's per base (with the exception of ValueCommitV)
|
||||
pub struct Z(pub Box<[pallas::Base; NUM_WINDOWS]>);
|
||||
|
||||
impl From<[u64; NUM_WINDOWS]> for Z {
|
||||
fn from(zs: [u64; NUM_WINDOWS]) -> Self {
|
||||
Self(
|
||||
zs.iter()
|
||||
.map(|z| pallas::Base::from_u64(*z))
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice()
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
// 22 Z's for ValueCommitV
|
||||
pub struct ZShort(pub Box<[pallas::Base; NUM_WINDOWS_SHORT]>);
|
||||
|
||||
impl From<[u64; NUM_WINDOWS_SHORT]> for ZShort {
|
||||
fn from(zs: [u64; NUM_WINDOWS_SHORT]) -> Self {
|
||||
Self(
|
||||
zs.iter()
|
||||
.map(|z| pallas::Base::from_u64(*z))
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice()
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
// 8 u's per window
|
||||
pub struct WindowUs(pub Box<[pallas::Base; H]>);
|
||||
|
||||
impl From<&[[u8; 32]; H]> for WindowUs {
|
||||
fn from(window_us: &[[u8; 32]; H]) -> Self {
|
||||
Self(
|
||||
window_us
|
||||
.iter()
|
||||
.map(|u| pallas::Base::from_bytes(u).unwrap())
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice()
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
// 85 windows per base (with the exception of ValueCommitV)
|
||||
pub struct U(pub Box<[WindowUs; NUM_WINDOWS]>);
|
||||
|
||||
impl From<Vec<WindowUs>> for U {
|
||||
fn from(windows: Vec<WindowUs>) -> Self {
|
||||
Self(windows.into_boxed_slice().try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[[[u8; 32]; H]; NUM_WINDOWS]> for U {
|
||||
fn from(window_us: [[[u8; 32]; H]; NUM_WINDOWS]) -> Self {
|
||||
let windows: Vec<WindowUs> = window_us.iter().map(|us| us.into()).collect();
|
||||
windows.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
// 22 windows for ValueCommitV
|
||||
pub struct UShort(pub Box<[WindowUs; NUM_WINDOWS_SHORT]>);
|
||||
|
||||
impl From<Vec<WindowUs>> for UShort {
|
||||
fn from(windows: Vec<WindowUs>) -> Self {
|
||||
Self(windows.into_boxed_slice().try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[[[u8; 32]; H]; NUM_WINDOWS_SHORT]> for UShort {
|
||||
fn from(window_us: [[[u8; 32]; H]; NUM_WINDOWS_SHORT]) -> Self {
|
||||
let windows: Vec<WindowUs> = window_us.iter().map(|us| us.into()).collect();
|
||||
windows.into()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue