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

Remove the fast variant #187

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
157 changes: 3 additions & 154 deletions ferveo-tdec/benches/tpke.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
#![allow(clippy::redundant_closure)]

use ark_bls12_381::{Bls12_381, Fr};
use ark_ec::pairing::Pairing;
use criterion::{
black_box, criterion_group, criterion_main, BenchmarkId, Criterion,
};
use ferveo_tdec::{
test_common::{setup_fast, setup_simple},
*,
};
use ferveo_tdec::{test_common::setup_simple, *};
use rand::prelude::StdRng;
use rand_core::{RngCore, SeedableRng};

const NUM_SHARES_CASES: [usize; 5] = [4, 8, 16, 32, 64];
const MSG_SIZE_CASES: [usize; 7] = [256, 512, 1024, 2048, 4096, 8192, 16384];

type E = Bls12_381;
type G2Prepared = <E as Pairing>::G2Prepared;

#[allow(dead_code)]
#[derive(Clone)]
Expand All @@ -31,63 +26,6 @@ struct SetupShared {
shared_secret: SharedSecret<E>,
}

#[derive(Clone)]
struct SetupFast {
shared: SetupShared,
contexts: Vec<PrivateDecryptionContextFast<E>>,
pub_contexts: Vec<PublicDecryptionContextFast<E>>,
decryption_shares: Vec<DecryptionShareFast<E>>,
prepared_key_shares: Vec<G2Prepared>,
}

impl SetupFast {
pub fn new(shares_num: usize, msg_size: usize, rng: &mut StdRng) -> Self {
let threshold = shares_num * 2 / 3;
let mut msg: Vec<u8> = vec![0u8; msg_size];
rng.fill_bytes(&mut msg[..]);
let aad: &[u8] = "my-aad".as_bytes();

let (pubkey, privkey, contexts) =
setup_fast::<E>(threshold, shares_num, rng);
let ciphertext =
encrypt::<E>(SecretBox::new(msg.clone()), aad, &pubkey, rng)
.unwrap();

let mut decryption_shares: Vec<DecryptionShareFast<E>> = vec![];
for context in contexts.iter() {
decryption_shares
.push(context.create_share(&ciphertext, aad).unwrap());
}

let pub_contexts = contexts[0].clone().public_decryption_contexts;
let prepared_key_shares =
prepare_combine_fast(&pub_contexts, &decryption_shares);

let shared_secret = share_combine_fast_unchecked(
&decryption_shares,
&prepared_key_shares,
);

let shared = SetupShared {
threshold,
shares_num,
msg: msg.to_vec(),
aad: aad.to_vec(),
pubkey,
privkey,
ciphertext,
shared_secret,
};
Self {
shared,
contexts,
pub_contexts,
decryption_shares,
prepared_key_shares,
}
}
}

