mirror of https://github.com/zcash/halo2.git
Merge pull request #250 from zcash/update-halo2-assignedcell
Migrate to halo2 version with `AssignedCell`
This commit is contained in:
commit
e4f338e758
|
@ -90,4 +90,4 @@ debug = true
|
|||
[patch.crates-io]
|
||||
zcash_note_encryption = { git = "https://github.com/zcash/librustzcash.git", rev = "35e75420657599fdc701cb45704878eb3fa2e59a" }
|
||||
incrementalmerkletree = { git = "https://github.com/zcash/incrementalmerkletree.git", rev = "b7bd6246122a6e9ace8edb51553fbf5228906cbb" }
|
||||
halo2 = { git = "https://github.com/zcash/halo2.git", rev = "8bfc58b7c76ae83ba5a9ed7ecdfe0ddfd40ed571" }
|
||||
halo2 = { git = "https://github.com/zcash/halo2.git", rev = "afd7bc5469674cd08eae1634225fd02706a36a4f" }
|
||||
|
|
|
@ -12,10 +12,7 @@ use halo2::{
|
|||
use pasta_curves::{pallas, vesta};
|
||||
|
||||
use orchard::{
|
||||
circuit::gadget::{
|
||||
poseidon::{Hash, Pow5Chip, Pow5Config},
|
||||
utilities::{CellValue, Var},
|
||||
},
|
||||
circuit::gadget::poseidon::{Hash, Pow5Chip, Pow5Config},
|
||||
primitives::poseidon::{self, ConstantLength, Spec},
|
||||
};
|
||||
use std::convert::TryInto;
|
||||
|
@ -91,13 +88,12 @@ where
|
|||
|mut region| {
|
||||
let message_word = |i: usize| {
|
||||
let value = self.message.map(|message_vals| message_vals[i]);
|
||||
let cell = region.assign_advice(
|
||||
region.assign_advice(
|
||||
|| format!("load message_{}", i),
|
||||
config.input[i],
|
||||
0,
|
||||
|| value.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
Ok(CellValue::new(cell, value))
|
||||
)
|
||||
};
|
||||
|
||||
let message: Result<Vec<_>, Error> = (0..L).map(message_word).collect();
|
||||
|
@ -121,7 +117,7 @@ where
|
|||
0,
|
||||
|| self.output.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
region.constrain_equal(output.cell(), expected_var)
|
||||
region.constrain_equal(output.cell(), expected_var.cell())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use group::{Curve, GroupEncoding};
|
||||
use halo2::{
|
||||
circuit::{floor_planner, Layouter},
|
||||
circuit::{floor_planner, AssignedCell, Layouter},
|
||||
plonk::{self, Advice, Column, Expression, Instance as InstanceColumn, Selector},
|
||||
poly::Rotation,
|
||||
transcript::{Blake2bRead, Blake2bWrite},
|
||||
|
@ -50,7 +50,7 @@ use gadget::{
|
|||
},
|
||||
note_commit::NoteCommitConfig,
|
||||
},
|
||||
utilities::{copy, CellValue, UtilitiesInstructions, Var},
|
||||
utilities::UtilitiesInstructions,
|
||||
};
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
@ -117,7 +117,7 @@ pub struct Circuit {
|
|||
}
|
||||
|
||||
impl UtilitiesInstructions<pallas::Base> for Circuit {
|
||||
type Var = CellValue<pallas::Base>;
|
||||
type Var = AssignedCell<pallas::Base, pallas::Base>;
|
||||
}
|
||||
|
||||
impl plonk::Circuit<pallas::Base> for Circuit {
|
||||
|
@ -405,7 +405,7 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
|||
leaf_pos: self.pos,
|
||||
path,
|
||||
};
|
||||
let leaf = *cm_old.extract_p().inner();
|
||||
let leaf = cm_old.extract_p().inner().clone();
|
||||
merkle_inputs.calculate_root(layouter.namespace(|| "MerkleCRH"), leaf)?
|
||||
};
|
||||
|
||||
|
@ -454,7 +454,7 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
|||
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)?
|
||||
value_commit_v.mul(layouter.namespace(|| "[v_net] ValueCommitV"), v_net.clone())?
|
||||
};
|
||||
|
||||
// blind = [rcv] ValueCommitR
|
||||
|
@ -481,7 +481,7 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
|||
let nf_old = {
|
||||
// hash_old = poseidon_hash(nk, rho_old)
|
||||
let hash_old = {
|
||||
let poseidon_message = [nk, rho_old];
|
||||
let poseidon_message = [nk.clone(), rho_old.clone()];
|
||||
let poseidon_hasher = PoseidonHash::<_, _, poseidon::P128Pow5T3, _, 3, 2>::init(
|
||||
config.poseidon_chip(),
|
||||
layouter.namespace(|| "Poseidon init"),
|
||||
|
@ -501,32 +501,19 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
|||
|mut region| {
|
||||
config.q_add.enable(&mut region, 0)?;
|
||||
|
||||
copy(
|
||||
&mut region,
|
||||
|| "copy hash_old",
|
||||
config.advices[7],
|
||||
0,
|
||||
&hash_old,
|
||||
)?;
|
||||
copy(
|
||||
&mut region,
|
||||
|| "copy psi_old",
|
||||
config.advices[8],
|
||||
0,
|
||||
&psi_old,
|
||||
)?;
|
||||
hash_old.copy_advice(|| "copy hash_old", &mut region, config.advices[7], 0)?;
|
||||
psi_old.copy_advice(|| "copy psi_old", &mut region, config.advices[8], 0)?;
|
||||
|
||||
let scalar_val = hash_old
|
||||
.value()
|
||||
.zip(psi_old.value())
|
||||
.map(|(hash_old, psi_old)| hash_old + psi_old);
|
||||
let cell = region.assign_advice(
|
||||
region.assign_advice(
|
||||
|| "poseidon_hash(nk, rho_old) + psi_old",
|
||||
config.advices[6],
|
||||
0,
|
||||
|| scalar_val.ok_or(plonk::Error::Synthesis),
|
||||
)?;
|
||||
Ok(CellValue::new(cell, scalar_val))
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
|
@ -581,7 +568,7 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
|||
config.sinsemilla_chip_1(),
|
||||
ecc_chip.clone(),
|
||||
layouter.namespace(|| "CommitIvk"),
|
||||
*ak.extract_p().inner(),
|
||||
ak.extract_p().inner().clone(),
|
||||
nk,
|
||||
rivk,
|
||||
)?
|
||||
|
@ -619,7 +606,7 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
|||
config.ecc_chip(),
|
||||
g_d_old.inner(),
|
||||
pk_d_old.inner(),
|
||||
v_old,
|
||||
v_old.clone(),
|
||||
rho_old,
|
||||
psi_old,
|
||||
rcm_old,
|
||||
|
@ -675,8 +662,8 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
|||
config.ecc_chip(),
|
||||
g_d_new.inner(),
|
||||
pk_d_new.inner(),
|
||||
v_new,
|
||||
*nf_old.inner(),
|
||||
v_new.clone(),
|
||||
nf_old.inner().clone(),
|
||||
psi_new,
|
||||
rcm_new,
|
||||
)?;
|
||||
|
@ -692,19 +679,13 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
|||
layouter.assign_region(
|
||||
|| "v_old - v_new = magnitude * sign",
|
||||
|mut region| {
|
||||
copy(&mut region, || "v_old", config.advices[0], 0, &v_old)?;
|
||||
copy(&mut region, || "v_new", config.advices[1], 0, &v_new)?;
|
||||
let (magnitude, sign) = v_net;
|
||||
copy(
|
||||
&mut region,
|
||||
|| "v_net magnitude",
|
||||
config.advices[2],
|
||||
0,
|
||||
&magnitude,
|
||||
)?;
|
||||
copy(&mut region, || "v_net sign", config.advices[3], 0, &sign)?;
|
||||
v_old.copy_advice(|| "v_old", &mut region, config.advices[0], 0)?;
|
||||
v_new.copy_advice(|| "v_new", &mut region, config.advices[1], 0)?;
|
||||
let (magnitude, sign) = v_net.clone();
|
||||
magnitude.copy_advice(|| "v_net magnitude", &mut region, config.advices[2], 0)?;
|
||||
sign.copy_advice(|| "v_net sign", &mut region, config.advices[3], 0)?;
|
||||
|
||||
copy(&mut region, || "anchor", config.advices[4], 0, &anchor)?;
|
||||
anchor.copy_advice(|| "anchor", &mut region, config.advices[4], 0)?;
|
||||
region.assign_advice_from_instance(
|
||||
|| "pub input anchor",
|
||||
config.primary,
|
||||
|
|
|
@ -508,7 +508,9 @@ mod tests {
|
|||
use super::chip::{EccChip, EccConfig};
|
||||
use crate::circuit::gadget::utilities::lookup_range_check::LookupRangeCheckConfig;
|
||||
|
||||
struct MyCircuit {}
|
||||
struct MyCircuit {
|
||||
test_errors: bool,
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
impl Circuit<pallas::Base> for MyCircuit {
|
||||
|
@ -516,7 +518,7 @@ mod tests {
|
|||
type FloorPlanner = SimpleFloorPlanner;
|
||||
|
||||
fn without_witnesses(&self) -> Self {
|
||||
MyCircuit {}
|
||||
MyCircuit { test_errors: false }
|
||||
}
|
||||
|
||||
fn configure(meta: &mut ConstraintSystem<pallas::Base>) -> Self::Config {
|
||||
|
@ -634,6 +636,7 @@ mod tests {
|
|||
q_val,
|
||||
&q,
|
||||
&p_neg,
|
||||
self.test_errors,
|
||||
)?;
|
||||
}
|
||||
|
||||
|
@ -678,7 +681,7 @@ mod tests {
|
|||
#[test]
|
||||
fn ecc_chip() {
|
||||
let k = 13;
|
||||
let circuit = MyCircuit {};
|
||||
let circuit = MyCircuit { test_errors: true };
|
||||
let prover = MockProver::run(k, &circuit, vec![]).unwrap();
|
||||
assert_eq!(prover.verify(), Ok(()))
|
||||
}
|
||||
|
@ -692,7 +695,7 @@ mod tests {
|
|||
root.fill(&WHITE).unwrap();
|
||||
let root = root.titled("Ecc Chip Layout", ("sans-serif", 60)).unwrap();
|
||||
|
||||
let circuit = MyCircuit {};
|
||||
let circuit = MyCircuit { test_errors: false };
|
||||
halo2::dev::CircuitLayout::default()
|
||||
.render(13, &circuit, &root)
|
||||
.unwrap();
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
use super::EccInstructions;
|
||||
use crate::{
|
||||
circuit::gadget::utilities::{
|
||||
copy, lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions, Var,
|
||||
lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions,
|
||||
},
|
||||
constants::{self, NullifierK, OrchardFixedBasesFull, ValueCommitV},
|
||||
primitives::sinsemilla,
|
||||
};
|
||||
use arrayvec::ArrayVec;
|
||||
|
||||
use ff::Field;
|
||||
use group::prime::PrimeCurveAffine;
|
||||
use halo2::{
|
||||
circuit::{Chip, Layouter},
|
||||
circuit::{AssignedCell, Chip, Layouter},
|
||||
plonk::{Advice, Column, ConstraintSystem, Error, Fixed},
|
||||
};
|
||||
use pasta_curves::{arithmetic::CurveAffine, pallas};
|
||||
|
@ -26,12 +27,12 @@ pub(super) mod witness_point;
|
|||
/// A curve point represented in affine (x, y) coordinates, or the
|
||||
/// identity represented as (0, 0).
|
||||
/// Each coordinate is assigned to a cell.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EccPoint {
|
||||
/// x-coordinate
|
||||
x: CellValue<pallas::Base>,
|
||||
x: AssignedCell<pallas::Base, pallas::Base>,
|
||||
/// y-coordinate
|
||||
y: CellValue<pallas::Base>,
|
||||
y: AssignedCell<pallas::Base, pallas::Base>,
|
||||
}
|
||||
|
||||
impl EccPoint {
|
||||
|
@ -40,8 +41,8 @@ impl EccPoint {
|
|||
/// This is an internal API that we only use where we know we have a valid curve point
|
||||
/// (specifically inside Sinsemilla).
|
||||
pub(in crate::circuit::gadget) fn from_coordinates_unchecked(
|
||||
x: CellValue<pallas::Base>,
|
||||
y: CellValue<pallas::Base>,
|
||||
x: AssignedCell<pallas::Base, pallas::Base>,
|
||||
y: AssignedCell<pallas::Base, pallas::Base>,
|
||||
) -> Self {
|
||||
EccPoint { x, y }
|
||||
}
|
||||
|
@ -50,10 +51,10 @@ impl EccPoint {
|
|||
pub fn point(&self) -> Option<pallas::Affine> {
|
||||
match (self.x.value(), self.y.value()) {
|
||||
(Some(x), Some(y)) => {
|
||||
if x == pallas::Base::zero() && y == pallas::Base::zero() {
|
||||
if x.is_zero_vartime() && y.is_zero_vartime() {
|
||||
Some(pallas::Affine::identity())
|
||||
} else {
|
||||
Some(pallas::Affine::from_xy(x, y).unwrap())
|
||||
Some(pallas::Affine::from_xy(*x, *y).unwrap())
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
|
@ -61,29 +62,29 @@ impl EccPoint {
|
|||
}
|
||||
/// The cell containing the affine short-Weierstrass x-coordinate,
|
||||
/// or 0 for the zero point.
|
||||
pub fn x(&self) -> CellValue<pallas::Base> {
|
||||
self.x
|
||||
pub fn x(&self) -> AssignedCell<pallas::Base, pallas::Base> {
|
||||
self.x.clone()
|
||||
}
|
||||
/// The cell containing the affine short-Weierstrass y-coordinate,
|
||||
/// or 0 for the zero point.
|
||||
pub fn y(&self) -> CellValue<pallas::Base> {
|
||||
self.y
|
||||
pub fn y(&self) -> AssignedCell<pallas::Base, pallas::Base> {
|
||||
self.y.clone()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn is_identity(&self) -> Option<bool> {
|
||||
self.x.value().map(|x| x == pallas::Base::zero())
|
||||
self.x.value().map(|x| x.is_zero_vartime())
|
||||
}
|
||||
}
|
||||
|
||||
/// A non-identity point represented in affine (x, y) coordinates.
|
||||
/// Each coordinate is assigned to a cell.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NonIdentityEccPoint {
|
||||
/// x-coordinate
|
||||
x: CellValue<pallas::Base>,
|
||||
x: AssignedCell<pallas::Base, pallas::Base>,
|
||||
/// y-coordinate
|
||||
y: CellValue<pallas::Base>,
|
||||
y: AssignedCell<pallas::Base, pallas::Base>,
|
||||
}
|
||||
|
||||
impl NonIdentityEccPoint {
|
||||
|
@ -92,8 +93,8 @@ impl NonIdentityEccPoint {
|
|||
/// This is an internal API that we only use where we know we have a valid non-identity
|
||||
/// curve point (specifically inside Sinsemilla).
|
||||
pub(in crate::circuit::gadget) fn from_coordinates_unchecked(
|
||||
x: CellValue<pallas::Base>,
|
||||
y: CellValue<pallas::Base>,
|
||||
x: AssignedCell<pallas::Base, pallas::Base>,
|
||||
y: AssignedCell<pallas::Base, pallas::Base>,
|
||||
) -> Self {
|
||||
NonIdentityEccPoint { x, y }
|
||||
}
|
||||
|
@ -102,19 +103,19 @@ impl NonIdentityEccPoint {
|
|||
pub fn point(&self) -> Option<pallas::Affine> {
|
||||
match (self.x.value(), self.y.value()) {
|
||||
(Some(x), Some(y)) => {
|
||||
assert!(x != pallas::Base::zero() && y != pallas::Base::zero());
|
||||
Some(pallas::Affine::from_xy(x, y).unwrap())
|
||||
assert!(!x.is_zero_vartime() && !y.is_zero_vartime());
|
||||
Some(pallas::Affine::from_xy(*x, *y).unwrap())
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
/// The cell containing the affine short-Weierstrass x-coordinate.
|
||||
pub fn x(&self) -> CellValue<pallas::Base> {
|
||||
self.x
|
||||
pub fn x(&self) -> AssignedCell<pallas::Base, pallas::Base> {
|
||||
self.x.clone()
|
||||
}
|
||||
/// The cell containing the affine short-Weierstrass y-coordinate.
|
||||
pub fn y(&self) -> CellValue<pallas::Base> {
|
||||
self.y
|
||||
pub fn y(&self) -> AssignedCell<pallas::Base, pallas::Base> {
|
||||
self.y.clone()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,7 +178,7 @@ impl Chip<pallas::Base> for EccChip {
|
|||
}
|
||||
|
||||
impl UtilitiesInstructions<pallas::Base> for EccChip {
|
||||
type Var = CellValue<pallas::Base>;
|
||||
type Var = AssignedCell<pallas::Base, pallas::Base>;
|
||||
}
|
||||
|
||||
impl EccChip {
|
||||
|
@ -259,9 +260,15 @@ impl EccChip {
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct EccScalarFixed {
|
||||
value: Option<pallas::Scalar>,
|
||||
windows: ArrayVec<CellValue<pallas::Base>, { constants::NUM_WINDOWS }>,
|
||||
windows: ArrayVec<AssignedCell<pallas::Base, pallas::Base>, { constants::NUM_WINDOWS }>,
|
||||
}
|
||||
|
||||
// TODO: Make V a `u64`
|
||||
type MagnitudeCell = AssignedCell<pallas::Base, pallas::Base>;
|
||||
// TODO: Make V an enum Sign { Positive, Negative }
|
||||
type SignCell = AssignedCell<pallas::Base, pallas::Base>;
|
||||
type MagnitudeSign = (MagnitudeCell, SignCell);
|
||||
|
||||
/// A signed short scalar used for fixed-base scalar multiplication.
|
||||
/// A short scalar must have magnitude in the range [0..2^64), with
|
||||
/// a sign of either 1 or -1.
|
||||
|
@ -276,9 +283,10 @@ pub struct EccScalarFixed {
|
|||
/// k_21 must be a single bit, i.e. 0 or 1.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EccScalarFixedShort {
|
||||
magnitude: CellValue<pallas::Base>,
|
||||
sign: CellValue<pallas::Base>,
|
||||
running_sum: ArrayVec<CellValue<pallas::Base>, { constants::NUM_WINDOWS_SHORT + 1 }>,
|
||||
magnitude: MagnitudeCell,
|
||||
sign: SignCell,
|
||||
running_sum:
|
||||
ArrayVec<AssignedCell<pallas::Base, pallas::Base>, { constants::NUM_WINDOWS_SHORT + 1 }>,
|
||||
}
|
||||
|
||||
/// A base field element used for fixed-base scalar multiplication.
|
||||
|
@ -292,23 +300,23 @@ pub struct EccScalarFixedShort {
|
|||
/// `base_field_elem`.
|
||||
#[derive(Clone, Debug)]
|
||||
struct EccBaseFieldElemFixed {
|
||||
base_field_elem: CellValue<pallas::Base>,
|
||||
running_sum: ArrayVec<CellValue<pallas::Base>, { constants::NUM_WINDOWS + 1 }>,
|
||||
base_field_elem: AssignedCell<pallas::Base, pallas::Base>,
|
||||
running_sum: ArrayVec<AssignedCell<pallas::Base, pallas::Base>, { constants::NUM_WINDOWS + 1 }>,
|
||||
}
|
||||
|
||||
impl EccBaseFieldElemFixed {
|
||||
fn base_field_elem(&self) -> CellValue<pallas::Base> {
|
||||
self.base_field_elem
|
||||
fn base_field_elem(&self) -> AssignedCell<pallas::Base, pallas::Base> {
|
||||
self.base_field_elem.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl EccInstructions<pallas::Affine> for EccChip {
|
||||
type ScalarFixed = EccScalarFixed;
|
||||
type ScalarFixedShort = EccScalarFixedShort;
|
||||
type ScalarVar = CellValue<pallas::Base>;
|
||||
type ScalarVar = AssignedCell<pallas::Base, pallas::Base>;
|
||||
type Point = EccPoint;
|
||||
type NonIdentityPoint = NonIdentityEccPoint;
|
||||
type X = CellValue<pallas::Base>;
|
||||
type X = AssignedCell<pallas::Base, pallas::Base>;
|
||||
type FixedPoints = OrchardFixedBasesFull;
|
||||
type FixedPointsBaseField = NullifierK;
|
||||
type FixedPointsShort = ValueCommitV;
|
||||
|
@ -396,7 +404,7 @@ impl EccInstructions<pallas::Affine> for EccChip {
|
|||
let config = self.config().mul;
|
||||
config.assign(
|
||||
layouter.namespace(|| "variable-base scalar mul"),
|
||||
*scalar,
|
||||
scalar.clone(),
|
||||
base,
|
||||
)
|
||||
}
|
||||
|
@ -418,7 +426,7 @@ impl EccInstructions<pallas::Affine> for EccChip {
|
|||
fn mul_fixed_short(
|
||||
&self,
|
||||
layouter: &mut impl Layouter<pallas::Base>,
|
||||
magnitude_sign: (CellValue<pallas::Base>, CellValue<pallas::Base>),
|
||||
magnitude_sign: MagnitudeSign,
|
||||
base: &Self::FixedPointsShort,
|
||||
) -> Result<(Self::Point, Self::ScalarFixedShort), Error> {
|
||||
let config: mul_fixed::short::Config = self.config().mul_fixed_short;
|
||||
|
@ -432,7 +440,7 @@ impl EccInstructions<pallas::Affine> for EccChip {
|
|||
fn mul_fixed_base_field_elem(
|
||||
&self,
|
||||
layouter: &mut impl Layouter<pallas::Base>,
|
||||
base_field_elem: CellValue<pallas::Base>,
|
||||
base_field_elem: AssignedCell<pallas::Base, pallas::Base>,
|
||||
base: &Self::FixedPointsBaseField,
|
||||
) -> Result<Self::Point, Error> {
|
||||
let config = self.config().mul_fixed_base_field;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::array;
|
||||
|
||||
use super::{copy, CellValue, EccPoint, Var};
|
||||
use super::EccPoint;
|
||||
use ff::{BatchInvert, Field};
|
||||
use halo2::{
|
||||
circuit::Region,
|
||||
|
@ -223,12 +223,12 @@ impl Config {
|
|||
self.q_add.enable(region, offset)?;
|
||||
|
||||
// Copy point `p` into `x_p`, `y_p` columns
|
||||
copy(region, || "x_p", self.x_p, offset, &p.x)?;
|
||||
copy(region, || "y_p", self.y_p, offset, &p.y)?;
|
||||
p.x.copy_advice(|| "x_p", region, self.x_p, offset)?;
|
||||
p.y.copy_advice(|| "y_p", region, self.y_p, offset)?;
|
||||
|
||||
// Copy point `q` into `x_qr`, `y_qr` columns
|
||||
copy(region, || "x_q", self.x_qr, offset, &q.x)?;
|
||||
copy(region, || "y_q", self.y_qr, offset, &q.y)?;
|
||||
q.x.copy_advice(|| "x_q", region, self.x_qr, offset)?;
|
||||
q.y.copy_advice(|| "y_q", region, self.y_qr, offset)?;
|
||||
|
||||
let (x_p, y_p) = (p.x.value(), p.y.value());
|
||||
let (x_q, y_q) = (q.x.value(), q.y.value());
|
||||
|
@ -248,7 +248,7 @@ impl Config {
|
|||
let gamma = x_q;
|
||||
let delta = y_q + y_p;
|
||||
|
||||
let mut inverses = [alpha, beta, gamma, delta];
|
||||
let mut inverses = [alpha, *beta, *gamma, delta];
|
||||
inverses.batch_invert();
|
||||
inverses
|
||||
});
|
||||
|
@ -300,7 +300,7 @@ impl Config {
|
|||
// know that x_q != x_p in this branch.
|
||||
(y_q - y_p) * alpha
|
||||
} else {
|
||||
if y_p != pallas::Base::zero() {
|
||||
if !y_p.is_zero_vartime() {
|
||||
// 3(x_p)^2
|
||||
let three_x_p_sq = pallas::Base::from_u64(3) * x_p.square();
|
||||
// 1 / 2(y_p)
|
||||
|
@ -327,13 +327,13 @@ impl Config {
|
|||
.zip(lambda)
|
||||
.map(|((((x_p, y_p), x_q), y_q), lambda)| {
|
||||
{
|
||||
if x_p == pallas::Base::zero() {
|
||||
if x_p.is_zero_vartime() {
|
||||
// 0 + Q = Q
|
||||
(x_q, y_q)
|
||||
} else if x_q == pallas::Base::zero() {
|
||||
(*x_q, *y_q)
|
||||
} else if x_q.is_zero_vartime() {
|
||||
// P + 0 = P
|
||||
(x_p, y_p)
|
||||
} else if (x_q == x_p) && (y_q == -y_p) {
|
||||
(*x_p, *y_p)
|
||||
} else if (x_q == x_p) && (*y_q == -y_p) {
|
||||
// P + (-P) maps to (0,0)
|
||||
(pallas::Base::zero(), pallas::Base::zero())
|
||||
} else {
|
||||
|
@ -365,8 +365,8 @@ impl Config {
|
|||
)?;
|
||||
|
||||
let result = EccPoint {
|
||||
x: CellValue::<pallas::Base>::new(x_r_cell, x_r),
|
||||
y: CellValue::<pallas::Base>::new(y_r_cell, y_r),
|
||||
x: x_r_cell,
|
||||
y: y_r_cell,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -414,7 +414,9 @@ pub mod tests {
|
|||
// Check complete addition P + (-P)
|
||||
let zero = {
|
||||
let result = p.add(layouter.namespace(|| "P + (-P)"), p_neg)?;
|
||||
assert!(result.inner().is_identity().unwrap());
|
||||
if let Some(is_identity) = result.inner().is_identity() {
|
||||
assert!(is_identity);
|
||||
}
|
||||
result
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use std::{array, collections::HashSet};
|
||||
|
||||
use super::{copy, CellValue, NonIdentityEccPoint, Var};
|
||||
use super::NonIdentityEccPoint;
|
||||
use ff::Field;
|
||||
use group::Curve;
|
||||
use halo2::{
|
||||
circuit::Region,
|
||||
|
@ -96,9 +97,9 @@ impl Config {
|
|||
.zip(y_q)
|
||||
.map(|(((x_p, y_p), x_q), y_q)| {
|
||||
// P is point at infinity
|
||||
if (x_p == pallas::Base::zero() && y_p == pallas::Base::zero())
|
||||
if (x_p.is_zero_vartime() && y_p.is_zero_vartime())
|
||||
// Q is point at infinity
|
||||
|| (x_q == pallas::Base::zero() && y_q == pallas::Base::zero())
|
||||
|| (x_q.is_zero_vartime() && y_q.is_zero_vartime())
|
||||
// x_p = x_q
|
||||
|| (x_p == x_q)
|
||||
{
|
||||
|
@ -110,12 +111,12 @@ impl Config {
|
|||
.transpose()?;
|
||||
|
||||
// Copy point `p` into `x_p`, `y_p` columns
|
||||
copy(region, || "x_p", self.x_p, offset, &p.x)?;
|
||||
copy(region, || "y_p", self.y_p, offset, &p.y)?;
|
||||
p.x.copy_advice(|| "x_p", region, self.x_p, offset)?;
|
||||
p.y.copy_advice(|| "y_p", region, self.y_p, offset)?;
|
||||
|
||||
// Copy point `q` into `x_qr`, `y_qr` columns
|
||||
copy(region, || "x_q", self.x_qr, offset, &q.x)?;
|
||||
copy(region, || "y_q", self.y_qr, offset, &q.y)?;
|
||||
q.x.copy_advice(|| "x_q", region, self.x_qr, offset)?;
|
||||
q.y.copy_advice(|| "y_q", region, self.y_qr, offset)?;
|
||||
|
||||
// Compute the sum `P + Q = R`
|
||||
let r = {
|
||||
|
@ -148,8 +149,8 @@ impl Config {
|
|||
)?;
|
||||
|
||||
let result = NonIdentityEccPoint {
|
||||
x: CellValue::<pallas::Base>::new(x_r_var, x_r),
|
||||
y: CellValue::<pallas::Base>::new(y_r_var, y_r),
|
||||
x: x_r_var,
|
||||
y: y_r_var,
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
|
@ -175,6 +176,7 @@ pub mod tests {
|
|||
q_val: pallas::Affine,
|
||||
q: &NonIdentityPoint<pallas::Affine, EccChip>,
|
||||
p_neg: &NonIdentityPoint<pallas::Affine, EccChip>,
|
||||
test_errors: bool,
|
||||
) -> Result<(), Error> {
|
||||
// P + Q
|
||||
{
|
||||
|
@ -187,13 +189,15 @@ pub mod tests {
|
|||
result.constrain_equal(layouter.namespace(|| "constrain P + Q"), &witnessed_result)?;
|
||||
}
|
||||
|
||||
// P + P should return an error
|
||||
p.add_incomplete(layouter.namespace(|| "P + P"), p)
|
||||
.expect_err("P + P should return an error");
|
||||
if test_errors {
|
||||
// P + P should return an error
|
||||
p.add_incomplete(layouter.namespace(|| "P + P"), p)
|
||||
.expect_err("P + P should return an error");
|
||||
|
||||
// P + (-P) should return an error
|
||||
p.add_incomplete(layouter.namespace(|| "P + (-P)"), p_neg)
|
||||
.expect_err("P + (-P) should return an error");
|
||||
// P + (-P) should return an error
|
||||
p.add_incomplete(layouter.namespace(|| "P + (-P)"), p_neg)
|
||||
.expect_err("P + (-P) should return an error");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use super::{add, CellValue, EccPoint, NonIdentityEccPoint, Var};
|
||||
use super::{add, EccPoint, NonIdentityEccPoint};
|
||||
use crate::{
|
||||
circuit::gadget::utilities::{
|
||||
bool_check, copy, lookup_range_check::LookupRangeCheckConfig, ternary,
|
||||
},
|
||||
circuit::gadget::utilities::{bool_check, lookup_range_check::LookupRangeCheckConfig, ternary},
|
||||
constants::T_Q,
|
||||
primitives::sinsemilla,
|
||||
};
|
||||
|
@ -15,7 +13,7 @@ use bigint::U256;
|
|||
use ff::PrimeField;
|
||||
use halo2::{
|
||||
arithmetic::FieldExt,
|
||||
circuit::{Layouter, Region},
|
||||
circuit::{AssignedCell, Layouter, Region},
|
||||
plonk::{Advice, Column, ConstraintSystem, Error, Selector},
|
||||
poly::Rotation,
|
||||
};
|
||||
|
@ -166,16 +164,16 @@ impl Config {
|
|||
pub(super) fn assign(
|
||||
&self,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
alpha: CellValue<pallas::Base>,
|
||||
alpha: AssignedCell<pallas::Base, pallas::Base>,
|
||||
base: &NonIdentityEccPoint,
|
||||
) -> Result<(EccPoint, CellValue<pallas::Base>), Error> {
|
||||
) -> Result<(EccPoint, AssignedCell<pallas::Base, pallas::Base>), Error> {
|
||||
let (result, zs): (EccPoint, Vec<Z<pallas::Base>>) = layouter.assign_region(
|
||||
|| "variable-base scalar mul",
|
||||
|mut region| {
|
||||
let offset = 0;
|
||||
|
||||
// Case `base` into an `EccPoint` for later use.
|
||||
let base_point: EccPoint = (*base).into();
|
||||
let base_point: EccPoint = base.clone().into();
|
||||
|
||||
// Decompose `k = alpha + t_q` bitwise (big-endian bit order).
|
||||
let bits = decompose_for_scalar_mul(alpha.value());
|
||||
|
@ -194,16 +192,12 @@ impl Config {
|
|||
let offset = offset + 1;
|
||||
|
||||
// Initialize the running sum for scalar decomposition to zero
|
||||
let z_init = {
|
||||
let z_init_cell = region.assign_advice_from_constant(
|
||||
|| "z_init = 0",
|
||||
self.hi_config.z,
|
||||
offset,
|
||||
pallas::Base::zero(),
|
||||
)?;
|
||||
|
||||
Z(CellValue::new(z_init_cell, Some(pallas::Base::zero())))
|
||||
};
|
||||
let z_init = Z(region.assign_advice_from_constant(
|
||||
|| "z_init = 0",
|
||||
self.hi_config.z,
|
||||
offset,
|
||||
pallas::Base::zero(),
|
||||
)?);
|
||||
|
||||
// Double-and-add (incomplete addition) for the `hi` half of the scalar decomposition
|
||||
let (x_a, y_a, zs_incomplete_hi) = self.hi_config.double_and_add(
|
||||
|
@ -211,7 +205,7 @@ impl Config {
|
|||
offset,
|
||||
base,
|
||||
bits_incomplete_hi,
|
||||
(X(acc.x), Y(acc.y), z_init),
|
||||
(X(acc.x), Y(acc.y), z_init.clone()),
|
||||
)?;
|
||||
|
||||
// Double-and-add (incomplete addition) for the `lo` half of the scalar decomposition
|
||||
|
@ -221,7 +215,7 @@ impl Config {
|
|||
offset,
|
||||
base,
|
||||
bits_incomplete_lo,
|
||||
(x_a, y_a, *z),
|
||||
(x_a, y_a, z.clone()),
|
||||
)?;
|
||||
|
||||
// Move from incomplete addition to complete addition.
|
||||
|
@ -245,7 +239,7 @@ impl Config {
|
|||
&base_point,
|
||||
x_a,
|
||||
y_a,
|
||||
*z,
|
||||
z.clone(),
|
||||
)?
|
||||
};
|
||||
|
||||
|
@ -253,8 +247,8 @@ impl Config {
|
|||
let offset = offset + COMPLETE_RANGE.len() * 2;
|
||||
|
||||
// Process the least significant bit
|
||||
let z_1 = zs_complete.last().unwrap();
|
||||
let (result, z_0) = self.process_lsb(&mut region, offset, base, acc, *z_1, lsb)?;
|
||||
let z_1 = zs_complete.last().unwrap().clone();
|
||||
let (result, z_0) = self.process_lsb(&mut region, offset, base, acc, z_1, lsb)?;
|
||||
|
||||
#[cfg(test)]
|
||||
// Check that the correct multiple is obtained.
|
||||
|
@ -292,8 +286,11 @@ impl Config {
|
|||
},
|
||||
)?;
|
||||
|
||||
self.overflow_config
|
||||
.overflow_check(layouter.namespace(|| "overflow check"), alpha, &zs)?;
|
||||
self.overflow_config.overflow_check(
|
||||
layouter.namespace(|| "overflow check"),
|
||||
alpha.clone(),
|
||||
&zs,
|
||||
)?;
|
||||
|
||||
Ok((result, alpha))
|
||||
}
|
||||
|
@ -339,29 +336,19 @@ impl Config {
|
|||
|| z_0_val.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
|
||||
Z(CellValue::new(z_0_cell, z_0_val))
|
||||
Z(z_0_cell)
|
||||
};
|
||||
|
||||
// Copy in `base_x`, `base_y` to use in the LSB gate
|
||||
copy(
|
||||
region,
|
||||
|| "copy base_x",
|
||||
self.add_config.x_p,
|
||||
offset + 1,
|
||||
&base.x(),
|
||||
)?;
|
||||
copy(
|
||||
region,
|
||||
|| "copy base_y",
|
||||
self.add_config.y_p,
|
||||
offset + 1,
|
||||
&base.y(),
|
||||
)?;
|
||||
base.x()
|
||||
.copy_advice(|| "copy base_x", region, self.add_config.x_p, offset + 1)?;
|
||||
base.y()
|
||||
.copy_advice(|| "copy base_y", region, self.add_config.y_p, offset + 1)?;
|
||||
|
||||
// If `lsb` is 0, return `Acc + (-P)`. If `lsb` is 1, simply return `Acc + 0`.
|
||||
let x = if let Some(lsb) = lsb {
|
||||
if !lsb {
|
||||
base.x.value()
|
||||
base.x.value().cloned()
|
||||
} else {
|
||||
Some(pallas::Base::zero())
|
||||
}
|
||||
|
@ -394,8 +381,8 @@ impl Config {
|
|||
)?;
|
||||
|
||||
let p = EccPoint {
|
||||
x: CellValue::<pallas::Base>::new(x_cell, x),
|
||||
y: CellValue::<pallas::Base>::new(y_cell, y),
|
||||
x: x_cell,
|
||||
y: y_cell,
|
||||
};
|
||||
|
||||
// Return the result of the final complete addition as `[scalar]B`
|
||||
|
@ -407,38 +394,38 @@ impl Config {
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
// `x`-coordinate of the accumulator.
|
||||
struct X<F: FieldExt>(CellValue<F>);
|
||||
struct X<F: FieldExt>(AssignedCell<F, F>);
|
||||
impl<F: FieldExt> Deref for X<F> {
|
||||
type Target = CellValue<F>;
|
||||
type Target = AssignedCell<F, F>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
// `y`-coordinate of the accumulator.
|
||||
struct Y<F: FieldExt>(CellValue<F>);
|
||||
struct Y<F: FieldExt>(AssignedCell<F, F>);
|
||||
impl<F: FieldExt> Deref for Y<F> {
|
||||
type Target = CellValue<F>;
|
||||
type Target = AssignedCell<F, F>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
// Cumulative sum `z` used to decompose the scalar.
|
||||
struct Z<F: FieldExt>(CellValue<F>);
|
||||
struct Z<F: FieldExt>(AssignedCell<F, F>);
|
||||
impl<F: FieldExt> Deref for Z<F> {
|
||||
type Target = CellValue<F>;
|
||||
type Target = AssignedCell<F, F>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
fn decompose_for_scalar_mul(scalar: Option<pallas::Base>) -> Vec<Option<bool>> {
|
||||
fn decompose_for_scalar_mul(scalar: Option<&pallas::Base>) -> Vec<Option<bool>> {
|
||||
let bitstring = scalar.map(|scalar| {
|
||||
// We use `k = scalar + t_q` in the double-and-add algorithm, where
|
||||
// the scalar field `F_q = 2^254 + t_q`.
|
||||
|
@ -548,7 +535,9 @@ pub mod tests {
|
|||
chip.load_private(layouter.namespace(|| "zero"), column, Some(scalar_val))?;
|
||||
p.mul(layouter.namespace(|| "[0]B"), &scalar)?
|
||||
};
|
||||
assert!(result.inner().is_identity().unwrap());
|
||||
if let Some(is_identity) = result.inner().is_identity() {
|
||||
assert!(is_identity);
|
||||
}
|
||||
}
|
||||
|
||||
// [-1]B (the largest possible base field element)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::super::{add, copy, CellValue, EccPoint, Var};
|
||||
use super::super::{add, EccPoint};
|
||||
use super::{COMPLETE_RANGE, X, Y, Z};
|
||||
use crate::circuit::gadget::utilities::{bool_check, ternary};
|
||||
|
||||
|
@ -106,16 +106,15 @@ impl Config {
|
|||
}
|
||||
|
||||
// Use x_a, y_a output from incomplete addition
|
||||
let mut acc = EccPoint { x: *x_a, y: *y_a };
|
||||
let mut acc = EccPoint { x: x_a.0, y: y_a.0 };
|
||||
|
||||
// Copy running sum `z` from incomplete addition
|
||||
let mut z = {
|
||||
let z = copy(
|
||||
region,
|
||||
let z = z.copy_advice(
|
||||
|| "Copy `z` running sum from incomplete addition",
|
||||
region,
|
||||
self.z_complete,
|
||||
offset,
|
||||
&z,
|
||||
)?;
|
||||
Z(z)
|
||||
};
|
||||
|
@ -146,37 +145,40 @@ impl Config {
|
|||
row + offset + 2,
|
||||
|| z_val.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
Z(CellValue::new(z_cell, z_val))
|
||||
Z(z_cell)
|
||||
};
|
||||
zs.push(z);
|
||||
zs.push(z.clone());
|
||||
|
||||
// Assign `y_p` for complete addition.
|
||||
let y_p = {
|
||||
let base_y = copy(
|
||||
region,
|
||||
let base_y = base.y.copy_advice(
|
||||
|| "Copy `base.y`",
|
||||
region,
|
||||
self.z_complete,
|
||||
row + offset + 1,
|
||||
&base.y,
|
||||
)?;
|
||||
|
||||
// If the bit is set, use `y`; if the bit is not set, use `-y`
|
||||
let y_p = base_y
|
||||
.value()
|
||||
.zip(k.as_ref())
|
||||
.map(|(base_y, k)| if !k { -base_y } else { base_y });
|
||||
let y_p =
|
||||
base_y
|
||||
.value()
|
||||
.cloned()
|
||||
.zip(k.as_ref())
|
||||
.map(|(base_y, k)| if !k { -base_y } else { base_y });
|
||||
|
||||
let y_p_cell = region.assign_advice(
|
||||
region.assign_advice(
|
||||
|| "y_p",
|
||||
self.add_config.y_p,
|
||||
row + offset,
|
||||
|| y_p.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
CellValue::<pallas::Base>::new(y_p_cell, y_p)
|
||||
)?
|
||||
};
|
||||
|
||||
// U = P if the bit is set; U = -P is the bit is not set.
|
||||
let U = EccPoint { x: base.x, y: y_p };
|
||||
let U = EccPoint {
|
||||
x: base.x.clone(),
|
||||
y: y_p,
|
||||
};
|
||||
|
||||
// Acc + U
|
||||
let tmp_acc = self
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::super::{copy, CellValue, NonIdentityEccPoint, Var};
|
||||
use super::super::NonIdentityEccPoint;
|
||||
use super::{X, Y, Z};
|
||||
use crate::circuit::gadget::utilities::bool_check;
|
||||
use ff::Field;
|
||||
|
@ -190,14 +190,14 @@ impl<const NUM_BITS: usize> Config<NUM_BITS> {
|
|||
assert_eq!(bits.len(), NUM_BITS);
|
||||
|
||||
// Handle exceptional cases
|
||||
let (x_p, y_p) = (base.x.value(), base.y.value());
|
||||
let (x_a, y_a) = (acc.0.value(), acc.1.value());
|
||||
let (x_p, y_p) = (base.x.value().cloned(), base.y.value().cloned());
|
||||
let (x_a, y_a) = (acc.0.value().cloned(), acc.1.value().cloned());
|
||||
|
||||
if let (Some(x_a), Some(y_a), Some(x_p), Some(y_p)) = (x_a, y_a, x_p, y_p) {
|
||||
// A is point at infinity
|
||||
if (x_p == pallas::Base::zero() && y_p == pallas::Base::zero())
|
||||
if (x_p.is_zero_vartime() && y_p.is_zero_vartime())
|
||||
// Q is point at infinity
|
||||
|| (x_a == pallas::Base::zero() && y_a == pallas::Base::zero())
|
||||
|| (x_a.is_zero_vartime() && y_a.is_zero_vartime())
|
||||
// x_p = x_a
|
||||
|| (x_p == x_a)
|
||||
{
|
||||
|
@ -223,13 +223,17 @@ impl<const NUM_BITS: usize> Config<NUM_BITS> {
|
|||
// Initialise double-and-add
|
||||
let (mut x_a, mut y_a, mut z) = {
|
||||
// Initialise the running `z` sum for the scalar bits.
|
||||
let z = copy(region, || "starting z", self.z, offset, &acc.2)?;
|
||||
let z = acc.2.copy_advice(|| "starting z", region, self.z, offset)?;
|
||||
|
||||
// Initialise acc
|
||||
let x_a = copy(region, || "starting x_a", self.x_a, offset + 1, &acc.0)?;
|
||||
let y_a = copy(region, || "starting y_a", self.lambda1, offset, &acc.1)?;
|
||||
let x_a = acc
|
||||
.0
|
||||
.copy_advice(|| "starting x_a", region, self.x_a, offset + 1)?;
|
||||
let y_a = acc
|
||||
.1
|
||||
.copy_advice(|| "starting y_a", region, self.lambda1, offset)?;
|
||||
|
||||
(x_a, y_a.value(), z)
|
||||
(x_a, y_a.value().cloned(), z)
|
||||
};
|
||||
|
||||
// Increase offset by 1; we used row 0 for initializing `z`.
|
||||
|
@ -244,14 +248,13 @@ impl<const NUM_BITS: usize> Config<NUM_BITS> {
|
|||
let z_val = z.value().zip(k.as_ref()).map(|(z_val, k)| {
|
||||
pallas::Base::from_u64(2) * z_val + pallas::Base::from_u64(*k as u64)
|
||||
});
|
||||
let z_cell = region.assign_advice(
|
||||
z = region.assign_advice(
|
||||
|| "z",
|
||||
self.z,
|
||||
row + offset,
|
||||
|| z_val.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
z = CellValue::new(z_cell, z_val);
|
||||
zs.push(Z(z));
|
||||
zs.push(Z(z.clone()));
|
||||
|
||||
// Assign `x_p`, `y_p`
|
||||
region.assign_advice(
|
||||
|
@ -313,30 +316,26 @@ impl<const NUM_BITS: usize> Config<NUM_BITS> {
|
|||
.zip(x_r)
|
||||
.map(|((lambda2, x_a), x_r)| lambda2.square() - x_a - x_r);
|
||||
y_a = lambda2
|
||||
.zip(x_a.value())
|
||||
.zip(x_a.value().cloned())
|
||||
.zip(x_a_new)
|
||||
.zip(y_a)
|
||||
.map(|(((lambda2, x_a), x_a_new), y_a)| lambda2 * (x_a - x_a_new) - y_a);
|
||||
let x_a_val = x_a_new;
|
||||
let x_a_cell = region.assign_advice(
|
||||
x_a = region.assign_advice(
|
||||
|| "x_a",
|
||||
self.x_a,
|
||||
row + offset + 1,
|
||||
|| x_a_val.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
x_a = CellValue::new(x_a_cell, x_a_val);
|
||||
}
|
||||
|
||||
// Witness final y_a
|
||||
let y_a = {
|
||||
let cell = region.assign_advice(
|
||||
|| "y_a",
|
||||
self.lambda1,
|
||||
offset + NUM_BITS,
|
||||
|| y_a.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
CellValue::new(cell, y_a)
|
||||
};
|
||||
let y_a = region.assign_advice(
|
||||
|| "y_a",
|
||||
self.lambda1,
|
||||
offset + NUM_BITS,
|
||||
|| y_a.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
|
||||
Ok((X(x_a), Y(y_a), zs))
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use super::super::{copy, CellValue, Var};
|
||||
use super::Z;
|
||||
use crate::{
|
||||
circuit::gadget::utilities::lookup_range_check::LookupRangeCheckConfig, constants::T_Q,
|
||||
primitives::sinsemilla,
|
||||
};
|
||||
use halo2::circuit::AssignedCell;
|
||||
use halo2::{
|
||||
circuit::Layouter,
|
||||
plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector},
|
||||
|
@ -99,7 +99,7 @@ impl Config {
|
|||
pub(super) fn overflow_check(
|
||||
&self,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
alpha: CellValue<pallas::Base>,
|
||||
alpha: AssignedCell<pallas::Base, pallas::Base>,
|
||||
zs: &[Z<pallas::Base>], // [z_0, z_1, ..., z_{254}, z_{255}]
|
||||
) -> Result<(), Error> {
|
||||
// s = alpha + k_254 ⋅ 2^130 is witnessed here, and then copied into
|
||||
|
@ -107,7 +107,7 @@ impl Config {
|
|||
// In the overflow check gate, we check that s is properly derived
|
||||
// from alpha and k_254.
|
||||
let s = {
|
||||
let k_254 = *zs[254];
|
||||
let k_254 = zs[254].clone();
|
||||
let s_val = alpha
|
||||
.value()
|
||||
.zip(k_254.value())
|
||||
|
@ -116,13 +116,12 @@ impl Config {
|
|||
layouter.assign_region(
|
||||
|| "s = alpha + k_254 ⋅ 2^130",
|
||||
|mut region| {
|
||||
let s_cell = region.assign_advice(
|
||||
region.assign_advice(
|
||||
|| "s = alpha + k_254 ⋅ 2^130",
|
||||
self.advices[0],
|
||||
0,
|
||||
|| s_val.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
Ok(CellValue::new(s_cell, s_val))
|
||||
)
|
||||
},
|
||||
)?
|
||||
};
|
||||
|
@ -130,7 +129,7 @@ impl Config {
|
|||
// Subtract the first 130 low bits of s = alpha + k_254 ⋅ 2^130
|
||||
// using thirteen 10-bit lookups, s_{0..=129}
|
||||
let s_minus_lo_130 =
|
||||
self.s_minus_lo_130(layouter.namespace(|| "decompose s_{0..=129}"), s)?;
|
||||
self.s_minus_lo_130(layouter.namespace(|| "decompose s_{0..=129}"), s.clone())?;
|
||||
|
||||
layouter.assign_region(
|
||||
|| "overflow check",
|
||||
|
@ -141,21 +140,15 @@ impl Config {
|
|||
self.q_mul_overflow.enable(&mut region, offset + 1)?;
|
||||
|
||||
// Copy `z_0`
|
||||
copy(&mut region, || "copy z_0", self.advices[0], offset, &*zs[0])?;
|
||||
zs[0].copy_advice(|| "copy z_0", &mut region, self.advices[0], offset)?;
|
||||
|
||||
// Copy `z_130`
|
||||
copy(
|
||||
&mut region,
|
||||
|| "copy z_130",
|
||||
self.advices[0],
|
||||
offset + 1,
|
||||
&*zs[130],
|
||||
)?;
|
||||
zs[130].copy_advice(|| "copy z_130", &mut region, self.advices[0], offset + 1)?;
|
||||
|
||||
// Witness η = inv0(z_130), where inv0(x) = 0 if x = 0, 1/x otherwise
|
||||
{
|
||||
let eta = zs[130].value().map(|z_130| {
|
||||
if z_130 == pallas::Base::zero() {
|
||||
if z_130.is_zero_vartime() {
|
||||
pallas::Base::zero()
|
||||
} else {
|
||||
z_130.invert().unwrap()
|
||||
|
@ -170,34 +163,26 @@ impl Config {
|
|||
}
|
||||
|
||||
// Copy `k_254` = z_254
|
||||
copy(
|
||||
&mut region,
|
||||
|| "copy k_254",
|
||||
self.advices[1],
|
||||
offset,
|
||||
&*zs[254],
|
||||
)?;
|
||||
zs[254].copy_advice(|| "copy k_254", &mut region, self.advices[1], offset)?;
|
||||
|
||||
// Copy original alpha
|
||||
copy(
|
||||
&mut region,
|
||||
alpha.copy_advice(
|
||||
|| "copy original alpha",
|
||||
&mut region,
|
||||
self.advices[1],
|
||||
offset + 1,
|
||||
&alpha,
|
||||
)?;
|
||||
|
||||
// Copy weighted sum of the decomposition of s = alpha + k_254 ⋅ 2^130.
|
||||
copy(
|
||||
&mut region,
|
||||
s_minus_lo_130.copy_advice(
|
||||
|| "copy s_minus_lo_130",
|
||||
&mut region,
|
||||
self.advices[1],
|
||||
offset + 2,
|
||||
&s_minus_lo_130,
|
||||
)?;
|
||||
|
||||
// Copy witnessed s to check that it was properly derived from alpha and k_254.
|
||||
copy(&mut region, || "copy s", self.advices[2], offset + 1, &s)?;
|
||||
s.copy_advice(|| "copy s", &mut region, self.advices[2], offset + 1)?;
|
||||
|
||||
Ok(())
|
||||
},
|
||||
|
@ -209,8 +194,8 @@ impl Config {
|
|||
fn s_minus_lo_130(
|
||||
&self,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
s: CellValue<pallas::Base>,
|
||||
) -> Result<CellValue<pallas::Base>, Error> {
|
||||
s: AssignedCell<pallas::Base, pallas::Base>,
|
||||
) -> Result<AssignedCell<pallas::Base, pallas::Base>, Error> {
|
||||
// Number of k-bit words we can use in the lookup decomposition.
|
||||
let num_words = 130 / sinsemilla::K;
|
||||
assert!(num_words * sinsemilla::K == 130);
|
||||
|
@ -223,6 +208,6 @@ impl Config {
|
|||
false,
|
||||
)?;
|
||||
// (s - (2^0 s_0 + 2^1 s_1 + ... + 2^129 s_129)) / 2^130
|
||||
Ok(zs[zs.len() - 1])
|
||||
Ok(zs[zs.len() - 1].clone())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::{
|
||||
add, add_incomplete, CellValue, EccBaseFieldElemFixed, EccScalarFixed, EccScalarFixedShort,
|
||||
NonIdentityEccPoint, Var,
|
||||
add, add_incomplete, EccBaseFieldElemFixed, EccScalarFixed, EccScalarFixedShort,
|
||||
NonIdentityEccPoint,
|
||||
};
|
||||
use crate::circuit::gadget::utilities::decompose_running_sum::RunningSumConfig;
|
||||
use crate::constants::{
|
||||
|
@ -10,7 +10,7 @@ use crate::constants::{
|
|||
|
||||
use group::Curve;
|
||||
use halo2::{
|
||||
circuit::Region,
|
||||
circuit::{AssignedCell, Region},
|
||||
plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, Selector, VirtualCells},
|
||||
poly::Rotation,
|
||||
};
|
||||
|
@ -353,26 +353,24 @@ impl Config {
|
|||
assert!(x != pallas::Base::zero());
|
||||
x
|
||||
});
|
||||
let x_cell = region.assign_advice(
|
||||
let x = region.assign_advice(
|
||||
|| format!("mul_b_x, window {}", w),
|
||||
self.x_p,
|
||||
offset + w,
|
||||
|| x.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
let x = CellValue::new(x_cell, x);
|
||||
|
||||
let y = mul_b.map(|mul_b| {
|
||||
let y = *mul_b.y();
|
||||
assert!(y != pallas::Base::zero());
|
||||
y
|
||||
});
|
||||
let y_cell = region.assign_advice(
|
||||
let y = region.assign_advice(
|
||||
|| format!("mul_b_y, window {}", w),
|
||||
self.y_p,
|
||||
offset + w,
|
||||
|| y.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
let y = CellValue::new(y_cell, y);
|
||||
|
||||
NonIdentityEccPoint { x, y }
|
||||
};
|
||||
|
@ -471,27 +469,24 @@ impl Config {
|
|||
assert!(x != pallas::Base::zero());
|
||||
x
|
||||
});
|
||||
let x_cell = region.assign_advice(
|
||||
let x = region.assign_advice(
|
||||
|| format!("mul_b_x, window {}", NUM_WINDOWS - 1),
|
||||
self.x_p,
|
||||
offset + NUM_WINDOWS - 1,
|
||||
|| x.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
|
||||
let x = CellValue::new(x_cell, x);
|
||||
|
||||
let y = mul_b.map(|mul_b| {
|
||||
let y = *mul_b.y();
|
||||
assert!(y != pallas::Base::zero());
|
||||
y
|
||||
});
|
||||
let y_cell = region.assign_advice(
|
||||
let y = region.assign_advice(
|
||||
|| format!("mul_b_y, window {}", NUM_WINDOWS - 1),
|
||||
self.y_p,
|
||||
offset + NUM_WINDOWS - 1,
|
||||
|| y.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
let y = CellValue::new(y_cell, y);
|
||||
|
||||
NonIdentityEccPoint { x, y }
|
||||
};
|
||||
|
@ -528,7 +523,7 @@ impl ScalarFixed {
|
|||
// The scalar decomposition was done in the base field. For computation
|
||||
// outside the circuit, we now convert them back into the scalar field.
|
||||
fn windows_field(&self) -> Vec<Option<pallas::Scalar>> {
|
||||
let running_sum_to_windows = |zs: Vec<CellValue<pallas::Base>>| {
|
||||
let running_sum_to_windows = |zs: Vec<AssignedCell<pallas::Base, pallas::Base>>| {
|
||||
(0..(zs.len() - 1))
|
||||
.map(|idx| {
|
||||
let z_cur = zs[idx].value();
|
||||
|
|
|
@ -3,12 +3,12 @@ use super::H_BASE;
|
|||
|
||||
use crate::{
|
||||
circuit::gadget::utilities::{
|
||||
bitrange_subset, copy, lookup_range_check::LookupRangeCheckConfig, range_check, CellValue,
|
||||
Var,
|
||||
bitrange_subset, lookup_range_check::LookupRangeCheckConfig, range_check,
|
||||
},
|
||||
constants::{self, T_P},
|
||||
primitives::sinsemilla,
|
||||
};
|
||||
use halo2::circuit::AssignedCell;
|
||||
use halo2::{
|
||||
circuit::Layouter,
|
||||
plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector},
|
||||
|
@ -160,7 +160,7 @@ impl Config {
|
|||
pub fn assign(
|
||||
&self,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
scalar: CellValue<pallas::Base>,
|
||||
scalar: AssignedCell<pallas::Base, pallas::Base>,
|
||||
base: NullifierK,
|
||||
) -> Result<EccPoint, Error> {
|
||||
let (scalar, acc, mul_b) = layouter.assign_region(
|
||||
|
@ -173,13 +173,13 @@ impl Config {
|
|||
let running_sum = self.super_config.running_sum_config.copy_decompose(
|
||||
&mut region,
|
||||
offset,
|
||||
scalar,
|
||||
scalar.clone(),
|
||||
true,
|
||||
constants::L_ORCHARD_BASE,
|
||||
constants::NUM_WINDOWS,
|
||||
)?;
|
||||
EccBaseFieldElemFixed {
|
||||
base_field_elem: running_sum[0],
|
||||
base_field_elem: running_sum[0].clone(),
|
||||
running_sum: (*running_sum).as_slice().try_into().unwrap(),
|
||||
}
|
||||
};
|
||||
|
@ -203,8 +203,8 @@ impl Config {
|
|||
|| "Base-field elem fixed-base mul (complete addition)",
|
||||
|mut region| {
|
||||
self.super_config.add_config.assign_region(
|
||||
&mul_b.into(),
|
||||
&acc.into(),
|
||||
&mul_b.clone().into(),
|
||||
&acc.clone().into(),
|
||||
0,
|
||||
&mut region,
|
||||
)
|
||||
|
@ -249,9 +249,9 @@ impl Config {
|
|||
// => z_13_alpha_0_prime = 0
|
||||
//
|
||||
let (alpha, running_sum) = (scalar.base_field_elem, &scalar.running_sum);
|
||||
let z_43_alpha = running_sum[43];
|
||||
let z_44_alpha = running_sum[44];
|
||||
let z_84_alpha = running_sum[84];
|
||||
let z_43_alpha = running_sum[43].clone();
|
||||
let z_44_alpha = running_sum[44].clone();
|
||||
let z_84_alpha = running_sum[84].clone();
|
||||
|
||||
// α_0 = α - z_84_alpha * 2^252
|
||||
let alpha_0 = alpha
|
||||
|
@ -275,9 +275,9 @@ impl Config {
|
|||
13,
|
||||
false,
|
||||
)?;
|
||||
let alpha_0_prime = zs[0];
|
||||
let alpha_0_prime = zs[0].clone();
|
||||
|
||||
(alpha_0_prime, zs[13])
|
||||
(alpha_0_prime, zs[13].clone())
|
||||
};
|
||||
|
||||
layouter.assign_region(
|
||||
|
@ -291,21 +291,14 @@ impl Config {
|
|||
let offset = 0;
|
||||
|
||||
// Copy α
|
||||
copy(
|
||||
&mut region,
|
||||
|| "Copy α",
|
||||
self.canon_advices[0],
|
||||
offset,
|
||||
&alpha,
|
||||
)?;
|
||||
alpha.copy_advice(|| "Copy α", &mut region, self.canon_advices[0], offset)?;
|
||||
|
||||
// z_84_alpha = the top three bits of alpha.
|
||||
copy(
|
||||
&mut region,
|
||||
z_84_alpha.copy_advice(
|
||||
|| "Copy z_84_alpha",
|
||||
&mut region,
|
||||
self.canon_advices[2],
|
||||
offset,
|
||||
&z_84_alpha,
|
||||
)?;
|
||||
}
|
||||
|
||||
|
@ -314,12 +307,11 @@ impl Config {
|
|||
let offset = 1;
|
||||
// Copy alpha_0_prime = alpha_0 + 2^130 - t_p.
|
||||
// We constrain this in the custom gate to be derived correctly.
|
||||
copy(
|
||||
&mut region,
|
||||
alpha_0_prime.copy_advice(
|
||||
|| "Copy α_0 + 2^130 - t_p",
|
||||
&mut region,
|
||||
self.canon_advices[0],
|
||||
offset,
|
||||
&alpha_0_prime,
|
||||
)?;
|
||||
|
||||
// Decompose α into three pieces,
|
||||
|
@ -348,30 +340,27 @@ impl Config {
|
|||
{
|
||||
let offset = 2;
|
||||
// Copy z_13_alpha_0_prime
|
||||
copy(
|
||||
&mut region,
|
||||
z_13_alpha_0_prime.copy_advice(
|
||||
|| "Copy z_13_alpha_0_prime",
|
||||
&mut region,
|
||||
self.canon_advices[0],
|
||||
offset,
|
||||
&z_13_alpha_0_prime,
|
||||
)?;
|
||||
|
||||
// Copy z_44_alpha
|
||||
copy(
|
||||
&mut region,
|
||||
z_44_alpha.copy_advice(
|
||||
|| "Copy z_44_alpha",
|
||||
&mut region,
|
||||
self.canon_advices[1],
|
||||
offset,
|
||||
&z_44_alpha,
|
||||
)?;
|
||||
|
||||
// Copy z_43_alpha
|
||||
copy(
|
||||
&mut region,
|
||||
z_43_alpha.copy_advice(
|
||||
|| "Copy z_43_alpha",
|
||||
&mut region,
|
||||
self.canon_advices[2],
|
||||
offset,
|
||||
&z_43_alpha,
|
||||
)?;
|
||||
}
|
||||
|
||||
|
@ -498,7 +487,9 @@ pub mod tests {
|
|||
chip.load_private(layouter.namespace(|| "zero"), column, Some(scalar_fixed))?;
|
||||
base.mul(layouter.namespace(|| "mul by zero"), scalar_fixed)?
|
||||
};
|
||||
assert!(result.inner().is_identity().unwrap());
|
||||
if let Some(is_identity) = result.inner().is_identity() {
|
||||
assert!(is_identity);
|
||||
}
|
||||
}
|
||||
|
||||
// [-1]B is the largest base field element
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
use super::super::{EccPoint, EccScalarFixed, OrchardFixedBasesFull};
|
||||
|
||||
use crate::{
|
||||
circuit::gadget::utilities::{range_check, CellValue, Var},
|
||||
circuit::gadget::utilities::range_check,
|
||||
constants::{self, util, L_ORCHARD_SCALAR, NUM_WINDOWS},
|
||||
};
|
||||
use arrayvec::ArrayVec;
|
||||
use halo2::{
|
||||
circuit::{Layouter, Region},
|
||||
circuit::{AssignedCell, Layouter, Region},
|
||||
plonk::{ConstraintSystem, Error, Selector},
|
||||
poly::Rotation,
|
||||
};
|
||||
|
@ -76,7 +76,7 @@ impl Config {
|
|||
scalar: Option<pallas::Scalar>,
|
||||
offset: usize,
|
||||
region: &mut Region<'_, pallas::Base>,
|
||||
) -> Result<ArrayVec<CellValue<pallas::Base>, NUM_WINDOWS>, Error> {
|
||||
) -> Result<ArrayVec<AssignedCell<pallas::Base, pallas::Base>, NUM_WINDOWS>, Error> {
|
||||
// Enable `q_mul_fixed_full` selector
|
||||
for idx in 0..NUM_WINDOWS {
|
||||
self.q_mul_fixed_full.enable(region, offset + idx)?;
|
||||
|
@ -85,14 +85,15 @@ impl Config {
|
|||
// Decompose scalar into `k-bit` windows
|
||||
let scalar_windows: Option<Vec<u8>> = scalar.map(|scalar| {
|
||||
util::decompose_word::<pallas::Scalar>(
|
||||
scalar,
|
||||
&scalar,
|
||||
SCALAR_NUM_BITS,
|
||||
constants::FIXED_BASE_WINDOW_SIZE,
|
||||
)
|
||||
});
|
||||
|
||||
// Store the scalar decomposition
|
||||
let mut windows: ArrayVec<CellValue<pallas::Base>, NUM_WINDOWS> = ArrayVec::new();
|
||||
let mut windows: ArrayVec<AssignedCell<pallas::Base, pallas::Base>, NUM_WINDOWS> =
|
||||
ArrayVec::new();
|
||||
|
||||
let scalar_windows: Vec<Option<pallas::Base>> = if let Some(windows) = scalar_windows {
|
||||
assert_eq!(windows.len(), NUM_WINDOWS);
|
||||
|
@ -111,7 +112,7 @@ impl Config {
|
|||
offset + idx,
|
||||
|| window.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
windows.push(CellValue::new(window_cell, window));
|
||||
windows.push(window_cell);
|
||||
}
|
||||
|
||||
Ok(windows)
|
||||
|
@ -149,8 +150,8 @@ impl Config {
|
|||
|| "Full-width fixed-base mul (last window, complete addition)",
|
||||
|mut region| {
|
||||
self.super_config.add_config.assign_region(
|
||||
&mul_b.into(),
|
||||
&acc.into(),
|
||||
&mul_b.clone().into(),
|
||||
&acc.clone().into(),
|
||||
0,
|
||||
&mut region,
|
||||
)
|
||||
|
@ -294,7 +295,9 @@ pub mod tests {
|
|||
{
|
||||
let scalar_fixed = pallas::Scalar::zero();
|
||||
let (result, _) = base.mul(layouter.namespace(|| "mul by zero"), Some(scalar_fixed))?;
|
||||
assert!(result.inner().is_identity().unwrap());
|
||||
if let Some(is_identity) = result.inner().is_identity() {
|
||||
assert!(is_identity);
|
||||
}
|
||||
}
|
||||
|
||||
// [-1]B is the largest scalar field element.
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::{array, convert::TryInto};
|
|||
|
||||
use super::super::{EccPoint, EccScalarFixedShort};
|
||||
use crate::{
|
||||
circuit::gadget::utilities::{bool_check, copy, CellValue, Var},
|
||||
circuit::gadget::{ecc::chip::MagnitudeSign, utilities::bool_check},
|
||||
constants::{ValueCommitV, L_VALUE, NUM_WINDOWS_SHORT},
|
||||
};
|
||||
|
||||
|
@ -74,7 +74,7 @@ impl Config {
|
|||
&self,
|
||||
region: &mut Region<'_, pallas::Base>,
|
||||
offset: usize,
|
||||
magnitude_sign: (CellValue<pallas::Base>, CellValue<pallas::Base>),
|
||||
magnitude_sign: MagnitudeSign,
|
||||
) -> Result<EccScalarFixedShort, Error> {
|
||||
let (magnitude, sign) = magnitude_sign;
|
||||
|
||||
|
@ -82,7 +82,7 @@ impl Config {
|
|||
let running_sum = self.super_config.running_sum_config.copy_decompose(
|
||||
region,
|
||||
offset,
|
||||
magnitude,
|
||||
magnitude.clone(),
|
||||
true,
|
||||
L_VALUE,
|
||||
NUM_WINDOWS_SHORT,
|
||||
|
@ -98,7 +98,7 @@ impl Config {
|
|||
pub fn assign(
|
||||
&self,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
magnitude_sign: (CellValue<pallas::Base>, CellValue<pallas::Base>),
|
||||
magnitude_sign: MagnitudeSign,
|
||||
base: &ValueCommitV,
|
||||
) -> Result<(EccPoint, EccScalarFixedShort), Error> {
|
||||
let (scalar, acc, mul_b) = layouter.assign_region(
|
||||
|
@ -107,7 +107,7 @@ impl Config {
|
|||
let offset = 0;
|
||||
|
||||
// Decompose the scalar
|
||||
let scalar = self.decompose(&mut region, offset, magnitude_sign)?;
|
||||
let scalar = self.decompose(&mut region, offset, magnitude_sign.clone())?;
|
||||
|
||||
let (acc, mul_b) = self.super_config.assign_region_inner::<NUM_WINDOWS_SHORT>(
|
||||
&mut region,
|
||||
|
@ -128,8 +128,8 @@ impl Config {
|
|||
let offset = 0;
|
||||
// Add to the cumulative sum to get `[magnitude]B`.
|
||||
let magnitude_mul = self.super_config.add_config.assign_region(
|
||||
&mul_b.into(),
|
||||
&acc.into(),
|
||||
&mul_b.clone().into(),
|
||||
&acc.clone().into(),
|
||||
offset,
|
||||
&mut region,
|
||||
)?;
|
||||
|
@ -138,32 +138,25 @@ impl Config {
|
|||
let offset = offset + 1;
|
||||
|
||||
// Copy sign to `window` column
|
||||
let sign = copy(
|
||||
&mut region,
|
||||
let sign = scalar.sign.copy_advice(
|
||||
|| "sign",
|
||||
&mut region,
|
||||
self.super_config.window,
|
||||
offset,
|
||||
&scalar.sign,
|
||||
)?;
|
||||
|
||||
// Copy last window to `u` column.
|
||||
// (Although the last window is not a `u` value; we are copying it into the `u`
|
||||
// column because there is an available cell there.)
|
||||
let z_21 = scalar.running_sum[21];
|
||||
copy(
|
||||
&mut region,
|
||||
|| "last_window",
|
||||
self.super_config.u,
|
||||
offset,
|
||||
&z_21,
|
||||
)?;
|
||||
let z_21 = scalar.running_sum[21].clone();
|
||||
z_21.copy_advice(|| "last_window", &mut region, self.super_config.u, offset)?;
|
||||
|
||||
// Conditionally negate `y`-coordinate
|
||||
let y_val = if let Some(sign) = sign.value() {
|
||||
if sign == -pallas::Base::one() {
|
||||
magnitude_mul.y.value().map(|y: pallas::Base| -y)
|
||||
if sign == &-pallas::Base::one() {
|
||||
magnitude_mul.y.value().cloned().map(|y: pallas::Base| -y)
|
||||
} else {
|
||||
magnitude_mul.y.value()
|
||||
magnitude_mul.y.value().cloned()
|
||||
}
|
||||
} else {
|
||||
None
|
||||
|
@ -182,7 +175,7 @@ impl Config {
|
|||
|
||||
Ok(EccPoint {
|
||||
x: magnitude_mul.x,
|
||||
y: CellValue::new(y_var, y_val),
|
||||
y: y_var,
|
||||
})
|
||||
},
|
||||
)?;
|
||||
|
@ -199,7 +192,7 @@ impl Config {
|
|||
|
||||
if let (Some(magnitude), Some(sign)) = (scalar.magnitude.value(), scalar.sign.value()) {
|
||||
let magnitude_is_valid =
|
||||
magnitude <= pallas::Base::from_u64(0xFFFF_FFFF_FFFF_FFFFu64);
|
||||
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();
|
||||
|
@ -211,7 +204,7 @@ impl Config {
|
|||
let magnitude =
|
||||
pallas::Scalar::from_bytes(&magnitude.to_bytes()).unwrap();
|
||||
|
||||
let sign = if sign == pallas::Base::one() {
|
||||
let sign = if sign == &pallas::Base::one() {
|
||||
pallas::Scalar::one()
|
||||
} else {
|
||||
-pallas::Scalar::one()
|
||||
|
@ -240,14 +233,17 @@ pub mod tests {
|
|||
use group::Curve;
|
||||
use halo2::{
|
||||
arithmetic::CurveAffine,
|
||||
circuit::{Chip, Layouter},
|
||||
circuit::{AssignedCell, Chip, Layouter},
|
||||
plonk::{Any, Error},
|
||||
};
|
||||
use pasta_curves::{arithmetic::FieldExt, pallas};
|
||||
|
||||
use crate::circuit::gadget::{
|
||||
ecc::{chip::EccChip, FixedPointShort, NonIdentityPoint, Point},
|
||||
utilities::{lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions},
|
||||
ecc::{
|
||||
chip::{EccChip, MagnitudeSign},
|
||||
FixedPointShort, NonIdentityPoint, Point,
|
||||
},
|
||||
utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions},
|
||||
};
|
||||
use crate::constants::load::ValueCommitV;
|
||||
|
||||
|
@ -266,7 +262,7 @@ pub mod tests {
|
|||
mut layouter: impl Layouter<pallas::Base>,
|
||||
magnitude: pallas::Base,
|
||||
sign: pallas::Base,
|
||||
) -> Result<(CellValue<pallas::Base>, CellValue<pallas::Base>), Error> {
|
||||
) -> Result<MagnitudeSign, Error> {
|
||||
let column = chip.config().advices[0];
|
||||
let magnitude =
|
||||
chip.load_private(layouter.namespace(|| "magnitude"), column, Some(magnitude))?;
|
||||
|
@ -371,7 +367,9 @@ pub mod tests {
|
|||
)?;
|
||||
value_commit_v.mul(layouter.namespace(|| *name), magnitude_sign)?
|
||||
};
|
||||
assert!(result.inner().is_identity().unwrap());
|
||||
if let Some(is_identity) = result.inner().is_identity() {
|
||||
assert!(is_identity);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -379,10 +377,7 @@ pub mod tests {
|
|||
|
||||
#[test]
|
||||
fn invalid_magnitude_sign() {
|
||||
use crate::circuit::gadget::{
|
||||
ecc::chip::EccConfig,
|
||||
utilities::{CellValue, UtilitiesInstructions},
|
||||
};
|
||||
use crate::circuit::gadget::{ecc::chip::EccConfig, utilities::UtilitiesInstructions};
|
||||
use halo2::{
|
||||
circuit::{Layouter, SimpleFloorPlanner},
|
||||
dev::{MockProver, VerifyFailure},
|
||||
|
@ -398,7 +393,7 @@ pub mod tests {
|
|||
}
|
||||
|
||||
impl UtilitiesInstructions<pallas::Base> for MyCircuit {
|
||||
type Var = CellValue<pallas::Base>;
|
||||
type Var = AssignedCell<pallas::Base, pallas::Base>;
|
||||
}
|
||||
|
||||
impl Circuit<pallas::Base> for MyCircuit {
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
use super::{CellValue, EccPoint, NonIdentityEccPoint, Var};
|
||||
use super::{EccPoint, NonIdentityEccPoint};
|
||||
|
||||
use group::prime::PrimeCurveAffine;
|
||||
|
||||
use halo2::{
|
||||
circuit::Region,
|
||||
circuit::{AssignedCell, Region},
|
||||
plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector, VirtualCells},
|
||||
poly::Rotation,
|
||||
};
|
||||
use pasta_curves::{arithmetic::CurveAffine, pallas};
|
||||
|
||||
type Coordinates = (
|
||||
AssignedCell<pallas::Base, pallas::Base>,
|
||||
AssignedCell<pallas::Base, pallas::Base>,
|
||||
);
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct Config {
|
||||
q_point: Selector,
|
||||
|
@ -76,7 +81,7 @@ impl Config {
|
|||
value: Option<(pallas::Base, pallas::Base)>,
|
||||
offset: usize,
|
||||
region: &mut Region<'_, pallas::Base>,
|
||||
) -> Result<(CellValue<pallas::Base>, CellValue<pallas::Base>), Error> {
|
||||
) -> Result<Coordinates, Error> {
|
||||
// Assign `x` value
|
||||
let x_val = value.map(|value| value.0);
|
||||
let x_var =
|
||||
|
@ -87,10 +92,7 @@ impl Config {
|
|||
let y_var =
|
||||
region.assign_advice(|| "y", self.y, offset, || y_val.ok_or(Error::Synthesis))?;
|
||||
|
||||
Ok((
|
||||
CellValue::<pallas::Base>::new(x_var, x_val),
|
||||
CellValue::<pallas::Base>::new(y_var, y_val),
|
||||
))
|
||||
Ok((x_var, y_var))
|
||||
}
|
||||
|
||||
/// Assigns a point that can be the identity.
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
//! Gadget and chips for the Poseidon algebraic hash function.
|
||||
|
||||
use std::array;
|
||||
use std::convert::TryInto;
|
||||
use std::fmt;
|
||||
|
||||
use halo2::{
|
||||
arithmetic::FieldExt,
|
||||
circuit::{Chip, Layouter},
|
||||
circuit::{AssignedCell, Chip, Layouter},
|
||||
plonk::Error,
|
||||
};
|
||||
|
||||
mod pow5;
|
||||
pub use pow5::{Pow5Chip, Pow5Config, StateWord};
|
||||
|
||||
use crate::circuit::gadget::utilities::CellValue;
|
||||
use crate::primitives::poseidon::{ConstantLength, Domain, Spec, Sponge, SpongeState, State};
|
||||
|
||||
/// The set of circuit instructions required to use the Poseidon permutation.
|
||||
|
@ -20,7 +20,7 @@ pub trait PoseidonInstructions<F: FieldExt, S: Spec<F, T, RATE>, const T: usize,
|
|||
Chip<F>
|
||||
{
|
||||
/// Variable representing the word over which the Poseidon permutation operates.
|
||||
type Word: Copy + fmt::Debug + From<CellValue<F>> + Into<CellValue<F>>;
|
||||
type Word: Clone + fmt::Debug + From<AssignedCell<F, F>> + Into<AssignedCell<F, F>>;
|
||||
|
||||
/// Applies the Poseidon permutation to the given state.
|
||||
fn permute(
|
||||
|
@ -82,7 +82,7 @@ impl<
|
|||
{
|
||||
/// The word contained in this gadget.
|
||||
pub fn inner(&self) -> PoseidonChip::Word {
|
||||
self.inner
|
||||
self.inner.clone()
|
||||
}
|
||||
|
||||
/// Construct a [`Word`] gadget from the inner word.
|
||||
|
@ -144,7 +144,13 @@ impl<
|
|||
chip.initial_state(&mut layouter, &domain)
|
||||
.map(|state| Duplex {
|
||||
chip,
|
||||
sponge: Sponge::Absorbing([None; RATE]),
|
||||
sponge: Sponge::Absorbing(
|
||||
(0..RATE)
|
||||
.map(|_| None)
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
),
|
||||
state,
|
||||
domain,
|
||||
})
|
||||
|
@ -154,7 +160,7 @@ impl<
|
|||
pub fn absorb(
|
||||
&mut self,
|
||||
mut layouter: impl Layouter<F>,
|
||||
value: CellValue<F>,
|
||||
value: AssignedCell<F, F>,
|
||||
) -> Result<(), Error> {
|
||||
match self.sponge {
|
||||
Sponge::Absorbing(ref mut input) => {
|
||||
|
@ -185,7 +191,7 @@ impl<
|
|||
}
|
||||
|
||||
/// Squeezes an element from the sponge.
|
||||
pub fn squeeze(&mut self, mut layouter: impl Layouter<F>) -> Result<CellValue<F>, Error> {
|
||||
pub fn squeeze(&mut self, mut layouter: impl Layouter<F>) -> Result<AssignedCell<F, F>, Error> {
|
||||
loop {
|
||||
match self.sponge {
|
||||
Sponge::Absorbing(ref input) => {
|
||||
|
@ -205,7 +211,13 @@ impl<
|
|||
}
|
||||
|
||||
// We've already squeezed out all available elements
|
||||
self.sponge = Sponge::Absorbing([None; RATE]);
|
||||
self.sponge = Sponge::Absorbing(
|
||||
(0..RATE)
|
||||
.map(|_| None)
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -253,8 +265,8 @@ impl<
|
|||
pub fn hash(
|
||||
mut self,
|
||||
mut layouter: impl Layouter<F>,
|
||||
message: [CellValue<F>; L],
|
||||
) -> Result<CellValue<F>, Error> {
|
||||
message: [AssignedCell<F, F>; L],
|
||||
) -> Result<AssignedCell<F, F>, Error> {
|
||||
for (i, value) in array::IntoIter::new(message).enumerate() {
|
||||
self.duplex
|
||||
.absorb(layouter.namespace(|| format!("absorb_{}", i)), value)?;
|
||||
|
|
|
@ -3,13 +3,13 @@ use std::iter;
|
|||
|
||||
use halo2::{
|
||||
arithmetic::FieldExt,
|
||||
circuit::{Cell, Chip, Layouter, Region},
|
||||
circuit::{AssignedCell, Cell, Chip, Layouter, Region},
|
||||
plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, Selector},
|
||||
poly::Rotation,
|
||||
};
|
||||
|
||||
use super::{PoseidonDuplexInstructions, PoseidonInstructions};
|
||||
use crate::circuit::gadget::utilities::{CellValue, Var};
|
||||
use crate::circuit::gadget::utilities::Var;
|
||||
use crate::primitives::poseidon::{Domain, Mds, Spec, SpongeState, State};
|
||||
|
||||
/// Configuration for a [`Pow5Chip`].
|
||||
|
@ -288,10 +288,7 @@ impl<F: FieldExt, S: Spec<F, WIDTH, RATE>, const WIDTH: usize, const RATE: usize
|
|||
0,
|
||||
value,
|
||||
)?;
|
||||
state.push(StateWord {
|
||||
var,
|
||||
value: Some(value),
|
||||
});
|
||||
state.push(StateWord(var));
|
||||
|
||||
Ok(())
|
||||
};
|
||||
|
@ -323,15 +320,15 @@ impl<F: FieldExt, S: Spec<F, WIDTH, RATE>, const WIDTH: usize, const RATE: usize
|
|||
|
||||
// Load the initial state into this region.
|
||||
let load_state_word = |i: usize| {
|
||||
let value = initial_state[i].value;
|
||||
let var = region.assign_advice(
|
||||
|| format!("load state_{}", i),
|
||||
config.state[i],
|
||||
0,
|
||||
|| value.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
region.constrain_equal(initial_state[i].var, var)?;
|
||||
Ok(StateWord { var, value })
|
||||
initial_state[i]
|
||||
.0
|
||||
.copy_advice(
|
||||
|| format!("load state_{}", i),
|
||||
&mut region,
|
||||
config.state[i],
|
||||
0,
|
||||
)
|
||||
.map(StateWord)
|
||||
};
|
||||
let initial_state: Result<Vec<_>, Error> =
|
||||
(0..WIDTH).map(load_state_word).collect();
|
||||
|
@ -341,49 +338,46 @@ impl<F: FieldExt, S: Spec<F, WIDTH, RATE>, const WIDTH: usize, const RATE: usize
|
|||
|
||||
// Load the input and padding into this region.
|
||||
let load_input_word = |i: usize| {
|
||||
let (constraint_var, value) = match (input[i], padding_values[i]) {
|
||||
(Some(word), None) => (word.var, word.value),
|
||||
(None, Some(padding_value)) => {
|
||||
let padding_var = region.assign_fixed(
|
||||
|| format!("load pad_{}", i),
|
||||
config.rc_b[i],
|
||||
1,
|
||||
|| Ok(padding_value),
|
||||
)?;
|
||||
(padding_var, Some(padding_value))
|
||||
}
|
||||
let constraint_var = match (input[i].clone(), padding_values[i]) {
|
||||
(Some(word), None) => word.0,
|
||||
(None, Some(padding_value)) => region.assign_fixed(
|
||||
|| format!("load pad_{}", i),
|
||||
config.rc_b[i],
|
||||
1,
|
||||
|| Ok(padding_value),
|
||||
)?,
|
||||
_ => panic!("Input and padding don't match"),
|
||||
};
|
||||
let var = region.assign_advice(
|
||||
|| format!("load input_{}", i),
|
||||
config.state[i],
|
||||
1,
|
||||
|| value.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
region.constrain_equal(constraint_var, var)?;
|
||||
|
||||
Ok(StateWord { var, value })
|
||||
constraint_var
|
||||
.copy_advice(
|
||||
|| format!("load input_{}", i),
|
||||
&mut region,
|
||||
config.state[i],
|
||||
1,
|
||||
)
|
||||
.map(StateWord)
|
||||
};
|
||||
let input: Result<Vec<_>, Error> = (0..RATE).map(load_input_word).collect();
|
||||
let input = input?;
|
||||
|
||||
// Constrain the output.
|
||||
let constrain_output_word = |i: usize| {
|
||||
let value = initial_state[i].value.and_then(|initial_word| {
|
||||
let value = initial_state[i].0.value().and_then(|initial_word| {
|
||||
input
|
||||
.get(i)
|
||||
.map(|word| word.value)
|
||||
.map(|word| word.0.value().cloned())
|
||||
// The capacity element is never altered by the input.
|
||||
.unwrap_or_else(|| Some(F::zero()))
|
||||
.map(|input_word| initial_word + input_word)
|
||||
.map(|input_word| *initial_word + input_word)
|
||||
});
|
||||
let var = region.assign_advice(
|
||||
|| format!("load output_{}", i),
|
||||
config.state[i],
|
||||
2,
|
||||
|| value.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
Ok(StateWord { var, value })
|
||||
region
|
||||
.assign_advice(
|
||||
|| format!("load output_{}", i),
|
||||
config.state[i],
|
||||
2,
|
||||
|| value.ok_or(Error::Synthesis),
|
||||
)
|
||||
.map(StateWord)
|
||||
};
|
||||
|
||||
let output: Result<Vec<_>, Error> = (0..WIDTH).map(constrain_output_word).collect();
|
||||
|
@ -395,7 +389,7 @@ impl<F: FieldExt, S: Spec<F, WIDTH, RATE>, const WIDTH: usize, const RATE: usize
|
|||
fn get_output(state: &State<Self::Word, WIDTH>) -> SpongeState<Self::Word, RATE> {
|
||||
state[..RATE]
|
||||
.iter()
|
||||
.map(|word| Some(*word))
|
||||
.map(|word| Some(word.clone()))
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.unwrap()
|
||||
|
@ -403,35 +397,28 @@ impl<F: FieldExt, S: Spec<F, WIDTH, RATE>, const WIDTH: usize, const RATE: usize
|
|||
}
|
||||
|
||||
/// A word in the Poseidon state.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct StateWord<F: FieldExt> {
|
||||
var: Cell,
|
||||
value: Option<F>,
|
||||
}
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StateWord<F: FieldExt>(AssignedCell<F, F>);
|
||||
|
||||
impl<F: FieldExt> From<StateWord<F>> for CellValue<F> {
|
||||
fn from(state_word: StateWord<F>) -> CellValue<F> {
|
||||
CellValue::new(state_word.var, state_word.value)
|
||||
impl<F: FieldExt> From<StateWord<F>> for AssignedCell<F, F> {
|
||||
fn from(state_word: StateWord<F>) -> AssignedCell<F, F> {
|
||||
state_word.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: FieldExt> From<CellValue<F>> for StateWord<F> {
|
||||
fn from(cell_value: CellValue<F>) -> StateWord<F> {
|
||||
StateWord::new(cell_value.cell(), cell_value.value())
|
||||
impl<F: FieldExt> From<AssignedCell<F, F>> for StateWord<F> {
|
||||
fn from(cell_value: AssignedCell<F, F>) -> StateWord<F> {
|
||||
StateWord(cell_value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: FieldExt> Var<F> for StateWord<F> {
|
||||
fn new(var: Cell, value: Option<F>) -> Self {
|
||||
Self { var, value }
|
||||
}
|
||||
|
||||
fn cell(&self) -> Cell {
|
||||
self.var
|
||||
self.0.cell()
|
||||
}
|
||||
|
||||
fn value(&self) -> Option<F> {
|
||||
self.value
|
||||
self.0.value().cloned()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -447,11 +434,11 @@ impl<F: FieldExt, const WIDTH: usize> Pow5State<F, WIDTH> {
|
|||
offset: usize,
|
||||
) -> Result<Self, Error> {
|
||||
Self::round(region, config, round, offset, config.s_full, |_| {
|
||||
let q = self
|
||||
.0
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, word)| word.value.map(|v| v + config.round_constants[round][idx]));
|
||||
let q = self.0.iter().enumerate().map(|(idx, word)| {
|
||||
word.0
|
||||
.value()
|
||||
.map(|v| *v + config.round_constants[round][idx])
|
||||
});
|
||||
let r: Option<Vec<F>> = q.map(|q| q.map(|q| q.pow(&config.alpha))).collect();
|
||||
let m = &config.m_reg;
|
||||
let state = m.iter().map(|m_i| {
|
||||
|
@ -475,7 +462,7 @@ impl<F: FieldExt, const WIDTH: usize> Pow5State<F, WIDTH> {
|
|||
) -> Result<Self, Error> {
|
||||
Self::round(region, config, round, offset, config.s_partial, |region| {
|
||||
let m = &config.m_reg;
|
||||
let p: Option<Vec<_>> = self.0.iter().map(|word| word.value).collect();
|
||||
let p: Option<Vec<_>> = self.0.iter().map(|word| word.0.value().cloned()).collect();
|
||||
|
||||
let r: Option<Vec<_>> = p.map(|p| {
|
||||
let r_0 = (p[0] + config.round_constants[round][0]).pow(&config.alpha);
|
||||
|
@ -547,15 +534,10 @@ impl<F: FieldExt, const WIDTH: usize> Pow5State<F, WIDTH> {
|
|||
initial_state: &State<StateWord<F>, WIDTH>,
|
||||
) -> Result<Self, Error> {
|
||||
let load_state_word = |i: usize| {
|
||||
let value = initial_state[i].value;
|
||||
let var = region.assign_advice(
|
||||
|| format!("load state_{}", i),
|
||||
config.state[i],
|
||||
0,
|
||||
|| value.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
region.constrain_equal(initial_state[i].var, var)?;
|
||||
Ok(StateWord { var, value })
|
||||
initial_state[i]
|
||||
.0
|
||||
.copy_advice(|| format!("load state_{}", i), region, config.state[i], 0)
|
||||
.map(StateWord)
|
||||
};
|
||||
|
||||
let state: Result<Vec<_>, _> = (0..WIDTH).map(load_state_word).collect();
|
||||
|
@ -597,7 +579,7 @@ impl<F: FieldExt, const WIDTH: usize> Pow5State<F, WIDTH> {
|
|||
offset + 1,
|
||||
|| value.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
Ok(StateWord { var, value })
|
||||
Ok(StateWord(var))
|
||||
};
|
||||
|
||||
let next_state: Result<Vec<_>, _> = (0..WIDTH).map(next_state_word).collect();
|
||||
|
@ -619,10 +601,7 @@ mod tests {
|
|||
|
||||
use super::{PoseidonInstructions, Pow5Chip, Pow5Config, StateWord};
|
||||
use crate::{
|
||||
circuit::gadget::{
|
||||
poseidon::Hash,
|
||||
utilities::{CellValue, Var},
|
||||
},
|
||||
circuit::gadget::poseidon::Hash,
|
||||
primitives::poseidon::{self, ConstantLength, P128Pow5T3 as OrchardNullifier, Spec},
|
||||
};
|
||||
use std::convert::TryInto;
|
||||
|
@ -674,7 +653,7 @@ mod tests {
|
|||
0,
|
||||
|| value.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
Ok(StateWord { var, value })
|
||||
Ok(StateWord(var))
|
||||
};
|
||||
|
||||
let state: Result<Vec<_>, Error> = (0..WIDTH).map(state_word).collect();
|
||||
|
@ -713,7 +692,7 @@ mod tests {
|
|||
0,
|
||||
|| Ok(expected_final_state[i]),
|
||||
)?;
|
||||
region.constrain_equal(final_state[i].var, var)
|
||||
region.constrain_equal(final_state[i].0.cell(), var.cell())
|
||||
};
|
||||
|
||||
for i in 0..(WIDTH) {
|
||||
|
@ -791,13 +770,12 @@ mod tests {
|
|||
|mut region| {
|
||||
let message_word = |i: usize| {
|
||||
let value = self.message.map(|message_vals| message_vals[i]);
|
||||
let cell = region.assign_advice(
|
||||
region.assign_advice(
|
||||
|| format!("load message_{}", i),
|
||||
config.state[i],
|
||||
0,
|
||||
|| value.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
Ok(CellValue::new(cell, value))
|
||||
)
|
||||
};
|
||||
|
||||
let message: Result<Vec<_>, Error> = (0..L).map(message_word).collect();
|
||||
|
@ -821,7 +799,7 @@ mod tests {
|
|||
0,
|
||||
|| self.output.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
region.constrain_equal(output.cell(), expected_var)
|
||||
region.constrain_equal(output.cell(), expected_var.cell())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ pub trait SinsemillaInstructions<C: CurveAffine, const K: usize, const MAX_WORDS
|
|||
///
|
||||
/// For example, in the case `K = 10`, `NUM_BITS = 255`, we can fit
|
||||
/// up to `N = 25` words in a single base field element.
|
||||
type MessagePiece: Copy + Clone + Debug;
|
||||
type MessagePiece: Clone + Debug;
|
||||
|
||||
/// A cumulative sum `z` is used to decompose a Sinsemilla message. It
|
||||
/// produces intermediate values for each word in the message, such
|
||||
|
@ -170,7 +170,7 @@ where
|
|||
SinsemillaChip: SinsemillaInstructions<C, K, MAX_WORDS> + Clone + Debug + Eq,
|
||||
{
|
||||
fn inner(&self) -> SinsemillaChip::MessagePiece {
|
||||
self.inner
|
||||
self.inner.clone()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,8 +4,7 @@ use super::{
|
|||
};
|
||||
use crate::{
|
||||
circuit::gadget::{
|
||||
ecc::chip::NonIdentityEccPoint,
|
||||
utilities::{lookup_range_check::LookupRangeCheckConfig, CellValue, Var},
|
||||
ecc::chip::NonIdentityEccPoint, utilities::lookup_range_check::LookupRangeCheckConfig,
|
||||
},
|
||||
constants::OrchardFixedBasesFull,
|
||||
primitives::sinsemilla::{
|
||||
|
@ -15,7 +14,7 @@ use crate::{
|
|||
|
||||
use halo2::{
|
||||
arithmetic::{CurveAffine, FieldExt},
|
||||
circuit::{Chip, Layouter},
|
||||
circuit::{AssignedCell, Chip, Layouter},
|
||||
plonk::{
|
||||
Advice, Column, ConstraintSystem, Error, Expression, Fixed, Selector, TableColumn,
|
||||
VirtualCells,
|
||||
|
@ -239,14 +238,14 @@ impl SinsemillaChip {
|
|||
impl SinsemillaInstructions<pallas::Affine, { sinsemilla::K }, { sinsemilla::C }>
|
||||
for SinsemillaChip
|
||||
{
|
||||
type CellValue = CellValue<pallas::Base>;
|
||||
type CellValue = AssignedCell<pallas::Base, pallas::Base>;
|
||||
|
||||
type Message = Message<pallas::Base, { sinsemilla::K }, { sinsemilla::C }>;
|
||||
type MessagePiece = MessagePiece<pallas::Base, { sinsemilla::K }>;
|
||||
|
||||
type RunningSum = Vec<Self::CellValue>;
|
||||
|
||||
type X = CellValue<pallas::Base>;
|
||||
type X = AssignedCell<pallas::Base, pallas::Base>;
|
||||
type NonIdentityPoint = NonIdentityEccPoint;
|
||||
type FixedPoints = OrchardFixedBasesFull;
|
||||
|
||||
|
@ -272,7 +271,7 @@ impl SinsemillaInstructions<pallas::Affine, { sinsemilla::K }, { sinsemilla::C }
|
|||
)
|
||||
},
|
||||
)?;
|
||||
Ok(MessagePiece::new(cell, field_elem, num_words))
|
||||
Ok(MessagePiece::new(cell, num_words))
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use super::super::SinsemillaInstructions;
|
||||
use super::{CellValue, NonIdentityEccPoint, SinsemillaChip, Var};
|
||||
use super::{NonIdentityEccPoint, SinsemillaChip};
|
||||
use crate::primitives::sinsemilla::{self, lebs2ip_k, INV_TWO_POW_K, SINSEMILLA_S};
|
||||
use halo2::circuit::AssignedCell;
|
||||
use halo2::{
|
||||
circuit::{Chip, Region},
|
||||
plonk::Error,
|
||||
|
@ -26,7 +27,13 @@ impl SinsemillaChip {
|
|||
{ sinsemilla::K },
|
||||
{ sinsemilla::C },
|
||||
>>::Message,
|
||||
) -> Result<(NonIdentityEccPoint, Vec<Vec<CellValue<pallas::Base>>>), Error> {
|
||||
) -> Result<
|
||||
(
|
||||
NonIdentityEccPoint,
|
||||
Vec<Vec<AssignedCell<pallas::Base, pallas::Base>>>,
|
||||
),
|
||||
Error,
|
||||
> {
|
||||
let config = self.config().clone();
|
||||
let mut offset = 0;
|
||||
|
||||
|
@ -46,16 +53,13 @@ impl SinsemillaChip {
|
|||
|
||||
// Constrain the initial x_q to equal the x-coordinate of the domain's `Q`.
|
||||
let mut x_a: X<pallas::Base> = {
|
||||
let x_a = {
|
||||
let cell =
|
||||
region.assign_advice_from_constant(|| "fixed x_q", config.x_a, offset, x_q)?;
|
||||
CellValue::new(cell, Some(x_q))
|
||||
};
|
||||
let x_a =
|
||||
region.assign_advice_from_constant(|| "fixed x_q", config.x_a, offset, x_q)?;
|
||||
|
||||
x_a.into()
|
||||
};
|
||||
|
||||
let mut zs_sum: Vec<Vec<CellValue<pallas::Base>>> = Vec::new();
|
||||
let mut zs_sum: Vec<Vec<AssignedCell<pallas::Base, pallas::Base>>> = Vec::new();
|
||||
|
||||
// Hash each piece in the message.
|
||||
for (idx, piece) in message.iter().enumerate() {
|
||||
|
@ -102,7 +106,7 @@ impl SinsemillaChip {
|
|||
)?;
|
||||
}
|
||||
|
||||
CellValue::new(y_a_cell, y_a.0)
|
||||
y_a_cell
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -142,14 +146,14 @@ impl SinsemillaChip {
|
|||
.chunks(K)
|
||||
.fold(Q.to_curve(), |acc, chunk| (acc + S(chunk)) + acc);
|
||||
let actual_point =
|
||||
pallas::Affine::from_xy(x_a.value().unwrap(), y_a.value().unwrap()).unwrap();
|
||||
pallas::Affine::from_xy(*x_a.value().unwrap(), *y_a.value().unwrap()).unwrap();
|
||||
assert_eq!(expected_point.to_affine(), actual_point);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(x_a) = x_a.value() {
|
||||
if let Some(y_a) = y_a.value() {
|
||||
if x_a == pallas::Base::zero() || y_a == pallas::Base::zero() {
|
||||
if x_a.is_zero_vartime() || y_a.is_zero_vartime() {
|
||||
return Err(Error::Synthesis);
|
||||
}
|
||||
}
|
||||
|
@ -183,7 +187,7 @@ impl SinsemillaChip {
|
|||
(
|
||||
X<pallas::Base>,
|
||||
Y<pallas::Base>,
|
||||
Vec<CellValue<pallas::Base>>,
|
||||
Vec<AssignedCell<pallas::Base, pallas::Base>>,
|
||||
),
|
||||
Error,
|
||||
> {
|
||||
|
@ -264,14 +268,13 @@ impl SinsemillaChip {
|
|||
let mut zs = Vec::with_capacity(piece.num_words() + 1);
|
||||
|
||||
// Copy message and initialize running sum `z` to decompose message in-circuit
|
||||
let cell = region.assign_advice(
|
||||
let initial_z = piece.cell_value().copy_advice(
|
||||
|| "z_0 (copy of message piece)",
|
||||
region,
|
||||
config.bits,
|
||||
offset,
|
||||
|| piece.field_elem().ok_or(Error::Synthesis),
|
||||
)?;
|
||||
region.constrain_equal(piece.cell(), cell)?;
|
||||
zs.push(CellValue::new(cell, piece.field_elem()));
|
||||
zs.push(initial_z);
|
||||
|
||||
// Assign cumulative sum such that for 0 <= i < n,
|
||||
// z_i = 2^K * z_{i + 1} + m_{i + 1}
|
||||
|
@ -295,7 +298,7 @@ impl SinsemillaChip {
|
|||
offset + idx + 1,
|
||||
|| z.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
zs.push(CellValue::new(cell, z))
|
||||
zs.push(cell)
|
||||
}
|
||||
|
||||
zs
|
||||
|
@ -381,7 +384,7 @@ impl SinsemillaChip {
|
|||
|| x_a_new.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
|
||||
CellValue::new(x_a_cell, x_a_new).into()
|
||||
x_a_cell.into()
|
||||
};
|
||||
|
||||
// Compute y_a for the next row.
|
||||
|
@ -402,18 +405,18 @@ impl SinsemillaChip {
|
|||
}
|
||||
|
||||
/// The x-coordinate of the accumulator in a Sinsemilla hash instance.
|
||||
struct X<F: FieldExt>(CellValue<F>);
|
||||
struct X<F: FieldExt>(AssignedCell<F, F>);
|
||||
|
||||
impl<F: FieldExt> From<CellValue<F>> for X<F> {
|
||||
fn from(cell_value: CellValue<F>) -> Self {
|
||||
impl<F: FieldExt> From<AssignedCell<F, F>> for X<F> {
|
||||
fn from(cell_value: AssignedCell<F, F>) -> Self {
|
||||
X(cell_value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: FieldExt> Deref for X<F> {
|
||||
type Target = CellValue<F>;
|
||||
type Target = AssignedCell<F, F>;
|
||||
|
||||
fn deref(&self) -> &CellValue<F> {
|
||||
fn deref(&self) -> &AssignedCell<F, F> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use halo2::{
|
||||
circuit::Layouter,
|
||||
circuit::{AssignedCell, Layouter},
|
||||
plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector},
|
||||
poly::Rotation,
|
||||
};
|
||||
|
@ -8,7 +8,7 @@ use pasta_curves::{arithmetic::FieldExt, pallas};
|
|||
use crate::{
|
||||
circuit::gadget::{
|
||||
ecc::{chip::EccChip, X},
|
||||
utilities::{bitrange_subset, bool_check, copy, CellValue, Var},
|
||||
utilities::{bitrange_subset, bool_check},
|
||||
},
|
||||
constants::T_P,
|
||||
};
|
||||
|
@ -225,8 +225,8 @@ impl CommitIvkConfig {
|
|||
sinsemilla_chip: SinsemillaChip,
|
||||
ecc_chip: EccChip,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
ak: CellValue<pallas::Base>,
|
||||
nk: CellValue<pallas::Base>,
|
||||
ak: AssignedCell<pallas::Base, pallas::Base>,
|
||||
nk: AssignedCell<pallas::Base, pallas::Base>,
|
||||
rivk: Option<pallas::Scalar>,
|
||||
) -> Result<X<pallas::Affine, EccChip>, Error> {
|
||||
// <https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit>
|
||||
|
@ -337,8 +337,8 @@ impl CommitIvkConfig {
|
|||
domain.short_commit(layouter.namespace(|| "Hash ak||nk"), message, rivk)?
|
||||
};
|
||||
|
||||
let z13_a = zs[0][13];
|
||||
let z13_c = zs[2][13];
|
||||
let z13_a = zs[0][13].clone();
|
||||
let z13_c = zs[2][13].clone();
|
||||
|
||||
let (a_prime, z13_a_prime) = self.ak_canonicity(
|
||||
layouter.namespace(|| "ak canonicity"),
|
||||
|
@ -347,7 +347,7 @@ impl CommitIvkConfig {
|
|||
|
||||
let (b2_c_prime, z14_b2_c_prime) = self.nk_canonicity(
|
||||
layouter.namespace(|| "nk canonicity"),
|
||||
b_2,
|
||||
b_2.clone(),
|
||||
c.inner().cell_value(),
|
||||
)?;
|
||||
|
||||
|
@ -384,8 +384,14 @@ impl CommitIvkConfig {
|
|||
fn ak_canonicity(
|
||||
&self,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
a: CellValue<pallas::Base>,
|
||||
) -> Result<(CellValue<pallas::Base>, CellValue<pallas::Base>), Error> {
|
||||
a: AssignedCell<pallas::Base, pallas::Base>,
|
||||
) -> Result<
|
||||
(
|
||||
AssignedCell<pallas::Base, pallas::Base>,
|
||||
AssignedCell<pallas::Base, pallas::Base>,
|
||||
),
|
||||
Error,
|
||||
> {
|
||||
// `ak` = `a (250 bits) || b_0 (4 bits) || b_1 (1 bit)`
|
||||
// - b_1 = 1 => b_0 = 0
|
||||
// - b_1 = 1 => a < t_P
|
||||
|
@ -406,10 +412,10 @@ impl CommitIvkConfig {
|
|||
13,
|
||||
false,
|
||||
)?;
|
||||
let a_prime = zs[0];
|
||||
let a_prime = zs[0].clone();
|
||||
assert_eq!(zs.len(), 14); // [z_0, z_1, ..., z13_a]
|
||||
|
||||
Ok((a_prime, zs[13]))
|
||||
Ok((a_prime, zs[13].clone()))
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
|
@ -417,9 +423,15 @@ impl CommitIvkConfig {
|
|||
fn nk_canonicity(
|
||||
&self,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
b_2: CellValue<pallas::Base>,
|
||||
c: CellValue<pallas::Base>,
|
||||
) -> Result<(CellValue<pallas::Base>, CellValue<pallas::Base>), Error> {
|
||||
b_2: AssignedCell<pallas::Base, pallas::Base>,
|
||||
c: AssignedCell<pallas::Base, pallas::Base>,
|
||||
) -> Result<
|
||||
(
|
||||
AssignedCell<pallas::Base, pallas::Base>,
|
||||
AssignedCell<pallas::Base, pallas::Base>,
|
||||
),
|
||||
Error,
|
||||
> {
|
||||
// `nk` = `b_2 (5 bits) || c (240 bits) || d_0 (9 bits) || d_1 (1 bit)
|
||||
// - d_1 = 1 => d_0 = 0
|
||||
// - d_1 = 1 => b_2 + c * 2^5 < t_P
|
||||
|
@ -443,10 +455,10 @@ impl CommitIvkConfig {
|
|||
14,
|
||||
false,
|
||||
)?;
|
||||
let b2_c_prime = zs[0];
|
||||
let b2_c_prime = zs[0].clone();
|
||||
assert_eq!(zs.len(), 15); // [z_0, z_1, ..., z14]
|
||||
|
||||
Ok((b2_c_prime, zs[14]))
|
||||
Ok((b2_c_prime, zs[14].clone()))
|
||||
}
|
||||
|
||||
// Assign cells for the canonicity gate.
|
||||
|
@ -474,28 +486,24 @@ impl CommitIvkConfig {
|
|||
{
|
||||
let offset = 0;
|
||||
// Copy in `ak`
|
||||
copy(
|
||||
&mut region,
|
||||
|| "ak",
|
||||
self.advices[0],
|
||||
offset,
|
||||
&gate_cells.ak,
|
||||
)?;
|
||||
gate_cells
|
||||
.ak
|
||||
.copy_advice(|| "ak", &mut region, self.advices[0], offset)?;
|
||||
|
||||
// Copy in `a`
|
||||
copy(&mut region, || "a", self.advices[1], offset, &gate_cells.a)?;
|
||||
gate_cells
|
||||
.a
|
||||
.copy_advice(|| "a", &mut region, self.advices[1], offset)?;
|
||||
|
||||
// Copy in `b`
|
||||
copy(&mut region, || "b", self.advices[2], offset, &gate_cells.b)?;
|
||||
gate_cells
|
||||
.b
|
||||
.copy_advice(|| "b", &mut region, self.advices[2], offset)?;
|
||||
|
||||
// Copy in `b_0`
|
||||
copy(
|
||||
&mut region,
|
||||
|| "b_0",
|
||||
self.advices[3],
|
||||
offset,
|
||||
&gate_cells.b_0,
|
||||
)?;
|
||||
gate_cells
|
||||
.b_0
|
||||
.copy_advice(|| "b_0", &mut region, self.advices[3], offset)?;
|
||||
|
||||
// Witness `b_1`
|
||||
region.assign_advice(
|
||||
|
@ -506,39 +514,32 @@ impl CommitIvkConfig {
|
|||
)?;
|
||||
|
||||
// Copy in `b_2`
|
||||
copy(
|
||||
&mut region,
|
||||
|| "b_2",
|
||||
self.advices[5],
|
||||
offset,
|
||||
&gate_cells.b_2,
|
||||
)?;
|
||||
gate_cells
|
||||
.b_2
|
||||
.copy_advice(|| "b_2", &mut region, self.advices[5], offset)?;
|
||||
|
||||
// Copy in z13_a
|
||||
copy(
|
||||
&mut region,
|
||||
gate_cells.z13_a.copy_advice(
|
||||
|| "z13_a",
|
||||
&mut region,
|
||||
self.advices[6],
|
||||
offset,
|
||||
&gate_cells.z13_a,
|
||||
)?;
|
||||
|
||||
// Copy in a_prime
|
||||
copy(
|
||||
&mut region,
|
||||
gate_cells.a_prime.copy_advice(
|
||||
|| "a_prime",
|
||||
&mut region,
|
||||
self.advices[7],
|
||||
offset,
|
||||
&gate_cells.a_prime,
|
||||
)?;
|
||||
|
||||
// Copy in z13_a_prime
|
||||
copy(
|
||||
&mut region,
|
||||
gate_cells.z13_a_prime.copy_advice(
|
||||
|| "z13_a_prime",
|
||||
&mut region,
|
||||
self.advices[8],
|
||||
offset,
|
||||
&gate_cells.z13_a_prime,
|
||||
)?;
|
||||
}
|
||||
|
||||
|
@ -547,28 +548,24 @@ impl CommitIvkConfig {
|
|||
let offset = 1;
|
||||
|
||||
// Copy in `nk`
|
||||
copy(
|
||||
&mut region,
|
||||
|| "nk",
|
||||
self.advices[0],
|
||||
offset,
|
||||
&gate_cells.nk,
|
||||
)?;
|
||||
gate_cells
|
||||
.nk
|
||||
.copy_advice(|| "nk", &mut region, self.advices[0], offset)?;
|
||||
|
||||
// Copy in `c`
|
||||
copy(&mut region, || "c", self.advices[1], offset, &gate_cells.c)?;
|
||||
gate_cells
|
||||
.c
|
||||
.copy_advice(|| "c", &mut region, self.advices[1], offset)?;
|
||||
|
||||
// Copy in `d`
|
||||
copy(&mut region, || "d", self.advices[2], offset, &gate_cells.d)?;
|
||||
gate_cells
|
||||
.d
|
||||
.copy_advice(|| "d", &mut region, self.advices[2], offset)?;
|
||||
|
||||
// Copy in `d_0`
|
||||
copy(
|
||||
&mut region,
|
||||
|| "d_0",
|
||||
self.advices[3],
|
||||
offset,
|
||||
&gate_cells.d_0,
|
||||
)?;
|
||||
gate_cells
|
||||
.d_0
|
||||
.copy_advice(|| "d_0", &mut region, self.advices[3], offset)?;
|
||||
|
||||
// Witness `d_1`
|
||||
region.assign_advice(
|
||||
|
@ -579,30 +576,27 @@ impl CommitIvkConfig {
|
|||
)?;
|
||||
|
||||
// Copy in z13_c
|
||||
copy(
|
||||
&mut region,
|
||||
gate_cells.z13_c.copy_advice(
|
||||
|| "z13_c",
|
||||
&mut region,
|
||||
self.advices[6],
|
||||
offset,
|
||||
&gate_cells.z13_c,
|
||||
)?;
|
||||
|
||||
// Copy in b2_c_prime
|
||||
copy(
|
||||
&mut region,
|
||||
gate_cells.b2_c_prime.copy_advice(
|
||||
|| "b2_c_prime",
|
||||
&mut region,
|
||||
self.advices[7],
|
||||
offset,
|
||||
&gate_cells.b2_c_prime,
|
||||
)?;
|
||||
|
||||
// Copy in z14_b2_c_prime
|
||||
copy(
|
||||
&mut region,
|
||||
gate_cells.z14_b2_c_prime.copy_advice(
|
||||
|| "z14_b2_c_prime",
|
||||
&mut region,
|
||||
self.advices[8],
|
||||
offset,
|
||||
&gate_cells.z14_b2_c_prime,
|
||||
)?;
|
||||
}
|
||||
|
||||
|
@ -614,23 +608,23 @@ impl CommitIvkConfig {
|
|||
|
||||
// Cells used in the canonicity gate.
|
||||
struct GateCells {
|
||||
a: CellValue<pallas::Base>,
|
||||
b: CellValue<pallas::Base>,
|
||||
c: CellValue<pallas::Base>,
|
||||
d: CellValue<pallas::Base>,
|
||||
ak: CellValue<pallas::Base>,
|
||||
nk: CellValue<pallas::Base>,
|
||||
b_0: CellValue<pallas::Base>,
|
||||
a: AssignedCell<pallas::Base, pallas::Base>,
|
||||
b: AssignedCell<pallas::Base, pallas::Base>,
|
||||
c: AssignedCell<pallas::Base, pallas::Base>,
|
||||
d: AssignedCell<pallas::Base, pallas::Base>,
|
||||
ak: AssignedCell<pallas::Base, pallas::Base>,
|
||||
nk: AssignedCell<pallas::Base, pallas::Base>,
|
||||
b_0: AssignedCell<pallas::Base, pallas::Base>,
|
||||
b_1: Option<pallas::Base>,
|
||||
b_2: CellValue<pallas::Base>,
|
||||
d_0: CellValue<pallas::Base>,
|
||||
b_2: AssignedCell<pallas::Base, pallas::Base>,
|
||||
d_0: AssignedCell<pallas::Base, pallas::Base>,
|
||||
d_1: Option<pallas::Base>,
|
||||
z13_a: CellValue<pallas::Base>,
|
||||
a_prime: CellValue<pallas::Base>,
|
||||
z13_a_prime: CellValue<pallas::Base>,
|
||||
z13_c: CellValue<pallas::Base>,
|
||||
b2_c_prime: CellValue<pallas::Base>,
|
||||
z14_b2_c_prime: CellValue<pallas::Base>,
|
||||
z13_a: AssignedCell<pallas::Base, pallas::Base>,
|
||||
a_prime: AssignedCell<pallas::Base, pallas::Base>,
|
||||
z13_a_prime: AssignedCell<pallas::Base, pallas::Base>,
|
||||
z13_c: AssignedCell<pallas::Base, pallas::Base>,
|
||||
b2_c_prime: AssignedCell<pallas::Base, pallas::Base>,
|
||||
z14_b2_c_prime: AssignedCell<pallas::Base, pallas::Base>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -640,16 +634,14 @@ mod tests {
|
|||
circuit::gadget::{
|
||||
ecc::chip::{EccChip, EccConfig},
|
||||
sinsemilla::chip::SinsemillaChip,
|
||||
utilities::{
|
||||
lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions, Var,
|
||||
},
|
||||
utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions},
|
||||
},
|
||||
constants::{COMMIT_IVK_PERSONALIZATION, L_ORCHARD_BASE, T_Q},
|
||||
primitives::sinsemilla::CommitDomain,
|
||||
};
|
||||
use ff::PrimeFieldBits;
|
||||
use halo2::{
|
||||
circuit::{Layouter, SimpleFloorPlanner},
|
||||
circuit::{AssignedCell, Layouter, SimpleFloorPlanner},
|
||||
dev::MockProver,
|
||||
plonk::{Circuit, ConstraintSystem, Error},
|
||||
};
|
||||
|
@ -666,7 +658,7 @@ mod tests {
|
|||
}
|
||||
|
||||
impl UtilitiesInstructions<pallas::Base> for MyCircuit {
|
||||
type Var = CellValue<pallas::Base>;
|
||||
type Var = AssignedCell<pallas::Base, pallas::Base>;
|
||||
}
|
||||
|
||||
impl Circuit<pallas::Base> for MyCircuit {
|
||||
|
@ -803,7 +795,7 @@ mod tests {
|
|||
.unwrap()
|
||||
};
|
||||
|
||||
assert_eq!(expected_ivk, ivk.inner().value().unwrap());
|
||||
assert_eq!(&expected_ivk, ivk.inner().value().unwrap());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -139,7 +139,7 @@ pub mod tests {
|
|||
use crate::{
|
||||
circuit::gadget::{
|
||||
sinsemilla::chip::{SinsemillaChip, SinsemillaHashDomains},
|
||||
utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions, Var},
|
||||
utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions},
|
||||
},
|
||||
constants::MERKLE_DEPTH_ORCHARD,
|
||||
note::commitment::ExtractedNoteCommitment,
|
||||
|
@ -266,7 +266,7 @@ pub mod tests {
|
|||
};
|
||||
|
||||
// Check the computed final root against the expected final root.
|
||||
assert_eq!(computed_final_root.value().unwrap(), final_root.inner());
|
||||
assert_eq!(computed_final_root.value().unwrap(), &final_root.inner());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use halo2::{
|
||||
circuit::{Chip, Layouter},
|
||||
circuit::{AssignedCell, Chip, Layouter},
|
||||
plonk::{Advice, Column, ConstraintSystem, Error, Selector},
|
||||
poly::Rotation,
|
||||
};
|
||||
|
@ -15,7 +15,7 @@ use crate::{
|
|||
circuit::gadget::utilities::{
|
||||
bitrange_subset,
|
||||
cond_swap::{CondSwapChip, CondSwapConfig, CondSwapInstructions},
|
||||
copy, CellValue, UtilitiesInstructions, Var,
|
||||
UtilitiesInstructions,
|
||||
},
|
||||
constants::{L_ORCHARD_BASE, MERKLE_DEPTH_ORCHARD},
|
||||
primitives::sinsemilla,
|
||||
|
@ -185,7 +185,7 @@ impl MerkleInstructions<pallas::Affine, MERKLE_DEPTH_ORCHARD, { sinsemilla::K },
|
|||
let a = {
|
||||
let a = {
|
||||
// a_0 = l
|
||||
let a_0 = bitrange_subset(pallas::Base::from_u64(l as u64), 0..10);
|
||||
let a_0 = bitrange_subset(&pallas::Base::from_u64(l as u64), 0..10);
|
||||
|
||||
// a_1 = (bits 0..=239 of `left`)
|
||||
let a_1 = left.value().map(|value| bitrange_subset(value, 0..240));
|
||||
|
@ -257,10 +257,10 @@ impl MerkleInstructions<pallas::Affine, MERKLE_DEPTH_ORCHARD, { sinsemilla::K },
|
|||
let (point, zs) = self.hash_to_point(
|
||||
layouter.namespace(|| format!("hash at l = {}", l)),
|
||||
Q,
|
||||
vec![a, b, c].into(),
|
||||
vec![a.clone(), b.clone(), c.clone()].into(),
|
||||
)?;
|
||||
let z1_a = zs[0][1];
|
||||
let z1_b = zs[1][1];
|
||||
let z1_a = zs[0][1].clone();
|
||||
let z1_b = zs[1][1].clone();
|
||||
|
||||
// Check that the pieces have been decomposed properly.
|
||||
/*
|
||||
|
@ -287,43 +287,28 @@ impl MerkleInstructions<pallas::Affine, MERKLE_DEPTH_ORCHARD, { sinsemilla::K },
|
|||
|
||||
// Offset 0
|
||||
// Copy and assign `a` at the correct position.
|
||||
copy(
|
||||
&mut region,
|
||||
|| "copy a",
|
||||
config.advices[0],
|
||||
0,
|
||||
&a.cell_value(),
|
||||
)?;
|
||||
a.cell_value()
|
||||
.copy_advice(|| "copy a", &mut region, config.advices[0], 0)?;
|
||||
// Copy and assign `b` at the correct position.
|
||||
copy(
|
||||
&mut region,
|
||||
|| "copy b",
|
||||
config.advices[1],
|
||||
0,
|
||||
&b.cell_value(),
|
||||
)?;
|
||||
b.cell_value()
|
||||
.copy_advice(|| "copy b", &mut region, config.advices[1], 0)?;
|
||||
// Copy and assign `c` at the correct position.
|
||||
copy(
|
||||
&mut region,
|
||||
|| "copy c",
|
||||
config.advices[2],
|
||||
0,
|
||||
&c.cell_value(),
|
||||
)?;
|
||||
c.cell_value()
|
||||
.copy_advice(|| "copy c", &mut region, config.advices[2], 0)?;
|
||||
// Copy and assign the left node at the correct position.
|
||||
copy(&mut region, || "left", config.advices[3], 0, &left)?;
|
||||
left.copy_advice(|| "left", &mut region, config.advices[3], 0)?;
|
||||
// Copy and assign the right node at the correct position.
|
||||
copy(&mut region, || "right", config.advices[4], 0, &right)?;
|
||||
right.copy_advice(|| "right", &mut region, config.advices[4], 0)?;
|
||||
|
||||
// Offset 1
|
||||
// Copy and assign z_1 of SinsemillaHash(a) = a_1
|
||||
copy(&mut region, || "z1_a", config.advices[0], 1, &z1_a)?;
|
||||
z1_a.copy_advice(|| "z1_a", &mut region, config.advices[0], 1)?;
|
||||
// Copy and assign z_1 of SinsemillaHash(b) = b_1
|
||||
copy(&mut region, || "z1_b", config.advices[1], 1, &z1_b)?;
|
||||
z1_b.copy_advice(|| "z1_b", &mut region, config.advices[1], 1)?;
|
||||
// Copy `b_1`, which has been constrained to be a 5-bit value
|
||||
copy(&mut region, || "b_1", config.advices[2], 1, &b_1)?;
|
||||
b_1.copy_advice(|| "b_1", &mut region, config.advices[2], 1)?;
|
||||
// Copy `b_2`, which has been constrained to be a 5-bit value
|
||||
copy(&mut region, || "b_2", config.advices[3], 1, &b_2)?;
|
||||
b_2.copy_advice(|| "b_2", &mut region, config.advices[3], 1)?;
|
||||
|
||||
Ok(())
|
||||
},
|
||||
|
@ -372,7 +357,7 @@ impl MerkleInstructions<pallas::Affine, MERKLE_DEPTH_ORCHARD, { sinsemilla::K },
|
|||
}
|
||||
|
||||
impl UtilitiesInstructions<pallas::Base> for MerkleChip {
|
||||
type Var = CellValue<pallas::Base>;
|
||||
type Var = AssignedCell<pallas::Base, pallas::Base>;
|
||||
}
|
||||
|
||||
impl CondSwapInstructions<pallas::Base> for MerkleChip {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
//! Gadget and chips for the Sinsemilla hash function.
|
||||
use crate::circuit::gadget::utilities::{CellValue, Var};
|
||||
use ff::PrimeFieldBits;
|
||||
use halo2::{arithmetic::FieldExt, circuit::Cell};
|
||||
use halo2::{
|
||||
arithmetic::FieldExt,
|
||||
circuit::{AssignedCell, Cell},
|
||||
};
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// A [`Message`] composed of several [`MessagePiece`]s.
|
||||
|
@ -32,17 +34,16 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize, const MAX_WORDS: usize> std::
|
|||
///
|
||||
/// The piece must fit within a base field element, which means its length
|
||||
/// cannot exceed the base field's `NUM_BITS`.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MessagePiece<F: FieldExt, const K: usize> {
|
||||
cell_value: CellValue<F>,
|
||||
cell_value: AssignedCell<F, F>,
|
||||
/// The number of K-bit words in this message piece.
|
||||
num_words: usize,
|
||||
}
|
||||
|
||||
impl<F: FieldExt + PrimeFieldBits, const K: usize> MessagePiece<F, K> {
|
||||
pub fn new(cell: Cell, field_elem: Option<F>, num_words: usize) -> Self {
|
||||
pub fn new(cell_value: AssignedCell<F, F>, num_words: usize) -> Self {
|
||||
assert!(num_words * K < F::NUM_BITS as usize);
|
||||
let cell_value = CellValue::new(cell, field_elem);
|
||||
Self {
|
||||
cell_value,
|
||||
num_words,
|
||||
|
@ -58,10 +59,10 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> MessagePiece<F, K> {
|
|||
}
|
||||
|
||||
pub fn field_elem(&self) -> Option<F> {
|
||||
self.cell_value.value()
|
||||
self.cell_value.value().cloned()
|
||||
}
|
||||
|
||||
pub fn cell_value(&self) -> CellValue<F> {
|
||||
self.cell_value
|
||||
pub fn cell_value(&self) -> AssignedCell<F, F> {
|
||||
self.cell_value.clone()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use halo2::{
|
||||
circuit::Layouter,
|
||||
circuit::{AssignedCell, Layouter},
|
||||
plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector},
|
||||
poly::Rotation,
|
||||
};
|
||||
|
@ -11,7 +11,7 @@ use crate::{
|
|||
chip::{EccChip, NonIdentityEccPoint},
|
||||
Point,
|
||||
},
|
||||
utilities::{bitrange_subset, bool_check, copy, CellValue, Var},
|
||||
utilities::{bitrange_subset, bool_check},
|
||||
},
|
||||
constants::T_P,
|
||||
};
|
||||
|
@ -21,6 +21,13 @@ use super::{
|
|||
CommitDomain, Message, MessagePiece,
|
||||
};
|
||||
|
||||
/// The values of the running sum at the start and end of the range being used for a
|
||||
/// canonicity check.
|
||||
type CanonicityBounds = (
|
||||
AssignedCell<pallas::Base, pallas::Base>,
|
||||
AssignedCell<pallas::Base, pallas::Base>,
|
||||
);
|
||||
|
||||
/*
|
||||
<https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit>
|
||||
We need to hash g★_d || pk★_d || i2lebsp_{64}(v) || rho || psi,
|
||||
|
@ -525,13 +532,16 @@ impl NoteCommitConfig {
|
|||
ecc_chip: EccChip,
|
||||
g_d: &NonIdentityEccPoint,
|
||||
pk_d: &NonIdentityEccPoint,
|
||||
value: CellValue<pallas::Base>,
|
||||
rho: CellValue<pallas::Base>,
|
||||
psi: CellValue<pallas::Base>,
|
||||
// TODO: Set V to Orchard value type
|
||||
value: AssignedCell<pallas::Base, pallas::Base>,
|
||||
rho: AssignedCell<pallas::Base, pallas::Base>,
|
||||
psi: AssignedCell<pallas::Base, pallas::Base>,
|
||||
rcm: Option<pallas::Scalar>,
|
||||
) -> Result<Point<pallas::Affine, EccChip>, 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 (gd_x, gd_y) = (g_d.x(), g_d.y());
|
||||
let (pkd_x, pkd_y) = (pk_d.x(), pk_d.y());
|
||||
let (gd_x, gd_y) = (gd_x.value(), gd_y.value());
|
||||
let (pkd_x, pkd_y) = (pkd_x.value(), pkd_y.value());
|
||||
let value_val = value.value();
|
||||
let rho_val = rho.value();
|
||||
let psi_val = psi.value();
|
||||
|
@ -738,13 +748,13 @@ impl NoteCommitConfig {
|
|||
)?
|
||||
};
|
||||
|
||||
let z13_a = zs[0][13];
|
||||
let z13_c = zs[2][13];
|
||||
let z1_d = zs[3][1];
|
||||
let z13_f = zs[5][13];
|
||||
let z1_g = zs[6][1];
|
||||
let g_2 = z1_g;
|
||||
let z13_g = zs[6][13];
|
||||
let z13_a = zs[0][13].clone();
|
||||
let z13_c = zs[2][13].clone();
|
||||
let z1_d = zs[3][1].clone();
|
||||
let z13_f = zs[5][13].clone();
|
||||
let z1_g = zs[6][1].clone();
|
||||
let g_2 = z1_g.clone();
|
||||
let z13_g = zs[6][13].clone();
|
||||
|
||||
let (a_prime, z13_a_prime) = self.canon_bitshift_130(
|
||||
layouter.namespace(|| "x(g_d) canonicity"),
|
||||
|
@ -753,18 +763,18 @@ impl NoteCommitConfig {
|
|||
|
||||
let (b3_c_prime, z14_b3_c_prime) = self.pkd_x_canonicity(
|
||||
layouter.namespace(|| "x(pk_d) canonicity"),
|
||||
b_3,
|
||||
b_3.clone(),
|
||||
c.inner().cell_value(),
|
||||
)?;
|
||||
|
||||
let (e1_f_prime, z14_e1_f_prime) = self.rho_canonicity(
|
||||
layouter.namespace(|| "rho canonicity"),
|
||||
e_1,
|
||||
e_1.clone(),
|
||||
f.inner().cell_value(),
|
||||
)?;
|
||||
|
||||
let (g1_g2_prime, z13_g1_g2_prime) =
|
||||
self.psi_canonicity(layouter.namespace(|| "psi canonicity"), g_1, g_2)?;
|
||||
self.psi_canonicity(layouter.namespace(|| "psi canonicity"), g_1.clone(), g_2)?;
|
||||
|
||||
let gate_cells = GateCells {
|
||||
a: a.inner().cell_value(),
|
||||
|
@ -814,13 +824,12 @@ impl NoteCommitConfig {
|
|||
Ok(cm)
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
// A canonicity check helper used in checking x(g_d), y(g_d), and y(pk_d).
|
||||
fn canon_bitshift_130(
|
||||
&self,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
a: CellValue<pallas::Base>,
|
||||
) -> Result<(CellValue<pallas::Base>, CellValue<pallas::Base>), Error> {
|
||||
a: AssignedCell<pallas::Base, pallas::Base>,
|
||||
) -> Result<CanonicityBounds, Error> {
|
||||
// element = `a (250 bits) || b_0 (4 bits) || b_1 (1 bit)`
|
||||
// - b_1 = 1 => b_0 = 0
|
||||
// - b_1 = 1 => a < t_P
|
||||
|
@ -841,19 +850,19 @@ impl NoteCommitConfig {
|
|||
13,
|
||||
false,
|
||||
)?;
|
||||
let a_prime = zs[0];
|
||||
let a_prime = zs[0].clone();
|
||||
assert_eq!(zs.len(), 14); // [z_0, z_1, ..., z_13]
|
||||
|
||||
Ok((a_prime, zs[13]))
|
||||
Ok((a_prime, zs[13].clone()))
|
||||
}
|
||||
|
||||
// Check canonicity of `x(pk_d)` encoding
|
||||
fn pkd_x_canonicity(
|
||||
&self,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
b_3: CellValue<pallas::Base>,
|
||||
c: CellValue<pallas::Base>,
|
||||
) -> Result<(CellValue<pallas::Base>, CellValue<pallas::Base>), Error> {
|
||||
b_3: AssignedCell<pallas::Base, pallas::Base>,
|
||||
c: AssignedCell<pallas::Base, pallas::Base>,
|
||||
) -> Result<CanonicityBounds, Error> {
|
||||
// `x(pk_d)` = `b_3 (4 bits) || c (250 bits) || d_0 (1 bit)`
|
||||
// - d_0 = 1 => b_3 + 2^4 c < t_P
|
||||
// - 0 ≤ b_3 + 2^4 c < 2^134
|
||||
|
@ -880,20 +889,19 @@ impl NoteCommitConfig {
|
|||
14,
|
||||
false,
|
||||
)?;
|
||||
let b3_c_prime = zs[0];
|
||||
let b3_c_prime = zs[0].clone();
|
||||
assert_eq!(zs.len(), 15); // [z_0, z_1, ..., z_13, z_14]
|
||||
|
||||
Ok((b3_c_prime, zs[14]))
|
||||
Ok((b3_c_prime, zs[14].clone()))
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
// Check canonicity of `rho` encoding
|
||||
fn rho_canonicity(
|
||||
&self,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
e_1: CellValue<pallas::Base>,
|
||||
f: CellValue<pallas::Base>,
|
||||
) -> Result<(CellValue<pallas::Base>, CellValue<pallas::Base>), Error> {
|
||||
e_1: AssignedCell<pallas::Base, pallas::Base>,
|
||||
f: AssignedCell<pallas::Base, pallas::Base>,
|
||||
) -> Result<CanonicityBounds, Error> {
|
||||
// `rho` = `e_1 (4 bits) || f (250 bits) || g_0 (1 bit)`
|
||||
// - g_0 = 1 => e_1 + 2^4 f < t_P
|
||||
// - 0 ≤ e_1 + 2^4 f < 2^134
|
||||
|
@ -920,19 +928,19 @@ impl NoteCommitConfig {
|
|||
14,
|
||||
false,
|
||||
)?;
|
||||
let e1_f_prime = zs[0];
|
||||
let e1_f_prime = zs[0].clone();
|
||||
assert_eq!(zs.len(), 15); // [z_0, z_1, ..., z_13, z_14]
|
||||
|
||||
Ok((e1_f_prime, zs[14]))
|
||||
Ok((e1_f_prime, zs[14].clone()))
|
||||
}
|
||||
|
||||
// Check canonicity of `psi` encoding
|
||||
fn psi_canonicity(
|
||||
&self,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
g_1: CellValue<pallas::Base>,
|
||||
g_2: CellValue<pallas::Base>,
|
||||
) -> Result<(CellValue<pallas::Base>, CellValue<pallas::Base>), Error> {
|
||||
g_1: AssignedCell<pallas::Base, pallas::Base>,
|
||||
g_2: AssignedCell<pallas::Base, pallas::Base>,
|
||||
) -> Result<CanonicityBounds, Error> {
|
||||
// `psi` = `g_1 (9 bits) || g_2 (240 bits) || h_0 (5 bits) || h_1 (1 bit)`
|
||||
// - h_1 = 1 => (h_0 = 0) ∧ (g_1 + 2^9 g_2 < t_P)
|
||||
// - 0 ≤ g_1 + 2^9 g_2 < 2^130
|
||||
|
@ -957,10 +965,10 @@ impl NoteCommitConfig {
|
|||
13,
|
||||
false,
|
||||
)?;
|
||||
let g1_g2_prime = zs[0];
|
||||
let g1_g2_prime = zs[0].clone();
|
||||
assert_eq!(zs.len(), 14); // [z_0, z_1, ..., z_13]
|
||||
|
||||
Ok((g1_g2_prime, zs[13]))
|
||||
Ok((g1_g2_prime, zs[13].clone()))
|
||||
}
|
||||
|
||||
// Check canonicity of y-coordinate given its LSB as a value.
|
||||
|
@ -968,9 +976,9 @@ impl NoteCommitConfig {
|
|||
fn y_canonicity(
|
||||
&self,
|
||||
mut layouter: impl Layouter<pallas::Base>,
|
||||
y: CellValue<pallas::Base>,
|
||||
y: AssignedCell<pallas::Base, pallas::Base>,
|
||||
lsb: Option<pallas::Base>,
|
||||
) -> Result<CellValue<pallas::Base>, Error> {
|
||||
) -> Result<AssignedCell<pallas::Base, pallas::Base>, Error> {
|
||||
// Decompose the field element
|
||||
// y = LSB || k_0 || k_1 || k_2 || k_3
|
||||
// = (bit 0) || (bits 1..=9) || (bits 10..=249) || (bits 250..=253) || (bit 254)
|
||||
|
@ -1010,13 +1018,15 @@ impl NoteCommitConfig {
|
|||
25,
|
||||
true,
|
||||
)?;
|
||||
(zs[0], zs[1], zs[13])
|
||||
(zs[0].clone(), zs[1].clone(), zs[13].clone())
|
||||
};
|
||||
|
||||
// Decompose j_prime = j + 2^130 - t_P using 13 ten-bit lookups.
|
||||
// We can reuse the canon_bitshift_130 logic here.
|
||||
let (j_prime, z13_j_prime) =
|
||||
self.canon_bitshift_130(layouter.namespace(|| "j_prime = j + 2^130 - t_P"), j)?;
|
||||
let (j_prime, z13_j_prime) = self.canon_bitshift_130(
|
||||
layouter.namespace(|| "j_prime = j + 2^130 - t_P"),
|
||||
j.clone(),
|
||||
)?;
|
||||
|
||||
/*
|
||||
|
||||
|
@ -1037,21 +1047,18 @@ impl NoteCommitConfig {
|
|||
let offset = 0;
|
||||
|
||||
// Copy y.
|
||||
copy(&mut region, || "copy y", self.advices[5], offset, &y)?;
|
||||
y.copy_advice(|| "copy y", &mut region, self.advices[5], offset)?;
|
||||
// Witness LSB.
|
||||
let lsb = {
|
||||
let cell = region.assign_advice(
|
||||
|| "witness LSB",
|
||||
self.advices[6],
|
||||
offset,
|
||||
|| lsb.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
CellValue::new(cell, lsb)
|
||||
};
|
||||
let lsb = region.assign_advice(
|
||||
|| "witness LSB",
|
||||
self.advices[6],
|
||||
offset,
|
||||
|| lsb.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
// Witness k_0.
|
||||
copy(&mut region, || "copy k_0", self.advices[7], offset, &k_0)?;
|
||||
k_0.copy_advice(|| "copy k_0", &mut region, self.advices[7], offset)?;
|
||||
// Copy k_2.
|
||||
copy(&mut region, || "copy k_2", self.advices[8], offset, &k_2)?;
|
||||
k_2.copy_advice(|| "copy k_2", &mut region, self.advices[8], offset)?;
|
||||
// Witness k_3.
|
||||
region.assign_advice(
|
||||
|| "witness k_3",
|
||||
|
@ -1068,32 +1075,19 @@ impl NoteCommitConfig {
|
|||
let offset = 1;
|
||||
|
||||
// Copy j.
|
||||
copy(&mut region, || "copy j", self.advices[5], offset, &j)?;
|
||||
j.copy_advice(|| "copy j", &mut region, self.advices[5], offset)?;
|
||||
// Copy z1_j.
|
||||
copy(&mut region, || "copy z1_j", self.advices[6], offset, &z1_j)?;
|
||||
z1_j.copy_advice(|| "copy z1_j", &mut region, self.advices[6], offset)?;
|
||||
// Copy z13_j.
|
||||
copy(
|
||||
&mut region,
|
||||
|| "copy z13_j",
|
||||
self.advices[7],
|
||||
offset,
|
||||
&z13_j,
|
||||
)?;
|
||||
z13_j.copy_advice(|| "copy z13_j", &mut region, self.advices[7], offset)?;
|
||||
// Copy j_prime.
|
||||
copy(
|
||||
&mut region,
|
||||
|| "copy j_prime",
|
||||
self.advices[8],
|
||||
offset,
|
||||
&j_prime,
|
||||
)?;
|
||||
j_prime.copy_advice(|| "copy j_prime", &mut region, self.advices[8], offset)?;
|
||||
// Copy z13_j_prime.
|
||||
copy(
|
||||
&mut region,
|
||||
z13_j_prime.copy_advice(
|
||||
|| "copy z13_j_prime",
|
||||
&mut region,
|
||||
self.advices[9],
|
||||
offset,
|
||||
&z13_j_prime,
|
||||
)?;
|
||||
}
|
||||
|
||||
|
@ -1122,20 +1116,23 @@ impl NoteCommitConfig {
|
|||
|mut region| {
|
||||
self.q_notecommit_b.enable(&mut region, 0)?;
|
||||
|
||||
copy(&mut region, || "b", col_l, 0, &gate_cells.b)?;
|
||||
copy(&mut region, || "b_0", col_m, 0, &gate_cells.b_0)?;
|
||||
let b_1 = {
|
||||
let cell = region.assign_advice(
|
||||
|| "b_1",
|
||||
col_r,
|
||||
0,
|
||||
|| gate_cells.b_1.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
CellValue::new(cell, gate_cells.b_1)
|
||||
};
|
||||
gate_cells.b.copy_advice(|| "b", &mut region, col_l, 0)?;
|
||||
gate_cells
|
||||
.b_0
|
||||
.copy_advice(|| "b_0", &mut region, col_m, 0)?;
|
||||
let b_1 = region.assign_advice(
|
||||
|| "b_1",
|
||||
col_r,
|
||||
0,
|
||||
|| gate_cells.b_1.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
|
||||
copy(&mut region, || "b_2", col_m, 1, &gate_cells.b_2)?;
|
||||
copy(&mut region, || "b_3", col_r, 1, &gate_cells.b_3)?;
|
||||
gate_cells
|
||||
.b_2
|
||||
.copy_advice(|| "b_2", &mut region, col_m, 1)?;
|
||||
gate_cells
|
||||
.b_3
|
||||
.copy_advice(|| "b_3", &mut region, col_r, 1)?;
|
||||
|
||||
Ok(b_1)
|
||||
},
|
||||
|
@ -1150,20 +1147,23 @@ impl NoteCommitConfig {
|
|||
|mut region| {
|
||||
self.q_notecommit_d.enable(&mut region, 0)?;
|
||||
|
||||
copy(&mut region, || "d", col_l, 0, &gate_cells.d)?;
|
||||
let d_0 = {
|
||||
let cell = region.assign_advice(
|
||||
|| "d_0",
|
||||
col_m,
|
||||
0,
|
||||
|| gate_cells.d_0.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
CellValue::new(cell, gate_cells.d_0)
|
||||
};
|
||||
copy(&mut region, || "d_1", col_r, 0, &gate_cells.d_1)?;
|
||||
gate_cells.d.copy_advice(|| "d", &mut region, col_l, 0)?;
|
||||
let d_0 = region.assign_advice(
|
||||
|| "d_0",
|
||||
col_m,
|
||||
0,
|
||||
|| gate_cells.d_0.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
gate_cells
|
||||
.d_1
|
||||
.copy_advice(|| "d_1", &mut region, col_r, 0)?;
|
||||
|
||||
copy(&mut region, || "d_2", col_m, 1, &gate_cells.d_2)?;
|
||||
copy(&mut region, || "d_3 = z1_d", col_r, 1, &gate_cells.z1_d)?;
|
||||
gate_cells
|
||||
.d_2
|
||||
.copy_advice(|| "d_2", &mut region, col_m, 1)?;
|
||||
gate_cells
|
||||
.z1_d
|
||||
.copy_advice(|| "d_3 = z1_d", &mut region, col_r, 1)?;
|
||||
|
||||
Ok(d_0)
|
||||
},
|
||||
|
@ -1177,9 +1177,13 @@ impl NoteCommitConfig {
|
|||
|mut region| {
|
||||
self.q_notecommit_e.enable(&mut region, 0)?;
|
||||
|
||||
copy(&mut region, || "e", col_l, 0, &gate_cells.e)?;
|
||||
copy(&mut region, || "e_0", col_m, 0, &gate_cells.e_0)?;
|
||||
copy(&mut region, || "e_1", col_r, 0, &gate_cells.e_1)?;
|
||||
gate_cells.e.copy_advice(|| "e", &mut region, col_l, 0)?;
|
||||
gate_cells
|
||||
.e_0
|
||||
.copy_advice(|| "e_0", &mut region, col_m, 0)?;
|
||||
gate_cells
|
||||
.e_1
|
||||
.copy_advice(|| "e_1", &mut region, col_r, 0)?;
|
||||
|
||||
Ok(())
|
||||
},
|
||||
|
@ -1194,19 +1198,20 @@ impl NoteCommitConfig {
|
|||
|mut region| {
|
||||
self.q_notecommit_g.enable(&mut region, 0)?;
|
||||
|
||||
copy(&mut region, || "g", col_l, 0, &gate_cells.g)?;
|
||||
let g_0 = {
|
||||
let cell = region.assign_advice(
|
||||
|| "g_0",
|
||||
col_m,
|
||||
0,
|
||||
|| gate_cells.g_0.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
CellValue::new(cell, gate_cells.g_0)
|
||||
};
|
||||
gate_cells.g.copy_advice(|| "g", &mut region, col_l, 0)?;
|
||||
let g_0 = region.assign_advice(
|
||||
|| "g_0",
|
||||
col_m,
|
||||
0,
|
||||
|| gate_cells.g_0.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
|
||||
copy(&mut region, || "g_1", col_l, 1, &gate_cells.g_1)?;
|
||||
copy(&mut region, || "g_2 = z1_g", col_m, 1, &gate_cells.z1_g)?;
|
||||
gate_cells
|
||||
.g_1
|
||||
.copy_advice(|| "g_1", &mut region, col_l, 1)?;
|
||||
gate_cells
|
||||
.z1_g
|
||||
.copy_advice(|| "g_2 = z1_g", &mut region, col_m, 1)?;
|
||||
|
||||
Ok(g_0)
|
||||
},
|
||||
|
@ -1220,17 +1225,16 @@ impl NoteCommitConfig {
|
|||
|mut region| {
|
||||
self.q_notecommit_h.enable(&mut region, 0)?;
|
||||
|
||||
copy(&mut region, || "h", col_l, 0, &gate_cells.h)?;
|
||||
copy(&mut region, || "h_0", col_m, 0, &gate_cells.h_0)?;
|
||||
let h_1 = {
|
||||
let cell = region.assign_advice(
|
||||
|| "h_1",
|
||||
col_r,
|
||||
0,
|
||||
|| gate_cells.h_1.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
CellValue::new(cell, gate_cells.h_1)
|
||||
};
|
||||
gate_cells.h.copy_advice(|| "h", &mut region, col_l, 0)?;
|
||||
gate_cells
|
||||
.h_0
|
||||
.copy_advice(|| "h_0", &mut region, col_m, 0)?;
|
||||
let h_1 = region.assign_advice(
|
||||
|| "h_1",
|
||||
col_r,
|
||||
0,
|
||||
|| gate_cells.h_1.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
|
||||
Ok(h_1)
|
||||
},
|
||||
|
@ -1243,22 +1247,26 @@ impl NoteCommitConfig {
|
|||
layouter.assign_region(
|
||||
|| "NoteCommit input g_d",
|
||||
|mut region| {
|
||||
copy(&mut region, || "gd_x", col_l, 0, &gate_cells.gd_x)?;
|
||||
gate_cells
|
||||
.gd_x
|
||||
.copy_advice(|| "gd_x", &mut region, col_l, 0)?;
|
||||
|
||||
copy(&mut region, || "b_0", col_m, 0, &gate_cells.b_0)?;
|
||||
copy(&mut region, || "b_1", col_m, 1, &b_1)?;
|
||||
gate_cells
|
||||
.b_0
|
||||
.copy_advice(|| "b_0", &mut region, col_m, 0)?;
|
||||
b_1.copy_advice(|| "b_1", &mut region, col_m, 1)?;
|
||||
|
||||
copy(&mut region, || "a", col_r, 0, &gate_cells.a)?;
|
||||
copy(&mut region, || "a_prime", col_r, 1, &gate_cells.a_prime)?;
|
||||
gate_cells.a.copy_advice(|| "a", &mut region, col_r, 0)?;
|
||||
gate_cells
|
||||
.a_prime
|
||||
.copy_advice(|| "a_prime", &mut region, col_r, 1)?;
|
||||
|
||||
copy(&mut region, || "z13_a", col_z, 0, &gate_cells.z13_a)?;
|
||||
copy(
|
||||
&mut region,
|
||||
|| "z13_a_prime",
|
||||
col_z,
|
||||
1,
|
||||
&gate_cells.z13_a_prime,
|
||||
)?;
|
||||
gate_cells
|
||||
.z13_a
|
||||
.copy_advice(|| "z13_a", &mut region, col_z, 0)?;
|
||||
gate_cells
|
||||
.z13_a_prime
|
||||
.copy_advice(|| "z13_a_prime", &mut region, col_z, 1)?;
|
||||
|
||||
self.q_notecommit_g_d.enable(&mut region, 0)
|
||||
},
|
||||
|
@ -1271,27 +1279,28 @@ impl NoteCommitConfig {
|
|||
layouter.assign_region(
|
||||
|| "NoteCommit input pk_d",
|
||||
|mut region| {
|
||||
copy(&mut region, || "pkd_x", col_l, 0, &gate_cells.pkd_x)?;
|
||||
gate_cells
|
||||
.pkd_x
|
||||
.copy_advice(|| "pkd_x", &mut region, col_l, 0)?;
|
||||
|
||||
copy(&mut region, || "b_3", col_m, 0, &gate_cells.b_3)?;
|
||||
copy(&mut region, || "d_0", col_m, 1, &d_0)?;
|
||||
gate_cells
|
||||
.b_3
|
||||
.copy_advice(|| "b_3", &mut region, col_m, 0)?;
|
||||
d_0.copy_advice(|| "d_0", &mut region, col_m, 1)?;
|
||||
|
||||
copy(&mut region, || "c", col_r, 0, &gate_cells.c)?;
|
||||
copy(
|
||||
&mut region,
|
||||
|| "b3_c_prime",
|
||||
col_r,
|
||||
1,
|
||||
&gate_cells.b3_c_prime,
|
||||
)?;
|
||||
gate_cells.c.copy_advice(|| "c", &mut region, col_r, 0)?;
|
||||
gate_cells
|
||||
.b3_c_prime
|
||||
.copy_advice(|| "b3_c_prime", &mut region, col_r, 1)?;
|
||||
|
||||
copy(&mut region, || "z13_c", col_z, 0, &gate_cells.z13_c)?;
|
||||
copy(
|
||||
&mut region,
|
||||
gate_cells
|
||||
.z13_c
|
||||
.copy_advice(|| "z13_c", &mut region, col_z, 0)?;
|
||||
gate_cells.z14_b3_c_prime.copy_advice(
|
||||
|| "z14_b3_c_prime",
|
||||
&mut region,
|
||||
col_z,
|
||||
1,
|
||||
&gate_cells.z14_b3_c_prime,
|
||||
)?;
|
||||
|
||||
self.q_notecommit_pk_d.enable(&mut region, 0)
|
||||
|
@ -1302,10 +1311,18 @@ impl NoteCommitConfig {
|
|||
layouter.assign_region(
|
||||
|| "NoteCommit input value",
|
||||
|mut region| {
|
||||
copy(&mut region, || "value", col_l, 0, &gate_cells.value)?;
|
||||
copy(&mut region, || "d_2", col_m, 0, &gate_cells.d_2)?;
|
||||
copy(&mut region, || "d3 = z1_d", col_r, 0, &gate_cells.z1_d)?;
|
||||
copy(&mut region, || "e_0", col_z, 0, &gate_cells.e_0)?;
|
||||
gate_cells
|
||||
.value
|
||||
.copy_advice(|| "value", &mut region, col_l, 0)?;
|
||||
gate_cells
|
||||
.d_2
|
||||
.copy_advice(|| "d_2", &mut region, col_m, 0)?;
|
||||
gate_cells
|
||||
.z1_d
|
||||
.copy_advice(|| "d3 = z1_d", &mut region, col_r, 0)?;
|
||||
gate_cells
|
||||
.e_0
|
||||
.copy_advice(|| "e_0", &mut region, col_z, 0)?;
|
||||
|
||||
self.q_notecommit_value.enable(&mut region, 0)
|
||||
},
|
||||
|
@ -1318,27 +1335,28 @@ impl NoteCommitConfig {
|
|||
layouter.assign_region(
|
||||
|| "NoteCommit input rho",
|
||||
|mut region| {
|
||||
copy(&mut region, || "rho", col_l, 0, &gate_cells.rho)?;
|
||||
gate_cells
|
||||
.rho
|
||||
.copy_advice(|| "rho", &mut region, col_l, 0)?;
|
||||
|
||||
copy(&mut region, || "e_1", col_m, 0, &gate_cells.e_1)?;
|
||||
copy(&mut region, || "g_0", col_m, 1, &g_0)?;
|
||||
gate_cells
|
||||
.e_1
|
||||
.copy_advice(|| "e_1", &mut region, col_m, 0)?;
|
||||
g_0.copy_advice(|| "g_0", &mut region, col_m, 1)?;
|
||||
|
||||
copy(&mut region, || "f", col_r, 0, &gate_cells.f)?;
|
||||
copy(
|
||||
&mut region,
|
||||
|| "e1_f_prime",
|
||||
col_r,
|
||||
1,
|
||||
&gate_cells.e1_f_prime,
|
||||
)?;
|
||||
gate_cells.f.copy_advice(|| "f", &mut region, col_r, 0)?;
|
||||
gate_cells
|
||||
.e1_f_prime
|
||||
.copy_advice(|| "e1_f_prime", &mut region, col_r, 1)?;
|
||||
|
||||
copy(&mut region, || "z13_f", col_z, 0, &gate_cells.z13_f)?;
|
||||
copy(
|
||||
&mut region,
|
||||
gate_cells
|
||||
.z13_f
|
||||
.copy_advice(|| "z13_f", &mut region, col_z, 0)?;
|
||||
gate_cells.z14_e1_f_prime.copy_advice(
|
||||
|| "z14_e1_f_prime",
|
||||
&mut region,
|
||||
col_z,
|
||||
1,
|
||||
&gate_cells.z14_e1_f_prime,
|
||||
)?;
|
||||
|
||||
self.q_notecommit_rho.enable(&mut region, 0)
|
||||
|
@ -1352,28 +1370,33 @@ impl NoteCommitConfig {
|
|||
layouter.assign_region(
|
||||
|| "NoteCommit input psi",
|
||||
|mut region| {
|
||||
copy(&mut region, || "psi", col_l, 0, &gate_cells.psi)?;
|
||||
copy(&mut region, || "h_0", col_l, 1, &gate_cells.h_0)?;
|
||||
gate_cells
|
||||
.psi
|
||||
.copy_advice(|| "psi", &mut region, col_l, 0)?;
|
||||
gate_cells
|
||||
.h_0
|
||||
.copy_advice(|| "h_0", &mut region, col_l, 1)?;
|
||||
|
||||
copy(&mut region, || "g_1", col_m, 0, &gate_cells.g_1)?;
|
||||
copy(&mut region, || "h_1", col_m, 1, &h_1)?;
|
||||
gate_cells
|
||||
.g_1
|
||||
.copy_advice(|| "g_1", &mut region, col_m, 0)?;
|
||||
h_1.copy_advice(|| "h_1", &mut region, col_m, 1)?;
|
||||
|
||||
copy(&mut region, || "g_2 = z1_g", col_r, 0, &gate_cells.z1_g)?;
|
||||
copy(
|
||||
&mut region,
|
||||
|| "g1_g2_prime",
|
||||
col_r,
|
||||
1,
|
||||
&gate_cells.g1_g2_prime,
|
||||
)?;
|
||||
gate_cells
|
||||
.z1_g
|
||||
.copy_advice(|| "g_2 = z1_g", &mut region, col_r, 0)?;
|
||||
gate_cells
|
||||
.g1_g2_prime
|
||||
.copy_advice(|| "g1_g2_prime", &mut region, col_r, 1)?;
|
||||
|
||||
copy(&mut region, || "z13_g", col_z, 0, &gate_cells.z13_g)?;
|
||||
copy(
|
||||
&mut region,
|
||||
gate_cells
|
||||
.z13_g
|
||||
.copy_advice(|| "z13_g", &mut region, col_z, 0)?;
|
||||
gate_cells.z13_g1_g2_prime.copy_advice(
|
||||
|| "z13_g1_g2_prime",
|
||||
&mut region,
|
||||
col_z,
|
||||
1,
|
||||
&gate_cells.z13_g1_g2_prime,
|
||||
)?;
|
||||
|
||||
self.q_notecommit_psi.enable(&mut region, 0)
|
||||
|
@ -1383,46 +1406,46 @@ impl NoteCommitConfig {
|
|||
}
|
||||
|
||||
struct GateCells {
|
||||
a: CellValue<pallas::Base>,
|
||||
b: CellValue<pallas::Base>,
|
||||
b_0: CellValue<pallas::Base>,
|
||||
a: AssignedCell<pallas::Base, pallas::Base>,
|
||||
b: AssignedCell<pallas::Base, pallas::Base>,
|
||||
b_0: AssignedCell<pallas::Base, pallas::Base>,
|
||||
b_1: Option<pallas::Base>,
|
||||
b_2: CellValue<pallas::Base>,
|
||||
b_3: CellValue<pallas::Base>,
|
||||
c: CellValue<pallas::Base>,
|
||||
d: CellValue<pallas::Base>,
|
||||
b_2: AssignedCell<pallas::Base, pallas::Base>,
|
||||
b_3: AssignedCell<pallas::Base, pallas::Base>,
|
||||
c: AssignedCell<pallas::Base, pallas::Base>,
|
||||
d: AssignedCell<pallas::Base, pallas::Base>,
|
||||
d_0: Option<pallas::Base>,
|
||||
d_1: CellValue<pallas::Base>,
|
||||
d_2: CellValue<pallas::Base>,
|
||||
z1_d: CellValue<pallas::Base>,
|
||||
e: CellValue<pallas::Base>,
|
||||
e_0: CellValue<pallas::Base>,
|
||||
e_1: CellValue<pallas::Base>,
|
||||
f: CellValue<pallas::Base>,
|
||||
g: CellValue<pallas::Base>,
|
||||
d_1: AssignedCell<pallas::Base, pallas::Base>,
|
||||
d_2: AssignedCell<pallas::Base, pallas::Base>,
|
||||
z1_d: AssignedCell<pallas::Base, pallas::Base>,
|
||||
e: AssignedCell<pallas::Base, pallas::Base>,
|
||||
e_0: AssignedCell<pallas::Base, pallas::Base>,
|
||||
e_1: AssignedCell<pallas::Base, pallas::Base>,
|
||||
f: AssignedCell<pallas::Base, pallas::Base>,
|
||||
g: AssignedCell<pallas::Base, pallas::Base>,
|
||||
g_0: Option<pallas::Base>,
|
||||
g_1: CellValue<pallas::Base>,
|
||||
z1_g: CellValue<pallas::Base>,
|
||||
h: CellValue<pallas::Base>,
|
||||
h_0: CellValue<pallas::Base>,
|
||||
g_1: AssignedCell<pallas::Base, pallas::Base>,
|
||||
z1_g: AssignedCell<pallas::Base, pallas::Base>,
|
||||
h: AssignedCell<pallas::Base, pallas::Base>,
|
||||
h_0: AssignedCell<pallas::Base, pallas::Base>,
|
||||
h_1: Option<pallas::Base>,
|
||||
gd_x: CellValue<pallas::Base>,
|
||||
pkd_x: CellValue<pallas::Base>,
|
||||
value: CellValue<pallas::Base>,
|
||||
rho: CellValue<pallas::Base>,
|
||||
psi: CellValue<pallas::Base>,
|
||||
a_prime: CellValue<pallas::Base>,
|
||||
b3_c_prime: CellValue<pallas::Base>,
|
||||
e1_f_prime: CellValue<pallas::Base>,
|
||||
g1_g2_prime: CellValue<pallas::Base>,
|
||||
z13_a_prime: CellValue<pallas::Base>,
|
||||
z14_b3_c_prime: CellValue<pallas::Base>,
|
||||
z14_e1_f_prime: CellValue<pallas::Base>,
|
||||
z13_g1_g2_prime: CellValue<pallas::Base>,
|
||||
z13_a: CellValue<pallas::Base>,
|
||||
z13_c: CellValue<pallas::Base>,
|
||||
z13_f: CellValue<pallas::Base>,
|
||||
z13_g: CellValue<pallas::Base>,
|
||||
gd_x: AssignedCell<pallas::Base, pallas::Base>,
|
||||
pkd_x: AssignedCell<pallas::Base, pallas::Base>,
|
||||
value: AssignedCell<pallas::Base, pallas::Base>,
|
||||
rho: AssignedCell<pallas::Base, pallas::Base>,
|
||||
psi: AssignedCell<pallas::Base, pallas::Base>,
|
||||
a_prime: AssignedCell<pallas::Base, pallas::Base>,
|
||||
b3_c_prime: AssignedCell<pallas::Base, pallas::Base>,
|
||||
e1_f_prime: AssignedCell<pallas::Base, pallas::Base>,
|
||||
g1_g2_prime: AssignedCell<pallas::Base, pallas::Base>,
|
||||
z13_a_prime: AssignedCell<pallas::Base, pallas::Base>,
|
||||
z14_b3_c_prime: AssignedCell<pallas::Base, pallas::Base>,
|
||||
z14_e1_f_prime: AssignedCell<pallas::Base, pallas::Base>,
|
||||
z13_g1_g2_prime: AssignedCell<pallas::Base, pallas::Base>,
|
||||
z13_a: AssignedCell<pallas::Base, pallas::Base>,
|
||||
z13_c: AssignedCell<pallas::Base, pallas::Base>,
|
||||
z13_f: AssignedCell<pallas::Base, pallas::Base>,
|
||||
z13_g: AssignedCell<pallas::Base, pallas::Base>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1435,9 +1458,7 @@ mod tests {
|
|||
NonIdentityPoint,
|
||||
},
|
||||
sinsemilla::chip::SinsemillaChip,
|
||||
utilities::{
|
||||
lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions,
|
||||
},
|
||||
utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions},
|
||||
},
|
||||
constants::{L_ORCHARD_BASE, L_VALUE, NOTE_COMMITMENT_PERSONALIZATION, T_Q},
|
||||
primitives::sinsemilla::CommitDomain,
|
||||
|
@ -1446,7 +1467,7 @@ mod tests {
|
|||
use ff::{Field, PrimeField, PrimeFieldBits};
|
||||
use group::Curve;
|
||||
use halo2::{
|
||||
circuit::{Layouter, SimpleFloorPlanner},
|
||||
circuit::{AssignedCell, Layouter, SimpleFloorPlanner},
|
||||
dev::MockProver,
|
||||
plonk::{Circuit, ConstraintSystem, Error},
|
||||
};
|
||||
|
@ -1471,7 +1492,7 @@ mod tests {
|
|||
}
|
||||
|
||||
impl UtilitiesInstructions<pallas::Base> for MyCircuit {
|
||||
type Var = CellValue<pallas::Base>;
|
||||
type Var = AssignedCell<pallas::Base, pallas::Base>;
|
||||
}
|
||||
|
||||
impl Circuit<pallas::Base> for MyCircuit {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use ff::PrimeFieldBits;
|
||||
use halo2::{
|
||||
circuit::{Cell, Layouter, Region},
|
||||
circuit::{AssignedCell, Cell, Layouter},
|
||||
plonk::{Advice, Column, Error, Expression},
|
||||
};
|
||||
use pasta_curves::arithmetic::FieldExt;
|
||||
|
@ -12,18 +12,8 @@ pub(crate) mod cond_swap;
|
|||
pub(crate) mod decompose_running_sum;
|
||||
pub(crate) mod lookup_range_check;
|
||||
|
||||
/// A variable representing a field element.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct CellValue<F: FieldExt> {
|
||||
cell: Cell,
|
||||
value: Option<F>,
|
||||
}
|
||||
|
||||
/// Trait for a variable in the circuit.
|
||||
pub trait Var<F: FieldExt>: Copy + Clone + std::fmt::Debug {
|
||||
/// Construct a new variable.
|
||||
fn new(cell: Cell, value: Option<F>) -> Self;
|
||||
|
||||
pub trait Var<F: FieldExt>: Clone + std::fmt::Debug + From<AssignedCell<F, F>> {
|
||||
/// The cell at which this variable was allocated.
|
||||
fn cell(&self) -> Cell;
|
||||
|
||||
|
@ -31,17 +21,13 @@ pub trait Var<F: FieldExt>: Copy + Clone + std::fmt::Debug {
|
|||
fn value(&self) -> Option<F>;
|
||||
}
|
||||
|
||||
impl<F: FieldExt> Var<F> for CellValue<F> {
|
||||
fn new(cell: Cell, value: Option<F>) -> Self {
|
||||
Self { cell, value }
|
||||
}
|
||||
|
||||
impl<F: FieldExt> Var<F> for AssignedCell<F, F> {
|
||||
fn cell(&self) -> Cell {
|
||||
self.cell
|
||||
self.cell()
|
||||
}
|
||||
|
||||
fn value(&self) -> Option<F> {
|
||||
self.value
|
||||
self.value().cloned()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,45 +46,19 @@ pub trait UtilitiesInstructions<F: FieldExt> {
|
|||
layouter.assign_region(
|
||||
|| "load private",
|
||||
|mut region| {
|
||||
let cell = region.assign_advice(
|
||||
|| "load private",
|
||||
column,
|
||||
0,
|
||||
|| value.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
Ok(Var::new(cell, value))
|
||||
region
|
||||
.assign_advice(
|
||||
|| "load private",
|
||||
column,
|
||||
0,
|
||||
|| value.ok_or(Error::Synthesis),
|
||||
)
|
||||
.map(Self::Var::from)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Assigns a cell at a specific offset within the given region, constraining it
|
||||
/// to the same value as another cell (which may be in any region).
|
||||
///
|
||||
/// Returns an error if either `column` or `copy` is not in a column that was passed to
|
||||
/// [`ConstraintSystem::enable_equality`] during circuit configuration.
|
||||
///
|
||||
/// [`ConstraintSystem::enable_equality`]: halo2::plonk::ConstraintSystem::enable_equality
|
||||
pub fn copy<A, AR, F: FieldExt>(
|
||||
region: &mut Region<'_, F>,
|
||||
annotation: A,
|
||||
column: Column<Advice>,
|
||||
offset: usize,
|
||||
copy: &CellValue<F>,
|
||||
) -> Result<CellValue<F>, Error>
|
||||
where
|
||||
A: Fn() -> AR,
|
||||
AR: Into<String>,
|
||||
{
|
||||
let cell = region.assign_advice(annotation, column, offset, || {
|
||||
copy.value.ok_or(Error::Synthesis)
|
||||
})?;
|
||||
|
||||
region.constrain_equal(cell, copy.cell)?;
|
||||
|
||||
Ok(CellValue::new(cell, copy.value))
|
||||
}
|
||||
|
||||
pub(crate) fn transpose_option_array<T: Copy + std::fmt::Debug, const LEN: usize>(
|
||||
option_array: Option<[T; LEN]>,
|
||||
) -> [Option<T>; LEN] {
|
||||
|
@ -126,7 +86,7 @@ pub fn ternary<F: FieldExt>(a: Expression<F>, b: Expression<F>, c: Expression<F>
|
|||
|
||||
/// Takes a specified subsequence of the little-endian bit representation of a field element.
|
||||
/// The bits are numbered from 0 for the LSB.
|
||||
pub fn bitrange_subset<F: FieldExt + PrimeFieldBits>(field_elem: F, bitrange: Range<usize>) -> F {
|
||||
pub fn bitrange_subset<F: FieldExt + PrimeFieldBits>(field_elem: &F, bitrange: Range<usize>) -> F {
|
||||
assert!(bitrange.end <= F::NUM_BITS as usize);
|
||||
|
||||
let bits: Vec<bool> = field_elem
|
||||
|
@ -172,7 +132,7 @@ mod tests {
|
|||
struct MyCircuit<const RANGE: usize>(u8);
|
||||
|
||||
impl<const RANGE: usize> UtilitiesInstructions<pallas::Base> for MyCircuit<RANGE> {
|
||||
type Var = CellValue<pallas::Base>;
|
||||
type Var = AssignedCell<pallas::Base, pallas::Base>;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -251,7 +211,7 @@ mod tests {
|
|||
{
|
||||
let field_elem = pallas::Base::rand();
|
||||
let bitrange = 0..(pallas::Base::NUM_BITS as usize);
|
||||
let subset = bitrange_subset(field_elem, bitrange);
|
||||
let subset = bitrange_subset(&field_elem, bitrange);
|
||||
assert_eq!(field_elem, subset);
|
||||
}
|
||||
|
||||
|
@ -259,7 +219,7 @@ mod tests {
|
|||
{
|
||||
let field_elem = pallas::Base::rand();
|
||||
let bitrange = 0..0;
|
||||
let subset = bitrange_subset(field_elem, bitrange);
|
||||
let subset = bitrange_subset(&field_elem, bitrange);
|
||||
assert_eq!(pallas::Base::zero(), subset);
|
||||
}
|
||||
|
||||
|
@ -286,7 +246,7 @@ mod tests {
|
|||
|
||||
let subsets = ranges
|
||||
.iter()
|
||||
.map(|range| bitrange_subset(field_elem, range.clone()))
|
||||
.map(|range| bitrange_subset(&field_elem, range.clone()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut sum = subsets[0];
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::{bool_check, copy, ternary, CellValue, UtilitiesInstructions, Var};
|
||||
use super::{bool_check, ternary, UtilitiesInstructions};
|
||||
use halo2::{
|
||||
circuit::{Chip, Layouter},
|
||||
circuit::{AssignedCell, Chip, Layouter},
|
||||
plonk::{Advice, Column, ConstraintSystem, Error, Selector},
|
||||
poly::Rotation,
|
||||
};
|
||||
|
@ -53,7 +53,7 @@ pub struct CondSwapConfig {
|
|||
}
|
||||
|
||||
impl<F: FieldExt> UtilitiesInstructions<F> for CondSwapChip<F> {
|
||||
type Var = CellValue<F>;
|
||||
type Var = AssignedCell<F, F>;
|
||||
}
|
||||
|
||||
impl<F: FieldExt> CondSwapInstructions<F> for CondSwapChip<F> {
|
||||
|
@ -73,18 +73,15 @@ impl<F: FieldExt> CondSwapInstructions<F> for CondSwapChip<F> {
|
|||
config.q_swap.enable(&mut region, 0)?;
|
||||
|
||||
// Copy in `a` value
|
||||
let a = copy(&mut region, || "copy a", config.a, 0, &pair.0)?;
|
||||
let a = pair.0.copy_advice(|| "copy a", &mut region, config.a, 0)?;
|
||||
|
||||
// Witness `b` value
|
||||
let b = {
|
||||
let cell = region.assign_advice(
|
||||
|| "witness b",
|
||||
config.b,
|
||||
0,
|
||||
|| pair.1.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
CellValue::new(cell, pair.1)
|
||||
};
|
||||
let b = region.assign_advice(
|
||||
|| "witness b",
|
||||
config.b,
|
||||
0,
|
||||
|| pair.1.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
|
||||
// Witness `swap` value
|
||||
let swap_val = swap.map(|swap| F::from_u64(swap as u64));
|
||||
|
@ -98,39 +95,33 @@ impl<F: FieldExt> CondSwapInstructions<F> for CondSwapChip<F> {
|
|||
// Conditionally swap a
|
||||
let a_swapped = {
|
||||
let a_swapped = a
|
||||
.value
|
||||
.zip(b.value)
|
||||
.value()
|
||||
.zip(b.value())
|
||||
.zip(swap)
|
||||
.map(|((a, b), swap)| if swap { b } else { a });
|
||||
let a_swapped_cell = region.assign_advice(
|
||||
.map(|((a, b), swap)| if swap { b } else { a })
|
||||
.cloned();
|
||||
region.assign_advice(
|
||||
|| "a_swapped",
|
||||
config.a_swapped,
|
||||
0,
|
||||
|| a_swapped.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
CellValue {
|
||||
cell: a_swapped_cell,
|
||||
value: a_swapped,
|
||||
}
|
||||
)?
|
||||
};
|
||||
|
||||
// Conditionally swap b
|
||||
let b_swapped = {
|
||||
let b_swapped = a
|
||||
.value
|
||||
.zip(b.value)
|
||||
.value()
|
||||
.zip(b.value())
|
||||
.zip(swap)
|
||||
.map(|((a, b), swap)| if swap { a } else { b });
|
||||
let b_swapped_cell = region.assign_advice(
|
||||
.map(|((a, b), swap)| if swap { a } else { b })
|
||||
.cloned();
|
||||
region.assign_advice(
|
||||
|| "b_swapped",
|
||||
config.b_swapped,
|
||||
0,
|
||||
|| b_swapped.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
CellValue {
|
||||
cell: b_swapped_cell,
|
||||
value: b_swapped,
|
||||
}
|
||||
)?
|
||||
};
|
||||
|
||||
// Return swapped pair
|
||||
|
@ -252,18 +243,21 @@ mod tests {
|
|||
// Load the pair and the swap flag into the circuit.
|
||||
let a = chip.load_private(layouter.namespace(|| "a"), config.a, self.a)?;
|
||||
// Return the swapped pair.
|
||||
let swapped_pair =
|
||||
chip.swap(layouter.namespace(|| "swap"), (a, self.b), self.swap)?;
|
||||
let swapped_pair = chip.swap(
|
||||
layouter.namespace(|| "swap"),
|
||||
(a.clone(), self.b),
|
||||
self.swap,
|
||||
)?;
|
||||
|
||||
if let Some(swap) = self.swap {
|
||||
if swap {
|
||||
// Check that `a` and `b` have been swapped
|
||||
assert_eq!(swapped_pair.0.value.unwrap(), self.b.unwrap());
|
||||
assert_eq!(swapped_pair.1.value.unwrap(), a.value.unwrap());
|
||||
assert_eq!(swapped_pair.0.value().unwrap(), &self.b.unwrap());
|
||||
assert_eq!(swapped_pair.1.value().unwrap(), a.value().unwrap());
|
||||
} else {
|
||||
// Check that `a` and `b` have not been swapped
|
||||
assert_eq!(swapped_pair.0.value.unwrap(), a.value.unwrap());
|
||||
assert_eq!(swapped_pair.1.value.unwrap(), self.b.unwrap());
|
||||
assert_eq!(swapped_pair.0.value().unwrap(), a.value().unwrap());
|
||||
assert_eq!(swapped_pair.1.value().unwrap(), &self.b.unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,22 +24,22 @@
|
|||
|
||||
use ff::PrimeFieldBits;
|
||||
use halo2::{
|
||||
circuit::Region,
|
||||
circuit::{AssignedCell, Region},
|
||||
plonk::{Advice, Column, ConstraintSystem, Error, Selector},
|
||||
poly::Rotation,
|
||||
};
|
||||
|
||||
use super::{copy, range_check, CellValue, Var};
|
||||
use super::range_check;
|
||||
use crate::constants::util::decompose_word;
|
||||
use pasta_curves::arithmetic::FieldExt;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// The running sum $[z_0, ..., z_W]$. If created in strict mode, $z_W = 0$.
|
||||
pub struct RunningSum<F: FieldExt + PrimeFieldBits>(Vec<CellValue<F>>);
|
||||
pub struct RunningSum<F: FieldExt + PrimeFieldBits>(Vec<AssignedCell<F, F>>);
|
||||
impl<F: FieldExt + PrimeFieldBits> std::ops::Deref for RunningSum<F> {
|
||||
type Target = Vec<CellValue<F>>;
|
||||
type Target = Vec<AssignedCell<F, F>>;
|
||||
|
||||
fn deref(&self) -> &Vec<CellValue<F>> {
|
||||
fn deref(&self) -> &Vec<AssignedCell<F, F>> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
@ -105,15 +105,12 @@ impl<F: FieldExt + PrimeFieldBits, const WINDOW_NUM_BITS: usize>
|
|||
word_num_bits: usize,
|
||||
num_windows: usize,
|
||||
) -> Result<RunningSum<F>, Error> {
|
||||
let z_0 = {
|
||||
let cell = region.assign_advice(
|
||||
|| "z_0 = alpha",
|
||||
self.z,
|
||||
offset,
|
||||
|| alpha.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
CellValue::new(cell, alpha)
|
||||
};
|
||||
let z_0 = region.assign_advice(
|
||||
|| "z_0 = alpha",
|
||||
self.z,
|
||||
offset,
|
||||
|| alpha.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
self.decompose(region, offset, z_0, strict, word_num_bits, num_windows)
|
||||
}
|
||||
|
||||
|
@ -125,12 +122,12 @@ impl<F: FieldExt + PrimeFieldBits, const WINDOW_NUM_BITS: usize>
|
|||
&self,
|
||||
region: &mut Region<'_, F>,
|
||||
offset: usize,
|
||||
alpha: CellValue<F>,
|
||||
alpha: AssignedCell<F, F>,
|
||||
strict: bool,
|
||||
word_num_bits: usize,
|
||||
num_windows: usize,
|
||||
) -> Result<RunningSum<F>, Error> {
|
||||
let z_0 = copy(region, || "copy z_0 = alpha", self.z, offset, &alpha)?;
|
||||
let z_0 = alpha.copy_advice(|| "copy z_0 = alpha", region, self.z, offset)?;
|
||||
self.decompose(region, offset, z_0, strict, word_num_bits, num_windows)
|
||||
}
|
||||
|
||||
|
@ -143,7 +140,7 @@ impl<F: FieldExt + PrimeFieldBits, const WINDOW_NUM_BITS: usize>
|
|||
&self,
|
||||
region: &mut Region<'_, F>,
|
||||
offset: usize,
|
||||
z_0: CellValue<F>,
|
||||
z_0: AssignedCell<F, F>,
|
||||
strict: bool,
|
||||
word_num_bits: usize,
|
||||
num_windows: usize,
|
||||
|
@ -179,7 +176,7 @@ impl<F: FieldExt + PrimeFieldBits, const WINDOW_NUM_BITS: usize>
|
|||
};
|
||||
|
||||
// Initialize empty vector to store running sum values [z_0, ..., z_W].
|
||||
let mut zs: Vec<CellValue<F>> = vec![z_0];
|
||||
let mut zs: Vec<AssignedCell<F, F>> = vec![z_0.clone()];
|
||||
let mut z = z_0;
|
||||
|
||||
// Assign running sum `z_{i+1}` = (z_i - k_i) / (2^K) for i = 0..=n-1.
|
||||
|
@ -193,19 +190,18 @@ impl<F: FieldExt + PrimeFieldBits, const WINDOW_NUM_BITS: usize>
|
|||
let z_next_val = z
|
||||
.value()
|
||||
.zip(word)
|
||||
.map(|(z_cur_val, word)| (z_cur_val - word) * two_pow_k_inv);
|
||||
let cell = region.assign_advice(
|
||||
.map(|(z_cur_val, word)| (*z_cur_val - word) * two_pow_k_inv);
|
||||
region.assign_advice(
|
||||
|| format!("z_{:?}", i + 1),
|
||||
self.z,
|
||||
offset + i + 1,
|
||||
|| z_next_val.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
CellValue::new(cell, z_next_val)
|
||||
)?
|
||||
};
|
||||
|
||||
// Update `z`.
|
||||
z = z_next;
|
||||
zs.push(z);
|
||||
zs.push(z.clone());
|
||||
}
|
||||
assert_eq!(zs.len(), num_windows + 1);
|
||||
|
||||
|
@ -284,7 +280,7 @@ mod tests {
|
|||
WORD_NUM_BITS,
|
||||
NUM_WINDOWS,
|
||||
)?;
|
||||
let alpha = zs[0];
|
||||
let alpha = zs[0].clone();
|
||||
|
||||
let offset = offset + NUM_WINDOWS + 1;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
use crate::spec::lebs2ip;
|
||||
use halo2::{
|
||||
circuit::{Layouter, Region},
|
||||
circuit::{AssignedCell, Layouter, Region},
|
||||
plonk::{Advice, Column, ConstraintSystem, Error, Selector, TableColumn},
|
||||
poly::Rotation,
|
||||
};
|
||||
|
@ -14,11 +14,11 @@ use ff::PrimeFieldBits;
|
|||
use super::*;
|
||||
|
||||
/// The running sum $[z_0, ..., z_W]$. If created in strict mode, $z_W = 0$.
|
||||
pub struct RunningSum<F: FieldExt + PrimeFieldBits>(Vec<CellValue<F>>);
|
||||
pub struct RunningSum<F: FieldExt + PrimeFieldBits>(Vec<AssignedCell<F, F>>);
|
||||
impl<F: FieldExt + PrimeFieldBits> std::ops::Deref for RunningSum<F> {
|
||||
type Target = Vec<CellValue<F>>;
|
||||
type Target = Vec<AssignedCell<F, F>>;
|
||||
|
||||
fn deref(&self) -> &Vec<CellValue<F>> {
|
||||
fn deref(&self) -> &Vec<AssignedCell<F, F>> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
|||
pub fn copy_check(
|
||||
&self,
|
||||
mut layouter: impl Layouter<F>,
|
||||
element: CellValue<F>,
|
||||
element: AssignedCell<F, F>,
|
||||
num_words: usize,
|
||||
strict: bool,
|
||||
) -> Result<RunningSum<F>, Error> {
|
||||
|
@ -151,7 +151,7 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
|||
|| format!("{:?} words range check", num_words),
|
||||
|mut region| {
|
||||
// Copy `element` and initialize running sum `z_0 = element` to decompose it.
|
||||
let z_0 = copy(&mut region, || "z_0", self.running_sum, 0, &element)?;
|
||||
let z_0 = element.copy_advice(|| "z_0", &mut region, self.running_sum, 0)?;
|
||||
self.range_check(&mut region, z_0, num_words, strict)
|
||||
},
|
||||
)
|
||||
|
@ -168,15 +168,12 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
|||
layouter.assign_region(
|
||||
|| "Witness element",
|
||||
|mut region| {
|
||||
let z_0 = {
|
||||
let cell = region.assign_advice(
|
||||
|| "Witness element",
|
||||
self.running_sum,
|
||||
0,
|
||||
|| value.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
CellValue::new(cell, value)
|
||||
};
|
||||
let z_0 = region.assign_advice(
|
||||
|| "Witness element",
|
||||
self.running_sum,
|
||||
0,
|
||||
|| value.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
self.range_check(&mut region, z_0, num_words, strict)
|
||||
},
|
||||
)
|
||||
|
@ -192,7 +189,7 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
|||
fn range_check(
|
||||
&self,
|
||||
region: &mut Region<'_, F>,
|
||||
element: CellValue<F>,
|
||||
element: AssignedCell<F, F>,
|
||||
num_words: usize,
|
||||
strict: bool,
|
||||
) -> Result<RunningSum<F>, Error> {
|
||||
|
@ -223,7 +220,7 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
|||
}
|
||||
};
|
||||
|
||||
let mut zs = vec![element];
|
||||
let mut zs = vec![element.clone()];
|
||||
|
||||
// Assign cumulative sum such that
|
||||
// z_i = 2^{K}⋅z_{i + 1} + a_i
|
||||
|
@ -244,19 +241,17 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
|||
let z_val = z
|
||||
.value()
|
||||
.zip(*word)
|
||||
.map(|(z, word)| (z - word) * inv_two_pow_k);
|
||||
.map(|(z, word)| (*z - word) * inv_two_pow_k);
|
||||
|
||||
// Assign z_next
|
||||
let z_cell = region.assign_advice(
|
||||
region.assign_advice(
|
||||
|| format!("z_{:?}", idx + 1),
|
||||
self.running_sum,
|
||||
idx + 1,
|
||||
|| z_val.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
|
||||
CellValue::new(z_cell, z_val)
|
||||
)?
|
||||
};
|
||||
zs.push(z);
|
||||
zs.push(z.clone());
|
||||
}
|
||||
|
||||
if strict {
|
||||
|
@ -275,7 +270,7 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
|||
pub fn copy_short_check(
|
||||
&self,
|
||||
mut layouter: impl Layouter<F>,
|
||||
element: CellValue<F>,
|
||||
element: AssignedCell<F, F>,
|
||||
num_bits: usize,
|
||||
) -> Result<(), Error> {
|
||||
assert!(num_bits < K);
|
||||
|
@ -283,7 +278,8 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
|||
|| format!("Range check {:?} bits", num_bits),
|
||||
|mut region| {
|
||||
// Copy `element` to use in the k-bit lookup.
|
||||
let element = copy(&mut region, || "element", self.running_sum, 0, &element)?;
|
||||
let element =
|
||||
element.copy_advice(|| "element", &mut region, self.running_sum, 0)?;
|
||||
|
||||
self.short_range_check(&mut region, element, num_bits)
|
||||
},
|
||||
|
@ -300,23 +296,20 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
|||
mut layouter: impl Layouter<F>,
|
||||
element: Option<F>,
|
||||
num_bits: usize,
|
||||
) -> Result<CellValue<F>, Error> {
|
||||
) -> Result<AssignedCell<F, F>, Error> {
|
||||
assert!(num_bits <= K);
|
||||
layouter.assign_region(
|
||||
|| format!("Range check {:?} bits", num_bits),
|
||||
|mut region| {
|
||||
// Witness `element` to use in the k-bit lookup.
|
||||
let element = {
|
||||
let cell = region.assign_advice(
|
||||
|| "Witness element",
|
||||
self.running_sum,
|
||||
0,
|
||||
|| element.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
CellValue::new(cell, element)
|
||||
};
|
||||
let element = region.assign_advice(
|
||||
|| "Witness element",
|
||||
self.running_sum,
|
||||
0,
|
||||
|| element.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
|
||||
self.short_range_check(&mut region, element, num_bits)?;
|
||||
self.short_range_check(&mut region, element.clone(), num_bits)?;
|
||||
|
||||
Ok(element)
|
||||
},
|
||||
|
@ -329,7 +322,7 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
|||
fn short_range_check(
|
||||
&self,
|
||||
region: &mut Region<'_, F>,
|
||||
element: CellValue<F>,
|
||||
element: AssignedCell<F, F>,
|
||||
num_bits: usize,
|
||||
) -> Result<(), Error> {
|
||||
// Enable lookup for `element`, to constrain it to 10 bits.
|
||||
|
@ -344,7 +337,7 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
|||
// Assign shifted `element * 2^{K - num_bits}`
|
||||
let shifted = element.value().map(|element| {
|
||||
let shift = F::from_u64(1 << (K - num_bits));
|
||||
element * shift
|
||||
*element * shift
|
||||
});
|
||||
|
||||
region.assign_advice(
|
||||
|
@ -369,7 +362,6 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::Var;
|
||||
use super::LookupRangeCheckConfig;
|
||||
|
||||
use crate::primitives::sinsemilla::{INV_TWO_POW_K, K};
|
||||
|
@ -468,7 +460,7 @@ mod tests {
|
|||
|
||||
for (expected_z, z) in expected_zs.into_iter().zip(zs.iter()) {
|
||||
if let Some(z) = z.value() {
|
||||
assert_eq!(expected_z, z);
|
||||
assert_eq!(&expected_z, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use halo2::arithmetic::{CurveAffine, FieldExt};
|
|||
/// We are returning a `Vec<u8>` which means the window size is limited to
|
||||
/// <= 8 bits.
|
||||
pub fn decompose_word<F: PrimeFieldBits>(
|
||||
word: F,
|
||||
word: &F,
|
||||
word_num_bits: usize,
|
||||
window_num_bits: usize,
|
||||
) -> Vec<u8> {
|
||||
|
@ -86,7 +86,7 @@ mod tests {
|
|||
window_num_bits in 1u8..9
|
||||
) {
|
||||
// Get decomposition into `window_num_bits` bits
|
||||
let decomposed = decompose_word(scalar, pallas::Scalar::NUM_BITS as usize, window_num_bits as usize);
|
||||
let decomposed = decompose_word(&scalar, pallas::Scalar::NUM_BITS as usize, window_num_bits as usize);
|
||||
|
||||
// Flatten bits
|
||||
let bits = decomposed
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! The Poseidon algebraic hash function.
|
||||
|
||||
use std::array;
|
||||
use std::convert::TryInto;
|
||||
use std::fmt;
|
||||
use std::iter;
|
||||
use std::marker::PhantomData;
|
||||
|
@ -147,9 +148,13 @@ pub(crate) enum Sponge<F, const RATE: usize> {
|
|||
Squeezing(SpongeState<F, RATE>),
|
||||
}
|
||||
|
||||
impl<F: Copy, const RATE: usize> Sponge<F, RATE> {
|
||||
impl<F: fmt::Debug, const RATE: usize> Sponge<F, RATE> {
|
||||
pub(crate) fn absorb(val: F) -> Self {
|
||||
let mut input = [None; RATE];
|
||||
let mut input: [Option<F>; RATE] = (0..RATE)
|
||||
.map(|_| None)
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
input[0] = Some(val);
|
||||
Sponge::Absorbing(input)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue