Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validity checks #38

Merged
merged 41 commits into from
Feb 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
08bac73
initial work on simple threshold decryption
piotr-roslaniec Nov 24, 2022
719b4a1
calculate lagrange using private context
piotr-roslaniec Dec 21, 2022
17cdb5b
calculate lagrange using public context
piotr-roslaniec Dec 21, 2022
8cb52d8
wip
piotr-roslaniec Dec 27, 2022
81d4dd2
incorrect length of decrypted shares after pvss combination
piotr-roslaniec Dec 28, 2022
9d38f62
initial removal of share partitioning
piotr-roslaniec Dec 29, 2022
9759860
updating scheme
piotr-roslaniec Dec 29, 2022
32f9c49
update aggregation
piotr-roslaniec Dec 29, 2022
57255f5
simple decryption with one validator works with ferveo dkg
piotr-roslaniec Dec 29, 2022
7cad9ae
fix clippy
piotr-roslaniec Dec 29, 2022
856790c
simple threshold decryption works
piotr-roslaniec Dec 30, 2022
364580e
remove dealer's lagrange coeffs calculation
piotr-roslaniec Dec 30, 2022
89ebffc
self code review
piotr-roslaniec Dec 30, 2022
44bd186
fix clippy after 1.66 update
piotr-roslaniec Dec 30, 2022
1d9f623
cargo fmt
piotr-roslaniec Dec 30, 2022
668184c
fix after rebase
piotr-roslaniec Jan 4, 2023
4f62c70
remove ValidatorSet
piotr-roslaniec Jan 5, 2023
995fdce
rename TendermintValidator to ExternalValidator
piotr-roslaniec Jan 5, 2023
fb05e62
remove unused code
piotr-roslaniec Jan 5, 2023
99d2b9c
fix rustfmt
piotr-roslaniec Jan 5, 2023
26fe690
fix after rebase
piotr-roslaniec Jan 18, 2023
8f7308b
documents and refactor code
piotr-roslaniec Jan 18, 2023
838d3d2
remove rebasing artifact
piotr-roslaniec Jan 18, 2023
b6c9189
refactor to a single share per validator
piotr-roslaniec Jan 19, 2023
a484971
enable key share blinding in fast tdec
piotr-roslaniec Jan 19, 2023
e99f43c
check ciphertext validity before creating a decryption share
piotr-roslaniec Jan 17, 2023
a0d9930
decryption share verification for fast variant
piotr-roslaniec Jan 17, 2023
c80a197
fix after rebase
piotr-roslaniec Jan 19, 2023
444ff80
fix formulas
piotr-roslaniec Jan 19, 2023
20445cd
implement simplified decryption share verification
piotr-roslaniec Jan 19, 2023
249c3c1
refactor share verification
piotr-roslaniec Jan 19, 2023
8e43ae4
add negative test case for verify_full
piotr-roslaniec Jan 20, 2023
da92818
update function docstring
piotr-roslaniec Jan 20, 2023
f0864ae
bench ciphertext validity check
piotr-roslaniec Jan 23, 2023
a21fb93
benchmark ciphertext validity check
piotr-roslaniec Jan 23, 2023
91fa243
disable arkworks benchmark
piotr-roslaniec Jan 23, 2023
534dce2
limit nr of benchmarks running on ci
piotr-roslaniec Jan 23, 2023
208d95c
Merge branch 'main' into validity-checks
piotr-roslaniec Jan 23, 2023
886ca60
add pvss verification benchmarks
piotr-roslaniec Jan 24, 2023
dd9e458
Merge branch 'main' into validity-checks
piotr-roslaniec Jan 30, 2023
1f76347
apply pr suggestions
piotr-roslaniec Feb 1, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 9 additions & 26 deletions .github/workflows/workspace.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,18 +104,20 @@ jobs:
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-

# - name: Run benchmarks
# uses: boa-dev/criterion-compare-action@v3
# if: github.event_name == 'pull_request'
# with:
# cwd: ${{ matrix.component }}
# branchName: ${{ github.base_ref }}
- name: Run benchmark for base branch comparison
uses: boa-dev/criterion-compare-action@v3
if: github.event_name == 'pull_request'
with:
cwd: ${{ matrix.component }}
branchName: ${{ github.base_ref }}

# The next steps have been adapted from https://raw.githubusercontent.com/unicode-org/icu4x/main/.github/workflows/build-test.yml

# Benchmarking & dashboards job > Run benchmark.

- name: Run benchmark
- name: Run benchmark for dashboard
# only merges to main (implies PR is finished and approved by this point)
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository == 'nucypher/ferveo'
run: |
pushd $PWD && cd ${{ matrix.component }};
export REL_OUTPUT_PATH="`dirs +1`/benchmarks/perf/${{ matrix.component }}";
Expand All @@ -136,25 +138,6 @@ jobs:
# # Push it to create a remote branch
# $ git push origin <newbranch>:<newbranch>

# Benchmarking & dashboards job > (unmerged PR only) Convert benchmark output into dashboard HTML in a commit of a branch of the local repo.