#[derive(Clone)]
struct SetupSimple {
shared: SetupShared,
Expand Down Expand Up @@ -158,25 +96,6 @@ pub fn bench_create_decryption_share(c: &mut Criterion) {
let msg_size = MSG_SIZE_CASES[0];

for shares_num in NUM_SHARES_CASES {
let fast = {
let setup = SetupFast::new(shares_num, msg_size, rng);
move || {
black_box({
// TODO: Consider running benchmarks for a single iteration and not for all iterations.
// This way we could test the performance of this method for a single participant.
setup
.contexts
.iter()
.map(|ctx| {
ctx.create_share(
&setup.shared.ciphertext,
&setup.shared.aad,
)
})
.collect::<Vec<_>>()
})
}
};
let simple = {
let setup = SetupSimple::new(shares_num, msg_size, rng);
move || {
Expand Down Expand Up @@ -218,11 +137,6 @@ pub fn bench_create_decryption_share(c: &mut Criterion) {
);
}
};

group.bench_function(
BenchmarkId::new("share_create_fast", shares_num),
|b| b.iter(|| fast()),
);
group.bench_function(
BenchmarkId::new("share_create_simple", shares_num),
|b| b.iter(|| simple()),
Expand All @@ -242,26 +156,12 @@ pub fn bench_share_prepare(c: &mut Criterion) {
let msg_size = MSG_SIZE_CASES[0];

for shares_num in NUM_SHARES_CASES {
let fast = {
let setup = SetupFast::new(shares_num, msg_size, rng);
move || {
black_box(prepare_combine_fast(
&setup.pub_contexts,
&setup.decryption_shares,
))
}
};
let simple = {
let setup = SetupSimple::new(shares_num, msg_size, rng);
let domain: Vec<Fr> =
setup.pub_contexts.iter().map(|c| c.domain).collect();
move || black_box(prepare_combine_simple::<E>(&domain))
};

group.bench_function(
BenchmarkId::new("share_prepare_fast", shares_num),
|b| b.iter(|| fast()),
);
group.bench_function(
BenchmarkId::new("share_prepare_simple", shares_num),
|b| b.iter(|| simple()),
Expand All @@ -278,15 +178,6 @@ pub fn bench_share_combine(c: &mut Criterion) {
let msg_size = MSG_SIZE_CASES[0];

for shares_num in NUM_SHARES_CASES {
let fast = {
let setup = SetupFast::new(shares_num, msg_size, rng);
move || {
black_box(share_combine_fast_unchecked(
&setup.decryption_shares,
&setup.prepared_key_shares,
));
}
};
let simple = {
let setup = SetupSimple::new(shares_num, msg_size, rng);
move || {
Expand Down Expand Up @@ -320,10 +211,6 @@ pub fn bench_share_combine(c: &mut Criterion) {
}
};

group.bench_function(
BenchmarkId::new("share_combine_fast", shares_num),
|b| b.iter(|| fast()),
);
group.bench_function(
BenchmarkId::new("share_combine_simple", shares_num),
|b| b.iter(|| simple()),
Expand All @@ -345,7 +232,7 @@ pub fn bench_share_encrypt_decrypt(c: &mut Criterion) {
for msg_size in MSG_SIZE_CASES {
let mut encrypt = {
let mut rng = rng.clone();
let setup = SetupFast::new(shares_num, msg_size, &mut rng);
let setup = SetupSimple::new(shares_num, msg_size, &mut rng);
move || {
let setup = setup.clone();
black_box(
Expand Down Expand Up @@ -393,7 +280,7 @@ pub fn bench_ciphertext_validity_checks(c: &mut Criterion) {
for msg_size in MSG_SIZE_CASES {
let ciphertext_verification = {
let mut rng = rng.clone();
let setup = SetupFast::new(shares_num, msg_size, &mut rng);
let setup = SetupSimple::new(shares_num, msg_size, &mut rng);
move || {
black_box(setup.shared.ciphertext.check(
&setup.shared.aad,
Expand All @@ -417,44 +304,6 @@ pub fn bench_decryption_share_validity_checks(c: &mut Criterion) {
let msg_size = MSG_SIZE_CASES[0];

for shares_num in NUM_SHARES_CASES {
let share_fast_verification = {
let mut rng = rng.clone();
let setup = SetupFast::new(shares_num, msg_size, &mut rng);
move || {
black_box(verify_decryption_shares_fast(
&setup.pub_contexts,
&setup.shared.ciphertext,
&setup.decryption_shares,
))
}
};
group.bench_function(
BenchmarkId::new("share_fast_verification", shares_num),
|b| b.iter(|| share_fast_verification()),
);

let mut share_fast_batch_verification = {
let mut rng = rng.clone();
let setup = SetupFast::new(shares_num, msg_size, &mut rng);
// We need to repackage a bunch of variables here to avoid borrowing issues:
let ciphertext = setup.shared.ciphertext.clone();
let ciphertexts = vec![ciphertext];
let decryption_shares = setup.decryption_shares.clone();
let decryption_shares = vec![decryption_shares];
move || {
black_box(batch_verify_decryption_shares(
&setup.pub_contexts,
&ciphertexts,
&decryption_shares,
&mut rng,
))
}
};
group.bench_function(
BenchmarkId::new("share_fast_batch_verification", shares_num),
|b| b.iter(|| share_fast_batch_verification()),
);

let share_simple_verification = {
let mut rng = rng.clone();
let setup = SetupSimple::new(shares_num, msg_size, &mut rng);
Expand Down
5 changes: 3 additions & 2 deletions ferveo-tdec/src/ciphertext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ mod tests {
let aad: &[u8] = "my-aad".as_bytes();

let (pubkey, privkey, contexts) =
setup_fast::<E>(threshold, shares_num, rng);
setup_simple::<E>(threshold, shares_num, rng);
let g_inv = &contexts[0].setup_params.g_inv;

let ciphertext =
Expand All @@ -285,7 +285,8 @@ mod tests {
let threshold = shares_num * 2 / 3;
let msg = "my-msg".as_bytes().to_vec();
let aad: &[u8] = "my-aad".as_bytes();
let (pubkey, _, contexts) = setup_fast::<E>(threshold, shares_num, rng);
let (pubkey, _, contexts) =
setup_simple::<E>(threshold, shares_num, rng);
let g_inv = contexts[0].setup_params.g_inv.clone();
let mut ciphertext =
encrypt::<E>(SecretBox::new(msg), aad, &pubkey, rng).unwrap();
Expand Down
87 changes: 2 additions & 85 deletions ferveo-tdec/src/combine.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
#![allow(non_snake_case)]

use std::ops::Mul;

use ark_ec::{pairing::Pairing, CurveGroup};
use ark_ec::pairing::Pairing;
use ark_ff::{Field, One, PrimeField, Zero};
use ferveo_common::serialization;
use itertools::izip;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use subproductdomain::SubproductDomain;
use zeroize::{Zeroize, ZeroizeOnDrop};

#[serde_as]
Expand All @@ -19,42 +16,7 @@ pub struct SharedSecret<E: Pairing>(
#[serde_as(as = "serialization::SerdeAs")] pub(crate) E::TargetField,
);

use crate::{
verify_decryption_shares_fast, Ciphertext, DecryptionShareFast,
DecryptionSharePrecomputed, DecryptionShareSimple, Error,
PublicDecryptionContextFast, Result,
};

pub fn prepare_combine_fast<E: Pairing>(
public_decryption_contexts: &[PublicDecryptionContextFast<E>],
shares: &[DecryptionShareFast<E>],
) -> Vec<E::G2Prepared> {
let mut domain = vec![]; // omega_i, vector of domain points
let mut n_0 = E::ScalarField::one();
for d_i in shares.iter() {
domain.push(public_decryption_contexts[d_i.decrypter_index].domain);
// n_0_i = 1 * t^1 * t^2 ...
n_0 *= public_decryption_contexts[d_i.decrypter_index].lagrange_n_0;
}
let s = SubproductDomain::<E::ScalarField>::new(domain);
let mut lagrange = s.inverse_lagrange_coefficients(); // 1/L_i

// Given a vector of field elements {v_i}, compute the vector {coeff * v_i^(-1)}
ark_ff::batch_inversion_and_mul(&mut lagrange, &n_0); // n_0 * L_i

// L_i * [b]Z_i
izip!(shares.iter(), lagrange.iter())
.map(|(d_i, lambda)| {
let decrypter = &public_decryption_contexts[d_i.decrypter_index];
let blinded_key_share =
decrypter.blinded_key_share.blinded_key_share;
E::G2Prepared::from(
// [b]Z_i * L_i
blinded_key_share.mul(*lambda).into_affine(),
)
})
.collect::<Vec<_>>()
}
use crate::{DecryptionSharePrecomputed, DecryptionShareSimple};

pub fn prepare_combine_simple<E: Pairing>(
domain: &[E::ScalarField],
Expand Down Expand Up @@ -82,51 +44,6 @@ pub fn lagrange_basis_at<E: Pairing>(
lagrange_coeffs
}

// TODO: Hide this from external users. Currently blocked by usage in benchmarks.
pub fn share_combine_fast_unchecked<E: Pairing>(
shares: &[DecryptionShareFast<E>],
prepared_key_shares: &[E::G2Prepared],
) -> SharedSecret<E> {
let mut pairing_a = vec![];
let mut pairing_b = vec![];

for (d_i, prepared_key_share) in izip!(shares, prepared_key_shares.iter()) {
pairing_a.push(
// D_i
E::G1Prepared::from(d_i.decryption_share),
);
pairing_b.push(
// Z_{i,omega_i}) = [dk_{i}^{-1}]*\hat{Y}_{i_omega_j}]
// Reference: https://nikkolasg.github.io/ferveo/pvss.html#validator-decryption-of-private-key-shares
// Prepared key share is a sum of L_i * [b]Z_i
prepared_key_share.clone(),
);
}
// e(D_i, [b*omega_i^-1] Z_{i,omega_i})
let shared_secret = E::multi_pairing(pairing_a, pairing_b).0;
SharedSecret(shared_secret)
}

pub fn share_combine_fast<E: Pairing>(
pub_contexts: &[PublicDecryptionContextFast<E>],
ciphertext: &Ciphertext<E>,
decryption_shares: &[DecryptionShareFast<E>],
prepared_key_shares: &[E::G2Prepared],
) -> Result<SharedSecret<E>> {
let is_valid_shares = verify_decryption_shares_fast(
pub_contexts,
ciphertext,
decryption_shares,
);
if !is_valid_shares {
return Err(Error::DecryptionShareVerificationFailed);
}
Ok(share_combine_fast_unchecked(
decryption_shares,
prepared_key_shares,
))
}

pub fn share_combine_simple<E: Pairing>(
decryption_shares: &[DecryptionShareSimple<E>],
lagrange_coeffs: &[E::ScalarField],
Expand Down
Loading
Loading