Add benchmark for note decryption

This commit is contained in:
Jack Grigg 2021-08-06 01:03:03 +01:00
parent 2283310236
commit cad3c8a1b8
2 changed files with 110 additions and 0 deletions

View File

@ -60,6 +60,10 @@ bench = false
dev-graph = ["halo2/dev-graph", "plotters"]
test-dependencies = ["proptest"]
[[bench]]
name = "note_decryption"
harness = false
[[bench]]
name = "small"
harness = false

106
benches/note_decryption.rs Normal file
View File

@ -0,0 +1,106 @@
use criterion::{criterion_group, criterion_main, Criterion, Throughput};
use orchard::{
builder::Builder,
bundle::Flags,
circuit::ProvingKey,
keys::{FullViewingKey, IncomingViewingKey, SpendingKey},
note_encryption::{CompactAction, OrchardDomain},
value::NoteValue,
Anchor, Bundle,
};
use rand::rngs::OsRng;
use zcash_note_encryption::{try_compact_note_decryption, try_note_decryption};
#[cfg(unix)]
use pprof::criterion::{Output, PProfProfiler};
fn bench_note_decryption(c: &mut Criterion) {
let rng = OsRng;
let pk = ProvingKey::build();
let fvk = FullViewingKey::from(&SpendingKey::from_bytes([7; 32]).unwrap());
let valid_ivk = IncomingViewingKey::from(&fvk);
let recipient = fvk.default_address();
// Compact actions don't have the full AEAD ciphertext, so ZIP 307 trial-decryption
// relies on an invalid ivk resulting in random noise for which the note commitment
// is invalid. However, in practice we still get early rejection:
// - The version byte will be invalid in 255/256 instances.
// - If the version byte is valid, one of either the note commitment check or the esk
// check will be invalid, saving us at least one scalar mul.
//
// Our fixed (action, invalid ivk) tuple will always fall into a specific rejection
// case. In order to reflect the real behaviour in the benchmarks, we trial-decrypt
// with 1000 invalid ivks (each of which will result in a different uniformly-random
// plaintext); this is equivalent to trial-decrypting 1000 different actions with the
// same ivk, but is faster to set up.
let invalid_ivks: Vec<_> = (0u32..1000)
.map(|i| {
let mut sk = [0; 32];
sk[..4].copy_from_slice(&i.to_le_bytes());
IncomingViewingKey::from(&FullViewingKey::from(&SpendingKey::from_bytes(sk).unwrap()))
})
.collect();
let bundle = {
let mut builder = Builder::new(
Flags::from_parts(true, true),
Anchor::from_bytes([0; 32]).unwrap(),
);
builder
.add_recipient(None, recipient, NoteValue::from_raw(10), None)
.unwrap();
let bundle: Bundle<_, i64> = builder.build(rng).unwrap();
bundle
.create_proof(&pk)
.unwrap()
.apply_signatures(rng, [0; 32], &[])
.unwrap()
};
let action = bundle.actions().first();
let domain = OrchardDomain::for_action(action);
let compact = {
let mut group = c.benchmark_group("note-decryption");
group.bench_function("valid", |b| {
b.iter(|| try_note_decryption(&domain, &valid_ivk, action).unwrap())
});
// Non-compact actions will always early-reject at the same point: AEAD decryption.
group.bench_function("invalid", |b| {
b.iter(|| try_note_decryption(&domain, &invalid_ivks[0], action))
});
let compact = CompactAction::from(action);
group.bench_function("compact-valid", |b| {
b.iter(|| try_compact_note_decryption(&domain, &valid_ivk, &compact).unwrap())
});
compact
};
{
let mut group = c.benchmark_group("compact-note-decryption");
group.throughput(Throughput::Elements(invalid_ivks.len() as u64));
group.bench_function("invalid", |b| {
b.iter(|| {
for ivk in &invalid_ivks {
try_compact_note_decryption(&domain, ivk, &compact);
}
})
});
}
}
#[cfg(unix)]
criterion_group! {
name = benches;
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
targets = bench_note_decryption
}
#[cfg(not(unix))]
criterion_group!(benches, bench_note_decryption);
criterion_main!(benches);