- name: Store benchmark result & create dashboard (unmerged PR only)
if: github.event_name == 'pull_request'
uses: rhysd/github-action-benchmark@v1
with:
name: Rust Benchmark
tool: 'cargo'
output-file-path: ./benchmarks/perf/${{ matrix.component }}/output.txt
benchmark-data-dir-path: ./benchmarks/perf/${{ matrix.component }}
# Show alert with commit comment on detecting possible performance regression
alert-threshold: '200%' # If for nothing else, enabling the possibility of alerts with meaningful thresholds requires this job to be done per-component
fail-on-alert: true
gh-pages-branch: unmerged-pr-bench-data # Requires one-time-only creation of this branch on remote repo.
auto-push: false # Do not store historical benchmark info of unfinished PRs. Commits seem to get made anyways, so make sure
# that the branch in `gh-pages-branch` is different from the branch used for merges to main branch.
github-token: ${{ secrets.GITHUB_TOKEN }}
comment-on-alert: true

# Benchmarking & dashboards job > (PR merge to main only) Convert benchmark output into dashboard HTML in a commit of a branch of the local repo.

- name: Store benchmark result & create dashboard (merge to main only)
Expand Down
10 changes: 8 additions & 2 deletions ferveo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,17 @@ pprof = { version = "0.6", features = ["flamegraph", "criterion"] }
name = "pvdkg"
path = "examples/pvdkg.rs"

#[[bench]]
#name = "pvdkg"
#path = "benches/benchmarks/pvdkg.rs"
#harness = false

[[bench]]
name = "pvdkg"
path = "benches/benchmarks/pvdkg.rs"
name = "benchmarks"
path = "benches/bench_main.rs"
harness = false


[profile.release]
opt-level = 3
lto = true
5 changes: 3 additions & 2 deletions ferveo/benches/bench_main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use criterion::criterion_main;
mod benchmarks;

criterion_main! {
benchmarks::pairing::micro,//bench_batch_inverse,
benchmarks::pairing::ec,
// benchmarks::pairing::micro,//bench_batch_inverse,
// benchmarks::pairing::ec,
benchmarks::validity_checks::validity_checks,
}
3 changes: 2 additions & 1 deletion ferveo/benches/benchmarks/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
//pub mod block_proposer;
pub mod pairing;
// pub mod pairing;
pub mod validity_checks;
109 changes: 109 additions & 0 deletions ferveo/benches/benchmarks/validity_checks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#![allow(clippy::redundant_closure)]
#![allow(clippy::unit_arg)]

use ark_bls12_381::Bls12_381;
pub use ark_bls12_381::Bls12_381 as EllipticCurve;
use criterion::{black_box, criterion_group, BenchmarkId, Criterion};
use digest::crypto_common::rand_core::SeedableRng;
use ferveo::*;
use ferveo_common::ExternalValidator;
use rand::prelude::StdRng;

const NUM_SHARES_CASES: [usize; 5] = [4, 8, 16, 32, 64];

// TODO: Can we expose ferveo test methods to reuse `setup_dkg` et al instead of reimplementing it here?

fn gen_keypairs(num: u32) -> Vec<ferveo_common::Keypair<EllipticCurve>> {
let rng = &mut ark_std::test_rng();
(0..num)
.map(|_| ferveo_common::Keypair::<EllipticCurve>::new(rng))
.collect()
}

fn gen_validators(
keypairs: &[ferveo_common::Keypair<EllipticCurve>],
) -> Vec<ExternalValidator<EllipticCurve>> {
(0..keypairs.len())
.map(|i| ExternalValidator {
address: format!("validator_{}", i),
public_key: keypairs[i].public(),
})
.collect()
}

fn setup_dkg(
validator: usize,
shares_num: u32,
) -> PubliclyVerifiableDkg<EllipticCurve> {
let keypairs = gen_keypairs(shares_num);
let validators = gen_validators(&keypairs);
let me = validators[validator].clone();
PubliclyVerifiableDkg::new(
validators,
Params {
tau: 0,
security_threshold: shares_num / 3,
shares_num,
retry_after: 1,
},
&me,
keypairs[validator],
)
.expect("Setup failed")
}

fn setup(
shares_num: u32,
rng: &mut StdRng,
) -> (PubliclyVerifiableDkg<Bls12_381>, Message<Bls12_381>) {
let mut transcripts = vec![];
for i in 0..shares_num {
let mut dkg = setup_dkg(i as usize, shares_num);
transcripts.push(dkg.share(rng).expect("Test failed"));
}
let dkg = setup_dkg(0, shares_num);
let transcript = transcripts[0].clone();
(dkg, transcript)
}

