Merge pull request #999 from zcash/737-move-sapling-circuits
Move Sapling circuits from `zcash_proofs` to `zcash_primitives::sapling`
This commit is contained in:
commit
eca7112963
|
@ -3079,6 +3079,7 @@ version = "0.13.0"
|
|||
dependencies = [
|
||||
"aes",
|
||||
"assert_matches",
|
||||
"bellman",
|
||||
"bip0039",
|
||||
"bitvec",
|
||||
"blake2b_simd",
|
||||
|
@ -3121,16 +3122,13 @@ dependencies = [
|
|||
"blake2b_simd",
|
||||
"bls12_381",
|
||||
"byteorder",
|
||||
"criterion",
|
||||
"group",
|
||||
"home",
|
||||
"jubjub",
|
||||
"known-folders",
|
||||
"lazy_static",
|
||||
"minreq",
|
||||
"pprof",
|
||||
"rand_core",
|
||||
"rand_xorshift",
|
||||
"redjubjub",
|
||||
"tracing",
|
||||
"wagyu-zcash-parameters",
|
||||
|
|
|
@ -571,10 +571,10 @@ mod tests {
|
|||
use zcash_primitives::{
|
||||
block::BlockHash,
|
||||
consensus::{BlockHeight, Network},
|
||||
constants::SPENDING_KEY_GENERATOR,
|
||||
memo::MemoBytes,
|
||||
sapling::{
|
||||
self,
|
||||
constants::SPENDING_KEY_GENERATOR,
|
||||
note_encryption::{sapling_note_encryption, PreparedIncomingViewingKey, SaplingDomain},
|
||||
util::generate_random_rseed,
|
||||
value::NoteValue,
|
||||
|
|
|
@ -6,6 +6,15 @@ and this library adheres to Rust's notion of
|
|||
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- Dependency on `bellman 0.14`.
|
||||
- `zcash_primitives::sapling`:
|
||||
- `circuit` module (moved from `zcash_proofs::circuit::sapling`).
|
||||
- `constants` module.
|
||||
|
||||
### Removed
|
||||
- `zcash_primitives::constants`:
|
||||
- All `const` values (moved to `zcash_primitives::sapling::constants`).
|
||||
|
||||
## [0.13.0] - 2023-09-25
|
||||
### Added
|
||||
|
|
|
@ -39,6 +39,7 @@ memuse.workspace = true
|
|||
subtle.workspace = true
|
||||
|
||||
# - Shielded protocols
|
||||
bellman = { version = "0.14", default-features = false, features = ["groth16"] }
|
||||
bls12_381.workspace = true
|
||||
ff.workspace = true
|
||||
group = { workspace = true, features = ["wnaf-memuse"] }
|
||||
|
@ -116,5 +117,10 @@ harness = false
|
|||
name = "pedersen_hash"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "sapling_circuit"
|
||||
harness = false
|
||||
required-features = ["local-prover"]
|
||||
|
||||
[badges]
|
||||
maintenance = { status = "actively-developed" }
|
||||
|
|
|
@ -7,8 +7,10 @@ use criterion::Criterion;
|
|||
use group::{ff::Field, Group};
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
use zcash_primitives::sapling::{Diversifier, ProofGenerationKey};
|
||||
use zcash_proofs::circuit::sapling::{Spend, ValueCommitmentOpening};
|
||||
use zcash_primitives::sapling::{
|
||||
circuit::{Spend, ValueCommitmentOpening},
|
||||
Diversifier, ProofGenerationKey,
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
use pprof::criterion::{Output, PProfProfiler};
|
|
@ -1,440 +1,5 @@
|
|||
//! Various constants used by the Zcash primitives.
|
||||
|
||||
use ff::PrimeField;
|
||||
use group::Group;
|
||||
use jubjub::SubgroupPoint;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
pub mod mainnet;
|
||||
pub mod regtest;
|
||||
pub mod testnet;
|
||||
|
||||
/// First 64 bytes of the BLAKE2s input during group hash.
|
||||
/// This is chosen to be some random string that we couldn't have anticipated when we designed
|
||||
/// the algorithm, for rigidity purposes.
|
||||
/// We deliberately use an ASCII hex string of 32 bytes here.
|
||||
pub const GH_FIRST_BLOCK: &[u8; 64] =
|
||||
b"096b36a5804bfacef1691e173c366a47ff5ba84a44f26ddd7e8d9f79d5b42df0";
|
||||
|
||||
// BLAKE2s invocation personalizations
|
||||
/// BLAKE2s Personalization for CRH^ivk = BLAKE2s(ak | nk)
|
||||
pub const CRH_IVK_PERSONALIZATION: &[u8; 8] = b"Zcashivk";
|
||||
|
||||
/// BLAKE2s Personalization for PRF^nf = BLAKE2s(nk | rho)
|
||||
pub const PRF_NF_PERSONALIZATION: &[u8; 8] = b"Zcash_nf";
|
||||
|
||||
// Group hash personalizations
|
||||
/// BLAKE2s Personalization for Pedersen hash generators.
|
||||
pub const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &[u8; 8] = b"Zcash_PH";
|
||||
|
||||
/// BLAKE2s Personalization for the group hash for key diversification
|
||||
pub const KEY_DIVERSIFICATION_PERSONALIZATION: &[u8; 8] = b"Zcash_gd";
|
||||
|
||||
/// BLAKE2s Personalization for the spending key base point
|
||||
pub const SPENDING_KEY_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_G_";
|
||||
|
||||
/// BLAKE2s Personalization for the proof generation key base point
|
||||
pub const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_H_";
|
||||
|
||||
/// BLAKE2s Personalization for the value commitment generator for the value
|
||||
pub const VALUE_COMMITMENT_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_cv";
|
||||
|
||||
/// BLAKE2s Personalization for the nullifier position generator (for computing rho)
|
||||
pub const NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_J_";
|
||||
|
||||
/// The prover will demonstrate knowledge of discrete log with respect to this base when
|
||||
/// they are constructing a proof, in order to authorize proof construction.
|
||||
pub const PROOF_GENERATION_KEY_GENERATOR: SubgroupPoint = SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x3af2_dbef_b96e_2571,
|
||||
0xadf2_d038_f2fb_b820,
|
||||
0x7043_03f1_e890_6081,
|
||||
0x1457_a502_31cd_e2df,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x467a_f9f7_e05d_e8e7,
|
||||
0x50df_51ea_f5a1_49d2,
|
||||
0xdec9_0184_0f49_48cc,
|
||||
0x54b6_d107_18df_2a7a,
|
||||
]),
|
||||
);
|
||||
|
||||
/// The note commitment is randomized over this generator.
|
||||
pub const NOTE_COMMITMENT_RANDOMNESS_GENERATOR: SubgroupPoint = SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0xa514_3b34_a8e3_6462,
|
||||
0xf091_9d06_ffb1_ecda,
|
||||
0xa140_9aa1_f33b_ec2c,
|
||||
0x26eb_9f8a_9ec7_2a8c,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0xd4fc_6365_796c_77ac,
|
||||
0x96b7_8bea_fa9c_c44c,
|
||||
0x949d_7747_6e26_2c95,
|
||||
0x114b_7501_ad10_4c57,
|
||||
]),
|
||||
);
|
||||
|
||||
/// The node commitment is randomized again by the position in order to supply the
|
||||
/// nullifier computation with a unique input w.r.t. the note being spent, to prevent
|
||||
/// Faerie gold attacks.
|
||||
pub const NULLIFIER_POSITION_GENERATOR: SubgroupPoint = SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x2ce3_3921_888d_30db,
|
||||
0xe81c_ee09_a561_229e,
|
||||
0xdb56_b6db_8d80_75ed,
|
||||
0x2400_c2e2_e336_2644,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0xa3f7_fa36_c72b_0065,
|
||||
0xe155_b8e8_ffff_2e42,
|
||||
0xfc9e_8a15_a096_ba8f,
|
||||
0x6136_9d54_40bf_84a5,
|
||||
]),
|
||||
);
|
||||
|
||||
/// The value commitment is used to check balance between inputs and outputs. The value is
|
||||
/// placed over this generator.
|
||||
pub const VALUE_COMMITMENT_VALUE_GENERATOR: SubgroupPoint = SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x3618_3b2c_b4d7_ef51,
|
||||
0x9472_c89a_c043_042d,
|
||||
0xd861_8ed1_d15f_ef4e,
|
||||
0x273f_910d_9ecc_1615,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0xa77a_81f5_0667_c8d7,
|
||||
0xbc33_32d0_fa1c_cd18,
|
||||
0xd322_94fd_8977_4ad6,
|
||||
0x466a_7e3a_82f6_7ab1,
|
||||
]),
|
||||
);
|
||||
|
||||
/// The value commitment is randomized over this generator, for privacy.
|
||||
pub const VALUE_COMMITMENT_RANDOMNESS_GENERATOR: SubgroupPoint = SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x3bce_3b77_9366_4337,
|
||||
0xd1d8_da41_af03_744e,
|
||||
0x7ff6_826a_d580_04b4,
|
||||
0x6800_f4fa_0f00_1cfc,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x3cae_fab9_380b_6a8b,
|
||||
0xad46_f1b0_473b_803b,
|
||||
0xe6fb_2a6e_1e22_ab50,
|
||||
0x6d81_d3a9_cb45_dedb,
|
||||
]),
|
||||
);
|
||||
|
||||
/// The spender proves discrete log with respect to this base at spend time.
|
||||
pub const SPENDING_KEY_GENERATOR: SubgroupPoint = SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x47bf_4692_0a95_a753,
|
||||
0xd5b9_a7d3_ef8e_2827,
|
||||
0xd418_a7ff_2675_3b6a,
|
||||
0x0926_d4f3_2059_c712,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x3056_32ad_aaf2_b530,
|
||||
0x6d65_674d_cedb_ddbc,
|
||||
0x53bb_37d0_c21c_fd05,
|
||||
0x57a1_019e_6de9_b675,
|
||||
]),
|
||||
);
|
||||
|
||||
/// The generators (for each segment) used in all Pedersen commitments.
|
||||
pub const PEDERSEN_HASH_GENERATORS: &[SubgroupPoint] = &[
|
||||
SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x194e_4292_6f66_1b51,
|
||||
0x2f0c_718f_6f0f_badd,
|
||||
0xb5ea_25de_7ec0_e378,
|
||||
0x73c0_16a4_2ded_9578,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x77bf_abd4_3224_3cca,
|
||||
0xf947_2e8b_c04e_4632,
|
||||
0x79c9_166b_837e_dc5e,
|
||||
0x289e_87a2_d352_1b57,
|
||||
]),
|
||||
),
|
||||
SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0xb981_9dc8_2d90_607e,
|
||||
0xa361_ee3f_d48f_df77,
|
||||
0x52a3_5a8c_1908_dd87,
|
||||
0x15a3_6d1f_0f39_0d88,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x7b0d_c53c_4ebf_1891,
|
||||
0x1f3a_beeb_98fa_d3e8,
|
||||
0xf789_1142_c001_d925,
|
||||
0x015d_8c7f_5b43_fe33,
|
||||
]),
|
||||
),
|
||||
SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x76d6_f7c2_b67f_c475,
|
||||
0xbae8_e5c4_6641_ae5c,
|
||||
0xeb69_ae39_f5c8_4210,
|
||||
0x6643_21a5_8246_e2f6,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x80ed_502c_9793_d457,
|
||||
0x8bb2_2a7f_1784_b498,
|
||||
0xe000_a46c_8e8c_e853,
|
||||
0x362e_1500_d24e_ee9e,
|
||||
]),
|
||||
),
|
||||
SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x4c76_7804_c1c4_a2cc,
|
||||
0x7d02_d50e_654b_87f2,
|
||||
0xedc5_f4a9_cff2_9fd5,
|
||||
0x323a_6548_ce9d_9876,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x8471_4bec_a335_70e9,
|
||||
0x5103_afa1_a11f_6a85,
|
||||
0x9107_0acb_d8d9_47b7,
|
||||
0x2f7e_e40c_4b56_cad8,
|
||||
]),
|
||||
),
|
||||
SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x4680_9430_657f_82d1,
|
||||
0xefd5_9313_05f2_f0bf,
|
||||
0x89b6_4b4e_0336_2796,
|
||||
0x3bd2_6660_00b5_4796,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x9996_8299_c365_8aef,
|
||||
0xb3b9_d809_5859_d14c,
|
||||
0x3978_3238_1406_c9e5,
|
||||
0x494b_c521_03ab_9d0a,
|
||||
]),
|
||||
),
|
||||
SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0xcb3c_0232_58d3_2079,
|
||||
0x1d9e_5ca2_1135_ff6f,
|
||||
0xda04_9746_d76d_3ee5,
|
||||
0x6344_7b2b_a31b_b28a,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x4360_8211_9f8d_629a,
|
||||
0xa802_00d2_c66b_13a7,
|
||||
0x64cd_b107_0a13_6a28,
|
||||
0x64ec_4689_e8bf_b6e5,
|
||||
]),
|
||||
),
|
||||
];
|
||||
|
||||
/// The maximum number of chunks per segment of the Pedersen hash.
|
||||
pub const PEDERSEN_HASH_CHUNKS_PER_GENERATOR: usize = 63;
|
||||
|
||||
/// The window size for exponentiation of Pedersen hash generators outside the circuit.
|
||||
pub const PEDERSEN_HASH_EXP_WINDOW_SIZE: u32 = 8;
|
||||
|
||||
lazy_static! {
|
||||
/// The exp table for [`PEDERSEN_HASH_GENERATORS`].
|
||||
pub static ref PEDERSEN_HASH_EXP_TABLE: Vec<Vec<Vec<SubgroupPoint>>> =
|
||||
generate_pedersen_hash_exp_table();
|
||||
}
|
||||
|
||||
/// Creates the exp table for the Pedersen hash generators.
|
||||
fn generate_pedersen_hash_exp_table() -> Vec<Vec<Vec<SubgroupPoint>>> {
|
||||
let window = PEDERSEN_HASH_EXP_WINDOW_SIZE;
|
||||
|
||||
PEDERSEN_HASH_GENERATORS
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|mut g| {
|
||||
let mut tables = vec![];
|
||||
|
||||
let mut num_bits = 0;
|
||||
while num_bits <= jubjub::Fr::NUM_BITS {
|
||||
let mut table = Vec::with_capacity(1 << window);
|
||||
let mut base = SubgroupPoint::identity();
|
||||
|
||||
for _ in 0..(1 << window) {
|
||||
table.push(base);
|
||||
base += g;
|
||||
}
|
||||
|
||||
tables.push(table);
|
||||
num_bits += window;
|
||||
|
||||
for _ in 0..window {
|
||||
g = g.double();
|
||||
}
|
||||
}
|
||||
|
||||
tables
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use jubjub::SubgroupPoint;
|
||||
|
||||
use super::*;
|
||||
use crate::sapling::group_hash::group_hash;
|
||||
|
||||
fn find_group_hash(m: &[u8], personalization: &[u8; 8]) -> SubgroupPoint {
|
||||
let mut tag = m.to_vec();
|
||||
let i = tag.len();
|
||||
tag.push(0u8);
|
||||
|
||||
loop {
|
||||
let gh = group_hash(&tag, personalization);
|
||||
|
||||
// We don't want to overflow and start reusing generators
|
||||
assert!(tag[i] != u8::max_value());
|
||||
tag[i] += 1;
|
||||
|
||||
if let Some(gh) = gh {
|
||||
break gh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn proof_generation_key_base_generator() {
|
||||
assert_eq!(
|
||||
find_group_hash(&[], PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION),
|
||||
PROOF_GENERATION_KEY_GENERATOR,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn note_commitment_randomness_generator() {
|
||||
assert_eq!(
|
||||
find_group_hash(b"r", PEDERSEN_HASH_GENERATORS_PERSONALIZATION),
|
||||
NOTE_COMMITMENT_RANDOMNESS_GENERATOR,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nullifier_position_generator() {
|
||||
assert_eq!(
|
||||
find_group_hash(&[], NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION),
|
||||
NULLIFIER_POSITION_GENERATOR,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn value_commitment_value_generator() {
|
||||
assert_eq!(
|
||||
find_group_hash(b"v", VALUE_COMMITMENT_GENERATOR_PERSONALIZATION),
|
||||
VALUE_COMMITMENT_VALUE_GENERATOR,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn value_commitment_randomness_generator() {
|
||||
assert_eq!(
|
||||
find_group_hash(b"r", VALUE_COMMITMENT_GENERATOR_PERSONALIZATION),
|
||||
VALUE_COMMITMENT_RANDOMNESS_GENERATOR,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spending_key_generator() {
|
||||
assert_eq!(
|
||||
find_group_hash(&[], SPENDING_KEY_GENERATOR_PERSONALIZATION),
|
||||
SPENDING_KEY_GENERATOR,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pedersen_hash_generators() {
|
||||
for (m, actual) in PEDERSEN_HASH_GENERATORS.iter().enumerate() {
|
||||
assert_eq!(
|
||||
&find_group_hash(
|
||||
&(m as u32).to_le_bytes(),
|
||||
PEDERSEN_HASH_GENERATORS_PERSONALIZATION
|
||||
),
|
||||
actual
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_duplicate_fixed_base_generators() {
|
||||
let fixed_base_generators = [
|
||||
PROOF_GENERATION_KEY_GENERATOR,
|
||||
NOTE_COMMITMENT_RANDOMNESS_GENERATOR,
|
||||
NULLIFIER_POSITION_GENERATOR,
|
||||
VALUE_COMMITMENT_VALUE_GENERATOR,
|
||||
VALUE_COMMITMENT_RANDOMNESS_GENERATOR,
|
||||
SPENDING_KEY_GENERATOR,
|
||||
];
|
||||
|
||||
// Check for duplicates, far worse than spec inconsistencies!
|
||||
for (i, p1) in fixed_base_generators.iter().enumerate() {
|
||||
if p1.is_identity().into() {
|
||||
panic!("Neutral element!");
|
||||
}
|
||||
|
||||
for p2 in fixed_base_generators.iter().skip(i + 1) {
|
||||
if p1 == p2 {
|
||||
panic!("Duplicate generator!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check for simple relations between the generators, that make finding collisions easy;
|
||||
/// far worse than spec inconsistencies!
|
||||
fn check_consistency_of_pedersen_hash_generators(
|
||||
pedersen_hash_generators: &[jubjub::SubgroupPoint],
|
||||
) {
|
||||
for (i, p1) in pedersen_hash_generators.iter().enumerate() {
|
||||
if p1.is_identity().into() {
|
||||
panic!("Neutral element!");
|
||||
}
|
||||
for p2 in pedersen_hash_generators.iter().skip(i + 1) {
|
||||
if p1 == p2 {
|
||||
panic!("Duplicate generator!");
|
||||
}
|
||||
if *p1 == -p2 {
|
||||
panic!("Inverse generator!");
|
||||
}
|
||||
}
|
||||
|
||||
// check for a generator being the sum of any other two
|
||||
for (j, p2) in pedersen_hash_generators.iter().enumerate() {
|
||||
if j == i {
|
||||
continue;
|
||||
}
|
||||
for (k, p3) in pedersen_hash_generators.iter().enumerate() {
|
||||
if k == j || k == i {
|
||||
continue;
|
||||
}
|
||||
let sum = p2 + p3;
|
||||
if sum == *p1 {
|
||||
panic!("Linear relation between generators!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pedersen_hash_generators_consistency() {
|
||||
check_consistency_of_pedersen_hash_generators(PEDERSEN_HASH_GENERATORS);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Linear relation between generators!")]
|
||||
fn test_jubjub_bls12_pedersen_hash_generators_consistency_check_linear_relation() {
|
||||
let mut pedersen_hash_generators = PEDERSEN_HASH_GENERATORS.to_vec();
|
||||
|
||||
// Test for linear relation
|
||||
pedersen_hash_generators.push(PEDERSEN_HASH_GENERATORS[0] + PEDERSEN_HASH_GENERATORS[1]);
|
||||
|
||||
check_consistency_of_pedersen_hash_generators(&pedersen_hash_generators);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
//! Structs and constants specific to the Sapling shielded pool.
|
||||
|
||||
mod address;
|
||||
pub mod circuit;
|
||||
pub mod constants;
|
||||
pub mod group_hash;
|
||||
pub mod keys;
|
||||
pub mod note;
|
||||
|
@ -16,7 +18,7 @@ pub mod value;
|
|||
use group::GroupEncoding;
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
|
||||
use crate::constants::SPENDING_KEY_GENERATOR;
|
||||
use constants::SPENDING_KEY_GENERATOR;
|
||||
|
||||
use self::redjubjub::{PrivateKey, PublicKey, Signature};
|
||||
|
||||
|
|
|
@ -4,28 +4,29 @@ use group::{ff::PrimeField, Curve};
|
|||
|
||||
use bellman::{Circuit, ConstraintSystem, SynthesisError};
|
||||
|
||||
use zcash_primitives::constants;
|
||||
use super::{PaymentAddress, ProofGenerationKey};
|
||||
|
||||
use zcash_primitives::sapling::{PaymentAddress, ProofGenerationKey};
|
||||
|
||||
use super::ecc;
|
||||
use super::pedersen_hash;
|
||||
use crate::constants::{
|
||||
NOTE_COMMITMENT_RANDOMNESS_GENERATOR, NULLIFIER_POSITION_GENERATOR,
|
||||
PROOF_GENERATION_KEY_GENERATOR, SPENDING_KEY_GENERATOR, VALUE_COMMITMENT_RANDOMNESS_GENERATOR,
|
||||
VALUE_COMMITMENT_VALUE_GENERATOR,
|
||||
};
|
||||
use bellman::gadgets::blake2s;
|
||||
use bellman::gadgets::boolean;
|
||||
use bellman::gadgets::multipack;
|
||||
use bellman::gadgets::num;
|
||||
use bellman::gadgets::Assignment;
|
||||
|
||||
use self::constants::{
|
||||
NOTE_COMMITMENT_RANDOMNESS_GENERATOR, NULLIFIER_POSITION_GENERATOR,
|
||||
PROOF_GENERATION_KEY_GENERATOR, SPENDING_KEY_GENERATOR, VALUE_COMMITMENT_RANDOMNESS_GENERATOR,
|
||||
VALUE_COMMITMENT_VALUE_GENERATOR,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
use group::ff::PrimeFieldBits;
|
||||
|
||||
#[cfg(test)]
|
||||
use zcash_primitives::sapling::value::NoteValue;
|
||||
use super::value::NoteValue;
|
||||
|
||||
mod constants;
|
||||
mod ecc;
|
||||
mod pedersen_hash;
|
||||
|
||||
/// The opening (value and randomness) of a Sapling value commitment.
|
||||
#[derive(Clone)]
|
||||
|
@ -37,8 +38,9 @@ pub struct ValueCommitmentOpening {
|
|||
#[cfg(test)]
|
||||
impl ValueCommitmentOpening {
|
||||
fn commitment(&self) -> jubjub::ExtendedPoint {
|
||||
let cv = (constants::VALUE_COMMITMENT_VALUE_GENERATOR * jubjub::Fr::from(self.value))
|
||||
+ (constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR * self.randomness);
|
||||
let cv = (super::constants::VALUE_COMMITMENT_VALUE_GENERATOR
|
||||
* jubjub::Fr::from(self.value))
|
||||
+ (super::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR * self.randomness);
|
||||
cv.into()
|
||||
}
|
||||
}
|
||||
|
@ -209,7 +211,7 @@ impl Circuit<bls12_381::Scalar> for Spend {
|
|||
let mut ivk = blake2s::blake2s(
|
||||
cs.namespace(|| "computation of ivk"),
|
||||
&ivk_preimage,
|
||||
constants::CRH_IVK_PERSONALIZATION,
|
||||
super::constants::CRH_IVK_PERSONALIZATION,
|
||||
)?;
|
||||
|
||||
// drop_5 to ensure it's in the field
|
||||
|
@ -402,7 +404,7 @@ impl Circuit<bls12_381::Scalar> for Spend {
|
|||
let nf = blake2s::blake2s(
|
||||
cs.namespace(|| "nf computation"),
|
||||
&nf_preimage,
|
||||
constants::PRF_NF_PERSONALIZATION,
|
||||
super::constants::PRF_NF_PERSONALIZATION,
|
||||
)?;
|
||||
|
||||
multipack::pack_into_inputs(cs.namespace(|| "pack nullifier"), &nf)
|
||||
|
@ -536,11 +538,11 @@ impl Circuit<bls12_381::Scalar> for Output {
|
|||
|
||||
#[test]
|
||||
fn test_input_circuit_with_bls12_381() {
|
||||
use crate::sapling::{pedersen_hash, Diversifier, Note, ProofGenerationKey, Rseed};
|
||||
use bellman::gadgets::test::*;
|
||||
use group::{ff::Field, Group};
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
use zcash_primitives::sapling::{pedersen_hash, Diversifier, Note, ProofGenerationKey, Rseed};
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x58, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
|
@ -682,11 +684,11 @@ fn test_input_circuit_with_bls12_381() {
|
|||
|
||||
#[test]
|
||||
fn test_input_circuit_with_bls12_381_external_test_vectors() {
|
||||
use crate::sapling::{pedersen_hash, Diversifier, Note, ProofGenerationKey, Rseed};
|
||||
use bellman::gadgets::test::*;
|
||||
use group::{ff::Field, Group};
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
use zcash_primitives::sapling::{pedersen_hash, Diversifier, Note, ProofGenerationKey, Rseed};
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
|
@ -862,11 +864,11 @@ fn test_input_circuit_with_bls12_381_external_test_vectors() {
|
|||
|
||||
#[test]
|
||||
fn test_output_circuit_with_bls12_381() {
|
||||
use crate::sapling::{Diversifier, ProofGenerationKey, Rseed};
|
||||
use bellman::gadgets::test::*;
|
||||
use group::{ff::Field, Group};
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
use zcash_primitives::sapling::{Diversifier, ProofGenerationKey, Rseed};
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x58, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
|
@ -1,10 +1,10 @@
|
|||
//! Various constants used for the Zcash proofs.
|
||||
|
||||
use crate::sapling::constants::{PEDERSEN_HASH_CHUNKS_PER_GENERATOR, PEDERSEN_HASH_GENERATORS};
|
||||
use bls12_381::Scalar;
|
||||
use group::{ff::Field, 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(crate) const EDWARDS_D: Scalar = Scalar::from_raw([
|
||||
|
@ -42,22 +42,22 @@ 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);
|
||||
generate_circuit_generator(crate::sapling::constants::PROOF_GENERATION_KEY_GENERATOR);
|
||||
|
||||
pub static ref NOTE_COMMITMENT_RANDOMNESS_GENERATOR: FixedGeneratorOwned =
|
||||
generate_circuit_generator(zcash_primitives::constants::NOTE_COMMITMENT_RANDOMNESS_GENERATOR);
|
||||
generate_circuit_generator(crate::sapling::constants::NOTE_COMMITMENT_RANDOMNESS_GENERATOR);
|
||||
|
||||
pub static ref NULLIFIER_POSITION_GENERATOR: FixedGeneratorOwned =
|
||||
generate_circuit_generator(zcash_primitives::constants::NULLIFIER_POSITION_GENERATOR);
|
||||
generate_circuit_generator(crate::sapling::constants::NULLIFIER_POSITION_GENERATOR);
|
||||
|
||||
pub static ref VALUE_COMMITMENT_VALUE_GENERATOR: FixedGeneratorOwned =
|
||||
generate_circuit_generator(zcash_primitives::constants::VALUE_COMMITMENT_VALUE_GENERATOR);
|
||||
generate_circuit_generator(crate::sapling::constants::VALUE_COMMITMENT_VALUE_GENERATOR);
|
||||
|
||||
pub static ref VALUE_COMMITMENT_RANDOMNESS_GENERATOR: FixedGeneratorOwned =
|
||||
generate_circuit_generator(zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR);
|
||||
generate_circuit_generator(crate::sapling::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR);
|
||||
|
||||
pub static ref SPENDING_KEY_GENERATOR: FixedGeneratorOwned =
|
||||
generate_circuit_generator(zcash_primitives::constants::SPENDING_KEY_GENERATOR);
|
||||
generate_circuit_generator(crate::sapling::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.
|
|
@ -14,7 +14,7 @@ use bellman::gadgets::boolean::Boolean;
|
|||
|
||||
use group::Curve;
|
||||
|
||||
use crate::constants::{FixedGenerator, EDWARDS_D, MONTGOMERY_A, MONTGOMERY_SCALE};
|
||||
use super::constants::{FixedGenerator, EDWARDS_D, MONTGOMERY_A, MONTGOMERY_SCALE};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct EdwardsPoint {
|
||||
|
@ -77,6 +77,7 @@ impl EdwardsPoint {
|
|||
&self.u
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn get_v(&self) -> &AllocatedNum<bls12_381::Scalar> {
|
||||
&self.v
|
||||
}
|
||||
|
@ -630,7 +631,9 @@ mod test {
|
|||
use bellman::gadgets::test::*;
|
||||
|
||||
use super::{fixed_base_multiplication, AllocatedNum, EdwardsPoint, MontgomeryPoint};
|
||||
use crate::constants::{to_montgomery_coords, NOTE_COMMITMENT_RANDOMNESS_GENERATOR};
|
||||
use crate::sapling::circuit::constants::{
|
||||
to_montgomery_coords, NOTE_COMMITMENT_RANDOMNESS_GENERATOR,
|
||||
};
|
||||
use bellman::gadgets::boolean::{AllocatedBit, Boolean};
|
||||
|
||||
#[test]
|
||||
|
@ -732,7 +735,7 @@ mod test {
|
|||
for _ in 0..100 {
|
||||
let mut cs = TestConstraintSystem::<bls12_381::Scalar>::new();
|
||||
|
||||
let p = zcash_primitives::constants::NOTE_COMMITMENT_RANDOMNESS_GENERATOR;
|
||||
let p = crate::sapling::constants::NOTE_COMMITMENT_RANDOMNESS_GENERATOR;
|
||||
let s = jubjub::Fr::random(&mut rng);
|
||||
let q = jubjub::ExtendedPoint::from(p * s).to_affine();
|
||||
let (u1, v1) = (q.get_u(), q.get_v());
|
|
@ -1,12 +1,12 @@
|
|||
//! Gadget for Zcash's Pedersen hash.
|
||||
|
||||
use super::ecc::{EdwardsPoint, MontgomeryPoint};
|
||||
pub use crate::sapling::pedersen_hash::Personalization;
|
||||
use bellman::gadgets::boolean::Boolean;
|
||||
use bellman::gadgets::lookup::*;
|
||||
use bellman::{ConstraintSystem, SynthesisError};
|
||||
pub use zcash_primitives::sapling::pedersen_hash::Personalization;
|
||||
|
||||
use crate::constants::PEDERSEN_CIRCUIT_GENERATORS;
|
||||
use super::constants::PEDERSEN_CIRCUIT_GENERATORS;
|
||||
|
||||
fn get_constant_bools(person: &Personalization) -> Vec<Boolean> {
|
||||
person
|
||||
|
@ -105,12 +105,12 @@ where
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::sapling::pedersen_hash;
|
||||
use bellman::gadgets::boolean::{AllocatedBit, Boolean};
|
||||
use bellman::gadgets::test::*;
|
||||
use group::{ff::PrimeField, Curve};
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
use zcash_primitives::sapling::pedersen_hash;
|
||||
|
||||
/// Predict the number of constraints of a Pedersen hash
|
||||
fn ph_num_constraints(input_bits: usize) -> usize {
|
|
@ -0,0 +1,436 @@
|
|||
//! Various constants used by the Sapling protocol.
|
||||
|
||||
use ff::PrimeField;
|
||||
use group::Group;
|
||||
use jubjub::SubgroupPoint;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
/// First 64 bytes of the BLAKE2s input during group hash.
|
||||
/// This is chosen to be some random string that we couldn't have anticipated when we designed
|
||||
/// the algorithm, for rigidity purposes.
|
||||
/// We deliberately use an ASCII hex string of 32 bytes here.
|
||||
pub const GH_FIRST_BLOCK: &[u8; 64] =
|
||||
b"096b36a5804bfacef1691e173c366a47ff5ba84a44f26ddd7e8d9f79d5b42df0";
|
||||
|
||||
// BLAKE2s invocation personalizations
|
||||
/// BLAKE2s Personalization for CRH^ivk = BLAKE2s(ak | nk)
|
||||
pub const CRH_IVK_PERSONALIZATION: &[u8; 8] = b"Zcashivk";
|
||||
|
||||
/// BLAKE2s Personalization for PRF^nf = BLAKE2s(nk | rho)
|
||||
pub const PRF_NF_PERSONALIZATION: &[u8; 8] = b"Zcash_nf";
|
||||
|
||||
// Group hash personalizations
|
||||
/// BLAKE2s Personalization for Pedersen hash generators.
|
||||
pub const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &[u8; 8] = b"Zcash_PH";
|
||||
|
||||
/// BLAKE2s Personalization for the group hash for key diversification
|
||||
pub const KEY_DIVERSIFICATION_PERSONALIZATION: &[u8; 8] = b"Zcash_gd";
|
||||
|
||||
/// BLAKE2s Personalization for the spending key base point
|
||||
pub const SPENDING_KEY_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_G_";
|
||||
|
||||
/// BLAKE2s Personalization for the proof generation key base point
|
||||
pub const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_H_";
|
||||
|
||||
/// BLAKE2s Personalization for the value commitment generator for the value
|
||||
pub const VALUE_COMMITMENT_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_cv";
|
||||
|
||||
/// BLAKE2s Personalization for the nullifier position generator (for computing rho)
|
||||
pub const NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_J_";
|
||||
|
||||
/// The prover will demonstrate knowledge of discrete log with respect to this base when
|
||||
/// they are constructing a proof, in order to authorize proof construction.
|
||||
pub const PROOF_GENERATION_KEY_GENERATOR: SubgroupPoint = SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x3af2_dbef_b96e_2571,
|
||||
0xadf2_d038_f2fb_b820,
|
||||
0x7043_03f1_e890_6081,
|
||||
0x1457_a502_31cd_e2df,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x467a_f9f7_e05d_e8e7,
|
||||
0x50df_51ea_f5a1_49d2,
|
||||
0xdec9_0184_0f49_48cc,
|
||||
0x54b6_d107_18df_2a7a,
|
||||
]),
|
||||
);
|
||||
|
||||
/// The note commitment is randomized over this generator.
|
||||
pub const NOTE_COMMITMENT_RANDOMNESS_GENERATOR: SubgroupPoint = SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0xa514_3b34_a8e3_6462,
|
||||
0xf091_9d06_ffb1_ecda,
|
||||
0xa140_9aa1_f33b_ec2c,
|
||||
0x26eb_9f8a_9ec7_2a8c,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0xd4fc_6365_796c_77ac,
|
||||
0x96b7_8bea_fa9c_c44c,
|
||||
0x949d_7747_6e26_2c95,
|
||||
0x114b_7501_ad10_4c57,
|
||||
]),
|
||||
);
|
||||
|
||||
/// The node commitment is randomized again by the position in order to supply the
|
||||
/// nullifier computation with a unique input w.r.t. the note being spent, to prevent
|
||||
/// Faerie gold attacks.
|
||||
pub const NULLIFIER_POSITION_GENERATOR: SubgroupPoint = SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x2ce3_3921_888d_30db,
|
||||
0xe81c_ee09_a561_229e,
|
||||
0xdb56_b6db_8d80_75ed,
|
||||
0x2400_c2e2_e336_2644,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0xa3f7_fa36_c72b_0065,
|
||||
0xe155_b8e8_ffff_2e42,
|
||||
0xfc9e_8a15_a096_ba8f,
|
||||
0x6136_9d54_40bf_84a5,
|
||||
]),
|
||||
);
|
||||
|
||||
/// The value commitment is used to check balance between inputs and outputs. The value is
|
||||
/// placed over this generator.
|
||||
pub const VALUE_COMMITMENT_VALUE_GENERATOR: SubgroupPoint = SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x3618_3b2c_b4d7_ef51,
|
||||
0x9472_c89a_c043_042d,
|
||||
0xd861_8ed1_d15f_ef4e,
|
||||
0x273f_910d_9ecc_1615,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0xa77a_81f5_0667_c8d7,
|
||||
0xbc33_32d0_fa1c_cd18,
|
||||
0xd322_94fd_8977_4ad6,
|
||||
0x466a_7e3a_82f6_7ab1,
|
||||
]),
|
||||
);
|
||||
|
||||
/// The value commitment is randomized over this generator, for privacy.
|
||||
pub const VALUE_COMMITMENT_RANDOMNESS_GENERATOR: SubgroupPoint = SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x3bce_3b77_9366_4337,
|
||||
0xd1d8_da41_af03_744e,
|
||||
0x7ff6_826a_d580_04b4,
|
||||
0x6800_f4fa_0f00_1cfc,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x3cae_fab9_380b_6a8b,
|
||||
0xad46_f1b0_473b_803b,
|
||||
0xe6fb_2a6e_1e22_ab50,
|
||||
0x6d81_d3a9_cb45_dedb,
|
||||
]),
|
||||
);
|
||||
|
||||
/// The spender proves discrete log with respect to this base at spend time.
|
||||
pub const SPENDING_KEY_GENERATOR: SubgroupPoint = SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x47bf_4692_0a95_a753,
|
||||
0xd5b9_a7d3_ef8e_2827,
|
||||
0xd418_a7ff_2675_3b6a,
|
||||
0x0926_d4f3_2059_c712,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x3056_32ad_aaf2_b530,
|
||||
0x6d65_674d_cedb_ddbc,
|
||||
0x53bb_37d0_c21c_fd05,
|
||||
0x57a1_019e_6de9_b675,
|
||||
]),
|
||||
);
|
||||
|
||||
/// The generators (for each segment) used in all Pedersen commitments.
|
||||
pub const PEDERSEN_HASH_GENERATORS: &[SubgroupPoint] = &[
|
||||
SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x194e_4292_6f66_1b51,
|
||||
0x2f0c_718f_6f0f_badd,
|
||||
0xb5ea_25de_7ec0_e378,
|
||||
0x73c0_16a4_2ded_9578,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x77bf_abd4_3224_3cca,
|
||||
0xf947_2e8b_c04e_4632,
|
||||
0x79c9_166b_837e_dc5e,
|
||||
0x289e_87a2_d352_1b57,
|
||||
]),
|
||||
),
|
||||
SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0xb981_9dc8_2d90_607e,
|
||||
0xa361_ee3f_d48f_df77,
|
||||
0x52a3_5a8c_1908_dd87,
|
||||
0x15a3_6d1f_0f39_0d88,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x7b0d_c53c_4ebf_1891,
|
||||
0x1f3a_beeb_98fa_d3e8,
|
||||
0xf789_1142_c001_d925,
|
||||
0x015d_8c7f_5b43_fe33,
|
||||
]),
|
||||
),
|
||||
SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x76d6_f7c2_b67f_c475,
|
||||
0xbae8_e5c4_6641_ae5c,
|
||||
0xeb69_ae39_f5c8_4210,
|
||||
0x6643_21a5_8246_e2f6,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x80ed_502c_9793_d457,
|
||||
0x8bb2_2a7f_1784_b498,
|
||||
0xe000_a46c_8e8c_e853,
|
||||
0x362e_1500_d24e_ee9e,
|
||||
]),
|
||||
),
|
||||
SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x4c76_7804_c1c4_a2cc,
|
||||
0x7d02_d50e_654b_87f2,
|
||||
0xedc5_f4a9_cff2_9fd5,
|
||||
0x323a_6548_ce9d_9876,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x8471_4bec_a335_70e9,
|
||||
0x5103_afa1_a11f_6a85,
|
||||
0x9107_0acb_d8d9_47b7,
|
||||
0x2f7e_e40c_4b56_cad8,
|
||||
]),
|
||||
),
|
||||
SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x4680_9430_657f_82d1,
|
||||
0xefd5_9313_05f2_f0bf,
|
||||
0x89b6_4b4e_0336_2796,
|
||||
0x3bd2_6660_00b5_4796,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x9996_8299_c365_8aef,
|
||||
0xb3b9_d809_5859_d14c,
|
||||
0x3978_3238_1406_c9e5,
|
||||
0x494b_c521_03ab_9d0a,
|
||||
]),
|
||||
),
|
||||
SubgroupPoint::from_raw_unchecked(
|
||||
bls12_381::Scalar::from_raw([
|
||||
0xcb3c_0232_58d3_2079,
|
||||
0x1d9e_5ca2_1135_ff6f,
|
||||
0xda04_9746_d76d_3ee5,
|
||||
0x6344_7b2b_a31b_b28a,
|
||||
]),
|
||||
bls12_381::Scalar::from_raw([
|
||||
0x4360_8211_9f8d_629a,
|
||||
0xa802_00d2_c66b_13a7,
|
||||
0x64cd_b107_0a13_6a28,
|
||||
0x64ec_4689_e8bf_b6e5,
|
||||
]),
|
||||
),
|
||||
];
|
||||
|
||||
/// The maximum number of chunks per segment of the Pedersen hash.
|
||||
pub const PEDERSEN_HASH_CHUNKS_PER_GENERATOR: usize = 63;
|
||||
|
||||
/// The window size for exponentiation of Pedersen hash generators outside the circuit.
|
||||
pub const PEDERSEN_HASH_EXP_WINDOW_SIZE: u32 = 8;
|
||||
|
||||
lazy_static! {
|
||||
/// The exp table for [`PEDERSEN_HASH_GENERATORS`].
|
||||
pub static ref PEDERSEN_HASH_EXP_TABLE: Vec<Vec<Vec<SubgroupPoint>>> =
|
||||
generate_pedersen_hash_exp_table();
|
||||
}
|
||||
|
||||
/// Creates the exp table for the Pedersen hash generators.
|
||||
fn generate_pedersen_hash_exp_table() -> Vec<Vec<Vec<SubgroupPoint>>> {
|
||||
let window = PEDERSEN_HASH_EXP_WINDOW_SIZE;
|
||||
|
||||
PEDERSEN_HASH_GENERATORS
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|mut g| {
|
||||
let mut tables = vec![];
|
||||
|
||||
let mut num_bits = 0;
|
||||
while num_bits <= jubjub::Fr::NUM_BITS {
|
||||
let mut table = Vec::with_capacity(1 << window);
|
||||
let mut base = SubgroupPoint::identity();
|
||||
|
||||
for _ in 0..(1 << window) {
|
||||
table.push(base);
|
||||
base += g;
|
||||
}
|
||||
|
||||
tables.push(table);
|
||||
num_bits += window;
|
||||
|
||||
for _ in 0..window {
|
||||
g = g.double();
|
||||
}
|
||||
}
|
||||
|
||||
tables
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use jubjub::SubgroupPoint;
|
||||
|
||||
use super::*;
|
||||
use crate::sapling::group_hash::group_hash;
|
||||
|
||||
fn find_group_hash(m: &[u8], personalization: &[u8; 8]) -> SubgroupPoint {
|
||||
let mut tag = m.to_vec();
|
||||
let i = tag.len();
|
||||
tag.push(0u8);
|
||||
|
||||
loop {
|
||||
let gh = group_hash(&tag, personalization);
|
||||
|
||||
// We don't want to overflow and start reusing generators
|
||||
assert!(tag[i] != u8::max_value());
|
||||
tag[i] += 1;
|
||||
|
||||
if let Some(gh) = gh {
|
||||
break gh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn proof_generation_key_base_generator() {
|
||||
assert_eq!(
|
||||
find_group_hash(&[], PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION),
|
||||
PROOF_GENERATION_KEY_GENERATOR,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn note_commitment_randomness_generator() {
|
||||
assert_eq!(
|
||||
find_group_hash(b"r", PEDERSEN_HASH_GENERATORS_PERSONALIZATION),
|
||||
NOTE_COMMITMENT_RANDOMNESS_GENERATOR,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nullifier_position_generator() {
|
||||
assert_eq!(
|
||||
find_group_hash(&[], NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION),
|
||||
NULLIFIER_POSITION_GENERATOR,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn value_commitment_value_generator() {
|
||||
assert_eq!(
|
||||
find_group_hash(b"v", VALUE_COMMITMENT_GENERATOR_PERSONALIZATION),
|
||||
VALUE_COMMITMENT_VALUE_GENERATOR,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn value_commitment_randomness_generator() {
|
||||
assert_eq!(
|
||||
find_group_hash(b"r", VALUE_COMMITMENT_GENERATOR_PERSONALIZATION),
|
||||
VALUE_COMMITMENT_RANDOMNESS_GENERATOR,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spending_key_generator() {
|
||||
assert_eq!(
|
||||
find_group_hash(&[], SPENDING_KEY_GENERATOR_PERSONALIZATION),
|
||||
SPENDING_KEY_GENERATOR,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pedersen_hash_generators() {
|
||||
for (m, actual) in PEDERSEN_HASH_GENERATORS.iter().enumerate() {
|
||||
assert_eq!(
|
||||
&find_group_hash(
|
||||
&(m as u32).to_le_bytes(),
|
||||
PEDERSEN_HASH_GENERATORS_PERSONALIZATION
|
||||
),
|
||||
actual
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_duplicate_fixed_base_generators() {
|
||||
let fixed_base_generators = [
|
||||
PROOF_GENERATION_KEY_GENERATOR,
|
||||
NOTE_COMMITMENT_RANDOMNESS_GENERATOR,
|
||||
NULLIFIER_POSITION_GENERATOR,
|
||||
VALUE_COMMITMENT_VALUE_GENERATOR,
|
||||
VALUE_COMMITMENT_RANDOMNESS_GENERATOR,
|
||||
SPENDING_KEY_GENERATOR,
|
||||
];
|
||||
|
||||
// Check for duplicates, far worse than spec inconsistencies!
|
||||
for (i, p1) in fixed_base_generators.iter().enumerate() {
|
||||
if p1.is_identity().into() {
|
||||
panic!("Neutral element!");
|
||||
}
|
||||
|
||||
for p2 in fixed_base_generators.iter().skip(i + 1) {
|
||||
if p1 == p2 {
|
||||
panic!("Duplicate generator!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check for simple relations between the generators, that make finding collisions easy;
|
||||
/// far worse than spec inconsistencies!
|
||||
fn check_consistency_of_pedersen_hash_generators(
|
||||
pedersen_hash_generators: &[jubjub::SubgroupPoint],
|
||||
) {
|
||||
for (i, p1) in pedersen_hash_generators.iter().enumerate() {
|
||||
if p1.is_identity().into() {
|
||||
panic!("Neutral element!");
|
||||
}
|
||||
for p2 in pedersen_hash_generators.iter().skip(i + 1) {
|
||||
if p1 == p2 {
|
||||
panic!("Duplicate generator!");
|
||||
}
|
||||
if *p1 == -p2 {
|
||||
panic!("Inverse generator!");
|
||||
}
|
||||
}
|
||||
|
||||
// check for a generator being the sum of any other two
|
||||
for (j, p2) in pedersen_hash_generators.iter().enumerate() {
|
||||
if j == i {
|
||||
continue;
|
||||
}
|
||||
for (k, p3) in pedersen_hash_generators.iter().enumerate() {
|
||||
if k == j || k == i {
|
||||
continue;
|
||||
}
|
||||
let sum = p2 + p3;
|
||||
if sum == *p1 {
|
||||
panic!("Linear relation between generators!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pedersen_hash_generators_consistency() {
|
||||
check_consistency_of_pedersen_hash_generators(PEDERSEN_HASH_GENERATORS);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Linear relation between generators!")]
|
||||
fn test_jubjub_bls12_pedersen_hash_generators_consistency_check_linear_relation() {
|
||||
let mut pedersen_hash_generators = PEDERSEN_HASH_GENERATORS.to_vec();
|
||||
|
||||
// Test for linear relation
|
||||
pedersen_hash_generators.push(PEDERSEN_HASH_GENERATORS[0] + PEDERSEN_HASH_GENERATORS[1]);
|
||||
|
||||
check_consistency_of_pedersen_hash_generators(&pedersen_hash_generators);
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
use ff::PrimeField;
|
||||
use group::{cofactor::CofactorGroup, Group, GroupEncoding};
|
||||
|
||||
use crate::constants;
|
||||
use super::constants;
|
||||
use blake2s_simd::Params;
|
||||
|
||||
/// Produces a random point in the Jubjub curve.
|
||||
|
|
|
@ -8,6 +8,7 @@ use std::io::{self, Read, Write};
|
|||
|
||||
use super::{
|
||||
address::PaymentAddress,
|
||||
constants::{self, PROOF_GENERATION_KEY_GENERATOR, SPENDING_KEY_GENERATOR},
|
||||
note_encryption::KDF_SAPLING_PERSONALIZATION,
|
||||
spec::{
|
||||
crh_ivk, diversify_hash, ka_sapling_agree, ka_sapling_agree_prepared,
|
||||
|
@ -15,10 +16,7 @@ use super::{
|
|||
PreparedBaseSubgroup, PreparedScalar,
|
||||
},
|
||||
};
|
||||
use crate::{
|
||||
constants::{self, PROOF_GENERATION_KEY_GENERATOR, SPENDING_KEY_GENERATOR},
|
||||
keys::prf_expand,
|
||||
};
|
||||
use crate::keys::prf_expand;
|
||||
|
||||
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
|
||||
use ff::PrimeField;
|
||||
|
@ -509,7 +507,7 @@ mod tests {
|
|||
use group::{Group, GroupEncoding};
|
||||
|
||||
use super::FullViewingKey;
|
||||
use crate::constants::SPENDING_KEY_GENERATOR;
|
||||
use crate::sapling::constants::SPENDING_KEY_GENERATOR;
|
||||
|
||||
#[test]
|
||||
fn ak_must_be_prime_order() {
|
||||
|
|
|
@ -8,7 +8,7 @@ use ff::PrimeField;
|
|||
use group::Group;
|
||||
use std::ops::{AddAssign, Neg};
|
||||
|
||||
use crate::constants::{
|
||||
use super::constants::{
|
||||
PEDERSEN_HASH_CHUNKS_PER_GENERATOR, PEDERSEN_HASH_EXP_TABLE, PEDERSEN_HASH_EXP_WINDOW_SIZE,
|
||||
};
|
||||
|
||||
|
|
|
@ -68,9 +68,9 @@ pub mod mock {
|
|||
|
||||
use super::TxProver;
|
||||
use crate::{
|
||||
constants::SPENDING_KEY_GENERATOR,
|
||||
sapling::{
|
||||
self,
|
||||
constants::SPENDING_KEY_GENERATOR,
|
||||
redjubjub::{PublicKey, Signature},
|
||||
value::{NoteValue, ValueCommitTrapdoor, ValueCommitment},
|
||||
Diversifier, PaymentAddress, ProofGenerationKey, Rseed,
|
||||
|
|
|
@ -228,7 +228,7 @@ mod tests {
|
|||
use rand_xorshift::XorShiftRng;
|
||||
|
||||
use super::*;
|
||||
use crate::constants::SPENDING_KEY_GENERATOR;
|
||||
use crate::sapling::constants::SPENDING_KEY_GENERATOR;
|
||||
|
||||
#[test]
|
||||
fn test_batch_verify() {
|
||||
|
|
|
@ -4,13 +4,13 @@ use blake2s_simd::Params as Blake2sParams;
|
|||
use group::{cofactor::CofactorGroup, ff::PrimeField, Curve, GroupEncoding, WnafBase, WnafScalar};
|
||||
|
||||
use super::{
|
||||
constants::{
|
||||
CRH_IVK_PERSONALIZATION, KEY_DIVERSIFICATION_PERSONALIZATION,
|
||||
NOTE_COMMITMENT_RANDOMNESS_GENERATOR, NULLIFIER_POSITION_GENERATOR, PRF_NF_PERSONALIZATION,
|
||||
},
|
||||
group_hash::group_hash,
|
||||
pedersen_hash::{pedersen_hash, Personalization},
|
||||
};
|
||||
use crate::constants::{
|
||||
CRH_IVK_PERSONALIZATION, KEY_DIVERSIFICATION_PERSONALIZATION,
|
||||
NOTE_COMMITMENT_RANDOMNESS_GENERATOR, NULLIFIER_POSITION_GENERATOR, PRF_NF_PERSONALIZATION,
|
||||
};
|
||||
|
||||
const PREPARED_WINDOW_SIZE: usize = 4;
|
||||
pub(crate) type PreparedBase = WnafBase<jubjub::ExtendedPoint, PREPARED_WINDOW_SIZE>;
|
||||
|
|
|
@ -43,7 +43,7 @@ use group::GroupEncoding;
|
|||
use rand::RngCore;
|
||||
use subtle::CtOption;
|
||||
|
||||
use crate::constants::{VALUE_COMMITMENT_RANDOMNESS_GENERATOR, VALUE_COMMITMENT_VALUE_GENERATOR};
|
||||
use super::constants::{VALUE_COMMITMENT_RANDOMNESS_GENERATOR, VALUE_COMMITMENT_VALUE_GENERATOR};
|
||||
|
||||
mod sums;
|
||||
pub use sums::{CommitmentSum, OverflowError, TrapdoorSum, ValueSum};
|
||||
|
|
|
@ -3,8 +3,7 @@ use core::iter::Sum;
|
|||
use core::ops::{Add, AddAssign, Sub, SubAssign};
|
||||
|
||||
use super::{NoteValue, ValueCommitTrapdoor, ValueCommitment};
|
||||
use crate::constants::VALUE_COMMITMENT_VALUE_GENERATOR;
|
||||
use crate::sapling::redjubjub;
|
||||
use crate::sapling::{constants::VALUE_COMMITMENT_VALUE_GENERATOR, redjubjub};
|
||||
|
||||
/// A value operation overflowed.
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -715,8 +715,8 @@ pub mod testing {
|
|||
use rand::{rngs::StdRng, SeedableRng};
|
||||
|
||||
use crate::{
|
||||
constants::{SPENDING_KEY_GENERATOR, VALUE_COMMITMENT_RANDOMNESS_GENERATOR},
|
||||
sapling::{
|
||||
constants::{SPENDING_KEY_GENERATOR, VALUE_COMMITMENT_RANDOMNESS_GENERATOR},
|
||||
note::ExtractedNoteCommitment,
|
||||
redjubjub::{PrivateKey, PublicKey},
|
||||
value::{
|
||||
|
|
|
@ -16,10 +16,12 @@ use super::{
|
|||
Scope, ViewingKey,
|
||||
};
|
||||
use crate::{
|
||||
constants::{PROOF_GENERATION_KEY_GENERATOR, SPENDING_KEY_GENERATOR},
|
||||
keys::{prf_expand, prf_expand_vec},
|
||||
sapling::keys::{DecodingError, ExpandedSpendingKey, FullViewingKey, OutgoingViewingKey},
|
||||
sapling::SaplingIvk,
|
||||
sapling::{
|
||||
constants::{PROOF_GENERATION_KEY_GENERATOR, SPENDING_KEY_GENERATOR},
|
||||
keys::{DecodingError, ExpandedSpendingKey, FullViewingKey, OutgoingViewingKey},
|
||||
SaplingIvk,
|
||||
},
|
||||
};
|
||||
|
||||
pub const ZIP32_SAPLING_MASTER_PERSONALIZATION: &[u8; 16] = b"ZcashIP32Sapling";
|
||||
|
|
|
@ -6,6 +6,10 @@ and this library adheres to Rust's notion of
|
|||
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
### Removed
|
||||
- `zcash_proofs::circuit::sapling` (moved to `zcash_primitives::sapling::circuit`).
|
||||
- `zcash_proofs::circuit::{ecc, pedersen_hash}`
|
||||
- `zcash_proofs::constants`
|
||||
|
||||
## [0.13.0] - 2023-09-25
|
||||
### Changed
|
||||
|
|
|
@ -41,11 +41,6 @@ xdg = { version = "2.5", optional = true }
|
|||
|
||||
[dev-dependencies]
|
||||
byteorder.workspace = true
|
||||
criterion.workspace = true
|
||||
rand_xorshift.workspace = true
|
||||
|
||||
[target.'cfg(unix)'.dev-dependencies]
|
||||
pprof = { version = "0.11", features = ["criterion", "flamegraph"] } # MSRV 1.56
|
||||
|
||||
[features]
|
||||
default = ["local-prover", "multicore"]
|
||||
|
@ -58,11 +53,6 @@ multicore = ["bellman/multicore", "zcash_primitives/multicore"]
|
|||
[lib]
|
||||
bench = false
|
||||
|
||||
[[bench]]
|
||||
name = "sapling"
|
||||
harness = false
|
||||
required-features = ["local-prover"]
|
||||
|
||||
[[example]]
|
||||
name = "get-params-path"
|
||||
required-features = ["directories"]
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
//! Implementations of the Zcash circuits and Zcash-specific gadgets.
|
||||
|
||||
pub mod ecc;
|
||||
pub mod pedersen_hash;
|
||||
|
||||
pub mod sapling;
|
||||
pub mod sprout;
|
||||
|
|
|
@ -19,7 +19,6 @@ use std::path::Path;
|
|||
use std::path::PathBuf;
|
||||
|
||||
pub mod circuit;
|
||||
pub mod constants;
|
||||
mod hashreader;
|
||||
pub mod sapling;
|
||||
pub mod sprout;
|
||||
|
|
|
@ -6,8 +6,9 @@ use bls12_381::Bls12;
|
|||
use group::{Curve, GroupEncoding};
|
||||
use rand_core::OsRng;
|
||||
use zcash_primitives::{
|
||||
constants::{SPENDING_KEY_GENERATOR, VALUE_COMMITMENT_RANDOMNESS_GENERATOR},
|
||||
sapling::{
|
||||
circuit::{Output, Spend, ValueCommitmentOpening},
|
||||
constants::{SPENDING_KEY_GENERATOR, VALUE_COMMITMENT_RANDOMNESS_GENERATOR},
|
||||
redjubjub::{PublicKey, Signature},
|
||||
value::{CommitmentSum, NoteValue, TrapdoorSum, ValueCommitTrapdoor, ValueCommitment},
|
||||
Diversifier, MerklePath, Note, PaymentAddress, ProofGenerationKey, Rseed,
|
||||
|
@ -15,8 +16,6 @@ use zcash_primitives::{
|
|||
transaction::components::Amount,
|
||||
};
|
||||
|
||||
use crate::circuit::sapling::{Output, Spend, ValueCommitmentOpening};
|
||||
|
||||
/// A context object for creating the Sapling components of a Zcash transaction.
|
||||
pub struct SaplingProvingContext {
|
||||
bsk: TrapdoorSum,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use bellman::groth16::{verify_proof, PreparedVerifyingKey, Proof};
|
||||
use bls12_381::Bls12;
|
||||
use zcash_primitives::{
|
||||
constants::{SPENDING_KEY_GENERATOR, VALUE_COMMITMENT_RANDOMNESS_GENERATOR},
|
||||
sapling::{
|
||||
constants::{SPENDING_KEY_GENERATOR, VALUE_COMMITMENT_RANDOMNESS_GENERATOR},
|
||||
note::ExtractedNoteCommitment,
|
||||
redjubjub::{PublicKey, Signature},
|
||||
value::ValueCommitment,
|
||||
|
|
Loading…
Reference in New Issue