mirror of https://github.com/zcash/halo2.git
Migrate to halo2 version with `AssignedCell`
We change `CellValue` into a typedef of `AssignedCell` to simplify the migration in this commit. The migration from `CellValue` to `AssignedCell` requires several other changes: - `<CellValue as Var>::value()` returned `Option<F>`, whereas `AssignedCell::<F, F>::value()` returns `Option<&F>`. This means we need to dereference, use `Option::cloned`, or alter functions to take `&F` arguments. - `StateWord` in the Poseidon chip has been changed to a newtype around `AssignedCell` (the chip was written before `CellValue` existed).
This commit is contained in:
parent
5cb838f1a2
commit
9b41a06363
|
@ -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" }
|
||||
|
|
|
@ -121,7 +121,7 @@ where
|
|||
0,
|
||||
|| self.output.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
region.constrain_equal(output.cell(), expected_var)
|
||||
region.constrain_equal(output.cell(), expected_var.cell())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ impl EccPoint {
|
|||
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,
|
||||
|
@ -104,7 +104,7 @@ impl NonIdentityEccPoint {
|
|||
match (self.x.value(), self.y.value()) {
|
||||
(Some(x), Some(y)) => {
|
||||
assert!(!x.is_zero_vartime() && !y.is_zero_vartime());
|
||||
Some(pallas::Affine::from_xy(x, y).unwrap())
|
||||
Some(pallas::Affine::from_xy(*x, *y).unwrap())
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
|
|
|
@ -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
|
||||
});
|
||||
|
@ -329,11 +329,11 @@ impl Config {
|
|||
{
|
||||
if x_p.is_zero_vartime() {
|
||||
// 0 + Q = Q
|
||||
(x_q, y_q)
|
||||
(*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 {
|
||||
|
|
|
@ -364,7 +364,7 @@ impl Config {
|
|||
// 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())
|
||||
}
|
||||
|
@ -441,7 +441,7 @@ impl<F: FieldExt> Deref for Z<F> {
|
|||
}
|
||||
}
|
||||
|
||||
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`.
|
||||
|
|
|
@ -161,10 +161,12 @@ impl Config {
|
|||
)?;
|
||||
|
||||
// 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(
|
||||
|| "y_p",
|
||||
|
|
|
@ -190,8 +190,8 @@ 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
|
||||
|
@ -229,7 +229,7 @@ impl<const NUM_BITS: usize> Config<NUM_BITS> {
|
|||
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)?;
|
||||
|
||||
(x_a, y_a.value(), z)
|
||||
(x_a, y_a.value().cloned(), z)
|
||||
};
|
||||
|
||||
// Increase offset by 1; we used row 0 for initializing `z`.
|
||||
|
@ -313,7 +313,7 @@ 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);
|
||||
|
|
|
@ -4,7 +4,6 @@ use super::H_BASE;
|
|||
use crate::{
|
||||
circuit::gadget::utilities::{
|
||||
bitrange_subset, copy, lookup_range_check::LookupRangeCheckConfig, range_check, CellValue,
|
||||
Var,
|
||||
},
|
||||
constants::{self, T_P},
|
||||
primitives::sinsemilla,
|
||||
|
|
|
@ -85,7 +85,7 @@ 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,
|
||||
)
|
||||
|
|
|
@ -160,10 +160,10 @@ impl Config {
|
|||
|
||||
// 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
|
||||
|
@ -199,7 +199,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 +211,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()
|
||||
|
|
|
@ -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 value = initial_state[i].0.value().cloned();
|
||||
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 })
|
||||
region.constrain_equal(initial_state[i].0.cell(), var.cell())?;
|
||||
Ok(StateWord(var))
|
||||
};
|
||||
let initial_state: Result<Vec<_>, Error> =
|
||||
(0..WIDTH).map(load_state_word).collect();
|
||||
|
@ -342,7 +339,7 @@ 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].clone(), padding_values[i]) {
|
||||
(Some(word), None) => (word.var, word.value),
|
||||
(Some(word), None) => (word.0.cell(), word.0.value().cloned()),
|
||||
(None, Some(padding_value)) => {
|
||||
let padding_var = region.assign_fixed(
|
||||
|| format!("load pad_{}", i),
|
||||
|
@ -350,7 +347,7 @@ impl<F: FieldExt, S: Spec<F, WIDTH, RATE>, const WIDTH: usize, const RATE: usize
|
|||
1,
|
||||
|| Ok(padding_value),
|
||||
)?;
|
||||
(padding_var, Some(padding_value))
|
||||
(padding_var.cell(), Some(padding_value))
|
||||
}
|
||||
_ => panic!("Input and padding don't match"),
|
||||
};
|
||||
|
@ -360,30 +357,31 @@ impl<F: FieldExt, S: Spec<F, WIDTH, RATE>, const WIDTH: usize, const RATE: usize
|
|||
1,
|
||||
|| value.ok_or(Error::Synthesis),
|
||||
)?;
|
||||
region.constrain_equal(constraint_var, var)?;
|
||||
region.constrain_equal(constraint_var, var.cell())?;
|
||||
|
||||
Ok(StateWord { var, value })
|
||||
Ok(StateWord(var))
|
||||
};
|
||||
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();
|
||||
|
@ -404,34 +402,31 @@ impl<F: FieldExt, S: Spec<F, WIDTH, RATE>, const WIDTH: usize, const RATE: usize
|
|||
|
||||
/// A word in the Poseidon state.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StateWord<F: FieldExt> {
|
||||
var: Cell,
|
||||
value: Option<F>,
|
||||
}
|
||||
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 new(var: AssignedCell<F, F>, value: Option<F>) -> Self {
|
||||
Self(var)
|
||||
}
|
||||
|
||||
fn cell(&self) -> Cell {
|
||||
self.var
|
||||
self.0.cell()
|
||||
}
|
||||
|
||||
fn value(&self) -> Option<F> {
|
||||
self.value
|
||||
self.0.value().cloned()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -447,11 +442,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 +470,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 +542,15 @@ 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 value = initial_state[i].0.value().cloned();
|
||||
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 })
|
||||
region.constrain_equal(initial_state[i].0.cell(), var.cell())?;
|
||||
Ok(StateWord(var))
|
||||
};
|
||||
|
||||
let state: Result<Vec<_>, _> = (0..WIDTH).map(load_state_word).collect();
|
||||
|
@ -597,7 +592,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();
|
||||
|
@ -674,7 +669,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 +708,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) {
|
||||
|
@ -821,7 +816,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())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -142,7 +142,7 @@ 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);
|
||||
}
|
||||
}
|
||||
|
@ -270,7 +270,7 @@ impl SinsemillaChip {
|
|||
offset,
|
||||
|| piece.field_elem().ok_or(Error::Synthesis),
|
||||
)?;
|
||||
region.constrain_equal(piece.cell(), cell)?;
|
||||
region.constrain_equal(piece.cell(), cell.cell())?;
|
||||
zs.push(CellValue::new(cell, piece.field_elem()));
|
||||
|
||||
// Assign cumulative sum such that for 0 <= i < n,
|
||||
|
|
|
@ -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, copy, CellValue},
|
||||
},
|
||||
constants::T_P,
|
||||
};
|
||||
|
@ -641,7 +641,7 @@ mod tests {
|
|||
ecc::chip::{EccChip, EccConfig},
|
||||
sinsemilla::chip::SinsemillaChip,
|
||||
utilities::{
|
||||
lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions, Var,
|
||||
lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions,
|
||||
},
|
||||
},
|
||||
constants::{COMMIT_IVK_PERSONALIZATION, L_ORCHARD_BASE, T_Q},
|
||||
|
@ -803,7 +803,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(())
|
||||
|
|
|
@ -15,7 +15,7 @@ use crate::{
|
|||
circuit::gadget::utilities::{
|
||||
bitrange_subset,
|
||||
cond_swap::{CondSwapChip, CondSwapConfig, CondSwapInstructions},
|
||||
copy, CellValue, UtilitiesInstructions, Var,
|
||||
copy, CellValue, 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));
|
||||
|
|
|
@ -40,7 +40,7 @@ pub struct MessagePiece<F: FieldExt, const K: 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: CellValue<F>, field_elem: Option<F>, num_words: usize) -> Self {
|
||||
assert!(num_words * K < F::NUM_BITS as usize);
|
||||
let cell_value = CellValue::new(cell, field_elem);
|
||||
Self {
|
||||
|
@ -58,7 +58,7 @@ 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> {
|
||||
|
|
|
@ -530,8 +530,10 @@ impl NoteCommitConfig {
|
|||
psi: CellValue<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();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use ff::PrimeFieldBits;
|
||||
use halo2::{
|
||||
circuit::{Cell, Layouter, Region},
|
||||
circuit::{AssignedCell, Cell, Layouter, Region},
|
||||
plonk::{Advice, Column, Error, Expression},
|
||||
};
|
||||
use pasta_curves::arithmetic::FieldExt;
|
||||
|
@ -13,16 +13,12 @@ pub(crate) mod decompose_running_sum;
|
|||
pub(crate) mod lookup_range_check;
|
||||
|
||||
/// A variable representing a field element.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CellValue<F: FieldExt> {
|
||||
cell: Cell,
|
||||
value: Option<F>,
|
||||
}
|
||||
pub type CellValue<F> = AssignedCell<F, F>;
|
||||
|
||||
/// Trait for a variable in the circuit.
|
||||
pub trait Var<F: FieldExt>: Clone + std::fmt::Debug {
|
||||
/// Construct a new variable.
|
||||
fn new(cell: Cell, value: Option<F>) -> Self;
|
||||
fn new(cell: AssignedCell<F, F>, value: Option<F>) -> Self;
|
||||
|
||||
/// The cell at which this variable was allocated.
|
||||
fn cell(&self) -> Cell;
|
||||
|
@ -32,16 +28,16 @@ pub trait Var<F: FieldExt>: Clone + std::fmt::Debug {
|
|||
}
|
||||
|
||||
impl<F: FieldExt> Var<F> for CellValue<F> {
|
||||
fn new(cell: Cell, value: Option<F>) -> Self {
|
||||
Self { cell, value }
|
||||
fn new(cell: AssignedCell<F, F>, _value: Option<F>) -> Self {
|
||||
cell
|
||||
}
|
||||
|
||||
fn cell(&self) -> Cell {
|
||||
self.cell
|
||||
self.cell()
|
||||
}
|
||||
|
||||
fn value(&self) -> Option<F> {
|
||||
self.value
|
||||
self.value().cloned()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,13 +86,9 @@ 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))
|
||||
// Temporarily implement `copy()` in terms of `AssignedCell::copy_advice`.
|
||||
// We will remove this in a subsequent commit.
|
||||
copy.copy_advice(annotation, region, column, offset)
|
||||
}
|
||||
|
||||
pub(crate) fn transpose_option_array<T: Copy + std::fmt::Debug, const LEN: usize>(
|
||||
|
@ -126,7 +118,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
|
||||
|
@ -251,7 +243,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 +251,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 +278,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];
|
||||
|
|
|
@ -98,39 +98,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
|
||||
|
@ -261,12 +255,12 @@ mod tests {
|
|||
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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -193,7 +193,7 @@ 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);
|
||||
.map(|(z_cur_val, word)| (*z_cur_val - word) * two_pow_k_inv);
|
||||
let cell = region.assign_advice(
|
||||
|| format!("z_{:?}", i + 1),
|
||||
self.z,
|
||||
|
|
|
@ -244,7 +244,7 @@ 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(
|
||||
|
@ -344,7 +344,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 +369,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 +467,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
|
||||
|
|
Loading…
Reference in New Issue