pub fn bench_verify_full(c: &mut Criterion) {
let mut group = c.benchmark_group("PVSS VALIDITY CHECKS");
group.sample_size(10);

let rng = &mut StdRng::seed_from_u64(0);

for shares_num in NUM_SHARES_CASES {
let (dkg, transcript) = setup(shares_num as u32, rng);
let transcript = &transcript;

let pvss_verify_optimistic = {
move || {
if let Message::Deal(ss) = transcript {
black_box(ss.verify_optimistic());
} else {
panic!("Expected Deal");
}
}
};
let pvss_verify_full = {
move || {
if let Message::Deal(ss) = transcript {
black_box(ss.verify_full(&dkg));
} else {
panic!("Expected Deal");
}
}
};

group.bench_function(
BenchmarkId::new("pvss_verify_optimistic", shares_num),
|b| b.iter(|| pvss_verify_optimistic()),
);
group.bench_function(
BenchmarkId::new("pvss_verify_full", shares_num),
|b| b.iter(|| pvss_verify_full()),
);
}
}

criterion_group!(validity_checks, bench_verify_full);
2 changes: 2 additions & 0 deletions ferveo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ mod test_dkg_full {
let plaintext = tpke::checked_decrypt_with_shared_secret(
&ciphertext,
aad,
&dkg.pvss_params.g_inv(),
&shared_secret,
)
.unwrap();
Expand Down Expand Up @@ -130,6 +131,7 @@ mod test_dkg_full {
let plaintext = tpke::checked_decrypt_with_shared_secret(
&ciphertext,
aad,
&dkg.pvss_params.g_inv(),
&shared_secret,
)
.unwrap();
Expand Down
57 changes: 43 additions & 14 deletions ferveo/src/vss/pvss.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ pub struct PubliclyVerifiableParams<E: PairingEngine> {
pub h: E::G2Projective,
}

impl<E: PairingEngine> PubliclyVerifiableParams<E> {
pub fn g_inv(&self) -> E::G1Prepared {
E::G1Prepared::from(-self.g.into_affine())
}
}

/// Each validator posts a transcript to the chain. Once enough
/// validators have done this (their total voting power exceeds
/// 2/3 the total), this will be aggregated into a final key
Expand Down Expand Up @@ -128,6 +134,8 @@ impl<E: PairingEngine, T> PubliclyVerifiableSS<E, T> {

/// Part of checking the validity of an aggregated PVSS transcript
///
/// Implements check #4 in 4.2.3 section of https://eprint.iacr.org/2022/898.pdf
///
/// If aggregation fails, a validator needs to know that their pvss
/// transcript was at fault so that the can issue a new one. This
/// function may also be used for that purpose.
Expand All @@ -138,26 +146,25 @@ impl<E: PairingEngine, T> PubliclyVerifiableSS<E, T> {
dkg.domain.fft_in_place(&mut commitment);

// Each validator checks that their share is correct
dkg.validators.iter().zip(self.shares.iter()).all(
|(validator, share)| {
// ek is the public key of the validator
// TODO: Is that the ek = [dk]H key?
let ek = validator
dkg.validators
.iter()
.zip(self.shares.iter())
.all(|(validator, y_i)| {
// TODO: Check #3 is missing
// See #3 in 4.2.3 section of https://eprint.iacr.org/2022/898.pdf

// Validator checks checks aggregated shares against commitment
let ek_i = validator
.validator
.public_key
.encryption_key
.into_projective();
// Validator checks checks aggregated shares against commitment
// TODO: Check #3 is missing
// See #3 in 4.2.3 section of https://eprint.iacr.org/2022/898.pdf
let y = *share;
let a = commitment[validator.share_index];
// We verify that e(G, Y_j) = e(A_j, ek_j) for all j
let a_i = commitment[validator.share_index];
// We verify that e(G, Y_i) = e(A_i, ek_i) for validator i
// See #4 in 4.2.3 section of https://eprint.iacr.org/2022/898.pdf
// e(G,Y) = e(A, ek)
E::pairing(dkg.pvss_params.g, y) == E::pairing(a, ek)
},
)
E::pairing(dkg.pvss_params.g, *y_i) == E::pairing(a_i, ek_i)
})
}
}

Expand Down Expand Up @@ -335,6 +342,28 @@ mod test_pvss {
assert!(!pvss.verify_optimistic());
}

/// Check that if PVSS shares are tampered with, the full verification fails
#[test]
fn test_verify_pvss_bad_shares() {
let rng = &mut ark_std::test_rng();
let dkg = setup_dkg(0);
let s = Fr::rand(rng);
let pvss = Pvss::<EllipticCurve>::new(&s, &dkg, rng).unwrap();

// So far, everything works
assert!(pvss.verify_optimistic());
assert!(pvss.verify_full(&dkg));

// Now, we're going to tamper with the PVSS shares
let mut bad_pvss = pvss;
bad_pvss.shares[0] = G2::zero();

// Optimistic verification should not catch this issue
assert!(bad_pvss.verify_optimistic());
// Full verification should catch this issue
assert!(!bad_pvss.verify_full(&dkg));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice test

}

/// Check that happy flow of aggregating PVSS transcripts
/// Should have the correct form and validations pass
#[test]
Expand Down
2 changes: 1 addition & 1 deletion tpke-wasm/benches/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub fn bench_encrypt_combine(c: &mut Criterion) {
for share in decryption_shares {
ss_builder.add_decryption_share(&share);
}
ss_builder.build();
ss_builder.build(&ciphertext);
})
}
}
Expand Down
Loading