use bls12_381::Scalar;
use group::{Curve, Group, ff::Field};
use jubjub::ExtendedPoint;
use lazy_static::lazy_static;
use masp_primitives::constants::{PEDERSEN_HASH_CHUNKS_PER_GENERATOR, pedersen_hash_generators};
pub(crate) fn edward_d() -> Scalar {
Scalar::from_u64s_le(&[
0x0106_5fd6_d634_3eb1,
0x292d_7f6d_3757_9d26,
0xf5fd_9207_e6bd_7fd4,
0x2a93_18e7_4bfa_2b48,
])
.unwrap()
}
pub(crate) fn montgomery_a() -> Scalar {
Scalar::from_u64s_le(&[
0x0000_0000_0000_a002,
0x0000_0000_0000_0000,
0x0000_0000_0000_0000,
0x0000_0000_0000_0000,
])
.unwrap()
}
pub(crate) fn montgomery_scale() -> Scalar {
Scalar::from_u64s_le(&[
0x8f45_35f7_cf82_b8d9,
0xce40_6970_3da8_8abd,
0x31de_341e_77d7_64e5,
0x2762_de61_e862_645e,
])
.unwrap()
}
const FIXED_BASE_CHUNKS_PER_GENERATOR: usize = 84;
pub type FixedGenerator = &'static [Vec<(Scalar, Scalar)>];
pub type FixedGeneratorOwned = Vec<Vec<(Scalar, Scalar)>>;
lazy_static! {
pub static ref PROOF_GENERATION_KEY_GENERATOR: FixedGeneratorOwned =
generate_circuit_generator(masp_primitives::constants::proof_generation_key_generator());
pub static ref NOTE_COMMITMENT_RANDOMNESS_GENERATOR: FixedGeneratorOwned =
generate_circuit_generator(masp_primitives::constants::note_commitment_randomness_generator());
pub static ref NULLIFIER_POSITION_GENERATOR: FixedGeneratorOwned =
generate_circuit_generator(masp_primitives::constants::nullifier_position_generator());
pub static ref VALUE_COMMITMENT_RANDOMNESS_GENERATOR: FixedGeneratorOwned =
generate_circuit_generator(masp_primitives::constants::value_commitment_randomness_generator());
pub static ref SPENDING_KEY_GENERATOR: FixedGeneratorOwned =
generate_circuit_generator(masp_primitives::constants::spending_key_generator());
pub static ref PEDERSEN_CIRCUIT_GENERATORS: Vec<Vec<Vec<(Scalar, Scalar)>>> =
generate_pedersen_circuit_generators();
}
pub fn generate_circuit_generator(mut r#gen: jubjub::SubgroupPoint) -> FixedGeneratorOwned {
let mut windows = vec![];
for _ in 0..FIXED_BASE_CHUNKS_PER_GENERATOR {
let mut coeffs = vec![(Scalar::ZERO, Scalar::ONE)];
let mut g = r#gen;
for _ in 0..7 {
let g_affine = jubjub::ExtendedPoint::from(g).to_affine();
coeffs.push((g_affine.get_u(), g_affine.get_v()));
g += r#gen;
}
windows.push(coeffs);
r#gen = g;
}
windows
}
#[allow(clippy::many_single_char_names)]
pub(crate) fn to_montgomery_coords(g: ExtendedPoint) -> Option<(Scalar, Scalar)> {
let g = g.to_affine();
let (x, y) = (g.get_u(), g.get_v());
if y == Scalar::ONE {
None
} else {
if x.is_zero_vartime() {
Some((Scalar::ZERO, Scalar::ZERO))
} else {
let u = (Scalar::ONE + y) * (Scalar::ONE - y).invert().unwrap();
let v = u * x.invert().unwrap();
Some((u, v * montgomery_scale()))
}
}
}
fn generate_pedersen_circuit_generators() -> Vec<Vec<Vec<(Scalar, Scalar)>>> {
pedersen_hash_generators()
.iter()
.cloned()
.map(|mut r#gen| {
let mut windows = vec![];
for _ in 0..PEDERSEN_HASH_CHUNKS_PER_GENERATOR {
let mut coeffs = vec![];
let mut g = r#gen;
for _ in 0..4 {
coeffs.push(
to_montgomery_coords(g.into())
.expect("we never encounter the point at infinity"),
);
g += r#gen;
}
windows.push(coeffs);
for _ in 0..4 {
r#gen = r#gen.double();
}
}
windows
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
pub(crate) fn edwards_d() -> Scalar {
Scalar::from_u64s_le(&[
0x0106_5fd6_d634_3eb1,
0x292d_7f6d_3757_9d26,
0xf5fd_9207_e6bd_7fd4,
0x2a93_18e7_4bfa_2b48,
])
.unwrap()
}
#[test]
fn test_edwards_d() {
assert_eq!(
-Scalar::from(10240) * Scalar::from(10241).invert().unwrap(),
edwards_d()
);
}
#[test]
fn test_montgomery_scale() {
assert_eq!(
montgomery_scale().square() * (-Scalar::ONE - edwards_d()),
Scalar::from(4),
);
}
}