summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openpgp/benches/merge_cert.rs20
-rw-r--r--openpgp/benches/run_benchmarks.rs5
-rw-r--r--openpgp/src/cert.rs79
3 files changed, 73 insertions, 31 deletions
diff --git a/openpgp/benches/merge_cert.rs b/openpgp/benches/merge_cert.rs
new file mode 100644
index 00000000..a628e60a
--- /dev/null
+++ b/openpgp/benches/merge_cert.rs
@@ -0,0 +1,20 @@
+use criterion::{
+ criterion_group, Criterion,
+};
+
+use sequoia_openpgp as openpgp;
+use openpgp::cert::Cert;
+use openpgp::parse::Parse;
+
+/// Benchmark merging a typical cert with itself.
+fn bench_merge_certs(c: &mut Criterion) {
+ let mut group = c.benchmark_group("merge cert with itself");
+ let neal = Cert::from_bytes(include_bytes!("../tests/data/keys/neal.pgp"))
+ .unwrap();
+ group.bench_function("neal.pgp", |b| b.iter(|| {
+ neal.clone().merge_public(neal.clone()).unwrap();
+ }));
+ group.finish();
+}
+
+criterion_group!(benches, bench_merge_certs);
diff --git a/openpgp/benches/run_benchmarks.rs b/openpgp/benches/run_benchmarks.rs
index fc872af7..f5210747 100644
--- a/openpgp/benches/run_benchmarks.rs
+++ b/openpgp/benches/run_benchmarks.rs
@@ -18,6 +18,8 @@ mod generate_cert;
use generate_cert::benches as generate_cert;
mod parse_cert;
use parse_cert::benches as parse_cert;
+mod merge_cert;
+use merge_cert::benches as merge_cert;
// Add all benchmark functions here
criterion_main!(
@@ -28,5 +30,6 @@ criterion_main!(
encrypt,
decrypt,
generate_cert,
- parse_cert
+ parse_cert,
+ merge_cert,
);
diff --git a/openpgp/src/cert.rs b/openpgp/src/cert.rs
index adb201f9..64b16bf7 100644
--- a/openpgp/src/cert.rs
+++ b/openpgp/src/cert.rs
@@ -1461,12 +1461,52 @@ impl Cert {
self.into()
}
+ /// Sorts and deduplicates all components and all signatures of
+ /// all components.
+ fn sort_and_dedup(&mut self) {
+ self.primary.sort_and_dedup();
+
+ self.bad.sort_by(Signature::normalized_cmp);
+ self.bad.dedup_by(|a, b| a.normalized_eq(b));
+ // Order bad signatures so that the most recent one comes
+ // first.
+ self.bad.sort_by(sig_cmp);
+
+ self.userids.sort_and_dedup(UserID::cmp, |_, _| {});
+ self.user_attributes.sort_and_dedup(UserAttribute::cmp, |_, _| {});
+ // XXX: If we have two keys with the same public parts and
+ // different non-empty secret parts, then one will be dropped
+ // (non-deterministicly)!
+ //
+ // This can happen if:
+ //
+ // - One is corrupted
+ // - There are two versions that are encrypted differently
+ self.subkeys.sort_and_dedup(Key::public_cmp,
+ |a, b| {
+ // Recall: if a and b are equal, a will be dropped.
+ if ! b.has_secret() && a.has_secret() {
+ std::mem::swap(a, b);
+ }
+ });
+
+ self.unknowns.sort_and_dedup(Unknown::best_effort_cmp, |_, _| {});
+ }
+
fn canonicalize(mut self) -> Self {
tracer!(TRACE, "canonicalize", 0);
- // The very first thing that we do is verify the
- // self signatures. There are a few things that we need to be
- // aware of:
+ // Before we do anything, we'll order and deduplicate the
+ // components. If two components are the same, they will be
+ // merged, and their signatures will also be deduplicated.
+ // This improves the performance considerably when we update a
+ // certificate, because the certificates will be most likely
+ // almost identical, and we avoid about half of the signature
+ // verifications.
+ self.sort_and_dedup();
+
+ // Now we verify the self signatures. There are a few things
+ // that we need to be aware of:
//
// - Signatures may be invalid. These should be dropped.
//
@@ -1968,38 +2008,17 @@ impl Cert {
self.keyid(), self.bad.len());
}
- self.primary.sort_and_dedup();
-
- self.bad.sort_by(Signature::normalized_cmp);
- self.bad.dedup_by(|a, b| a.normalized_eq(b));
- // Order bad signatures so that the most recent one comes
- // first.
- self.bad.sort_by(sig_cmp);
-
- self.userids.sort_and_dedup(UserID::cmp, |_, _| {});
- self.user_attributes.sort_and_dedup(UserAttribute::cmp, |_, _| {});
- // XXX: If we have two keys with the same public parts and
- // different non-empty secret parts, then one will be dropped
- // (non-deterministicly)!
- //
- // This can happen if:
- //
- // - One is corrupted
- // - There are two versions that are encrypted differently
- self.subkeys.sort_and_dedup(Key::public_cmp,
- |a, b| {
- // Recall: if a and b are equal, a will be dropped.
- if ! b.has_secret() && a.has_secret() {
- std::mem::swap(a, b);
- }
- });
-
+ // Split signatures on unknown components.
let primary_fp: KeyHandle = self.key_handle();
let primary_keyid = KeyHandle::KeyID(primary_fp.clone().into());
for c in self.unknowns.iter_mut() {
parser::split_sigs(&primary_fp, &primary_keyid, c);
}
- self.unknowns.sort_and_dedup(Unknown::best_effort_cmp, |_, _| {});
+
+ // Sort again. We may have moved signatures to the right
+ // component, and we need to ensure they are in the right spot
+ // (i.e. newest first).
+ self.sort_and_dedup();
// XXX: Check if the sigs in other_sigs issuer are actually
// designated revokers for this key (listed in a "Revocation