mirror of https://github.com/zcash/orchard.git
Minor refactors, cleanups, clippy fixes, docfixes.
Co-authored-by: Daira Hopwood <daira@jacaranda.org> Co-authored-by: Jack Grigg <jack@electriccoin.co>
This commit is contained in:
parent
96863c9f73
commit
22ec16f129
|
@ -284,8 +284,12 @@ pub struct EccScalarFixed {
|
|||
/// 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.
|
||||
/// This is decomposed into 22 3-bit windows in little-endian order,
|
||||
/// i.e. `windows` = [k_0, k_1, ..., k_21] (for a 64-bit magnitude)
|
||||
/// This is decomposed into 3-bit windows in little-endian order
|
||||
/// using a running sum `z`, where z_{i+1} = (z_i - a_i) / (2^3)
|
||||
/// for element α = a_0 + (2^3) a_1 + ... + (2^{3(n-1)}) a_{n-1}.
|
||||
/// Each `a_i` is in the range [0..2^3).
|
||||
///
|
||||
/// `windows` = [k_0, k_1, ..., k_21] (for a 64-bit magnitude)
|
||||
/// where `scalar = k_0 + k_1 * (2^3) + ... + k_84 * (2^3)^84` and
|
||||
/// each `k_i` is in the range [0..2^3).
|
||||
/// k_21 must be a single bit, i.e. 0 or 1.
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
use super::{add, CellValue, EccConfig, EccPoint, EccScalarVar, Var};
|
||||
use crate::{
|
||||
circuit::gadget::utilities::copy,
|
||||
constants::{NUM_COMPLETE_BITS, T_Q},
|
||||
};
|
||||
use crate::{circuit::gadget::utilities::copy, constants::T_Q};
|
||||
use std::ops::{Deref, Range};
|
||||
|
||||
use bigint::U256;
|
||||
|
@ -20,12 +17,18 @@ mod complete;
|
|||
mod incomplete;
|
||||
mod overflow;
|
||||
|
||||
/// Number of bits for which complete addition needs to be used in variable-base
|
||||
/// scalar multiplication
|
||||
const NUM_COMPLETE_BITS: usize = 3;
|
||||
|
||||
// Bits used in incomplete addition. k_{254} to k_{4} inclusive
|
||||
const INCOMPLETE_LEN: usize = pallas::Scalar::NUM_BITS as usize - 1 - NUM_COMPLETE_BITS;
|
||||
const INCOMPLETE_RANGE: Range<usize> = 0..INCOMPLETE_LEN;
|
||||
|
||||
// Bits k_{254} to k_{4} inclusive are used in incomplete addition.
|
||||
// The `hi` half is k_{254} to k_{130} inclusive (length 125 bits).
|
||||
// (It is a coincidence that k_{130} matches the boundary of the
|
||||
// overflow check described in [the book](https://zcash.github.io/halo2/design/gadgets/ecc/var-base-scalar-mul.html#overflow-check).)
|
||||
const INCOMPLETE_HI_RANGE: Range<usize> = 0..(INCOMPLETE_LEN / 2);
|
||||
|
||||
// Bits k_{254} to k_{4} inclusive are used in incomplete addition.
|
||||
|
|
|
@ -16,6 +16,7 @@ use halo2::{
|
|||
},
|
||||
poly::Rotation,
|
||||
};
|
||||
use lazy_static::lazy_static;
|
||||
use pasta_curves::{
|
||||
arithmetic::{CurveAffine, FieldExt},
|
||||
pallas,
|
||||
|
@ -25,6 +26,13 @@ pub mod base_field_elem;
|
|||
pub mod full_width;
|
||||
pub mod short;
|
||||
|
||||
lazy_static! {
|
||||
static ref TWO_SCALAR: pallas::Scalar = pallas::Scalar::from_u64(2);
|
||||
// H = 2^3 (3-bit window)
|
||||
static ref H_SCALAR: pallas::Scalar = pallas::Scalar::from_u64(constants::H as u64);
|
||||
static ref H_BASE: pallas::Base = pallas::Base::from_u64(constants::H as u64);
|
||||
}
|
||||
|
||||
// A sum type for both full-width and short bases. This enables us to use the
|
||||
// shared functionality of full-width and short fixed-base scalar multiplication.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
@ -301,6 +309,57 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn process_window(
|
||||
&self,
|
||||
region: &mut Region<'_, pallas::Base>,
|
||||
offset: usize,
|
||||
w: usize,
|
||||
k: Option<pallas::Scalar>,
|
||||
k_usize: Option<usize>,
|
||||
base: OrchardFixedBases,
|
||||
) -> Result<EccPoint, Error> {
|
||||
let base_value = base.generator();
|
||||
let base_u = base.u();
|
||||
|
||||
// Compute [(k_w + 2) ⋅ 8^w]B
|
||||
let mul_b = {
|
||||
let mul_b =
|
||||
k.map(|k| base_value * (k + *TWO_SCALAR) * H_SCALAR.pow(&[w as u64, 0, 0, 0]));
|
||||
let mul_b = mul_b.map(|mul_b| mul_b.to_affine().coordinates().unwrap());
|
||||
|
||||
let x = mul_b.map(|mul_b| *mul_b.x());
|
||||
let x_cell = region.assign_advice(
|
||||
|| format!("mul_b_x, window {}", w),
|
||||
self.x_p,
|
||||
offset + w,
|
||||
|| x.ok_or(Error::SynthesisError),
|
||||
)?;
|
||||
let x = CellValue::new(x_cell, x);
|
||||
|
||||
let y = mul_b.map(|mul_b| *mul_b.y());
|
||||
let y_cell = region.assign_advice(
|
||||
|| format!("mul_b_y, window {}", w),
|
||||
self.y_p,
|
||||
offset + w,
|
||||
|| y.ok_or(Error::SynthesisError),
|
||||
)?;
|
||||
let y = CellValue::new(y_cell, y);
|
||||
|
||||
EccPoint { x, y }
|
||||
};
|
||||
|
||||
// Assign u = (y_p + z_w).sqrt()
|
||||
let u_val = k_usize.map(|k| base_u[w].0[k]);
|
||||
region.assign_advice(
|
||||
|| "u",
|
||||
self.u,
|
||||
offset + w,
|
||||
|| u_val.ok_or(Error::SynthesisError),
|
||||
)?;
|
||||
|
||||
Ok(mul_b)
|
||||
}
|
||||
|
||||
fn initialize_accumulator(
|
||||
&self,
|
||||
region: &mut Region<'_, pallas::Base>,
|
||||
|
@ -311,60 +370,10 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
|
|||
// Recall that the message at each window `w` is represented as
|
||||
// `m_w = [(k_w + 2) ⋅ 8^w]B`.
|
||||
// When `w = 0`, we have `m_0 = [(k_0 + 2)]B`.
|
||||
let m0 = {
|
||||
let k0 = scalar.windows_field()[0];
|
||||
let m0 = k0.map(|k0| base.generator() * (k0 + pallas::Scalar::from_u64(2)));
|
||||
let m0 = m0.map(|m0| m0.to_affine().coordinates().unwrap());
|
||||
|
||||
let x = m0.map(|m0| *m0.x());
|
||||
let x_cell = region.assign_advice(
|
||||
|| "m0_x",
|
||||
self.x_p,
|
||||
offset,
|
||||
|| x.ok_or(Error::SynthesisError),
|
||||
)?;
|
||||
let x = CellValue::new(x_cell, x);
|
||||
|
||||
let y = m0.map(|m0| *m0.y());
|
||||
let y_cell = region.assign_advice(
|
||||
|| "m0_y",
|
||||
self.y_p,
|
||||
offset,
|
||||
|| y.ok_or(Error::SynthesisError),
|
||||
)?;
|
||||
let y = CellValue::new(y_cell, y);
|
||||
|
||||
EccPoint { x, y }
|
||||
};
|
||||
|
||||
// Assign u = (y_p + z_w).sqrt() for `m0`
|
||||
{
|
||||
let k0 = scalar.windows_usize()[0];
|
||||
let u0 = &base.u()[0];
|
||||
let u0 = k0.map(|k0| u0.0[k0]);
|
||||
|
||||
region.assign_advice(|| "u", self.u, offset, || u0.ok_or(Error::SynthesisError))?;
|
||||
}
|
||||
|
||||
// Copy `m0` into `x_qr`, `y_qr` cells on row 1 of the incomplete addition.
|
||||
let x = copy(
|
||||
region,
|
||||
|| "initialize acc x",
|
||||
self.add_incomplete_config.x_qr,
|
||||
offset + 1,
|
||||
&m0.x,
|
||||
&self.perm,
|
||||
)?;
|
||||
let y = copy(
|
||||
region,
|
||||
|| "initialize acc y",
|
||||
self.add_incomplete_config.y_qr,
|
||||
offset + 1,
|
||||
&m0.y,
|
||||
&self.perm,
|
||||
)?;
|
||||
|
||||
Ok(EccPoint { x, y })
|
||||
let w = 0;
|
||||
let k0 = scalar.windows_field()[0];
|
||||
let k0_usize = scalar.windows_usize()[0];
|
||||
self.process_window(region, offset, w, k0, k0_usize, base)
|
||||
}
|
||||
|
||||
fn add_incomplete(
|
||||
|
@ -375,57 +384,18 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
|
|||
base: OrchardFixedBases,
|
||||
scalar: &ScalarFixed,
|
||||
) -> Result<EccPoint, Error> {
|
||||
// This is 2^w, where w is the window width
|
||||
let h = pallas::Scalar::from_u64(constants::H as u64);
|
||||
|
||||
let base_value = base.generator();
|
||||
let base_u = base.u();
|
||||
let scalar_windows_field = scalar.windows_field();
|
||||
let scalar_windows_usize = scalar.windows_usize();
|
||||
|
||||
for (w, k) in scalar_windows_field[1..(scalar_windows_field.len() - 1)]
|
||||
for (w, (k, k_usize)) in scalar_windows_field[..(scalar_windows_field.len() - 1)]
|
||||
.iter()
|
||||
.zip(scalar_windows_usize[..(scalar_windows_field.len() - 1)].iter())
|
||||
.enumerate()
|
||||
// Skip k_0 (already processed).
|
||||
.skip(1)
|
||||
{
|
||||
// Offset window index by 1 since we are starting on k_1
|
||||
let w = w + 1;
|
||||
|
||||
// Compute [(k_w + 2) ⋅ 8^w]B
|
||||
let mul_b = {
|
||||
let mul_b = k.map(|k| {
|
||||
base_value * (k + pallas::Scalar::from_u64(2)) * h.pow(&[w as u64, 0, 0, 0])
|
||||
});
|
||||
let mul_b = mul_b.map(|mul_b| mul_b.to_affine().coordinates().unwrap());
|
||||
|
||||
let x = mul_b.map(|mul_b| *mul_b.x());
|
||||
let x_cell = region.assign_advice(
|
||||
|| format!("mul_b_x, window {}", w),
|
||||
self.x_p,
|
||||
offset + w,
|
||||
|| x.ok_or(Error::SynthesisError),
|
||||
)?;
|
||||
let x = CellValue::new(x_cell, x);
|
||||
|
||||
let y = mul_b.map(|mul_b| *mul_b.y());
|
||||
let y_cell = region.assign_advice(
|
||||
|| format!("mul_b_y, window {}", w),
|
||||
self.y_p,
|
||||
offset + w,
|
||||
|| y.ok_or(Error::SynthesisError),
|
||||
)?;
|
||||
let y = CellValue::new(y_cell, y);
|
||||
|
||||
EccPoint { x, y }
|
||||
};
|
||||
|
||||
// Assign u = (y_p + z_w).sqrt()
|
||||
let u_val = scalar_windows_usize[w].map(|k| base_u[w].0[k]);
|
||||
region.assign_advice(
|
||||
|| "u",
|
||||
self.u,
|
||||
offset + w,
|
||||
|| u_val.ok_or(Error::SynthesisError),
|
||||
)?;
|
||||
let mul_b = self.process_window(region, offset, w, *k, *k_usize, base)?;
|
||||
|
||||
// Add to the accumulator
|
||||
acc = self
|
||||
|
@ -442,9 +412,6 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
|
|||
base: OrchardFixedBases,
|
||||
scalar: &ScalarFixed,
|
||||
) -> Result<EccPoint, Error> {
|
||||
// This is 2^w, where w is the window width
|
||||
let h = pallas::Scalar::from_u64(constants::H as u64);
|
||||
|
||||
// Assign u = (y_p + z_w).sqrt() for the most significant window
|
||||
{
|
||||
let u_val =
|
||||
|
@ -459,7 +426,7 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
|
|||
|
||||
// offset_acc = \sum_{j = 0}^{NUM_WINDOWS - 2} 2^{FIXED_BASE_WINDOW_SIZE * j+1}
|
||||
let offset_acc = (0..(NUM_WINDOWS - 1)).fold(pallas::Scalar::zero(), |acc, w| {
|
||||
acc + pallas::Scalar::from_u64(2).pow(&[
|
||||
acc + (*TWO_SCALAR).pow(&[
|
||||
constants::FIXED_BASE_WINDOW_SIZE as u64 * w as u64 + 1,
|
||||
0,
|
||||
0,
|
||||
|
@ -469,7 +436,7 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
|
|||
|
||||
// `scalar = [k * 8^84 - offset_acc]`, where `offset_acc = \sum_{j = 0}^{83} 2^{FIXED_BASE_WINDOW_SIZE * j + 1}`.
|
||||
let scalar = scalar.windows_field()[scalar.windows_field().len() - 1]
|
||||
.map(|k| k * h.pow(&[(NUM_WINDOWS - 1) as u64, 0, 0, 0]) - offset_acc);
|
||||
.map(|k| k * (*H_SCALAR).pow(&[(NUM_WINDOWS - 1) as u64, 0, 0, 0]) - offset_acc);
|
||||
|
||||
let mul_b = {
|
||||
let mul_b = scalar.map(|scalar| base.generator() * scalar);
|
||||
|
@ -545,9 +512,9 @@ impl ScalarFixed {
|
|||
.map(|idx| {
|
||||
let z_cur = zs[idx].value();
|
||||
let z_next = zs[idx + 1].value();
|
||||
let word = z_cur.zip(z_next).map(|(z_cur, z_next)| {
|
||||
z_cur - z_next * pallas::Base::from_u64(constants::H as u64)
|
||||
});
|
||||
let word = z_cur
|
||||
.zip(z_next)
|
||||
.map(|(z_cur, z_next)| z_cur - z_next * *H_BASE);
|
||||
word.map(|word| pallas::Scalar::from_bytes(&word.to_bytes()).unwrap())
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
|
|
|
@ -2,7 +2,8 @@ use super::super::{EccBaseFieldElemFixed, EccConfig, EccPoint, OrchardFixedBases
|
|||
|
||||
use crate::{
|
||||
circuit::gadget::utilities::{
|
||||
bitrange_subset, copy, lookup_range_check::LookupRangeCheckConfig, CellValue, Var,
|
||||
bitrange_subset, copy, lookup_range_check::LookupRangeCheckConfig, range_check, CellValue,
|
||||
Var,
|
||||
},
|
||||
constants::{self, util::decompose_scalar_fixed, T_P},
|
||||
primitives::sinsemilla,
|
||||
|
@ -37,7 +38,7 @@ impl From<&EccConfig> for Config {
|
|||
let add_incomplete_advices = config.super_config.add_incomplete_config.advice_columns();
|
||||
for canon_advice in config.canon_advices.iter() {
|
||||
assert!(
|
||||
!add_incomplete_advices.contains(&canon_advice),
|
||||
!add_incomplete_advices.contains(canon_advice),
|
||||
"Deconflict canon_advice columns with incomplete addition columns."
|
||||
);
|
||||
}
|
||||
|
@ -48,29 +49,21 @@ impl From<&EccConfig> for Config {
|
|||
|
||||
impl Config {
|
||||
pub fn create_gate(&self, meta: &mut ConstraintSystem<pallas::Base>) {
|
||||
// Check that an expression is in the range [0..range),
|
||||
// i.e. 0 ≤ word < range.
|
||||
let range_check = |word: Expression<pallas::Base>, range: usize| {
|
||||
(0..range).fold(Expression::Constant(pallas::Base::one()), |acc, i| {
|
||||
acc * (word.clone() - Expression::Constant(pallas::Base::from_u64(i as u64)))
|
||||
})
|
||||
};
|
||||
|
||||
// Decompose the base field element α into three-bit windows
|
||||
// using a running sum `z`, where z_{i+1} = (z_i - a_i) / (2^3)
|
||||
// for α = a_0 + (2^3) a_1 + ... + (2^{3(84)}) a_{84}.
|
||||
// for α = a_0 + 2^3 a_1 + ... + 2^{3*84} a_84.
|
||||
//
|
||||
// We set z_0 = α, which implies:
|
||||
// z_1 = (α - a_0) / 2^3, (subtract the lowest 3 bits)
|
||||
// = a_1 + (2^3) a_2 + ... + 2^{3(83)} a_{84},
|
||||
// = a_1 + 2^3 a_2 + ... + 2^{3*83} a_84,
|
||||
// z_2 = (z_1 - a_1) / 2^3
|
||||
// = a_2 + (2^3) a_3 + ... + 2^{3(82)} a_{84},
|
||||
// = a_2 + 2^3 a_3 + ... + 2^{3*82} a_84,
|
||||
// ...,
|
||||
// z_{84} = a_{84}
|
||||
// z_n = (z_{84} - a_{84}) / 2^3
|
||||
// z_84 = a_84
|
||||
// z_n = (z_84 - a_84) / 2^3
|
||||
// = 0.
|
||||
//
|
||||
// This gate checks that each a_i = z_i - z_{i+1} * (2^3) is within
|
||||
// This gate checks that each a_i = z_i - z_{i+1} * 2^3 is within
|
||||
// 3 bits.
|
||||
//
|
||||
// This gate also checks that this window uses the correct y_p and
|
||||
|
@ -81,8 +74,8 @@ impl Config {
|
|||
let z_cur = meta.query_advice(self.super_config.window, Rotation::cur());
|
||||
let z_next = meta.query_advice(self.super_config.window, Rotation::next());
|
||||
|
||||
// z_{i+1} = (z_i - a_i) / (2^3)
|
||||
// => a_i = z_i - (z_{i+1} * (2^3))
|
||||
// z_{i+1} = (z_i - a_i) / 2^3
|
||||
// => a_i = z_i - z_{i+1} * 2^3
|
||||
let word = z_cur - z_next * pallas::Base::from_u64(constants::H as u64);
|
||||
|
||||
// (word - 7) * (word - 6) * ... * (word - 1) * word = 0
|
||||
|
@ -108,7 +101,7 @@ impl Config {
|
|||
// The last three bits of α.
|
||||
let z_84_alpha = meta.query_advice(self.canon_advices[2], Rotation::prev());
|
||||
|
||||
// Decompose α into three pieces,
|
||||
// Decompose α into three pieces, in little-endian order:
|
||||
// α = α_0 (252 bits) || α_1 (2 bits) || α_2 (1 bit).
|
||||
//
|
||||
// α_0 is derived, not witnessed.
|
||||
|
@ -152,8 +145,9 @@ impl Config {
|
|||
// = 2^254 + 45560315531419706090280762371685220353.
|
||||
// Note that t_p < 2^130.
|
||||
//
|
||||
// α has been decomposed into three pieces,
|
||||
// α has been decomposed into three pieces in little-endian order:
|
||||
// α = α_0 (252 bits) || α_1 (2 bits) || α_2 (1 bit).
|
||||
// = α_0 + 2^252 α_1 + 2^254 α_2.
|
||||
//
|
||||
// If the MSB α_2 = 1, then:
|
||||
// - α_2 = 1 => α_1 = 0, and
|
||||
|
@ -259,8 +253,9 @@ impl Config {
|
|||
// = 2^254 + 45560315531419706090280762371685220353.
|
||||
// Note that t_p < 2^130.
|
||||
//
|
||||
// α has been decomposed into three pieces,
|
||||
// α has been decomposed into three pieces in little-endian order:
|
||||
// α = α_0 (252 bits) || α_1 (2 bits) || α_2 (1 bit).
|
||||
// = α_0 + 2^252 α_1 + 2^254 α_2.
|
||||
//
|
||||
// If the MSB α_2 = 1, then:
|
||||
// - α_2 = 1 => α_1 = 0, and
|
||||
|
@ -274,14 +269,6 @@ impl Config {
|
|||
let (alpha, running_sum) = (scalar.base_field_elem, &scalar.running_sum);
|
||||
let z_43_alpha = running_sum[42];
|
||||
let z_44_alpha = running_sum[43];
|
||||
{
|
||||
let a_43 = z_44_alpha
|
||||
.value()
|
||||
.zip(z_43_alpha.value())
|
||||
.map(|(z_44, z_43)| z_43 - z_44 * pallas::Base::from_u64(8));
|
||||
println!("a_43: {:?}", a_43);
|
||||
}
|
||||
|
||||
let z_84_alpha = running_sum[83];
|
||||
let z_85_alpha = running_sum[84];
|
||||
|
||||
|
@ -485,7 +472,7 @@ impl Config {
|
|||
.zip(word)
|
||||
.map(|(z_cur_val, word)| (z_cur_val - word) * eight_inv);
|
||||
let cell = region.assign_advice(
|
||||
|| format!("word {:?}", idx),
|
||||
|| format!("z_{:?}", idx + 1),
|
||||
self.super_config.window,
|
||||
offset + idx,
|
||||
|| z_next_val.ok_or(Error::SynthesisError),
|
||||
|
@ -538,7 +525,7 @@ pub mod tests {
|
|||
chip.clone(),
|
||||
layouter.namespace(|| "commit_ivk_r"),
|
||||
commit_ivk_r,
|
||||
&zero,
|
||||
zero,
|
||||
)?;
|
||||
|
||||
// note_commit_r
|
||||
|
@ -548,7 +535,7 @@ pub mod tests {
|
|||
chip.clone(),
|
||||
layouter.namespace(|| "note_commit_r"),
|
||||
note_commit_r,
|
||||
&zero,
|
||||
zero,
|
||||
)?;
|
||||
|
||||
// nullifier_k
|
||||
|
@ -558,7 +545,7 @@ pub mod tests {
|
|||
chip.clone(),
|
||||
layouter.namespace(|| "nullifier_k"),
|
||||
nullifier_k,
|
||||
&zero,
|
||||
zero,
|
||||
)?;
|
||||
|
||||
// value_commit_r
|
||||
|
@ -568,7 +555,7 @@ pub mod tests {
|
|||
chip.clone(),
|
||||
layouter.namespace(|| "value_commit_r"),
|
||||
value_commit_r,
|
||||
&zero,
|
||||
zero,
|
||||
)?;
|
||||
|
||||
// spend_auth_g
|
||||
|
@ -578,7 +565,7 @@ pub mod tests {
|
|||
chip,
|
||||
layouter.namespace(|| "spend_auth_g"),
|
||||
spend_auth_g,
|
||||
&zero,
|
||||
zero,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
|
@ -637,7 +624,7 @@ pub mod tests {
|
|||
)?;
|
||||
let result =
|
||||
base.mul_base_field_elem(layouter.namespace(|| "mul by zero"), scalar_fixed)?;
|
||||
result.constrain_equal(layouter.namespace(|| "[0]B = 𝒪"), &zero)?;
|
||||
result.constrain_equal(layouter.namespace(|| "[0]B = 𝒪"), zero)?;
|
||||
}
|
||||
|
||||
// [-1]B is the largest base field element
|
||||
|
|
|
@ -88,7 +88,7 @@ pub mod tests {
|
|||
chip.clone(),
|
||||
layouter.namespace(|| "commit_ivk_r"),
|
||||
commit_ivk_r,
|
||||
&zero,
|
||||
zero,
|
||||
)?;
|
||||
|
||||
// note_commit_r
|
||||
|
@ -98,7 +98,7 @@ pub mod tests {
|
|||
chip.clone(),
|
||||
layouter.namespace(|| "note_commit_r"),
|
||||
note_commit_r,
|
||||
&zero,
|
||||
zero,
|
||||
)?;
|
||||
|
||||
// nullifier_k
|
||||
|
@ -108,7 +108,7 @@ pub mod tests {
|
|||
chip.clone(),
|
||||
layouter.namespace(|| "nullifier_k"),
|
||||
nullifier_k,
|
||||
&zero,
|
||||
zero,
|
||||
)?;
|
||||
|
||||
// value_commit_r
|
||||
|
@ -118,7 +118,7 @@ pub mod tests {
|
|||
chip.clone(),
|
||||
layouter.namespace(|| "value_commit_r"),
|
||||
value_commit_r,
|
||||
&zero,
|
||||
zero,
|
||||
)?;
|
||||
|
||||
// spend_auth_g
|
||||
|
@ -128,7 +128,7 @@ pub mod tests {
|
|||
chip,
|
||||
layouter.namespace(|| "spend_auth_g"),
|
||||
spend_auth_g,
|
||||
&zero,
|
||||
zero,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
|
@ -188,7 +188,7 @@ pub mod tests {
|
|||
Some(scalar_fixed),
|
||||
)?;
|
||||
let result = base.mul(layouter.namespace(|| "mul by zero"), &scalar_fixed)?;
|
||||
result.constrain_equal(layouter.namespace(|| "[0]B = 𝒪"), &zero)?;
|
||||
result.constrain_equal(layouter.namespace(|| "[0]B = 𝒪"), zero)?;
|
||||
}
|
||||
|
||||
// [-1]B is the largest scalar field element.
|
||||
|
|
|
@ -194,7 +194,7 @@ pub mod tests {
|
|||
Some(scalar_fixed),
|
||||
)?;
|
||||
let result = value_commit_v.mul(layouter.namespace(|| "mul by zero"), &scalar_fixed)?;
|
||||
result.constrain_equal(layouter.namespace(|| "[0]B = 𝒪"), &zero)?;
|
||||
result.constrain_equal(layouter.namespace(|| "[0]B = 𝒪"), zero)?;
|
||||
}
|
||||
|
||||
// Random [a]B
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
use super::{CellValue, EccConfig, Var};
|
||||
use crate::constants::{self, util};
|
||||
use crate::{
|
||||
circuit::gadget::utilities::range_check,
|
||||
constants::{self, util},
|
||||
};
|
||||
use arrayvec::ArrayVec;
|
||||
use halo2::{
|
||||
circuit::Region,
|
||||
plonk::{Advice, Column, ConstraintSystem, Error, Expression, Permutation, Selector},
|
||||
plonk::{Advice, Column, ConstraintSystem, Error, Permutation, Selector},
|
||||
poly::Rotation,
|
||||
};
|
||||
use pasta_curves::{arithmetic::FieldExt, pallas};
|
||||
|
@ -38,11 +41,7 @@ impl Config {
|
|||
|
||||
// Constrain each window to a 3-bit value:
|
||||
// 1 * (window - 0) * (window - 1) * ... * (window - 7)
|
||||
let range_check =
|
||||
(0..constants::H).fold(Expression::Constant(pallas::Base::one()), |acc, i| {
|
||||
acc * (window.clone() - Expression::Constant(pallas::Base::from_u64(i as u64)))
|
||||
});
|
||||
vec![q_scalar_fixed * range_check]
|
||||
vec![q_scalar_fixed * range_check(window, constants::H)]
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use ff::PrimeFieldBits;
|
||||
use halo2::{
|
||||
circuit::{Cell, Layouter, Region},
|
||||
plonk::{Advice, Column, Error, Permutation},
|
||||
plonk::{Advice, Column, Error, Expression, Permutation},
|
||||
};
|
||||
use pasta_curves::arithmetic::FieldExt;
|
||||
use std::array;
|
||||
|
@ -123,3 +123,12 @@ pub fn bitrange_subset<F: FieldExt + PrimeFieldBits>(
|
|||
|
||||
F::from_bytes(&bytearray.try_into().unwrap()).unwrap()
|
||||
}
|
||||
|
||||
/// Check that an expression is in the small range [0..range),
|
||||
/// i.e. 0 ≤ word < range.
|
||||
pub fn range_check<F: FieldExt>(word: Expression<F>, range: usize) -> Expression<F> {
|
||||
(0..range)
|
||||
.map(|i| Expression::Constant(F::from_u64(i as u64)))
|
||||
.reduce(|acc, i| acc * (word.clone() - i))
|
||||
.expect("range > 0")
|
||||
}
|
||||
|
|
|
@ -82,10 +82,6 @@ pub const NUM_WINDOWS: usize =
|
|||
pub const NUM_WINDOWS_SHORT: usize =
|
||||
(L_VALUE + FIXED_BASE_WINDOW_SIZE - 1) / FIXED_BASE_WINDOW_SIZE;
|
||||
|
||||
/// Number of bits for which complete addition needs to be used in variable-base
|
||||
/// scalar multiplication
|
||||
pub const NUM_COMPLETE_BITS: usize = 3;
|
||||
|
||||
/// For each fixed base, we calculate its scalar multiples in three-bit windows.
|
||||
/// Each window will have $2^3 = 8$ points.
|
||||
fn compute_window_table<C: CurveAffine>(base: C, num_windows: usize) -> Vec<[C; H]> {
|
||||
|
|
Loading…
Reference in New Issue