mirror of https://github.com/zcash/halo2.git
Merge pull request #106 from zcash/refactor-constants
Refactor `constants` to add `constants::load`
This commit is contained in:
commit
cd1e72bbcd
362
src/constants.rs
362
src/constants.rs
|
@ -14,11 +14,17 @@ pub mod spend_auth_g;
|
|||
pub mod value_commit_r;
|
||||
pub mod value_commit_v;
|
||||
|
||||
pub mod load;
|
||||
pub mod util;
|
||||
|
||||
pub use load::{OrchardFixedBase, OrchardFixedBasesFull, ValueCommitV};
|
||||
|
||||
/// $\ell^\mathsf{Orchard}_\mathsf{base}$
|
||||
pub(crate) const L_ORCHARD_BASE: usize = 255;
|
||||
|
||||
/// $\ell^\mathsf{Orchard}_\mathsf{scalar}$
|
||||
pub(crate) const L_ORCHARD_SCALAR: usize = 255;
|
||||
|
||||
/// $\ell_\mathsf{value}$
|
||||
pub(crate) const L_VALUE: usize = 64;
|
||||
|
||||
|
@ -59,237 +65,181 @@ pub const NUM_WINDOWS_SHORT: usize =
|
|||
/// scalar multiplication
|
||||
pub const NUM_COMPLETE_BITS: usize = 3;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct CommitIvkR<C: CurveAffine>(pub OrchardFixedBase<C>);
|
||||
/// 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]> {
|
||||
let mut window_table: Vec<[C; H]> = Vec::with_capacity(num_windows);
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct NoteCommitR<C: CurveAffine>(pub OrchardFixedBase<C>);
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct NullifierK<C: CurveAffine>(pub OrchardFixedBase<C>);
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ValueCommitR<C: CurveAffine>(pub OrchardFixedBase<C>);
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ValueCommitV<C: CurveAffine>(pub OrchardFixedBase<C>);
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct SpendAuthG<C: CurveAffine>(pub OrchardFixedBase<C>);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct OrchardFixedBase<C: CurveAffine>(C);
|
||||
|
||||
impl<C: CurveAffine> OrchardFixedBase<C> {
|
||||
pub fn new(generator: C) -> Self {
|
||||
OrchardFixedBase(generator)
|
||||
}
|
||||
|
||||
pub fn value(&self) -> C {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub trait FixedBase<C: CurveAffine> {
|
||||
/// 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(&self, num_windows: usize) -> Vec<[C; H]>;
|
||||
|
||||
/// For each window, we interpolate the $x$-coordinate.
|
||||
/// Here, we pre-compute and store the coefficients of the interpolation polynomial.
|
||||
fn compute_lagrange_coeffs(&self, num_windows: usize) -> Vec<[C::Base; H]>;
|
||||
|
||||
/// For each window, $z$ is a field element such that for each point $(x, y)$ in the window:
|
||||
/// - $z + y = u^2$ (some square in the field); and
|
||||
/// - $z - y$ is not a square.
|
||||
/// If successful, return a vector of `(z: u64, us: [C::Base; H])` for each window.
|
||||
fn find_zs_and_us(&self, num_windows: usize) -> Option<Vec<(u64, [C::Base; H])>>;
|
||||
}
|
||||
|
||||
impl<C: CurveAffine> FixedBase<C> for OrchardFixedBase<C> {
|
||||
fn compute_window_table(&self, num_windows: usize) -> Vec<[C; H]> {
|
||||
let mut window_table: Vec<[C; H]> = Vec::with_capacity(num_windows);
|
||||
|
||||
// Generate window table entries for all windows but the last.
|
||||
// For these first `num_windows - 1` windows, we compute the multiple [(k+2)*(2^3)^w]B.
|
||||
// Here, w ranges from [0..`num_windows - 1`)
|
||||
for w in 0..(num_windows - 1) {
|
||||
window_table.push(
|
||||
(0..H)
|
||||
.map(|k| {
|
||||
// scalar = (k+2)*(8^w)
|
||||
let scalar = C::ScalarExt::from_u64(k as u64 + 2)
|
||||
* C::ScalarExt::from_u64(H as u64).pow(&[w as u64, 0, 0, 0]);
|
||||
(self.0 * scalar).to_affine()
|
||||
})
|
||||
.collect::<ArrayVec<C, H>>()
|
||||
.into_inner()
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
// Generate window table entries for the last window, w = `num_windows - 1`.
|
||||
// For the last window, we compute [k * (2^3)^w - sum]B, where sum is defined
|
||||
// as sum = \sum_{j = 0}^{`num_windows - 2`} 2^{3j+1}
|
||||
let sum = (0..(num_windows - 1)).fold(C::ScalarExt::zero(), |acc, j| {
|
||||
acc + C::ScalarExt::from_u64(2).pow(&[
|
||||
FIXED_BASE_WINDOW_SIZE as u64 * j as u64 + 1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
])
|
||||
});
|
||||
// Generate window table entries for all windows but the last.
|
||||
// For these first `num_windows - 1` windows, we compute the multiple [(k+2)*(2^3)^w]B.
|
||||
// Here, w ranges from [0..`num_windows - 1`)
|
||||
for w in 0..(num_windows - 1) {
|
||||
window_table.push(
|
||||
(0..H)
|
||||
.map(|k| {
|
||||
// scalar = k * (2^3)^w - sum, where w = `num_windows - 1`
|
||||
let scalar = C::ScalarExt::from_u64(k as u64)
|
||||
* C::ScalarExt::from_u64(H as u64).pow(&[
|
||||
(num_windows - 1) as u64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
])
|
||||
- sum;
|
||||
(self.0 * scalar).to_affine()
|
||||
// scalar = (k+2)*(8^w)
|
||||
let scalar = C::ScalarExt::from_u64(k as u64 + 2)
|
||||
* C::ScalarExt::from_u64(H as u64).pow(&[w as u64, 0, 0, 0]);
|
||||
(base * scalar).to_affine()
|
||||
})
|
||||
.collect::<ArrayVec<C, H>>()
|
||||
.into_inner()
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
window_table
|
||||
}
|
||||
|
||||
fn compute_lagrange_coeffs(&self, num_windows: usize) -> Vec<[C::Base; H]> {
|
||||
// We are interpolating over the 3-bit window, k \in [0..8)
|
||||
let points: Vec<_> = (0..H).map(|i| C::Base::from_u64(i as u64)).collect();
|
||||
|
||||
let window_table = self.compute_window_table(num_windows);
|
||||
|
||||
window_table
|
||||
.iter()
|
||||
.map(|window_points| {
|
||||
let x_window_points: Vec<_> = window_points
|
||||
.iter()
|
||||
.map(|point| *point.coordinates().unwrap().x())
|
||||
.collect();
|
||||
lagrange_interpolate(&points, &x_window_points)
|
||||
.into_iter()
|
||||
.collect::<ArrayVec<C::Base, H>>()
|
||||
.into_inner()
|
||||
.unwrap()
|
||||
// Generate window table entries for the last window, w = `num_windows - 1`.
|
||||
// For the last window, we compute [k * (2^3)^w - sum]B, where sum is defined
|
||||
// as sum = \sum_{j = 0}^{`num_windows - 2`} 2^{3j+1}
|
||||
let sum = (0..(num_windows - 1)).fold(C::ScalarExt::zero(), |acc, j| {
|
||||
acc + C::ScalarExt::from_u64(2).pow(&[
|
||||
FIXED_BASE_WINDOW_SIZE as u64 * j as u64 + 1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
])
|
||||
});
|
||||
window_table.push(
|
||||
(0..H)
|
||||
.map(|k| {
|
||||
// scalar = k * (2^3)^w - sum, where w = `num_windows - 1`
|
||||
let scalar = C::ScalarExt::from_u64(k as u64)
|
||||
* C::ScalarExt::from_u64(H as u64).pow(&[(num_windows - 1) as u64, 0, 0, 0])
|
||||
- sum;
|
||||
(base * scalar).to_affine()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
.collect::<ArrayVec<C, H>>()
|
||||
.into_inner()
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
/// For each window, z is a field element such that for each point (x, y) in the window:
|
||||
/// - z + y = u^2 (some square in the field); and
|
||||
/// - z - y is not a square.
|
||||
/// If successful, return a vector of `(z: u64, us: [C::Base; H])` for each window.
|
||||
fn find_zs_and_us(&self, num_windows: usize) -> Option<Vec<(u64, [C::Base; H])>> {
|
||||
// Closure to find z and u's for one window
|
||||
let find_z_and_us = |window_points: &[C]| {
|
||||
assert_eq!(H, window_points.len());
|
||||
window_table
|
||||
}
|
||||
|
||||
let ys: Vec<_> = window_points
|
||||
/// For each window, we interpolate the $x$-coordinate.
|
||||
/// Here, we pre-compute and store the coefficients of the interpolation polynomial.
|
||||
fn compute_lagrange_coeffs<C: CurveAffine>(base: C, num_windows: usize) -> Vec<[C::Base; H]> {
|
||||
// We are interpolating over the 3-bit window, k \in [0..8)
|
||||
let points: Vec<_> = (0..H).map(|i| C::Base::from_u64(i as u64)).collect();
|
||||
|
||||
let window_table = compute_window_table(base, num_windows);
|
||||
|
||||
window_table
|
||||
.iter()
|
||||
.map(|window_points| {
|
||||
let x_window_points: Vec<_> = window_points
|
||||
.iter()
|
||||
.map(|point| *point.coordinates().unwrap().y())
|
||||
.map(|point| *point.coordinates().unwrap().x())
|
||||
.collect();
|
||||
(0..(1000 * (1 << (2 * H)))).find_map(|z| {
|
||||
ys.iter()
|
||||
.map(|&y| {
|
||||
if (-y + C::Base::from_u64(z)).sqrt().is_none().into() {
|
||||
(y + C::Base::from_u64(z)).sqrt().into()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Option<ArrayVec<C::Base, H>>>()
|
||||
.map(|us| (z, us.into_inner().unwrap()))
|
||||
})
|
||||
};
|
||||
lagrange_interpolate(&points, &x_window_points)
|
||||
.into_iter()
|
||||
.collect::<ArrayVec<C::Base, H>>()
|
||||
.into_inner()
|
||||
.unwrap()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
let window_table = self.compute_window_table(num_windows);
|
||||
window_table
|
||||
/// For each window, $z$ is a field element such that for each point $(x, y)$ in the window:
|
||||
/// - $z + y = u^2$ (some square in the field); and
|
||||
/// - $z - y$ is not a square.
|
||||
/// If successful, return a vector of `(z: u64, us: [C::Base; H])` for each window.
|
||||
fn find_zs_and_us<C: CurveAffine>(base: C, num_windows: usize) -> Option<Vec<(u64, [C::Base; H])>> {
|
||||
// Closure to find z and u's for one window
|
||||
let find_z_and_us = |window_points: &[C]| {
|
||||
assert_eq!(H, window_points.len());
|
||||
|
||||
let ys: Vec<_> = window_points
|
||||
.iter()
|
||||
.map(|window_points| find_z_and_us(window_points))
|
||||
.collect()
|
||||
}
|
||||
.map(|point| *point.coordinates().unwrap().y())
|
||||
.collect();
|
||||
(0..(1000 * (1 << (2 * H)))).find_map(|z| {
|
||||
ys.iter()
|
||||
.map(|&y| {
|
||||
if (-y + C::Base::from_u64(z)).sqrt().is_none().into() {
|
||||
(y + C::Base::from_u64(z)).sqrt().into()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Option<ArrayVec<C::Base, H>>>()
|
||||
.map(|us| (z, us.into_inner().unwrap()))
|
||||
})
|
||||
};
|
||||
|
||||
let window_table = compute_window_table(base, num_windows);
|
||||
window_table
|
||||
.iter()
|
||||
.map(|window_points| find_z_and_us(window_points))
|
||||
.collect()
|
||||
}
|
||||
|
||||
trait TestFixedBase<C: CurveAffine> {
|
||||
// Test that Lagrange interpolation coefficients reproduce the correct x-coordinate
|
||||
// for each fixed-base multiple in each window.
|
||||
fn test_lagrange_coeffs(&self, num_windows: usize);
|
||||
#[cfg(test)]
|
||||
// Test that Lagrange interpolation coefficients reproduce the correct x-coordinate
|
||||
// for each fixed-base multiple in each window.
|
||||
fn test_lagrange_coeffs<C: CurveAffine>(base: C, num_windows: usize) {
|
||||
let lagrange_coeffs = compute_lagrange_coeffs(base, num_windows);
|
||||
|
||||
// Test that the z-values and u-values satisfy the conditions:
|
||||
// 1. z + y = u^2,
|
||||
// 2. z - y is not a square
|
||||
// for the y-coordinate of each fixed-base multiple in each window.
|
||||
fn test_zs_and_us(&self, z: &[u64], u: &[[[u8; 32]; H]], num_windows: usize);
|
||||
}
|
||||
|
||||
impl<C: CurveAffine> TestFixedBase<C> for OrchardFixedBase<C> {
|
||||
fn test_lagrange_coeffs(&self, num_windows: usize) {
|
||||
let lagrange_coeffs = self.compute_lagrange_coeffs(num_windows);
|
||||
|
||||
// Check first 84 windows, i.e. `k_0, k_1, ..., k_83`
|
||||
for (idx, coeffs) in lagrange_coeffs[0..(num_windows - 1)].iter().enumerate() {
|
||||
// Test each three-bit chunk in this window.
|
||||
for bits in 0..(1 << FIXED_BASE_WINDOW_SIZE) {
|
||||
{
|
||||
// Interpolate the x-coordinate using this window's coefficients
|
||||
let interpolated_x = util::evaluate::<C>(bits, coeffs);
|
||||
|
||||
// Compute the actual x-coordinate of the multiple [(k+2)*(8^w)]B.
|
||||
let point = self.0
|
||||
* C::Scalar::from_u64(bits as u64 + 2)
|
||||
* C::Scalar::from_u64(H as u64).pow(&[idx as u64, 0, 0, 0]);
|
||||
let x = *point.to_affine().coordinates().unwrap().x();
|
||||
|
||||
// Check that the interpolated x-coordinate matches the actual one.
|
||||
assert_eq!(x, interpolated_x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check last window.
|
||||
// Check first 84 windows, i.e. `k_0, k_1, ..., k_83`
|
||||
for (idx, coeffs) in lagrange_coeffs[0..(num_windows - 1)].iter().enumerate() {
|
||||
// Test each three-bit chunk in this window.
|
||||
for bits in 0..(1 << FIXED_BASE_WINDOW_SIZE) {
|
||||
// Interpolate the x-coordinate using the last window's coefficients
|
||||
let interpolated_x = util::evaluate::<C>(bits, &lagrange_coeffs[num_windows - 1]);
|
||||
{
|
||||
// Interpolate the x-coordinate using this window's coefficients
|
||||
let interpolated_x = util::evaluate::<C>(bits, coeffs);
|
||||
|
||||
// Compute the actual x-coordinate of the multiple [k * (8^84) - offset]B,
|
||||
// where offset = \sum_{j = 0}^{83} 2^{3j+1}
|
||||
let offset = (0..(num_windows - 1)).fold(C::Scalar::zero(), |acc, w| {
|
||||
acc + C::Scalar::from_u64(2).pow(&[
|
||||
FIXED_BASE_WINDOW_SIZE as u64 * w as u64 + 1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
])
|
||||
});
|
||||
let scalar = C::Scalar::from_u64(bits as u64)
|
||||
* C::Scalar::from_u64(H as u64).pow(&[(num_windows - 1) as u64, 0, 0, 0])
|
||||
- offset;
|
||||
let point = self.0 * scalar;
|
||||
let x = *point.to_affine().coordinates().unwrap().x();
|
||||
// Compute the actual x-coordinate of the multiple [(k+2)*(8^w)]B.
|
||||
let point = base
|
||||
* C::Scalar::from_u64(bits as u64 + 2)
|
||||
* C::Scalar::from_u64(H as u64).pow(&[idx as u64, 0, 0, 0]);
|
||||
let x = *point.to_affine().coordinates().unwrap().x();
|
||||
|
||||
// Check that the interpolated x-coordinate matches the actual one.
|
||||
assert_eq!(x, interpolated_x);
|
||||
}
|
||||
}
|
||||
|
||||
fn test_zs_and_us(&self, z: &[u64], u: &[[[u8; 32]; H]], num_windows: usize) {
|
||||
let window_table = self.compute_window_table(num_windows);
|
||||
|
||||
for ((u, z), window_points) in u.iter().zip(z.iter()).zip(window_table) {
|
||||
for (u, point) in u.iter().zip(window_points.iter()) {
|
||||
let y = *point.coordinates().unwrap().y();
|
||||
let u = C::Base::from_bytes(u).unwrap();
|
||||
assert_eq!(C::Base::from_u64(*z) + y, u * u); // allow either square root
|
||||
assert!(bool::from((C::Base::from_u64(*z) - y).sqrt().is_none()));
|
||||
// Check that the interpolated x-coordinate matches the actual one.
|
||||
assert_eq!(x, interpolated_x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check last window.
|
||||
for bits in 0..(1 << FIXED_BASE_WINDOW_SIZE) {
|
||||
// Interpolate the x-coordinate using the last window's coefficients
|
||||
let interpolated_x = util::evaluate::<C>(bits, &lagrange_coeffs[num_windows - 1]);
|
||||
|
||||
// Compute the actual x-coordinate of the multiple [k * (8^84) - offset]B,
|
||||
// where offset = \sum_{j = 0}^{83} 2^{3j+1}
|
||||
let offset = (0..(num_windows - 1)).fold(C::Scalar::zero(), |acc, w| {
|
||||
acc + C::Scalar::from_u64(2).pow(&[
|
||||
FIXED_BASE_WINDOW_SIZE as u64 * w as u64 + 1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
])
|
||||
});
|
||||
let scalar = C::Scalar::from_u64(bits as u64)
|
||||
* C::Scalar::from_u64(H as u64).pow(&[(num_windows - 1) as u64, 0, 0, 0])
|
||||
- offset;
|
||||
let point = base * scalar;
|
||||
let x = *point.to_affine().coordinates().unwrap().x();
|
||||
|
||||
// Check that the interpolated x-coordinate matches the actual one.
|
||||
assert_eq!(x, interpolated_x);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
// Test that the z-values and u-values satisfy the conditions:
|
||||
// 1. z + y = u^2,
|
||||
// 2. z - y is not a square
|
||||
// for the y-coordinate of each fixed-base multiple in each window.
|
||||
fn test_zs_and_us<C: CurveAffine>(base: C, z: &[u64], u: &[[[u8; 32]; H]], num_windows: usize) {
|
||||
let window_table = compute_window_table(base, num_windows);
|
||||
|
||||
for ((u, z), window_points) in u.iter().zip(z.iter()).zip(window_table) {
|
||||
for (u, point) in u.iter().zip(window_points.iter()) {
|
||||
let y = *point.coordinates().unwrap().y();
|
||||
let u = C::Base::from_bytes(u).unwrap();
|
||||
assert_eq!(C::Base::from_u64(*z) + y, u * u); // allow either square root
|
||||
assert!(bool::from((C::Base::from_u64(*z) - y).sqrt().is_none()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use super::{CommitIvkR, OrchardFixedBase};
|
||||
use halo2::arithmetic::{CurveAffine, FieldExt};
|
||||
|
||||
/// Generator used in SinsemillaCommit randomness for IVK commitment
|
||||
|
@ -2918,19 +2917,19 @@ pub const U: [[[u8; 32]; super::H]; super::NUM_WINDOWS] = [
|
|||
],
|
||||
];
|
||||
|
||||
pub fn generator<C: CurveAffine>() -> CommitIvkR<C> {
|
||||
CommitIvkR(OrchardFixedBase::<C>::new(
|
||||
C::from_xy(
|
||||
C::Base::from_bytes(&GENERATOR.0).unwrap(),
|
||||
C::Base::from_bytes(&GENERATOR.1).unwrap(),
|
||||
)
|
||||
.unwrap(),
|
||||
))
|
||||
pub fn generator<C: CurveAffine>() -> C {
|
||||
C::from_xy(
|
||||
C::Base::from_bytes(&GENERATOR.0).unwrap(),
|
||||
C::Base::from_bytes(&GENERATOR.1).unwrap(),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::{TestFixedBase, COMMIT_IVK_PERSONALIZATION, NUM_WINDOWS};
|
||||
use super::super::{
|
||||
test_lagrange_coeffs, test_zs_and_us, COMMIT_IVK_PERSONALIZATION, NUM_WINDOWS,
|
||||
};
|
||||
use super::*;
|
||||
use crate::primitives::sinsemilla::CommitDomain;
|
||||
use group::Curve;
|
||||
|
@ -2952,12 +2951,12 @@ mod tests {
|
|||
#[test]
|
||||
fn lagrange_coeffs() {
|
||||
let base = super::generator::<pallas::Affine>();
|
||||
base.0.test_lagrange_coeffs(NUM_WINDOWS);
|
||||
test_lagrange_coeffs(base, NUM_WINDOWS);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn z() {
|
||||
let base = super::generator::<pallas::Affine>();
|
||||
base.0.test_zs_and_us(&Z, &U, NUM_WINDOWS);
|
||||
test_zs_and_us(base, &Z, &U, NUM_WINDOWS);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,215 @@
|
|||
use std::convert::TryInto;
|
||||
|
||||
use crate::constants::{self, compute_lagrange_coeffs, H, NUM_WINDOWS, NUM_WINDOWS_SHORT};
|
||||
use halo2::arithmetic::{CurveAffine, FieldExt};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum OrchardFixedBasesFull<C: CurveAffine> {
|
||||
CommitIvkR(PhantomData<C>),
|
||||
NoteCommitR(PhantomData<C>),
|
||||
NullifierK(PhantomData<C>),
|
||||
ValueCommitR(PhantomData<C>),
|
||||
SpendAuthG(PhantomData<C>),
|
||||
}
|
||||
|
||||
/// A fixed base to be used in scalar multiplication with a full-width scalar.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct OrchardFixedBase<C: CurveAffine> {
|
||||
pub generator: C,
|
||||
pub lagrange_coeffs: LagrangeCoeffs<C::Base>,
|
||||
pub z: Z<C::Base>,
|
||||
pub u: U<C::Base>,
|
||||
}
|
||||
|
||||
impl<C: CurveAffine> From<OrchardFixedBasesFull<C>> for OrchardFixedBase<C> {
|
||||
fn from(base: OrchardFixedBasesFull<C>) -> Self {
|
||||
let (generator, z, u) = match base {
|
||||
OrchardFixedBasesFull::CommitIvkR(_) => (
|
||||
super::commit_ivk_r::generator(),
|
||||
super::commit_ivk_r::Z.into(),
|
||||
super::commit_ivk_r::U.into(),
|
||||
),
|
||||
OrchardFixedBasesFull::NoteCommitR(_) => (
|
||||
super::note_commit_r::generator(),
|
||||
super::note_commit_r::Z.into(),
|
||||
super::note_commit_r::U.into(),
|
||||
),
|
||||
OrchardFixedBasesFull::NullifierK(_) => (
|
||||
super::nullifier_k::generator(),
|
||||
super::nullifier_k::Z.into(),
|
||||
super::nullifier_k::U.into(),
|
||||
),
|
||||
OrchardFixedBasesFull::ValueCommitR(_) => (
|
||||
super::value_commit_r::generator(),
|
||||
super::value_commit_r::Z.into(),
|
||||
super::value_commit_r::U.into(),
|
||||
),
|
||||
OrchardFixedBasesFull::SpendAuthG(_) => (
|
||||
super::spend_auth_g::generator(),
|
||||
super::spend_auth_g::Z.into(),
|
||||
super::spend_auth_g::U.into(),
|
||||
),
|
||||
};
|
||||
|
||||
Self {
|
||||
generator,
|
||||
lagrange_coeffs: compute_lagrange_coeffs(generator, NUM_WINDOWS).into(),
|
||||
z,
|
||||
u,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A fixed base to be used in scalar multiplication with a short signed exponent.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct ValueCommitV<C: CurveAffine> {
|
||||
pub generator: C,
|
||||
pub lagrange_coeffs_short: LagrangeCoeffsShort<C::Base>,
|
||||
pub z_short: ZShort<C::Base>,
|
||||
pub u_short: UShort<C::Base>,
|
||||
}
|
||||
|
||||
impl<C: CurveAffine> ValueCommitV<C> {
|
||||
pub fn get() -> Self {
|
||||
let generator = super::value_commit_v::generator();
|
||||
Self {
|
||||
generator,
|
||||
lagrange_coeffs_short: compute_lagrange_coeffs(generator, NUM_WINDOWS_SHORT).into(),
|
||||
z_short: super::value_commit_v::Z_SHORT.into(),
|
||||
u_short: super::value_commit_v::U_SHORT.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
// 8 coefficients per window
|
||||
pub struct WindowLagrangeCoeffs<F: FieldExt>(pub Box<[F; H]>);
|
||||
|
||||
impl<F: FieldExt> From<&[F; H]> for WindowLagrangeCoeffs<F> {
|
||||
fn from(array: &[F; H]) -> Self {
|
||||
Self(Box::new(*array))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
// 85 windows per base (with the exception of ValueCommitV)
|
||||
pub struct LagrangeCoeffs<F: FieldExt>(pub Box<[WindowLagrangeCoeffs<F>; constants::NUM_WINDOWS]>);
|
||||
|
||||
impl<F: FieldExt> From<Vec<WindowLagrangeCoeffs<F>>> for LagrangeCoeffs<F> {
|
||||
fn from(windows: Vec<WindowLagrangeCoeffs<F>>) -> Self {
|
||||
Self(windows.into_boxed_slice().try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: FieldExt> From<Vec<[F; H]>> for LagrangeCoeffs<F> {
|
||||
fn from(arrays: Vec<[F; H]>) -> Self {
|
||||
let windows: Vec<WindowLagrangeCoeffs<F>> =
|
||||
arrays.iter().map(|array| array.into()).collect();
|
||||
windows.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
// 22 windows for ValueCommitV
|
||||
pub struct LagrangeCoeffsShort<F: FieldExt>(pub Box<[WindowLagrangeCoeffs<F>; NUM_WINDOWS_SHORT]>);
|
||||
|
||||
impl<F: FieldExt> From<Vec<WindowLagrangeCoeffs<F>>> for LagrangeCoeffsShort<F> {
|
||||
fn from(windows: Vec<WindowLagrangeCoeffs<F>>) -> Self {
|
||||
Self(windows.into_boxed_slice().try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: FieldExt> From<Vec<[F; H]>> for LagrangeCoeffsShort<F> {
|
||||
fn from(arrays: Vec<[F; H]>) -> Self {
|
||||
let windows: Vec<WindowLagrangeCoeffs<F>> =
|
||||
arrays.iter().map(|array| array.into()).collect();
|
||||
windows.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
// 85 Z's per base (with the exception of ValueCommitV)
|
||||
pub struct Z<F: FieldExt>(pub Box<[F; NUM_WINDOWS]>);
|
||||
|
||||
impl<F: FieldExt> From<[u64; NUM_WINDOWS]> for Z<F> {
|
||||
fn from(zs: [u64; NUM_WINDOWS]) -> Self {
|
||||
Self(
|
||||
zs.iter()
|
||||
.map(|z| F::from_u64(*z))
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice()
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
// 22 Z's for ValueCommitV
|
||||
pub struct ZShort<F: FieldExt>(pub Box<[F; NUM_WINDOWS_SHORT]>);
|
||||
|
||||
impl<F: FieldExt> From<[u64; NUM_WINDOWS_SHORT]> for ZShort<F> {
|
||||
fn from(zs: [u64; NUM_WINDOWS_SHORT]) -> Self {
|
||||
Self(
|
||||
zs.iter()
|
||||
.map(|z| F::from_u64(*z))
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice()
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
// 8 u's per window
|
||||
pub struct WindowUs<F: FieldExt>(pub Box<[F; H]>);
|
||||
|
||||
impl<F: FieldExt> From<&[[u8; 32]; H]> for WindowUs<F> {
|
||||
fn from(window_us: &[[u8; 32]; H]) -> Self {
|
||||
Self(
|
||||
window_us
|
||||
.iter()
|
||||
.map(|u| F::from_bytes(u).unwrap())
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice()
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
// 85 windows per base (with the exception of ValueCommitV)
|
||||
pub struct U<F: FieldExt>(pub Box<[WindowUs<F>; NUM_WINDOWS]>);
|
||||
|
||||
impl<F: FieldExt> From<Vec<WindowUs<F>>> for U<F> {
|
||||
fn from(windows: Vec<WindowUs<F>>) -> Self {
|
||||
Self(windows.into_boxed_slice().try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: FieldExt> From<[[[u8; 32]; H]; NUM_WINDOWS]> for U<F> {
|
||||
fn from(window_us: [[[u8; 32]; H]; NUM_WINDOWS]) -> Self {
|
||||
let windows: Vec<WindowUs<F>> = window_us.iter().map(|us| us.into()).collect();
|
||||
windows.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
// 22 windows for ValueCommitV
|
||||
pub struct UShort<F: FieldExt>(pub Box<[WindowUs<F>; NUM_WINDOWS_SHORT]>);
|
||||
|
||||
impl<F: FieldExt> From<Vec<WindowUs<F>>> for UShort<F> {
|
||||
fn from(windows: Vec<WindowUs<F>>) -> Self {
|
||||
Self(windows.into_boxed_slice().try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: FieldExt> From<[[[u8; 32]; H]; NUM_WINDOWS_SHORT]> for UShort<F> {
|
||||
fn from(window_us: [[[u8; 32]; H]; NUM_WINDOWS_SHORT]) -> Self {
|
||||
let windows: Vec<WindowUs<F>> = window_us.iter().map(|us| us.into()).collect();
|
||||
windows.into()
|
||||
}
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
use super::{NoteCommitR, OrchardFixedBase};
|
||||
use halo2::arithmetic::{CurveAffine, FieldExt};
|
||||
|
||||
/// Generator used in SinsemillaCommit randomness for note commitment
|
||||
|
@ -2918,19 +2917,19 @@ pub const U: [[[u8; 32]; super::H]; super::NUM_WINDOWS] = [
|
|||
],
|
||||
];
|
||||
|
||||
pub fn generator<C: CurveAffine>() -> NoteCommitR<C> {
|
||||
NoteCommitR(OrchardFixedBase::<C>::new(
|
||||
C::from_xy(
|
||||
C::Base::from_bytes(&GENERATOR.0).unwrap(),
|
||||
C::Base::from_bytes(&GENERATOR.1).unwrap(),
|
||||
)
|
||||
.unwrap(),
|
||||
))
|
||||
pub fn generator<C: CurveAffine>() -> C {
|
||||
C::from_xy(
|
||||
C::Base::from_bytes(&GENERATOR.0).unwrap(),
|
||||
C::Base::from_bytes(&GENERATOR.1).unwrap(),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::{TestFixedBase, NOTE_COMMITMENT_PERSONALIZATION, NUM_WINDOWS};
|
||||
use super::super::{
|
||||
test_lagrange_coeffs, test_zs_and_us, NOTE_COMMITMENT_PERSONALIZATION, NUM_WINDOWS,
|
||||
};
|
||||
use super::*;
|
||||
use crate::primitives::sinsemilla::CommitDomain;
|
||||
use group::Curve;
|
||||
|
@ -2952,12 +2951,12 @@ mod tests {
|
|||
#[test]
|
||||
fn lagrange_coeffs() {
|
||||
let base = super::generator::<pallas::Affine>();
|
||||
base.0.test_lagrange_coeffs(NUM_WINDOWS);
|
||||
test_lagrange_coeffs(base, NUM_WINDOWS);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn z() {
|
||||
let base = super::generator::<pallas::Affine>();
|
||||
base.0.test_zs_and_us(&Z, &U, NUM_WINDOWS);
|
||||
test_zs_and_us(base, &Z, &U, NUM_WINDOWS);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::constants::{NullifierK, OrchardFixedBase};
|
||||
use halo2::arithmetic::{CurveAffine, FieldExt};
|
||||
|
||||
pub const GENERATOR: ([u8; 32], [u8; 32]) = (
|
||||
|
@ -2917,19 +2916,19 @@ pub const U: [[[u8; 32]; super::H]; super::NUM_WINDOWS] = [
|
|||
],
|
||||
];
|
||||
|
||||
pub fn generator<C: CurveAffine>() -> NullifierK<C> {
|
||||
NullifierK(OrchardFixedBase::<C>::new(
|
||||
C::from_xy(
|
||||
C::Base::from_bytes(&GENERATOR.0).unwrap(),
|
||||
C::Base::from_bytes(&GENERATOR.1).unwrap(),
|
||||
)
|
||||
.unwrap(),
|
||||
))
|
||||
pub fn generator<C: CurveAffine>() -> C {
|
||||
C::from_xy(
|
||||
C::Base::from_bytes(&GENERATOR.0).unwrap(),
|
||||
C::Base::from_bytes(&GENERATOR.1).unwrap(),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::{TestFixedBase, NUM_WINDOWS, ORCHARD_PERSONALIZATION};
|
||||
use super::super::{
|
||||
test_lagrange_coeffs, test_zs_and_us, NUM_WINDOWS, ORCHARD_PERSONALIZATION,
|
||||
};
|
||||
use super::*;
|
||||
use group::Curve;
|
||||
use halo2::{
|
||||
|
@ -2950,12 +2949,12 @@ mod tests {
|
|||
#[test]
|
||||
fn lagrange_coeffs() {
|
||||
let base = super::generator::<pallas::Affine>();
|
||||
base.0.test_lagrange_coeffs(NUM_WINDOWS);
|
||||
test_lagrange_coeffs(base, NUM_WINDOWS);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn z() {
|
||||
let base = super::generator::<pallas::Affine>();
|
||||
base.0.test_zs_and_us(&Z, &U, NUM_WINDOWS);
|
||||
test_zs_and_us(base, &Z, &U, NUM_WINDOWS);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use super::{OrchardFixedBase, SpendAuthG};
|
||||
use halo2::arithmetic::{CurveAffine, FieldExt};
|
||||
|
||||
/// The value commitment is used to check balance between inputs and outputs. The value is
|
||||
|
@ -2919,19 +2918,19 @@ pub const U: [[[u8; 32]; super::H]; super::NUM_WINDOWS] = [
|
|||
],
|
||||
];
|
||||
|
||||
pub fn generator<C: CurveAffine>() -> SpendAuthG<C> {
|
||||
SpendAuthG(OrchardFixedBase::<C>::new(
|
||||
C::from_xy(
|
||||
C::Base::from_bytes(&GENERATOR.0).unwrap(),
|
||||
C::Base::from_bytes(&GENERATOR.1).unwrap(),
|
||||
)
|
||||
.unwrap(),
|
||||
))
|
||||
pub fn generator<C: CurveAffine>() -> C {
|
||||
C::from_xy(
|
||||
C::Base::from_bytes(&GENERATOR.0).unwrap(),
|
||||
C::Base::from_bytes(&GENERATOR.1).unwrap(),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::{TestFixedBase, NUM_WINDOWS, ORCHARD_PERSONALIZATION};
|
||||
use super::super::{
|
||||
test_lagrange_coeffs, test_zs_and_us, NUM_WINDOWS, ORCHARD_PERSONALIZATION,
|
||||
};
|
||||
use super::*;
|
||||
use group::Curve;
|
||||
use halo2::{
|
||||
|
@ -2952,12 +2951,12 @@ mod tests {
|
|||
#[test]
|
||||
fn lagrange_coeffs() {
|
||||
let base = super::generator::<pallas::Affine>();
|
||||
base.0.test_lagrange_coeffs(NUM_WINDOWS);
|
||||
test_lagrange_coeffs(base, NUM_WINDOWS);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn z() {
|
||||
let base = super::generator::<pallas::Affine>();
|
||||
base.0.test_zs_and_us(&Z, &U, NUM_WINDOWS);
|
||||
test_zs_and_us(base, &Z, &U, NUM_WINDOWS);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use super::{OrchardFixedBase, ValueCommitR};
|
||||
use halo2::arithmetic::{CurveAffine, FieldExt};
|
||||
|
||||
/// The value commitment is used to check balance between inputs and outputs. The value is
|
||||
|
@ -2919,19 +2918,19 @@ pub const U: [[[u8; 32]; super::H]; super::NUM_WINDOWS] = [
|
|||
],
|
||||
];
|
||||
|
||||
pub fn generator<C: CurveAffine>() -> ValueCommitR<C> {
|
||||
ValueCommitR(OrchardFixedBase::<C>::new(
|
||||
C::from_xy(
|
||||
C::Base::from_bytes(&GENERATOR.0).unwrap(),
|
||||
C::Base::from_bytes(&GENERATOR.1).unwrap(),
|
||||
)
|
||||
.unwrap(),
|
||||
))
|
||||
pub fn generator<C: CurveAffine>() -> C {
|
||||
C::from_xy(
|
||||
C::Base::from_bytes(&GENERATOR.0).unwrap(),
|
||||
C::Base::from_bytes(&GENERATOR.1).unwrap(),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::{TestFixedBase, NUM_WINDOWS, VALUE_COMMITMENT_PERSONALIZATION};
|
||||
use super::super::{
|
||||
test_lagrange_coeffs, test_zs_and_us, NUM_WINDOWS, VALUE_COMMITMENT_PERSONALIZATION,
|
||||
};
|
||||
use super::*;
|
||||
use group::Curve;
|
||||
use halo2::{
|
||||
|
@ -2952,12 +2951,12 @@ mod tests {
|
|||
#[test]
|
||||
fn lagrange_coeffs() {
|
||||
let base = super::generator::<pallas::Affine>();
|
||||
base.0.test_lagrange_coeffs(NUM_WINDOWS);
|
||||
test_lagrange_coeffs(base, NUM_WINDOWS);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn z() {
|
||||
let base = super::generator::<pallas::Affine>();
|
||||
base.0.test_zs_and_us(&Z, &U, NUM_WINDOWS);
|
||||
test_zs_and_us(base, &Z, &U, NUM_WINDOWS);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use super::{OrchardFixedBase, ValueCommitV};
|
||||
use halo2::arithmetic::{CurveAffine, FieldExt};
|
||||
|
||||
/// The value commitment is used to check balance between inputs and outputs. The value is
|
||||
|
@ -772,19 +771,19 @@ pub const U_SHORT: [[[u8; 32]; super::H]; super::NUM_WINDOWS_SHORT] = [
|
|||
],
|
||||
];
|
||||
|
||||
pub fn generator<C: CurveAffine>() -> ValueCommitV<C> {
|
||||
ValueCommitV(OrchardFixedBase::<C>::new(
|
||||
C::from_xy(
|
||||
C::Base::from_bytes(&GENERATOR.0).unwrap(),
|
||||
C::Base::from_bytes(&GENERATOR.1).unwrap(),
|
||||
)
|
||||
.unwrap(),
|
||||
))
|
||||
pub fn generator<C: CurveAffine>() -> C {
|
||||
C::from_xy(
|
||||
C::Base::from_bytes(&GENERATOR.0).unwrap(),
|
||||
C::Base::from_bytes(&GENERATOR.1).unwrap(),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::{TestFixedBase, NUM_WINDOWS_SHORT, VALUE_COMMITMENT_PERSONALIZATION};
|
||||
use super::super::{
|
||||
test_lagrange_coeffs, test_zs_and_us, NUM_WINDOWS_SHORT, VALUE_COMMITMENT_PERSONALIZATION,
|
||||
};
|
||||
use super::*;
|
||||
use group::Curve;
|
||||
use halo2::{
|
||||
|
@ -805,12 +804,12 @@ mod tests {
|
|||
#[test]
|
||||
fn lagrange_coeffs_short() {
|
||||
let base = super::generator::<pallas::Affine>();
|
||||
base.0.test_lagrange_coeffs(NUM_WINDOWS_SHORT);
|
||||
test_lagrange_coeffs(base, NUM_WINDOWS_SHORT);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn z_short() {
|
||||
let base = super::generator::<pallas::Affine>();
|
||||
base.0.test_zs_and_us(&Z_SHORT, &U_SHORT, NUM_WINDOWS_SHORT);
|
||||
test_zs_and_us(base, &Z_SHORT, &U_SHORT, NUM_WINDOWS_SHORT);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue