Skip to content

Commit

Permalink
Moves variable-time proving behind a feature gate (tari-project#103)
Browse files Browse the repository at this point in the history
It can be risky to make variable-time prover functionality available. This PR moves it behind a feature gate.

BREAKING CHANGE: Moves parts of the public API behind a feature gate.
  • Loading branch information
AaronFeickert authored Aug 10, 2024
1 parent fc3682c commit 24e5a20
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 50 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ rand_chacha = { version = "0.3.1", default-features = false }
default = ["rand", "std"]
# Adds proof serialization and deserialization via [`borsh`](https://crates.io/crates/borsh)
borsh = ["dep:borsh"]
# Adds variable-time prover functionality that should only be used if you absolutely know what you're doing
hazmat = []
# Adds additional prover functionality that supplies a cryptographically-secure random number generator
rand = ["rand_core/getrandom"]
# Adds proof serialization and deserialization via [`serde`](https://crates.io/crates/serde)
Expand All @@ -41,10 +43,12 @@ std = ["blake3/std", "borsh?/std", "itertools/use_std", "merlin/std", "rand_core
[[bench]]
name = "triptych"
harness = false
required-features = ["hazmat"]

[[bench]]
name = "parallel"
harness = false
required-features = ["hazmat"]

[[example]]
name = "ringct"
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,14 @@ There are several features available.
| Feature | Default? | Description |
| :--- | :---: | :--- |
| `borsh` | | Adds proof serialization and deserialization via [`borsh`](https://crates.io/crates/borsh) |
| `serde` | | Adds proof serialization and deserialization via [`serde`](https://crates.io/crates/serde) |
| `hazmat` | | Adds variable-time prover functionality that should only be used if you absolutely know what you're doing |
| `rand` || Adds additional prover functionality that supplies a cryptographically-secure random number generator |
| `serde` | | Adds proof serialization and deserialization via [`serde`](https://crates.io/crates/serde) |
| `std` || Adds corresponding dependency features |

The underlying [curve library](https://crates.io/crates/curve25519-dalek) chooses an arithmetic backend based on CPU feature detection.
Using a nightly compiler broadens the backend set, and may provide better performance.
You can examine performance using the benchmarks: either `cargo bench` or `cargo +nightly bench`.
You can examine performance using the benchmarks: either `cargo bench --all-features` or `cargo +nightly bench --all-features`.

Proofs support a custom serialization format designed to be efficient and canonical.
This is used for `borsh` serialization and deserialization, or can be accessed directly.
Expand Down
6 changes: 4 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@
//! | Feature | Default? | Description |
//! | :--- | :---: | :--- |
//! | `borsh` | | Adds proof serialization and deserialization via [`borsh`](https://crates.io/crates/borsh) |
//! | `serde` | | Adds proof serialization and deserialization via [`serde`](https://crates.io/crates/serde) |
//! | `hazmat` | | Adds variable-time prover functionality that should only be used if you absolutely know what you're doing |
//! | `rand` | ✓ | Adds additional prover functionality that supplies a cryptographically-secure random number generator |
//! | `serde` | | Adds proof serialization and deserialization via [`serde`](https://crates.io/crates/serde) |
//! | `std` | ✓ | Adds corresponding dependency features |
//!
//! The underlying [curve library](https://crates.io/crates/curve25519-dalek) chooses an arithmetic backend based on CPU feature detection.
//! Using a nightly compiler broadens the backend set, and may provide better performance.
//! You can examine performance using the benchmarks: either `cargo bench` or `cargo +nightly bench`.
//! You can examine performance using the benchmarks: either `cargo bench --all-features` or `cargo +nightly bench
//! --all-features`.
//!
//! Proofs support a custom serialization format designed to be efficient and canonical.
//! This is used for `borsh` serialization and deserialization, or can be accessed directly.
Expand Down
48 changes: 22 additions & 26 deletions src/parallel/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ impl TriptychProof {
/// You must also supply a [`Transcript`] `transcript`.
///
/// This function specifically avoids constant-time operations for efficiency.
#[cfg(feature = "rand")]
#[cfg(all(feature = "rand", feature = "hazmat"))]
pub fn prove_vartime(
witness: &TriptychWitness,
statement: &TriptychStatement,
Expand All @@ -113,6 +113,7 @@ impl TriptychProof {
/// You must also supply a [`CryptoRngCore`] random number generator `rng` and a [`Transcript`] `transcript`.
///
/// This function specifically avoids constant-time operations for efficiency.
#[cfg(feature = "hazmat")]
pub fn prove_with_rng_vartime<R: CryptoRngCore>(
witness: &TriptychWitness,
statement: &TriptychStatement,
Expand Down Expand Up @@ -1143,7 +1144,7 @@ mod test {
}

#[test]
#[cfg(feature = "rand")]
#[cfg(all(feature = "rand", feature = "hazmat"))]
#[allow(non_snake_case, non_upper_case_globals)]
fn test_prove_verify_vartime() {
// Generate data
Expand All @@ -1158,6 +1159,7 @@ mod test {
}

#[test]
#[cfg(feature = "hazmat")]
#[allow(non_snake_case, non_upper_case_globals)]
fn test_prove_verify_vartime_with_rng() {
// Generate data
Expand All @@ -1183,9 +1185,8 @@ mod test {
let (witnesses, statements, mut transcripts) = generate_data(n, m, 1, &mut rng);

// Generate and verify a proof
let proof =
TriptychProof::prove_with_rng_vartime(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0].clone())
.unwrap();
let proof = TriptychProof::prove_with_rng(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0].clone())
.unwrap();
assert!(proof.verify(&statements[0], &mut transcripts[0]).is_ok());

// Serialize the proof
Expand All @@ -1207,9 +1208,8 @@ mod test {
let (witnesses, statements, mut transcripts) = generate_data(n, m, 1, &mut rng);

// Generate and verify a proof
let proof =
TriptychProof::prove_with_rng_vartime(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0].clone())
.unwrap();
let proof = TriptychProof::prove_with_rng(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0].clone())
.unwrap();
assert!(proof.verify(&statements[0], &mut transcripts[0]).is_ok());

// Serialize the proof
Expand All @@ -1232,7 +1232,7 @@ mod test {

// Generate the proofs
let proofs = izip!(witnesses.iter(), statements.iter(), transcripts.clone().iter_mut())
.map(|(w, s, t)| TriptychProof::prove_with_rng_vartime(w, s, &mut rng, t).unwrap())
.map(|(w, s, t)| TriptychProof::prove_with_rng(w, s, &mut rng, t).unwrap())
.collect::<Vec<TriptychProof>>();

// Verify the batch with and without blame
Expand Down Expand Up @@ -1261,7 +1261,7 @@ mod test {

// Generate the proofs
let proofs = izip!(witnesses.iter(), statements.iter(), transcripts.clone().iter_mut())
.map(|(w, s, t)| TriptychProof::prove_with_rng_vartime(w, s, &mut rng, t).unwrap())
.map(|(w, s, t)| TriptychProof::prove_with_rng(w, s, &mut rng, t).unwrap())
.collect::<Vec<TriptychProof>>();

// Manipulate a transcript so the corresponding proof is invalid
Expand All @@ -1285,7 +1285,7 @@ mod test {

// Generate the proofs
let proofs = izip!(witnesses.iter(), statements.iter(), transcripts.clone().iter_mut())
.map(|(w, s, t)| TriptychProof::prove_with_rng_vartime(w, s, &mut rng, t).unwrap())
.map(|(w, s, t)| TriptychProof::prove_with_rng(w, s, &mut rng, t).unwrap())
.collect::<Vec<TriptychProof>>();

// Iteratively manipulate each transcript to make the corresponding proof invalid
Expand Down Expand Up @@ -1319,7 +1319,7 @@ mod test {

// Generate the proofs
let proofs = izip!(witnesses.iter(), statements.iter(), transcripts.clone().iter_mut())
.map(|(w, s, t)| TriptychProof::prove_with_rng_vartime(w, s, &mut rng, t).unwrap())
.map(|(w, s, t)| TriptychProof::prove_with_rng(w, s, &mut rng, t).unwrap())
.collect::<Vec<TriptychProof>>();

// Manipulate some of the transcripts to make the corresponding proofs invalid
Expand All @@ -1346,8 +1346,8 @@ mod test {
let (witnesses, statements, mut transcripts) = generate_data(n, m, 1, &mut rng);

// Generate a proof
let proof = TriptychProof::prove_with_rng_vartime(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0])
.unwrap();
let proof =
TriptychProof::prove_with_rng(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0]).unwrap();

// Generate a modified transcript
let mut evil_transcript = Transcript::new(b"Evil transcript");
Expand All @@ -1366,9 +1366,8 @@ mod test {
let (witnesses, statements, mut transcripts) = generate_data(n, m, 1, &mut rng);

// Generate a proof
let proof =
TriptychProof::prove_with_rng_vartime(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0].clone())
.unwrap();
let proof = TriptychProof::prove_with_rng(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0].clone())
.unwrap();

// Generate a statement with a modified input set
let mut M = statements[0].get_input_set().get_keys().to_vec();
Expand Down Expand Up @@ -1398,9 +1397,8 @@ mod test {
let (witnesses, statements, mut transcripts) = generate_data(n, m, 1, &mut rng);

// Generate a proof
let proof =
TriptychProof::prove_with_rng_vartime(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0].clone())
.unwrap();
let proof = TriptychProof::prove_with_rng(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0].clone())
.unwrap();

// Generate a statement with a modified input set
let M = statements[0].get_input_set().get_keys().to_vec();
Expand Down Expand Up @@ -1430,9 +1428,8 @@ mod test {
let (witnesses, statements, mut transcripts) = generate_data(n, m, 1, &mut rng);

// Generate a proof
let proof =
TriptychProof::prove_with_rng_vartime(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0].clone())
.unwrap();
let proof = TriptychProof::prove_with_rng(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0].clone())
.unwrap();

// Generate a statement with a modified linking tag
let evil_statement = TriptychStatement::new(
Expand All @@ -1457,9 +1454,8 @@ mod test {
let (witnesses, statements, mut transcripts) = generate_data(n, m, 1, &mut rng);

// Generate a proof
let proof =
TriptychProof::prove_with_rng_vartime(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0].clone())
.unwrap();
let proof = TriptychProof::prove_with_rng(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0].clone())
.unwrap();

// Generate a statement with a modified offset
let evil_statement = TriptychStatement::new(
Expand Down
38 changes: 18 additions & 20 deletions src/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ impl TriptychProof {
/// You must also supply a [`Transcript`] `transcript`.
///
/// This function specifically avoids constant-time operations for efficiency.
#[cfg(feature = "rand")]
#[cfg(all(feature = "rand", feature = "hazmat"))]
pub fn prove_vartime(
witness: &TriptychWitness,
statement: &TriptychStatement,
Expand All @@ -113,6 +113,7 @@ impl TriptychProof {
/// You must also supply a [`CryptoRngCore`] random number generator `rng` and a [`Transcript`] `transcript`.
///
/// This function specifically avoids constant-time operations for efficiency.
#[cfg(feature = "hazmat")]
pub fn prove_with_rng_vartime<R: CryptoRngCore>(
witness: &TriptychWitness,
statement: &TriptychStatement,
Expand Down Expand Up @@ -1051,7 +1052,7 @@ mod test {
}

#[test]
#[cfg(feature = "rand")]
#[cfg(all(feature = "rand", feature = "hazmat"))]
#[allow(non_snake_case, non_upper_case_globals)]
fn test_prove_verify_vartime() {
// Generate data
Expand All @@ -1066,6 +1067,7 @@ mod test {
}

#[test]
#[cfg(feature = "hazmat")]
#[allow(non_snake_case, non_upper_case_globals)]
fn test_prove_verify_vartime_with_rng() {
// Generate data
Expand All @@ -1091,9 +1093,8 @@ mod test {
let (witnesses, statements, mut transcripts) = generate_data(n, m, 1, &mut rng);

// Generate and verify a proof
let proof =
TriptychProof::prove_with_rng_vartime(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0].clone())
.unwrap();
let proof = TriptychProof::prove_with_rng(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0].clone())
.unwrap();
assert!(proof.verify(&statements[0], &mut transcripts[0]).is_ok());

// Serialize the proof
Expand All @@ -1115,9 +1116,8 @@ mod test {
let (witnesses, statements, mut transcripts) = generate_data(n, m, 1, &mut rng);

// Generate and verify a proof
let proof =
TriptychProof::prove_with_rng_vartime(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0].clone())
.unwrap();
let proof = TriptychProof::prove_with_rng(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0].clone())
.unwrap();
assert!(proof.verify(&statements[0], &mut transcripts[0]).is_ok());

// Serialize the proof
Expand All @@ -1140,7 +1140,7 @@ mod test {

// Generate the proofs
let proofs = izip!(witnesses.iter(), statements.iter(), transcripts.clone().iter_mut())
.map(|(w, s, t)| TriptychProof::prove_with_rng_vartime(w, s, &mut rng, t).unwrap())
.map(|(w, s, t)| TriptychProof::prove_with_rng(w, s, &mut rng, t).unwrap())
.collect::<Vec<TriptychProof>>();

// Verify the batch with and without blame
Expand Down Expand Up @@ -1169,7 +1169,7 @@ mod test {

// Generate the proofs
let proofs = izip!(witnesses.iter(), statements.iter(), transcripts.clone().iter_mut())
.map(|(w, s, t)| TriptychProof::prove_with_rng_vartime(w, s, &mut rng, t).unwrap())
.map(|(w, s, t)| TriptychProof::prove_with_rng(w, s, &mut rng, t).unwrap())
.collect::<Vec<TriptychProof>>();

// Manipulate a transcript so the corresponding proof is invalid
Expand All @@ -1193,7 +1193,7 @@ mod test {

// Generate the proofs
let proofs = izip!(witnesses.iter(), statements.iter(), transcripts.clone().iter_mut())
.map(|(w, s, t)| TriptychProof::prove_with_rng_vartime(w, s, &mut rng, t).unwrap())
.map(|(w, s, t)| TriptychProof::prove_with_rng(w, s, &mut rng, t).unwrap())
.collect::<Vec<TriptychProof>>();

// Iteratively manipulate each transcript to make the corresponding proof invalid
Expand Down Expand Up @@ -1227,7 +1227,7 @@ mod test {

// Generate the proofs
let proofs = izip!(witnesses.iter(), statements.iter(), transcripts.clone().iter_mut())
.map(|(w, s, t)| TriptychProof::prove_with_rng_vartime(w, s, &mut rng, t).unwrap())
.map(|(w, s, t)| TriptychProof::prove_with_rng(w, s, &mut rng, t).unwrap())
.collect::<Vec<TriptychProof>>();

// Manipulate some of the transcripts to make the corresponding proofs invalid
Expand All @@ -1254,8 +1254,8 @@ mod test {
let (witnesses, statements, mut transcripts) = generate_data(n, m, 1, &mut rng);

// Generate a proof
let proof = TriptychProof::prove_with_rng_vartime(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0])
.unwrap();
let proof =
TriptychProof::prove_with_rng(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0]).unwrap();

// Generate a modified transcript
let mut evil_transcript = Transcript::new(b"Evil transcript");
Expand All @@ -1274,9 +1274,8 @@ mod test {
let (witnesses, statements, mut transcripts) = generate_data(n, m, 1, &mut rng);

// Generate a proof
let proof =
TriptychProof::prove_with_rng_vartime(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0].clone())
.unwrap();
let proof = TriptychProof::prove_with_rng(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0].clone())
.unwrap();

// Generate a statement with a modified input set
let mut M = statements[0].get_input_set().get_keys().to_vec();
Expand All @@ -1300,9 +1299,8 @@ mod test {
let (witnesses, statements, mut transcripts) = generate_data(n, m, 1, &mut rng);

// Generate a proof
let proof =
TriptychProof::prove_with_rng_vartime(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0].clone())
.unwrap();
let proof = TriptychProof::prove_with_rng(&witnesses[0], &statements[0], &mut rng, &mut transcripts[0].clone())
.unwrap();

// Generate a statement with a modified linking tag
let evil_statement = TriptychStatement::new(
Expand Down
1 change: 1 addition & 0 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use zeroize::Zeroize;

/// Options for constant- or variable-time operations.
#[derive(Clone, Copy)]
#[allow(dead_code)]
pub(crate) enum OperationTiming {
/// The operation should attempt to run in constant time
Constant,
Expand Down

0 comments on commit 24e5a20

Please sign in to comment.