Skip to content

Commit

Permalink
feature!: remove fast variant
Browse files Browse the repository at this point in the history
  • Loading branch information
piotr-roslaniec committed Mar 13, 2024
1 parent 2fe8753 commit 9fa869e
Show file tree
Hide file tree
Showing 8 changed files with 20 additions and 589 deletions.
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, G1Affine as G1, G2Affine as G2};
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 @@ -215,11 +134,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 @@ -239,26 +153,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 @@ -275,15 +175,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 @@ -314,10 +205,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 @@ -339,7 +226,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 @@ -387,7 +274,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 @@ -411,44 +298,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 @@ -258,7 +258,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 @@ -282,7 +282,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};

// TODO: Combine `tpke::prepare_combine_simple` and `tpke::share_combine_simple` into
// one function and expose it in the tpke::api?
Expand Down Expand Up @@ -84,51 +46,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

0 comments on commit 9fa869e

Please sign in to comment.