Browse Source

Test nullifiers in constant time

Checking for spent notes in a block is still not completely constant
time, due to filtering out negative results of the constant-time
comparison.

Part of #84.
master
Jack Grigg 5 years ago
parent
commit
2bafc688ff
No known key found for this signature in database
GPG Key ID: 9E8255172BBF9898
  1. 7
      Cargo.lock
  2. 1
      zcash_client_backend/Cargo.toml
  3. 46
      zcash_client_backend/src/welding_rig.rs

7
Cargo.lock generated

@ -493,6 +493,11 @@ dependencies = [
"opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "subtle"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "syn" name = "syn"
version = "0.14.9" version = "0.14.9"
@ -545,6 +550,7 @@ dependencies = [
"rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_os 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_os 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"subtle 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"zcash_primitives 0.0.0", "zcash_primitives 0.0.0",
] ]
@ -642,6 +648,7 @@ dependencies = [
"checksum rand_os 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ddb525a78d3a0b0e05b6fe0f7df14d7a4dc957944c7b403911ba5a0f1c694967" "checksum rand_os 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ddb525a78d3a0b0e05b6fe0f7df14d7a4dc957944c7b403911ba5a0f1c694967"
"checksum rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" "checksum rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8"
"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d"
"checksum subtle 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "01f40907d9ffc762709e4ff3eb4a6f6b41b650375a3f09ac92b641942b7fb082"
"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"

1
zcash_client_backend/Cargo.toml

@ -12,6 +12,7 @@ ff = { path = "../ff" }
hex = "0.3" hex = "0.3"
pairing = { path = "../pairing" } pairing = { path = "../pairing" }
protobuf = "2" protobuf = "2"
subtle = "2"
zcash_primitives = { path = "../zcash_primitives" } zcash_primitives = { path = "../zcash_primitives" }
[build-dependencies] [build-dependencies]

46
zcash_client_backend/src/welding_rig.rs

@ -3,6 +3,7 @@
use ff::{PrimeField, PrimeFieldRepr}; use ff::{PrimeField, PrimeFieldRepr};
use pairing::bls12_381::{Bls12, Fr, FrRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr};
use std::collections::HashSet; use std::collections::HashSet;
use subtle::{ConditionallySelectable, ConstantTimeEq, CtOption};
use zcash_primitives::{ use zcash_primitives::{
jubjub::{edwards, fs::Fs}, jubjub::{edwards, fs::Fs},
merkle_tree::{CommitmentTree, IncrementalWitness}, merkle_tree::{CommitmentTree, IncrementalWitness},
@ -116,28 +117,29 @@ pub fn scan_block(
let num_outputs = tx.outputs.len(); let num_outputs = tx.outputs.len();
// Check for spent notes // Check for spent notes
let shielded_spends: Vec<_> = // The only step that is not constant-time is the filter() at the end.
tx.spends let shielded_spends: Vec<_> = tx
.into_iter() .spends
.enumerate() .into_iter()
.filter_map(|(index, spend)| { .enumerate()
if let Some(account) = nullifiers.iter().find_map(|&(nf, acc)| { .map(|(index, spend)| {
if nf == &spend.nf[..] { // Find the first tracked nullifier that matches this spend, and produce
Some(acc) // a WalletShieldedSpend if there is a match, in constant time.
} else { nullifiers
None .iter()
} .map(|&(nf, account)| CtOption::new(account as u64, nf.ct_eq(&spend.nf[..])))
}) { .fold(CtOption::new(0, 0.into()), |first, next| {
Some(WalletShieldedSpend { CtOption::conditional_select(&next, &first, first.is_some())
index, })
nf: spend.nf, .map(|account| WalletShieldedSpend {
account, index,
}) nf: spend.nf,
} else { account: account as usize,
None })
} })
}) .filter(|spend| spend.is_some().into())
.collect(); .map(|spend| spend.unwrap())
.collect();
// Collect the set of accounts that were spent from in this transaction // Collect the set of accounts that were spent from in this transaction
let spent_from_accounts: HashSet<_> = let spent_from_accounts: HashSet<_> =

Loading…
Cancel
Save