Skip to content

Commit 833b87f

Browse files
committed
Merge branch 'main' into tw/contracts-build-rs
2 parents 948c001 + 0e605cd commit 833b87f

File tree

4 files changed

+209
-58
lines changed

4 files changed

+209
-58
lines changed

timeboost-crypto/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,7 @@ criterion = { workspace = true }
4141
[[bench]]
4242
name = "decryption"
4343
harness = false
44+
45+
[[bench]]
46+
name = "vess"
47+
harness = false

timeboost-crypto/benches/vess.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
use std::{collections::BTreeMap, iter::repeat_with};
2+
3+
use ark_ec::CurveGroup;
4+
use ark_std::{
5+
UniformRand,
6+
rand::{Rng, SeedableRng, rngs::StdRng},
7+
};
8+
use criterion::{Criterion, criterion_group, criterion_main};
9+
use timeboost_crypto::mre::{self, LabeledDecryptionKey};
10+
use timeboost_crypto::vess::ShoupVess;
11+
12+
const KB: usize = 1 << 10;
13+
14+
/// Helper function to create a test committee with specified parameters
15+
fn create_test_committee(epoch: u64, size: usize) -> multisig::Committee {
16+
let keypairs: Vec<multisig::Keypair> =
17+
(0..size).map(|_| multisig::Keypair::generate()).collect();
18+
multisig::Committee::new(
19+
epoch,
20+
keypairs
21+
.iter()
22+
.enumerate()
23+
.map(|(i, kp)| (i as u8, kp.public_key())),
24+
)
25+
}
26+
27+
fn shoup_vess<C: CurveGroup>(c: &mut Criterion, vess: ShoupVess<C>) {
28+
let rng = &mut StdRng::seed_from_u64(42);
29+
let committee_sizes = [13];
30+
let secret = C::ScalarField::rand(rng);
31+
32+
for committee_size in committee_sizes {
33+
let benchmark_group_name = |op_name| format!("ShoupVESS_{committee_size}_{op_name}");
34+
35+
// Create a test committee
36+
let committee = create_test_committee(0, committee_size);
37+
let n = committee.size().get();
38+
let aad = b"vess aad";
39+
40+
// prepare their encryption keys for secure communication
41+
let recv_sks: Vec<mre::DecryptionKey<C>> = repeat_with(|| mre::DecryptionKey::rand(rng))
42+
.take(n)
43+
.collect();
44+
let recv_pks: BTreeMap<usize, mre::EncryptionKey<C>> = recv_sks
45+
.iter()
46+
.enumerate()
47+
.map(|(i, sk)| (i, mre::EncryptionKey::from(sk)))
48+
.collect();
49+
let labeled_sks: Vec<LabeledDecryptionKey<C>> = recv_sks
50+
.into_iter()
51+
.enumerate()
52+
.map(|(i, sk)| sk.label(i))
53+
.collect();
54+
55+
// benchmark encrypt_shares
56+
c.bench_function(&benchmark_group_name("encrypt"), |b| {
57+
b.iter(|| {
58+
vess.encrypt_shares(&committee, recv_pks.values(), secret, aad)
59+
.unwrap();
60+
})
61+
});
62+
63+
// benchmark verify
64+
let (ct, comm) = vess
65+
.encrypt_shares(&committee, recv_pks.values(), secret, aad)
66+
.unwrap();
67+
println!(
68+
"{}: ciphertext: {} KB",
69+
benchmark_group_name("size"),
70+
ct.as_bytes().len() / KB
71+
);
72+
c.bench_function(&benchmark_group_name("verify"), |b| {
73+
b.iter(|| {
74+
vess.verify_shares(&committee, recv_pks.values(), &ct, &comm, aad)
75+
.unwrap();
76+
})
77+
});
78+
79+
// benchmark decrypt
80+
// select a random receiver to test its decryption
81+
let recv_idx = rng.gen_range(0..committee_size);
82+
let labeled_recv_sk = &labeled_sks[recv_idx];
83+
c.bench_function(&benchmark_group_name("decrypt"), |b| {
84+
b.iter(|| {
85+
vess.decrypt_share(&committee, labeled_recv_sk, &ct, aad)
86+
.unwrap();
87+
})
88+
});
89+
}
90+
}
91+
92+
fn vess_main(c: &mut Criterion) {
93+
shoup_vess(c, ShoupVess::<ark_bls12_381::G1Projective>::new_fast());
94+
}
95+
96+
criterion_group!(name = benches; config = Criterion::default().sample_size(10); targets = vess_main);
97+
98+
criterion_main!(benches);

