Add Orchard fixed bases and tests

This commit is contained in:
therealyingtong 2021-03-18 23:38:31 +08:00
parent 4f1f32dab0
commit 2c11f3a048
7 changed files with 670 additions and 0 deletions

View File

@ -1,4 +1,18 @@
//! Constants used in the Orchard protocol.
use ff::{Field, PrimeField};
use group::Curve;
use halo2::{
arithmetic::{lagrange_interpolate, CurveAffine, FieldExt},
pasta::pallas,
};
pub mod commit_ivk_r;
pub mod note_commit_r;
pub mod nullifier_k;
pub mod value_commit_r;
pub mod value_commit_v;
pub mod util;
/// $\ell^\mathsf{Orchard}_\mathsf{base}$
pub(crate) const L_ORCHARD_BASE: usize = 255;
@ -26,3 +40,228 @@ pub const MERKLE_CRH_PERSONALIZATION: &str = "z.cash:Orchard-MerkleCRH";
/// Window size for fixed-base scalar multiplication
pub const FIXED_BASE_WINDOW_SIZE: usize = 3;
/// Number of windows
pub const NUM_WINDOWS: usize = pallas::Base::NUM_BITS as usize / FIXED_BASE_WINDOW_SIZE;
/// Number of bits used in complete addition (for variable-base scalar mul)
pub const NUM_COMPLETE_BITS: usize = 3;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum OrchardFixedBases<C: CurveAffine> {
CommitIvkR(OrchardFixedBase<C>),
NoteCommitR(OrchardFixedBase<C>),
NullifierK(OrchardFixedBase<C>),
ValueCommitR(OrchardFixedBase<C>),
ValueCommitV(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) -> Vec<Vec<C>>;
/// 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) -> Vec<Vec<C::Base>>;
/// 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.
fn find_zs(&self) -> Option<Vec<u64>>;
}
impl<C: CurveAffine> FixedBase<C> for OrchardFixedBase<C> {
fn compute_window_table(&self) -> Vec<Vec<C>> {
let h: usize = 1 << FIXED_BASE_WINDOW_SIZE;
let mut window_table: Vec<Vec<C>> = Vec::with_capacity(NUM_WINDOWS);
// Generate window table entries for all windows but the last.
// For these first 84 windows, we compute the multiple [(k+1)*(8^w)]B.
// Here, w ranges from [0..84)
for w in 0..(NUM_WINDOWS - 1) {
window_table.push(
(0..h)
.map(|k| {
// scalar = (k+1)*(8^w)
let scalar = C::ScalarExt::from_u64(k as u64 + 1)
* C::ScalarExt::from_u64(h as u64).pow(&[w as u64, 0, 0, 0]);
(self.0 * scalar).to_affine()
})
.collect(),
);
}
// Generate window table entries for the last window, w = 84.
// For the last window, we compute [k * (8^w) - sum]B, where sum is defined
// as sum = \sum_{j = 0}^{83} 8^j
let sum = (0..(NUM_WINDOWS - 1)).fold(C::ScalarExt::zero(), |acc, w| {
acc + C::ScalarExt::from_u64(h as u64).pow(&[w as u64, 0, 0, 0])
});
window_table.push(
(0..h)
.map(|k| {
// scalar = k * (8^w) - sum, where w = 84
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()
})
.collect(),
);
window_table
}
fn compute_lagrange_coeffs(&self) -> Vec<Vec<C::Base>> {
let h: usize = 1 << FIXED_BASE_WINDOW_SIZE;
// 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();
window_table
.iter()
.map(|window_points| {
let x_window_points: Vec<_> = window_points
.iter()
.map(|point| point.get_xy().unwrap().0)
.collect();
let coeffs = lagrange_interpolate(&points, &x_window_points);
coeffs
})
.collect::<Vec<Vec<_>>>()
}
/// 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.
fn find_zs(&self) -> Option<Vec<u64>> {
// Closure to find z for one window
let find_z = |window_points: &[C]| {
let h: usize = 1 << FIXED_BASE_WINDOW_SIZE;
assert_eq!(h, window_points.len());
let ys: Vec<_> = window_points
.iter()
.map(|point| point.get_xy().unwrap().1)
.collect();
let z_for_single_y = |y: C::Base, z: u64| {
let sum_y_is_square: bool = (y + C::Base::from_u64(z)).sqrt().is_some().into();
let sum_neg_y_is_square: bool = (-y + C::Base::from_u64(z)).sqrt().is_some().into();
(sum_y_is_square && !sum_neg_y_is_square) as usize
};
for z in 0..(1000 * (1 << (2 * h))) {
if ys.iter().map(|y| z_for_single_y(*y, z)).sum::<usize>() == h {
return Some(z);
}
}
None
};
let window_table = self.compute_window_table();
window_table
.iter()
.map(|window_points| find_z(window_points))
.collect()
}
}
pub trait TestFixedBase<C: CurveAffine> {
fn test_lagrange_coeffs(&self);
fn test_z(&self, z: &[u64]);
}
impl<C: CurveAffine> TestFixedBase<C> for OrchardFixedBase<C> {
fn test_lagrange_coeffs(&self) {
let h = 1 << FIXED_BASE_WINDOW_SIZE;
let lagrange_coeffs = self.compute_lagrange_coeffs();
let mut points = Vec::<C::CurveExt>::with_capacity(NUM_WINDOWS);
let scalar = C::Scalar::rand();
let bits = util::decompose_scalar_fixed::<C>(
scalar,
C::Scalar::NUM_BITS as usize,
FIXED_BASE_WINDOW_SIZE,
);
// Check first 84 windows, i.e. `k_0, k_1, ..., k_83`
for ((idx, bits), coeffs) in bits[0..(NUM_WINDOWS - 1)]
.iter()
.enumerate()
.zip(lagrange_coeffs[0..(NUM_WINDOWS - 1)].iter())
{
let interpolated_x = util::evaluate::<C>(*bits, coeffs);
// [(k+1)*(8^w)]B
let point = self.0
* C::Scalar::from_u64(*bits as u64 + 1)
* C::Scalar::from_u64(h as u64).pow(&[idx as u64, 0, 0, 0]);
let x = point.to_affine().get_xy().unwrap().0;
assert_eq!(x, interpolated_x);
points.push(point);
}
// Check last window
{
let last_bits = bits[NUM_WINDOWS - 1];
let interpolated_x = util::evaluate::<C>(last_bits, &lagrange_coeffs[NUM_WINDOWS - 1]);
// [k * (8^w) - offset]B, where offset = \sum_{j = 0}^{83} 8^j
let offset = (0..(NUM_WINDOWS - 1)).fold(C::Scalar::zero(), |acc, w| {
acc + C::Scalar::from_u64(h as u64).pow(&[w as u64, 0, 0, 0])
});
let scalar = C::Scalar::from_u64(last_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().get_xy().unwrap().0;
assert_eq!(x, interpolated_x);
points.push(point);
}
// Check the sum of all the window points
let window_sum = points
.iter()
.fold(C::CurveExt::default(), |acc, point| acc + point);
let multiple = self.0 * scalar;
assert_eq!(window_sum, multiple);
}
fn test_z(&self, z: &[u64]) {
let window_table = self.compute_window_table();
for (z, window_points) in z.iter().zip(window_table) {
for point in window_points.iter() {
let y = point.get_xy().unwrap().1;
assert_eq!((C::Base::from_u64(*z) + y).sqrt().is_some().unwrap_u8(), 1);
assert_eq!((C::Base::from_u64(*z) - y).sqrt().is_some().unwrap_u8(), 0);
}
}
}
}

View File

@ -0,0 +1,77 @@
use super::{OrchardFixedBase, OrchardFixedBases, COMMIT_IVK_PERSONALIZATION};
use halo2::arithmetic::{CurveAffine, FieldExt};
pub const PERSONALIZATION: &str = COMMIT_IVK_PERSONALIZATION;
/// Generator used in SinsemillaCommit randomness for IVK commitment
pub const GENERATOR: ([u8; 32], [u8; 32]) = (
[
148, 238, 176, 134, 155, 115, 130, 32, 71, 108, 43, 81, 122, 0, 18, 183, 189, 78, 168, 64,
186, 250, 116, 181, 109, 239, 205, 50, 185, 198, 91, 14,
],
[
250, 170, 248, 240, 127, 69, 3, 58, 247, 119, 172, 189, 199, 234, 17, 244, 34, 155, 121,
180, 206, 194, 252, 134, 55, 107, 139, 116, 163, 117, 220, 15,
],
);
/// z-values for GENERATOR
pub const Z: [u64; 85] = [
1640, 16319, 75535, 213644, 22431, 77718, 73598, 44704, 58426, 90793, 51317, 35788, 62987,
39128, 29961, 196204, 23144, 4960, 31792, 67688, 156889, 128199, 394678, 1391, 49801, 69085,
177001, 27216, 17637, 12069, 8898, 134862, 137982, 35001, 261172, 3219, 171891, 6532, 93082,
27872, 44212, 66355, 4768, 96884, 4793, 37757, 26619, 5486, 1315, 15325, 48605, 9168, 2511,
84012, 73415, 74774, 224831, 26856, 4179, 82322, 39504, 32139, 75335, 14373, 63220, 39155,
29901, 33099, 758, 27784, 6442, 252, 142824, 106033, 24247, 47057, 170067, 30302, 304042,
163259, 49391, 34561, 350373, 139177, 147760,
];
pub fn generator<C: CurveAffine>() -> OrchardFixedBases<C> {
OrchardFixedBases::CommitIvkR(OrchardFixedBase::<C>::new(
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;
use super::*;
use crate::primitives::sinsemilla::CommitDomain;
use group::Curve;
use halo2::{
arithmetic::{CurveAffine, FieldExt},
pasta::pallas,
};
#[test]
fn generator() {
let domain = CommitDomain::new(PERSONALIZATION);
let point = domain.R();
let (x, y) = point.to_affine().get_xy().unwrap();
assert_eq!(x, pallas::Base::from_bytes(&GENERATOR.0).unwrap());
assert_eq!(y, pallas::Base::from_bytes(&GENERATOR.1).unwrap());
}
#[test]
fn lagrange_coeffs() {
let base = super::generator::<pallas::Affine>();
match base {
OrchardFixedBases::CommitIvkR(inner) => inner.test_lagrange_coeffs(),
_ => unreachable!(),
}
}
#[test]
fn z() {
let base = super::generator::<pallas::Affine>();
match base {
OrchardFixedBases::CommitIvkR(inner) => inner.test_z(&Z),
_ => unreachable!(),
}
}
}

View File

@ -0,0 +1,77 @@
use super::{OrchardFixedBase, OrchardFixedBases, NOTE_COMMITMENT_PERSONALIZATION};
use halo2::arithmetic::{CurveAffine, FieldExt};
pub const PERSONALIZATION: &str = NOTE_COMMITMENT_PERSONALIZATION;
/// Generator used in SinsemillaCommit randomness for note commitment
pub const GENERATOR: ([u8; 32], [u8; 32]) = (
[
27, 85, 45, 121, 90, 101, 108, 254, 2, 206, 235, 232, 42, 16, 38, 207, 116, 73, 104, 35,
246, 164, 144, 15, 230, 159, 210, 102, 11, 44, 179, 36,
],
[
184, 34, 111, 203, 218, 243, 248, 43, 50, 219, 6, 34, 114, 46, 198, 187, 54, 179, 135, 26,
92, 178, 197, 64, 187, 63, 245, 129, 53, 180, 231, 25,
],
);
/// z-values for GENERATOR
pub const Z: [u64; 85] = [
10213, 84688, 5015, 29076, 5250, 12480, 1589, 21978, 40626, 116200, 36680, 56513, 80295, 1371,
36801, 26527, 11103, 61032, 199301, 33177, 49711, 167190, 1448, 51069, 40410, 171413, 82827,
15451, 53663, 4202, 47840, 93100, 44310, 10271, 27499, 76928, 39695, 59189, 70288, 24401,
33207, 3472, 13911, 8835, 193349, 259, 41151, 2318, 33540, 21052, 14435, 18358, 49426, 52169,
96418, 52931, 85348, 392973, 85905, 92539, 22878, 26933, 41387, 22788, 89854, 54883, 18584,
19451, 4488, 283677, 74400, 56046, 20644, 5330, 27521, 99158, 9360, 10834, 78610, 7963, 19984,
149297, 10335, 32061, 214389,
];
pub fn generator<C: CurveAffine>() -> OrchardFixedBases<C> {
OrchardFixedBases::NoteCommitR(OrchardFixedBase::<C>::new(
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;
use super::*;
use crate::primitives::sinsemilla::CommitDomain;
use group::Curve;
use halo2::{
arithmetic::{CurveAffine, FieldExt},
pasta::pallas,
};
#[test]
fn generator() {
let domain = CommitDomain::new(PERSONALIZATION);
let point = domain.R();
let (x, y) = point.to_affine().get_xy().unwrap();
assert_eq!(x, pallas::Base::from_bytes(&GENERATOR.0).unwrap());
assert_eq!(y, pallas::Base::from_bytes(&GENERATOR.1).unwrap());
}
#[test]
fn lagrange_coeffs() {
let base = super::generator::<pallas::Affine>();
match base {
OrchardFixedBases::NoteCommitR(inner) => inner.test_lagrange_coeffs(),
_ => unreachable!(),
}
}
#[test]
fn z() {
let base = super::generator::<pallas::Affine>();
match base {
OrchardFixedBases::NoteCommitR(inner) => inner.test_z(&Z),
_ => unreachable!(),
}
}
}

View File

@ -0,0 +1,75 @@
use crate::constants::{OrchardFixedBase, OrchardFixedBases, ORCHARD_PERSONALIZATION};
use halo2::arithmetic::{CurveAffine, FieldExt};
pub const PERSONALIZATION: &str = ORCHARD_PERSONALIZATION;
pub const GENERATOR: ([u8; 32], [u8; 32]) = (
[
74, 166, 88, 164, 116, 16, 207, 20, 93, 0, 62, 45, 168, 59, 130, 172, 228, 79, 239, 35, 33,
244, 20, 8, 126, 126, 100, 17, 248, 88, 183, 52,
],
[
141, 155, 6, 243, 162, 111, 188, 180, 253, 188, 17, 96, 117, 217, 25, 246, 206, 193, 176,
192, 64, 196, 91, 252, 21, 22, 204, 177, 62, 197, 187, 44,
],
);
/// z-values for GENERATOR
pub const Z: [u64; 85] = [
32517, 3118, 55842, 5295, 2252, 43091, 193188, 73424, 27335, 55867, 11015, 46382, 29066, 69577,
2838, 245429, 25519, 172913, 25762, 138009, 11170, 132216, 114997, 52870, 52313, 102066, 5989,
365, 73950, 74675, 191463, 34356, 16506, 63389, 4652, 81717, 108428, 120446, 80918, 25398,
75806, 116193, 63775, 97332, 2183, 43473, 92592, 38016, 47712, 30288, 25445, 10737, 211404,
26095, 72119, 25953, 3730, 19087, 28678, 11891, 69181, 214129, 2050, 72933, 124047, 16956,
16977, 37315, 74647, 49184, 75499, 30521, 12997, 11908, 108937, 37055, 47165, 40492, 22849,
89930, 69888, 193158, 105211, 27681, 32387,
];
pub fn generator<C: CurveAffine>() -> OrchardFixedBases<C> {
OrchardFixedBases::NullifierK(OrchardFixedBase::<C>::new(
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;
use super::*;
use group::Curve;
use halo2::{
arithmetic::{CurveAffine, CurveExt, FieldExt},
pasta::pallas,
};
#[test]
fn generator() {
let hasher = pallas::Point::hash_to_curve(PERSONALIZATION);
let point = hasher(b"K");
let (x, y) = point.to_affine().get_xy().unwrap();
assert_eq!(x, pallas::Base::from_bytes(&GENERATOR.0).unwrap());
assert_eq!(y, pallas::Base::from_bytes(&GENERATOR.1).unwrap());
}
#[test]
fn lagrange_coeffs() {
let base = super::generator::<pallas::Affine>();
match base {
OrchardFixedBases::NullifierK(inner) => inner.test_lagrange_coeffs(),
_ => unreachable!(),
}
}
#[test]
fn z() {
let base = super::generator::<pallas::Affine>();
match base {
OrchardFixedBases::NullifierK(inner) => inner.test_z(&Z),
_ => unreachable!(),
}
}
}

45
src/constants/util.rs Normal file
View File

@ -0,0 +1,45 @@
use ff::PrimeField;
use halo2::arithmetic::{CurveAffine, FieldExt};
/// Decompose a scalar into FIXED_BASE_WINDOW_SIZE bits (little-endian)
/// For a window size of `w`, this returns [k_0, ..., k_n] where each `k_i`
/// is a `w`-bit value, and `scalar = k_0 + k_1 * w + k_n * w^n`.
pub fn decompose_scalar_fixed<C: CurveAffine>(
scalar: C::Scalar,
scalar_num_bits: usize,
window_num_bits: usize,
) -> Vec<u8> {
let mut bits: Vec<bool> = scalar
.to_le_bits()
.into_iter()
.take(scalar_num_bits)
.collect();
assert_eq!(bits.len(), scalar_num_bits);
// Pad bits to multiple of window_num_bits
bits.append(&mut vec![
false;
(window_num_bits
- (scalar_num_bits % window_num_bits))
% window_num_bits
]);
bits.chunks_exact(window_num_bits)
.map(|chunk| {
let mut chunk = chunk.iter();
*(chunk.next().unwrap()) as u8
+ ((*(chunk.next().unwrap()) as u8) << 1)
+ ((*(chunk.next().unwrap()) as u8) << 2)
})
.collect()
}
/// Evaluate y = f(x) given the coefficients of f(x)
pub fn evaluate<C: CurveAffine>(x: u8, coeffs: &[C::Base]) -> C::Base {
(0..coeffs.len())
.zip(coeffs.iter())
.fold(C::Base::default(), |acc, (pow, coeff)| {
acc + (*coeff) * C::Base::from_u64(x as u64).pow(&[pow as u64, 0, 0, 0])
})
}

View File

@ -0,0 +1,77 @@
use super::{OrchardFixedBase, OrchardFixedBases, VALUE_COMMITMENT_PERSONALIZATION};
use halo2::arithmetic::{CurveAffine, FieldExt};
pub const PERSONALIZATION: &str = VALUE_COMMITMENT_PERSONALIZATION;
/// The value commitment is used to check balance between inputs and outputs. The value is
/// placed over this generator.
pub const GENERATOR: ([u8; 32], [u8; 32]) = (
[
199, 209, 64, 100, 24, 110, 206, 85, 59, 77, 6, 42, 67, 76, 118, 116, 253, 250, 208, 71,
184, 191, 140, 13, 93, 79, 56, 33, 94, 39, 101, 10,
],
[
76, 105, 226, 202, 61, 74, 65, 200, 220, 56, 136, 63, 71, 255, 94, 246, 153, 160, 21, 162,
106, 112, 47, 120, 165, 32, 53, 96, 19, 181, 110, 36,
],
);
/// z-values for GENERATOR
pub const Z: [u64; 85] = [
287008, 5261, 10541, 67788, 1084, 31201, 1662, 32921, 2652, 52006, 3486, 82692, 7295, 40007,
37754, 44773, 3021, 171863, 33315, 8829, 67034, 50428, 40391, 6615, 40340, 238, 199437, 50234,
899, 27825, 139735, 36053, 194684, 28229, 31719, 66166, 100600, 59796, 52804, 10221, 159298,
32923, 158, 40332, 100062, 8923, 23819, 96460, 44805, 2951, 50005, 134465, 44269, 51778, 73741,
11413, 19391, 84631, 96003, 71276, 61444, 49575, 154646, 229521, 4555, 313045, 30544, 15466,
7134, 12520, 164127, 29119, 11279, 103167, 63033, 13765, 35197, 71168, 10379, 9560, 54432,
132537, 189703, 29967, 9941,
];
pub fn generator<C: CurveAffine>() -> OrchardFixedBases<C> {
OrchardFixedBases::ValueCommitR(OrchardFixedBase::<C>::new(
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;
use super::*;
use group::Curve;
use halo2::{
arithmetic::{CurveAffine, CurveExt, FieldExt},
pasta::pallas,
};
#[test]
fn generator() {
let hasher = pallas::Point::hash_to_curve(PERSONALIZATION);
let point = hasher(b"-r");
let (x, y) = point.to_affine().get_xy().unwrap();
assert_eq!(x, pallas::Base::from_bytes(&GENERATOR.0).unwrap());
assert_eq!(y, pallas::Base::from_bytes(&GENERATOR.1).unwrap());
}
#[test]
fn lagrange_coeffs() {
let base = super::generator::<pallas::Affine>();
match base {
OrchardFixedBases::ValueCommitR(inner) => inner.test_lagrange_coeffs(),
_ => unreachable!(),
}
}
#[test]
fn z() {
let base = super::generator::<pallas::Affine>();
match base {
OrchardFixedBases::ValueCommitR(inner) => inner.test_z(&Z),
_ => unreachable!(),
}
}
}

View File

@ -0,0 +1,80 @@
use super::{OrchardFixedBase, OrchardFixedBases, VALUE_COMMITMENT_PERSONALIZATION};
use halo2::arithmetic::{CurveAffine, FieldExt};
pub const PERSONALIZATION: &str = VALUE_COMMITMENT_PERSONALIZATION;
/// The value commitment is used to check balance between inputs and outputs. The value is
/// placed over this generator.
pub const GENERATOR: ([u8; 32], [u8; 32]) = (
[
146, 134, 252, 1, 6, 122, 71, 38, 242, 210, 12, 65, 214, 129, 99, 228, 216, 165, 217, 139,
4, 159, 130, 201, 115, 100, 204, 172, 241, 221, 192, 57,
],
[
104, 21, 198, 148, 56, 181, 122, 135, 95, 147, 179, 108, 174, 10, 183, 200, 243, 25, 27,
248, 167, 68, 37, 105, 11, 87, 167, 253, 72, 189, 248, 33,
],
);
/// z-values for GENERATOR
pub const Z: [u64; 85] = [
12093, 20558, 3369, 22650, 43666, 81863, 2960, 131095, 84, 117033, 7349, 122998, 47884, 43451,
22237, 3461, 71521, 147314, 31021, 70554, 47822, 44159, 45362, 7756, 19977, 41666, 82714,
21407, 16731, 48013, 173284, 356652, 3027, 9756, 10560, 1554, 40272, 131726, 32724, 6152,
67912, 2642, 100128, 8950, 20487, 58314, 7440, 63032, 586, 32770, 37328, 21775, 4186, 172635,
111256, 35867, 23903, 137179, 16694, 43650, 32899, 40670, 55501, 44805, 20211, 207309, 2718,
63301, 145483, 5584, 55596, 349346, 30535, 112990, 44821, 48471, 107386, 16232, 16492, 88498,
33976, 106405, 11043, 44897, 98652,
];
pub fn generator<C: CurveAffine>() -> OrchardFixedBases<C> {
OrchardFixedBases::ValueCommitV(OrchardFixedBase::<C>::new(
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;
use super::*;
use group::Curve;
use halo2::{
arithmetic::{CurveAffine, CurveExt, FieldExt},
pasta::pallas,
};
#[test]
fn generator() {
let hasher = pallas::Point::hash_to_curve(PERSONALIZATION);
let point = hasher(b"-v");
let (x, y) = point.to_affine().get_xy().unwrap();
println!("{:?}", x.to_bytes());
println!("{:?}", y.to_bytes());
assert_eq!(x, pallas::Base::from_bytes(&GENERATOR.0).unwrap());
assert_eq!(y, pallas::Base::from_bytes(&GENERATOR.1).unwrap());
}
#[test]
fn lagrange_coeffs() {
let base = super::generator::<pallas::Affine>();
match base {
OrchardFixedBases::ValueCommitV(inner) => inner.test_lagrange_coeffs(),
_ => unreachable!(),
}
}
#[test]
fn z() {
let base = super::generator::<pallas::Affine>();
match base {
OrchardFixedBases::ValueCommitV(inner) => inner.test_z(&Z),
_ => unreachable!(),
}
}
}