zcash_proofs: Define generator constants using new crates
Includes tests to ensure that the new generator constants match the current zcash_primitives::JUBJUB generators.
This commit is contained in:
parent
10c571f2cd
commit
315f00d6d4
|
@ -14,9 +14,13 @@ edition = "2018"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bellman = { version = "0.6", path = "../bellman", default-features = false, features = ["groth16"] }
|
bellman = { version = "0.6", path = "../bellman", default-features = false, features = ["groth16"] }
|
||||||
blake2b_simd = "0.5"
|
blake2b_simd = "0.5"
|
||||||
|
bls12_381 = { version = "0.1", path = "../bls12_381" }
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
directories = { version = "3", optional = true }
|
directories = { version = "3", optional = true }
|
||||||
ff = { version = "0.6", path = "../ff" }
|
ff = { version = "0.6", path = "../ff" }
|
||||||
|
group = { version = "0.6", path = "../group" }
|
||||||
|
jubjub = { version = "0.3", path = "../jubjub" }
|
||||||
|
lazy_static = "1"
|
||||||
minreq = { version = "2", features = ["https"], optional = true }
|
minreq = { version = "2", features = ["https"], optional = true }
|
||||||
pairing = { version = "0.16", path = "../pairing" }
|
pairing = { version = "0.16", path = "../pairing" }
|
||||||
rand_core = "0.5.1"
|
rand_core = "0.5.1"
|
||||||
|
|
|
@ -0,0 +1,293 @@
|
||||||
|
//! Various constants used for the Zcash proofs.
|
||||||
|
|
||||||
|
use bls12_381::Scalar;
|
||||||
|
use ff::Field;
|
||||||
|
use group::{Curve, Group};
|
||||||
|
use jubjub::ExtendedPoint;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use zcash_primitives::constants::{PEDERSEN_HASH_CHUNKS_PER_GENERATOR, PEDERSEN_HASH_GENERATORS};
|
||||||
|
|
||||||
|
/// The `d` constant of the twisted Edwards curve.
|
||||||
|
pub const EDWARDS_D: Scalar = Scalar::from_raw([
|
||||||
|
0x0106_5fd6_d634_3eb1,
|
||||||
|
0x292d_7f6d_3757_9d26,
|
||||||
|
0xf5fd_9207_e6bd_7fd4,
|
||||||
|
0x2a93_18e7_4bfa_2b48,
|
||||||
|
]);
|
||||||
|
|
||||||
|
/// The `A` constant of the birationally equivalent Montgomery curve.
|
||||||
|
pub const MONTGOMERY_A: Scalar = Scalar::from_raw([
|
||||||
|
0x0000_0000_0000_a002,
|
||||||
|
0x0000_0000_0000_0000,
|
||||||
|
0x0000_0000_0000_0000,
|
||||||
|
0x0000_0000_0000_0000,
|
||||||
|
]);
|
||||||
|
|
||||||
|
/// The scaling factor used for conversion to and from the Montgomery form.
|
||||||
|
pub const MONTGOMERY_SCALE: Scalar = Scalar::from_raw([
|
||||||
|
0x8f45_35f7_cf82_b8d9,
|
||||||
|
0xce40_6970_3da8_8abd,
|
||||||
|
0x31de_341e_77d7_64e5,
|
||||||
|
0x2762_de61_e862_645e,
|
||||||
|
]);
|
||||||
|
|
||||||
|
/// The number of chunks needed to represent a full scalar during fixed-base
|
||||||
|
/// exponentiation.
|
||||||
|
const FIXED_BASE_CHUNKS_PER_GENERATOR: usize = 84;
|
||||||
|
|
||||||
|
/// Reference to a circuit version of a generator for fixed-base salar multiplication.
|
||||||
|
pub type FixedGenerator = &'static [Vec<(Scalar, Scalar)>];
|
||||||
|
|
||||||
|
/// Circuit version of a generator for fixed-base salar multiplication.
|
||||||
|
pub type FixedGeneratorOwned = Vec<Vec<(Scalar, Scalar)>>;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref PROOF_GENERATION_KEY_GENERATOR: FixedGeneratorOwned =
|
||||||
|
generate_circuit_generator(zcash_primitives::constants::PROOF_GENERATION_KEY_GENERATOR);
|
||||||
|
|
||||||
|
pub static ref NOTE_COMMITMENT_RANDOMNESS_GENERATOR: FixedGeneratorOwned =
|
||||||
|
generate_circuit_generator(zcash_primitives::constants::NOTE_COMMITMENT_RANDOMNESS_GENERATOR);
|
||||||
|
|
||||||
|
pub static ref NULLIFIER_POSITION_GENERATOR: FixedGeneratorOwned =
|
||||||
|
generate_circuit_generator(zcash_primitives::constants::NULLIFIER_POSITION_GENERATOR);
|
||||||
|
|
||||||
|
pub static ref VALUE_COMMITMENT_VALUE_GENERATOR: FixedGeneratorOwned =
|
||||||
|
generate_circuit_generator(zcash_primitives::constants::VALUE_COMMITMENT_VALUE_GENERATOR);
|
||||||
|
|
||||||
|
pub static ref VALUE_COMMITMENT_RANDOMNESS_GENERATOR: FixedGeneratorOwned =
|
||||||
|
generate_circuit_generator(zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR);
|
||||||
|
|
||||||
|
pub static ref SPENDING_KEY_GENERATOR: FixedGeneratorOwned =
|
||||||
|
generate_circuit_generator(zcash_primitives::constants::SPENDING_KEY_GENERATOR);
|
||||||
|
|
||||||
|
/// The pre-computed window tables `[-4, 3, 2, 1, 1, 2, 3, 4]` of different magnitudes
|
||||||
|
/// of the Pedersen hash segment generators.
|
||||||
|
pub static ref PEDERSEN_CIRCUIT_GENERATORS: Vec<Vec<Vec<(Scalar, Scalar)>>> =
|
||||||
|
generate_pedersen_circuit_generators();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates the 3-bit window table `[0, 1, ..., 8]` for different magnitudes of a fixed
|
||||||
|
/// generator.
|
||||||
|
fn generate_circuit_generator(mut 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 = gen.clone();
|
||||||
|
for _ in 0..7 {
|
||||||
|
let g_affine = jubjub::ExtendedPoint::from(g).to_affine();
|
||||||
|
coeffs.push((g_affine.get_u(), g_affine.get_v()));
|
||||||
|
g += gen;
|
||||||
|
}
|
||||||
|
windows.push(coeffs);
|
||||||
|
|
||||||
|
// gen = gen * 8
|
||||||
|
gen = g;
|
||||||
|
}
|
||||||
|
|
||||||
|
windows
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the coordinates of this point's Montgomery curve representation, or `None` if
|
||||||
|
/// it is the point at infinity.
|
||||||
|
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() {
|
||||||
|
// The only solution for y = 1 is x = 0. (0, 1) is the neutral element, so we map
|
||||||
|
// this to the point at infinity.
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
// The map from a twisted Edwards curve is defined as
|
||||||
|
// (x, y) -> (u, v) where
|
||||||
|
// u = (1 + y) / (1 - y)
|
||||||
|
// v = u / x
|
||||||
|
//
|
||||||
|
// This mapping is not defined for y = 1 and for x = 0.
|
||||||
|
//
|
||||||
|
// We have that y != 1 above. If x = 0, the only
|
||||||
|
// solutions for y are 1 (contradiction) or -1.
|
||||||
|
if x.is_zero() {
|
||||||
|
// (0, -1) is the point of order two which is not
|
||||||
|
// the neutral element, so we map it to (0, 0) which is
|
||||||
|
// the only affine point of order 2.
|
||||||
|
Some((Scalar::zero(), Scalar::zero()))
|
||||||
|
} else {
|
||||||
|
// The mapping is defined as above.
|
||||||
|
//
|
||||||
|
// (x, y) -> (u, v) where
|
||||||
|
// u = (1 + y) / (1 - y)
|
||||||
|
// v = u / x
|
||||||
|
|
||||||
|
let u = (Scalar::one() + y) * (Scalar::one() - y).invert().unwrap();
|
||||||
|
let v = u * x.invert().unwrap();
|
||||||
|
|
||||||
|
// Scale it into the correct curve constants
|
||||||
|
// scaling factor = sqrt(4 / (a - d))
|
||||||
|
Some((u, v * MONTGOMERY_SCALE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates the 2-bit window table lookups for each 4-bit "chunk" in each segment of the
|
||||||
|
/// Pedersen hash.
|
||||||
|
fn generate_pedersen_circuit_generators() -> Vec<Vec<Vec<(Scalar, Scalar)>>> {
|
||||||
|
// Process each segment
|
||||||
|
PEDERSEN_HASH_GENERATORS
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|mut gen| {
|
||||||
|
let mut windows = vec![];
|
||||||
|
|
||||||
|
for _ in 0..PEDERSEN_HASH_CHUNKS_PER_GENERATOR {
|
||||||
|
// Create (x, y) coeffs for this chunk
|
||||||
|
let mut coeffs = vec![];
|
||||||
|
let mut g = gen.clone();
|
||||||
|
|
||||||
|
// coeffs = g, g*2, g*3, g*4
|
||||||
|
for _ in 0..4 {
|
||||||
|
coeffs.push(
|
||||||
|
to_montgomery_coords(g.into())
|
||||||
|
.expect("we never encounter the point at infinity"),
|
||||||
|
);
|
||||||
|
g += gen;
|
||||||
|
}
|
||||||
|
windows.push(coeffs);
|
||||||
|
|
||||||
|
// Our chunks are separated by 2 bits to prevent overlap.
|
||||||
|
for _ in 0..4 {
|
||||||
|
gen = gen.double();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
windows
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use bls12_381::Scalar;
|
||||||
|
use ff::PrimeField;
|
||||||
|
use pairing::bls12_381::Fr;
|
||||||
|
use zcash_primitives::{
|
||||||
|
jubjub::{FixedGenerators, JubjubParams},
|
||||||
|
JUBJUB,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn check_scalar(expected: Fr, actual: Scalar) {
|
||||||
|
assert_eq!(expected.to_repr().0, actual.to_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_generator(expected: FixedGenerators, actual: FixedGenerator) {
|
||||||
|
let expected = JUBJUB.circuit_generators(expected);
|
||||||
|
|
||||||
|
// Same number of windows per generator.
|
||||||
|
assert_eq!(expected.len(), actual.len());
|
||||||
|
for (expected, actual) in expected.iter().zip(actual) {
|
||||||
|
// Same size table per window.
|
||||||
|
assert_eq!(expected.len(), actual.len());
|
||||||
|
for (expected, actual) in expected.iter().zip(actual) {
|
||||||
|
// Same coordinates.
|
||||||
|
check_scalar(expected.0, actual.0);
|
||||||
|
check_scalar(expected.1, actual.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn edwards_d() {
|
||||||
|
check_scalar(*JUBJUB.edwards_d(), EDWARDS_D);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn montgomery_a() {
|
||||||
|
check_scalar(*JUBJUB.montgomery_a(), MONTGOMERY_A);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn montgomery_scale() {
|
||||||
|
check_scalar(*JUBJUB.scale(), MONTGOMERY_SCALE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fixed_base_chunks_per_generator() {
|
||||||
|
assert_eq!(
|
||||||
|
JUBJUB.fixed_base_chunks_per_generator(),
|
||||||
|
FIXED_BASE_CHUNKS_PER_GENERATOR
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn proof_generation_key_base_generator() {
|
||||||
|
check_generator(
|
||||||
|
FixedGenerators::ProofGenerationKey,
|
||||||
|
&PROOF_GENERATION_KEY_GENERATOR,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn note_commitment_randomness_generator() {
|
||||||
|
check_generator(
|
||||||
|
FixedGenerators::NoteCommitmentRandomness,
|
||||||
|
&NOTE_COMMITMENT_RANDOMNESS_GENERATOR,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nullifier_position_generator() {
|
||||||
|
check_generator(
|
||||||
|
FixedGenerators::NullifierPosition,
|
||||||
|
&NULLIFIER_POSITION_GENERATOR,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn value_commitment_value_generator() {
|
||||||
|
check_generator(
|
||||||
|
FixedGenerators::ValueCommitmentValue,
|
||||||
|
&VALUE_COMMITMENT_VALUE_GENERATOR,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn value_commitment_randomness_generator() {
|
||||||
|
check_generator(
|
||||||
|
FixedGenerators::ValueCommitmentRandomness,
|
||||||
|
&VALUE_COMMITMENT_RANDOMNESS_GENERATOR,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn spending_key_generator() {
|
||||||
|
check_generator(
|
||||||
|
FixedGenerators::SpendingKeyGenerator,
|
||||||
|
&SPENDING_KEY_GENERATOR,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pedersen_circuit_generators() {
|
||||||
|
let expected = JUBJUB.pedersen_circuit_generators();
|
||||||
|
let actual = &PEDERSEN_CIRCUIT_GENERATORS;
|
||||||
|
|
||||||
|
// Same number of Pedersen hash generators.
|
||||||
|
assert_eq!(expected.len(), actual.len());
|
||||||
|
for (expected, actual) in expected.iter().zip(actual.iter()) {
|
||||||
|
// Same number of windows per generator.
|
||||||
|
assert_eq!(expected.len(), actual.len());
|
||||||
|
for (expected, actual) in expected.iter().zip(actual) {
|
||||||
|
// Same size table per window.
|
||||||
|
assert_eq!(expected.len(), actual.len());
|
||||||
|
for (expected, actual) in expected.iter().zip(actual) {
|
||||||
|
// Same coordinates.
|
||||||
|
check_scalar(expected.0, actual.0);
|
||||||
|
check_scalar(expected.1, actual.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ use directories::BaseDirs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub mod circuit;
|
pub mod circuit;
|
||||||
|
mod constants;
|
||||||
mod hashreader;
|
mod hashreader;
|
||||||
pub mod sapling;
|
pub mod sapling;
|
||||||
pub mod sprout;
|
pub mod sprout;
|
||||||
|
|
Loading…
Reference in New Issue