commit
bea0286f53
|
@ -0,0 +1,10 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
timezone: Etc/UTC
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- "A-CI"
|
|
@ -0,0 +1,88 @@
|
|||
name: CI checks
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Run tests
|
||||
run: cargo test --all-features --verbose --release
|
||||
- name: Verify working directory is clean
|
||||
run: git diff --exit-code
|
||||
|
||||
build-latest:
|
||||
name: Latest build on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
id: toolchain
|
||||
- run: rustup override set ${{steps.toolchain.outputs.name}}
|
||||
- name: Remove lockfile to build with latest dependencies
|
||||
run: rm Cargo.lock
|
||||
- name: Build crate
|
||||
run: cargo build --all-targets --all-features --verbose
|
||||
- name: Verify working directory is clean (excluding lockfile)
|
||||
run: git diff --exit-code ':!Cargo.lock'
|
||||
|
||||
build-nodefault:
|
||||
name: Build target ${{ matrix.target }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
target:
|
||||
- wasm32-wasi
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Add target
|
||||
run: rustup target add ${{ matrix.target }}
|
||||
- name: Build crate
|
||||
run: cargo build --no-default-features --verbose --target ${{ matrix.target }}
|
||||
|
||||
bitrot:
|
||||
name: Bitrot check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
# Build benchmarks to prevent bitrot
|
||||
- name: Build benchmarks
|
||||
run: cargo build --all --benches
|
||||
|
||||
clippy:
|
||||
name: Clippy (MSRV)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Run Clippy
|
||||
uses: auguwu/clippy-action@1.3.0
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
working-directory: ${{ inputs.target }}
|
||||
deny: warnings
|
||||
|
||||
doc-links:
|
||||
name: Intra-doc links
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: cargo fetch
|
||||
# Requires #![deny(rustdoc::broken_intra_doc_links)] in crate.
|
||||
- name: Check intra-doc links
|
||||
run: cargo doc --all-features --document-private-items
|
||||
|
||||
fmt:
|
||||
name: Rustfmt
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Check formatting
|
||||
run: cargo fmt -- --check
|
|
@ -1,3 +1,2 @@
|
|||
/target/
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
|
|
File diff suppressed because it is too large
Load Diff
24
Cargo.toml
24
Cargo.toml
|
@ -15,7 +15,7 @@ license = "MIT OR Apache-2.0"
|
|||
|
||||
[dependencies]
|
||||
ff = "0.13"
|
||||
group = "0.13"
|
||||
group = { version = "0.13", features = ["wnaf-memuse"] }
|
||||
|
||||
bls12_381 = "0.8"
|
||||
jubjub = "0.10"
|
||||
|
@ -43,10 +43,10 @@ tracing = "0.1"
|
|||
|
||||
# Note Commitment Trees
|
||||
bitvec = "1"
|
||||
incrementalmerkletree = "0.5"
|
||||
incrementalmerkletree = { version = "0.5", features = ["legacy-api"] }
|
||||
|
||||
# Note encryption
|
||||
zcash_note_encryption = "0.4"
|
||||
zcash_note_encryption = { version = "0.4", features = ["pre-zip-212"] }
|
||||
|
||||
# Secret management
|
||||
subtle = "2.2.3"
|
||||
|
@ -64,9 +64,25 @@ zip32 = "0.1"
|
|||
|
||||
[dev-dependencies]
|
||||
chacha20poly1305 = "0.10"
|
||||
criterion = "0.4"
|
||||
incrementalmerkletree = { version = "0.5", features = ["legacy-api", "test-dependencies"] }
|
||||
proptest = "1"
|
||||
rand_xorshift = "0.3"
|
||||
|
||||
[target.'cfg(unix)'.dev-dependencies]
|
||||
pprof = { version = "0.11", features = ["criterion", "flamegraph"] } # MSRV 1.56
|
||||
|
||||
[features]
|
||||
multicore = ["bellman/multicore"]
|
||||
test-dependencies = ["proptest"]
|
||||
test-dependencies = [
|
||||
"incrementalmerkletree/test-dependencies",
|
||||
"proptest",
|
||||
]
|
||||
|
||||
[[bench]]
|
||||
name = "circuit"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "pedersen_hash"
|
||||
harness = false
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
#[macro_use]
|
||||
extern crate criterion;
|
||||
|
||||
use bellman::groth16::*;
|
||||
use bls12_381::Bls12;
|
||||
use criterion::Criterion;
|
||||
use group::ff::Field;
|
||||
use rand::{Rng, RngCore, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
use sapling_crypto::{
|
||||
circuit::{Spend, ValueCommitmentOpening},
|
||||
keys::ExpandedSpendingKey,
|
||||
value::NoteValue,
|
||||
Diversifier,
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
use pprof::criterion::{Output, PProfProfiler};
|
||||
|
||||
const TREE_DEPTH: usize = 32;
|
||||
|
||||
fn criterion_benchmark(c: &mut Criterion) {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
]);
|
||||
|
||||
let groth_params = generate_random_parameters::<Bls12, _, _>(
|
||||
Spend {
|
||||
value_commitment_opening: None,
|
||||
proof_generation_key: None,
|
||||
payment_address: None,
|
||||
commitment_randomness: None,
|
||||
ar: None,
|
||||
auth_path: vec![None; TREE_DEPTH],
|
||||
anchor: None,
|
||||
},
|
||||
&mut rng,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
c.bench_function("sapling-spend-prove", |b| {
|
||||
let value_commitment = ValueCommitmentOpening {
|
||||
value: NoteValue::from_raw(1),
|
||||
randomness: jubjub::Fr::random(&mut rng),
|
||||
};
|
||||
|
||||
let sk: [u8; 32] = rng.gen();
|
||||
let expsk = ExpandedSpendingKey::from_spending_key(&sk);
|
||||
|
||||
let proof_generation_key = expsk.proof_generation_key();
|
||||
|
||||
let viewing_key = proof_generation_key.to_viewing_key();
|
||||
|
||||
let payment_address = loop {
|
||||
let diversifier = {
|
||||
let mut d = [0; 11];
|
||||
rng.fill_bytes(&mut d);
|
||||
Diversifier(d)
|
||||
};
|
||||
|
||||
if let Some(p) = viewing_key.to_payment_address(diversifier) {
|
||||
break p;
|
||||
}
|
||||
};
|
||||
|
||||
let commitment_randomness = jubjub::Fr::random(&mut rng);
|
||||
let auth_path =
|
||||
vec![Some((bls12_381::Scalar::random(&mut rng), rng.next_u32() % 2 != 0)); TREE_DEPTH];
|
||||
let ar = jubjub::Fr::random(&mut rng);
|
||||
let anchor = bls12_381::Scalar::random(&mut rng);
|
||||
|
||||
b.iter(|| {
|
||||
create_random_proof(
|
||||
Spend {
|
||||
value_commitment_opening: Some(value_commitment.clone()),
|
||||
proof_generation_key: Some(proof_generation_key.clone()),
|
||||
payment_address: Some(payment_address),
|
||||
commitment_randomness: Some(commitment_randomness),
|
||||
ar: Some(ar),
|
||||
auth_path: auth_path.clone(),
|
||||
anchor: Some(anchor),
|
||||
},
|
||||
&groth_params,
|
||||
&mut rng,
|
||||
)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
criterion_group! {
|
||||
name = benches;
|
||||
config = Criterion::default()
|
||||
.sample_size(10)
|
||||
.with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
|
||||
targets = criterion_benchmark
|
||||
}
|
||||
#[cfg(windows)]
|
||||
criterion_group! {
|
||||
name = benches;
|
||||
config = Criterion::default().sample_size(10);
|
||||
targets = criterion_benchmark
|
||||
}
|
||||
criterion_main!(benches);
|
|
@ -1,23 +1,28 @@
|
|||
#![feature(test)]
|
||||
|
||||
extern crate rand;
|
||||
extern crate test;
|
||||
extern crate pairing;
|
||||
extern crate sapling_crypto;
|
||||
|
||||
use rand::{Rand, thread_rng};
|
||||
use pairing::bls12_381::Bls12;
|
||||
use sapling_crypto::jubjub::JubjubBls12;
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use rand_core::{OsRng, RngCore};
|
||||
use sapling_crypto::pedersen_hash::{pedersen_hash, Personalization};
|
||||
|
||||
#[bench]
|
||||
fn bench_pedersen_hash(b: &mut test::Bencher) {
|
||||
let params = JubjubBls12::new();
|
||||
let rng = &mut thread_rng();
|
||||
let bits = (0..510).map(|_| bool::rand(rng)).collect::<Vec<_>>();
|
||||
#[cfg(unix)]
|
||||
use pprof::criterion::{Output, PProfProfiler};
|
||||
|
||||
fn bench_pedersen_hash(c: &mut Criterion) {
|
||||
let rng = &mut OsRng;
|
||||
let bits = (0..510)
|
||||
.map(|_| (rng.next_u32() % 2) != 0)
|
||||
.collect::<Vec<_>>();
|
||||
let personalization = Personalization::MerkleTree(31);
|
||||
|
||||
b.iter(|| {
|
||||
pedersen_hash::<Bls12, _>(personalization, bits.clone(), ¶ms)
|
||||
c.bench_function("pedersen-hash", |b| {
|
||||
b.iter(|| pedersen_hash(personalization, bits.clone()))
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
criterion_group! {
|
||||
name = benches;
|
||||
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
|
||||
targets = bench_pedersen_hash
|
||||
}
|
||||
#[cfg(not(unix))]
|
||||
criterion_group!(benches, bench_pedersen_hash);
|
||||
criterion_main!(benches);
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
extern crate sapling_crypto;
|
||||
extern crate bellman;
|
||||
extern crate rand;
|
||||
extern crate pairing;
|
||||
|
||||
use std::time::{Duration, Instant};
|
||||
use sapling_crypto::jubjub::{
|
||||
JubjubBls12,
|
||||
edwards,
|
||||
fs,
|
||||
};
|
||||
use sapling_crypto::circuit::sapling::{
|
||||
Spend
|
||||
};
|
||||
use sapling_crypto::primitives::{
|
||||
Diversifier,
|
||||
ProofGenerationKey,
|
||||
ValueCommitment
|
||||
};
|
||||
use bellman::groth16::*;
|
||||
use rand::{XorShiftRng, SeedableRng, Rng};
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
|
||||
const TREE_DEPTH: usize = 32;
|
||||
|
||||
fn main() {
|
||||
let jubjub_params = &JubjubBls12::new();
|
||||
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
println!("Creating sample parameters...");
|
||||
let groth_params = generate_random_parameters::<Bls12, _, _>(
|
||||
Spend {
|
||||
params: jubjub_params,
|
||||
value_commitment: None,
|
||||
proof_generation_key: None,
|
||||
payment_address: None,
|
||||
commitment_randomness: None,
|
||||
ar: None,
|
||||
auth_path: vec![None; TREE_DEPTH],
|
||||
anchor: None
|
||||
},
|
||||
rng
|
||||
).unwrap();
|
||||
|
||||
const SAMPLES: u32 = 50;
|
||||
|
||||
let mut total_time = Duration::new(0, 0);
|
||||
for _ in 0..SAMPLES {
|
||||
let value_commitment = ValueCommitment {
|
||||
value: 1,
|
||||
randomness: rng.gen()
|
||||
};
|
||||
|
||||
let nsk: fs::Fs = rng.gen();
|
||||
let ak = edwards::Point::rand(rng, jubjub_params).mul_by_cofactor(jubjub_params);
|
||||
|
||||
let proof_generation_key = ProofGenerationKey {
|
||||
ak: ak.clone(),
|
||||
nsk: nsk.clone()
|
||||
};
|
||||
|
||||
let viewing_key = proof_generation_key.into_viewing_key(jubjub_params);
|
||||
|
||||
let payment_address;
|
||||
|
||||
loop {
|
||||
let diversifier = Diversifier(rng.gen());
|
||||
|
||||
if let Some(p) = viewing_key.into_payment_address(
|
||||
diversifier,
|
||||
jubjub_params
|
||||
)
|
||||
{
|
||||
payment_address = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let commitment_randomness: fs::Fs = rng.gen();
|
||||
let auth_path = vec![Some((rng.gen(), rng.gen())); TREE_DEPTH];
|
||||
let ar: fs::Fs = rng.gen();
|
||||
let anchor: Fr = rng.gen();
|
||||
|
||||
let start = Instant::now();
|
||||
let _ = create_random_proof(Spend {
|
||||
params: jubjub_params,
|
||||
value_commitment: Some(value_commitment),
|
||||
proof_generation_key: Some(proof_generation_key),
|
||||
payment_address: Some(payment_address),
|
||||
commitment_randomness: Some(commitment_randomness),
|
||||
ar: Some(ar),
|
||||
auth_path: auth_path,
|
||||
anchor: Some(anchor)
|
||||
}, &groth_params, rng).unwrap();
|
||||
total_time += start.elapsed();
|
||||
}
|
||||
let avg = total_time / SAMPLES;
|
||||
let avg = avg.subsec_nanos() as f64 / 1_000_000_000f64
|
||||
+ (avg.as_secs() as f64);
|
||||
|
||||
println!("Average proving time (in seconds): {}", avg);
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "1.65.0"
|
||||
components = ["clippy", "rustfmt"]
|
|
@ -50,10 +50,9 @@ pub trait MapAuth<A: Authorization, B: Authorization> {
|
|||
|
||||
/// The identity map.
|
||||
///
|
||||
/// This can be used with [`TransactionData::map_authorization`] when you want to map the
|
||||
/// authorization of a subset of the transaction's bundles.
|
||||
///
|
||||
/// [`TransactionData::map_authorization`]: crate::transaction::TransactionData::map_authorization
|
||||
/// This can be used with [`Bundle::map_authorization`] when you want to map the
|
||||
/// authorization of a subset of a transaction's bundles (excluding the Sapling bundle) in
|
||||
/// a higher-level transaction type.
|
||||
impl MapAuth<Authorized, Authorized> for () {
|
||||
fn map_spend_proof(
|
||||
&mut self,
|
||||
|
|
13
src/lib.rs
13
src/lib.rs
|
@ -1,4 +1,15 @@
|
|||
//! Structs and constants specific to the Sapling shielded pool.
|
||||
//! # sapling
|
||||
//!
|
||||
//! ## Nomenclature
|
||||
//!
|
||||
//! All types in the `sapling-crypto` crate, unless otherwise specified, are
|
||||
//! Sapling-specific types. For example, [`PaymentAddress`] is documented as being a
|
||||
//! shielded payment address; we implicitly mean it is an Sapling payment address (as
|
||||
//! opposed to e.g. an Orchard payment address, which is also shielded).
|
||||
|
||||
// Catch documentation errors caused by code changes.
|
||||
#![deny(rustdoc::broken_intra_doc_links)]
|
||||
#![deny(unsafe_code)]
|
||||
|
||||
mod address;
|
||||
pub mod builder;
|
||||
|
|
|
@ -38,12 +38,12 @@ pub trait SpendProver {
|
|||
|
||||
/// Create the proof for a Sapling [`SpendDescription`].
|
||||
///
|
||||
/// [`SpendDescription`]: crate::transaction::components::SpendDescription
|
||||
/// [`SpendDescription`]: crate::bundle::SpendDescription
|
||||
fn create_proof<R: RngCore>(&self, circuit: circuit::Spend, rng: &mut R) -> Self::Proof;
|
||||
|
||||
/// Encodes the given Sapling [`SpendDescription`] proof, erasing its type.
|
||||
///
|
||||
/// [`SpendDescription`]: crate::transaction::components::SpendDescription
|
||||
/// [`SpendDescription`]: crate::bundle::SpendDescription
|
||||
fn encode_proof(proof: Self::Proof) -> GrothProofBytes;
|
||||
}
|
||||
|
||||
|
@ -65,12 +65,12 @@ pub trait OutputProver {
|
|||
|
||||
/// Create the proof for a Sapling [`OutputDescription`].
|
||||
///
|
||||
/// [`OutputDescription`]: crate::transaction::components::OutputDescription
|
||||
/// [`OutputDescription`]: crate::bundle::OutputDescription
|
||||
fn create_proof<R: RngCore>(&self, circuit: circuit::Output, rng: &mut R) -> Self::Proof;
|
||||
|
||||
/// Encodes the given Sapling [`OutputDescription`] proof, erasing its type.
|
||||
///
|
||||
/// [`OutputDescription`]: crate::transaction::components::OutputDescription
|
||||
/// [`OutputDescription`]: crate::bundle::OutputDescription
|
||||
fn encode_proof(proof: Self::Proof) -> GrothProofBytes;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,10 +31,10 @@
|
|||
//! you should only need to interact with [`NoteValue`] (which can be safely constructed
|
||||
//! from a `u64`) and `valueBalanceSapling` (which can be represented as an `i64`).
|
||||
//!
|
||||
//! [`Bundle`]: crate::sapling::Bundle
|
||||
//! [`Bundle::value_balance`]: crate::sapling::Bundle::value_balance
|
||||
//! [`SaplingBuilder::value_balance`]: crate::sapling::builder::SaplingBuilder::value_balance
|
||||
//! [`SaplingBuilder::add_output`]: crate::sapling::builder::SaplingBuilder::add_output
|
||||
//! [`Bundle`]: crate::Bundle
|
||||
//! [`Bundle::value_balance`]: crate::Bundle::value_balance
|
||||
//! [`SaplingBuilder::value_balance`]: crate::builder::SaplingBuilder::value_balance
|
||||
//! [`SaplingBuilder::add_output`]: crate::builder::SaplingBuilder::add_output
|
||||
//! [Rust documentation]: https://doc.rust-lang.org/stable/std/primitive.i64.html
|
||||
|
||||
use bitvec::{array::BitArray, order::Lsb0};
|
||||
|
|
Loading…
Reference in New Issue