timeboost-crypto/src/feldman.rs

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
//! Implementation of Feldman VSS
22
3-
use ark_ec::CurveGroup;
3+
use ark_ec::{CurveGroup, scalar_mul::BatchMulPreprocessing};
44
use ark_poly::{DenseUVPolynomial, Polynomial, univariate::DensePolynomial};
55
use ark_serialize::{CanonicalSerialize, SerializationError, serialize_to_vec};
66
use ark_std::marker::PhantomData;
77
use ark_std::rand::Rng;
8-
use derive_more::{Deref, From, IntoIterator};
8+
use derive_more::{Debug, Deref, From, IntoIterator};
99
use multisig::Committee;
1010
use rayon::prelude::*;
1111
use serde::{Deserialize, Serialize};
1212
use serde_with::serde_as;
13-
use std::{iter::successors, num::NonZeroUsize, ops::Add};
13+
use std::{iter::successors, num::NonZeroUsize, ops::Add, sync::Arc};
1414

1515
use crate::{
1616
interpolation::{interpolate, interpolate_in_exponent},
@@ -21,23 +21,48 @@ use crate::{
2121
#[derive(Debug, Clone)]
2222
pub struct FeldmanVss<C: CurveGroup>(PhantomData<C>);
2323

24-
#[derive(Debug, Clone, Copy)]
25-
pub struct FeldmanVssPublicParam {
24+
#[derive(Debug, Clone)]
25+
pub struct FeldmanVssPublicParam<C: CurveGroup> {
2626
// reconstruction threshold t
2727
pub t: NonZeroUsize,
2828
// total number of nodes
2929
pub n: NonZeroUsize,
30+
31+
// preprocessing lookup table to accelerate batch_mul
32+
#[debug(skip)]
33+
table: Option<Arc<BatchMulPreprocessing<C>>>,
3034
}
3135

32-
impl FeldmanVssPublicParam {
36+
impl<C: CurveGroup> FeldmanVssPublicParam<C> {
3337
pub fn new(t: NonZeroUsize, n: NonZeroUsize) -> Self {
34-
Self { t, n }
38+
Self { t, n, table: None }
3539
}
3640

3741
pub fn from(c: &Committee) -> Self {
3842
Self::new(c.one_honest_threshold(), c.size())
3943
}
4044

45+
/// `Self::from().with_lookup_table()`: this precompute a lookup table for faster commit
46+
pub fn with_lookup_table(self) -> Self {
47+
let table = BatchMulPreprocessing::new(C::generator(), self.t.get());
48+
Self {
49+
t: self.t,
50+
n: self.n,
51+
table: Some(Arc::new(table)),
52+
}
53+
}
54+
55+
/// compute Feldman commit (potentially with accelerated lookup table)
56+
/// ASSUME: coeffs has length t, we skip checks and avoid returning Result, not publicly visble
57+
pub(crate) fn commit(&self, coeffs: &[C::ScalarField]) -> FeldmanCommitment<C> {
58+
if let Some(table) = self.table.as_ref() {
59+
table.batch_mul(coeffs).into()
60+
} else {
61+
let base = C::generator();
62+
FeldmanCommitment::new(coeffs.par_iter().map(|s| base * s).collect::<Vec<_>>())
63+
}
64+
}
65+
4166
pub fn threshold(&self) -> usize {
4267
self.t.get()
4368
}
@@ -50,7 +75,7 @@ impl FeldmanVssPublicParam {
5075
impl<C: CurveGroup> FeldmanVss<C> {
5176
/// sample a random polynomial for VSS `secret`, returns the poly and its feldman commitment
5277
pub(crate) fn rand_poly_and_commit<R: Rng>(
53-
pp: &FeldmanVssPublicParam,
78+
pp: &FeldmanVssPublicParam<C>,
5479
secret: C::ScalarField,
5580
rng: &mut R,
5681
) -> (DensePolynomial<C::ScalarField>, FeldmanCommitment<C>) {
@@ -61,23 +86,23 @@ impl<C: CurveGroup> FeldmanVss<C> {
6186
poly.coeffs[0] = secret;
6287

6388
// prepare commitment, u = (g^a_0, g^a_1, ..., g^a_t-1)
64-
let commitment = C::generator().batch_mul(&poly.coeffs);
89+
let commitment = pp.commit(&poly.coeffs);
6590

66-
(poly, commitment.into())
91+
(poly, commitment)
6792
}
6893

6994
/// given a secret-embedded polynomial, compute the Shamir secret shares
7095
/// node i \in {0,.. ,n-1} get f(i+1)
7196
pub(crate) fn compute_shares(
72-
pp: &FeldmanVssPublicParam,
97+
pp: &FeldmanVssPublicParam<C>,
7398
poly: &DensePolynomial<C::ScalarField>,
7499
) -> impl Iterator<Item = C::ScalarField> {
75100
(0..pp.n.get()).map(|node_idx| poly.evaluate(&((node_idx + 1) as u64).into()))
76101
}
77102

78103
/// same as [`Self::compute_shares()`], but output an iterator of bytes
79104
pub(crate) fn compute_serialized_shares(
80-
pp: &FeldmanVssPublicParam,
105+
pp: &FeldmanVssPublicParam<C>,
81106
poly: &DensePolynomial<C::ScalarField>,
82107
) -> impl Iterator<Item = Vec<u8>> {
83108
Self::compute_shares(pp, poly)
@@ -87,7 +112,7 @@ impl<C: CurveGroup> FeldmanVss<C> {
87112
/// given the Feldman commitment (\vec{u} in paper), compute the `i`-th node's public share,
88113
/// which is g^alpha_i where alpha_i is `i`-th secret share.
89114
pub(crate) fn derive_public_share(
90-
pp: &FeldmanVssPublicParam,
115+
pp: &FeldmanVssPublicParam<C>,
91116
node_idx: usize,
92117
commitment: &[C::Affine],
93118
) -> Result<C, VssError> {
@@ -127,7 +152,7 @@ impl<C: CurveGroup> FeldmanVss<C> {
127152
}
128153

129154
impl<C: CurveGroup> VerifiableSecretSharing for FeldmanVss<C> {
130-
type PublicParam = FeldmanVssPublicParam;
155+
type PublicParam = FeldmanVssPublicParam<C>;
131156
type Secret = C::ScalarField;
132157
type SecretShare = C::ScalarField;
133158
type Commitment = FeldmanCommitment<C>;
@@ -203,6 +228,12 @@ pub struct FeldmanCommitment<C: CurveGroup> {
203228
}
204229

205230
impl<C: CurveGroup> FeldmanCommitment<C> {
231+
/// If you already have value in affine form, use `.into()`
232+
pub fn new(v: Vec<C>) -> Self {
233+
let comm = C::normalize_batch(&v);
234+
Self { comm }
235+
}
236+
206237
pub fn to_bytes(&self) -> Vec<u8> {
207238
bincode::serde::encode_to_vec(self, bincode::config::standard())
208239
.expect("serializing feldman commitment")
@@ -248,7 +279,7 @@ impl<C: CurveGroup> Add<&FeldmanCommitment<C>> for &FeldmanCommitment<C> {
248279

249280
impl<C: CurveGroup> KeyResharing<Self> for FeldmanVss<C> {
250281
fn reshare<R: Rng>(
251-
new_pp: &FeldmanVssPublicParam,
282+
new_pp: &FeldmanVssPublicParam<C>,
252283
old_share: &C::ScalarField,
253284
rng: &mut R,
254285
) -> (Vec<C::ScalarField>, FeldmanCommitment<C>) {
@@ -258,8 +289,8 @@ impl<C: CurveGroup> KeyResharing<Self> for FeldmanVss<C> {
258289
}
259290

260291
fn verify_reshare(
261-
old_pp: &FeldmanVssPublicParam,
262-
new_pp: &FeldmanVssPublicParam,
292+
old_pp: &FeldmanVssPublicParam<C>,
293+
new_pp: &FeldmanVssPublicParam<C>,
263294
send_node_idx: usize,
264295
recv_node_idx: usize,
265296
old_commitment: &FeldmanCommitment<C>,
@@ -279,8 +310,8 @@ impl<C: CurveGroup> KeyResharing<Self> for FeldmanVss<C> {
279310
}
280311

281312
fn combine(
282-
old_pp: &FeldmanVssPublicParam,
283-
new_pp: &FeldmanVssPublicParam,
313+
old_pp: &FeldmanVssPublicParam<C>,
314+
new_pp: &FeldmanVssPublicParam<C>,
284315
recv_node_idx: usize,
285316
reshares: impl ExactSizeIterator<Item = (usize, C::ScalarField, FeldmanCommitment<C>)> + Clone,
286317
) -> Result<(C::ScalarField, FeldmanCommitment<C>), VssError> {

0 commit comments

Comments
 (0)