Skip to content

Commit

Permalink
Move core mpc and multiplication code out of BBS+ crate and to OT cra…
Browse files Browse the repository at this point in the history
…te and protyping threshold accumulator update and witness creation

Signed-off-by: lovesh <[email protected]>
  • Loading branch information
lovesh committed May 23, 2024
1 parent fe99471 commit d932a3e
Show file tree
Hide file tree
Showing 29 changed files with 1,462 additions and 1,018 deletions.
1 change: 1 addition & 0 deletions bbs_plus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ ark-bls12-381.workspace = true
serde_json = "1.0"
rmp-serde = "1.0"
ark-poly.workspace = true
test_utils = { path = "../test_utils" }

[features]
default = [ "parallel" ]
Expand Down
5 changes: 2 additions & 3 deletions bbs_plus/src/threshold/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@
//! Both BBS and BBS+ implementations share the same multiplication phase and the base OT phase but their phase 1 is slightly
//! less expensive as BBS+ needs 2 random fields elements but BBS needs only 1.

pub mod base_ot_phase;
pub mod cointoss;
pub mod multiplication_phase;
pub mod randomness_generation_phase;
pub mod threshold_bbs;
pub mod threshold_bbs_plus;
pub mod utils;
pub mod zero_sharing;

pub type ParticipantId = oblivious_transfer_protocols::ParticipantId;
337 changes: 33 additions & 304 deletions bbs_plus/src/threshold/multiplication_phase.rs

Large diffs are not rendered by default.

19 changes: 9 additions & 10 deletions bbs_plus/src/threshold/randomness_generation_phase.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use crate::{
error::BBSPlusError,
threshold::{cointoss::Commitments, utils::compute_masked_arguments_to_multiply},
};
use super::ParticipantId;
use crate::{error::BBSPlusError, threshold::utils::compute_masked_arguments_to_multiply};
use ark_ff::PrimeField;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::vec::Vec;
use digest::DynDigest;
use oblivious_transfer_protocols::ParticipantId;
use oblivious_transfer_protocols::{cointoss, zero_sharing};

/// This is the first phase of the signing protocol where parties generate random values, jointly and
/// individually including additive shares of 0.
Expand All @@ -15,11 +13,12 @@ pub struct Phase1<F: PrimeField, const SALT_SIZE: usize> {
pub id: ParticipantId,
/// Number of threshold signatures being generated in a single batch.
pub batch_size: u32,
/// Shares of the random `r`, one share for each item in the batch
pub r: Vec<F>,
/// Protocols to generate shares of random values used in signature like `e`
pub commitment_protocol: super::cointoss::Party<F, SALT_SIZE>,
/// Protocols to generate shares of random values used in signature like `e` for BBS and (`e`, `s`) for BBS+
pub commitment_protocol: cointoss::Party<F, SALT_SIZE>,
/// Protocols to generate shares of 0s.
pub zero_sharing_protocol: super::zero_sharing::Party<F, SALT_SIZE>,
pub zero_sharing_protocol: zero_sharing::Party<F, SALT_SIZE>,
}

impl<F: PrimeField, const SALT_SIZE: usize> Phase1<F, SALT_SIZE> {
Expand All @@ -44,8 +43,8 @@ impl<F: PrimeField, const SALT_SIZE: usize> Phase1<F, SALT_SIZE> {
pub fn receive_commitment(
&mut self,
sender_id: ParticipantId,
comm: Commitments,
comm_zero_share: Commitments,
comm: cointoss::Commitments,
comm_zero_share: cointoss::Commitments,
) -> Result<(), BBSPlusError> {
self.commitment_protocol
.receive_commitment(sender_id, comm)?;
Expand Down
32 changes: 20 additions & 12 deletions bbs_plus/src/threshold/threshold_bbs.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use ark_ec::{AffineRepr, CurveGroup};

use super::{cointoss::Commitments, multiplication_phase::Phase2Output, utils::compute_R_and_u};
use super::{multiplication_phase::Phase2Output, utils::compute_R_and_u};
use ark_ec::pairing::Pairing;
use ark_ff::{Field, PrimeField, Zero};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
Expand All @@ -17,14 +17,15 @@ use crate::{
threshold::randomness_generation_phase::Phase1,
};
use dock_crypto_utils::signature::MultiMessageSignatureParams;
use oblivious_transfer_protocols::ParticipantId;
use oblivious_transfer_protocols::{cointoss, zero_sharing, ParticipantId};

/// The length of vectors `r`, `e`, `masked_signing_key_shares`, `masked_rs` should
/// be `batch_size` each item of the vector corresponds to 1 signature
/// be `batch_size` as each item of the vector corresponds to 1 signature
#[derive(Clone, Debug, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
pub struct Phase1Output<F: PrimeField> {
pub id: ParticipantId,
pub batch_size: u32,
/// Shares of the random `r`, one share for each item in the batch
pub r: Vec<F>,
pub e: Vec<F>,
/// Additive shares of the signing key masked by a random `alpha`
Expand All @@ -51,17 +52,24 @@ impl<F: PrimeField, const SALT_SIZE: usize> Phase1<F, SALT_SIZE> {
id: ParticipantId,
others: BTreeSet<ParticipantId>,
protocol_id: Vec<u8>,
) -> Result<(Self, Commitments, BTreeMap<ParticipantId, Commitments>), BBSPlusError> {
) -> Result<
(
Self,
cointoss::Commitments,
BTreeMap<ParticipantId, cointoss::Commitments>,
),
BBSPlusError,
> {
if others.contains(&id) {
return Err(BBSPlusError::ParticipantCannotBePresentInOthers(id));
}
let r = (0..batch_size).map(|_| F::rand(rng)).collect();
// 1 random values `e` need to be generated per signature
// 1 random value `e` need to be generated per signature
let (commitment_protocol, comm) =
super::cointoss::Party::commit(rng, id, batch_size, protocol_id.clone());
cointoss::Party::commit(rng, id, batch_size, protocol_id.clone());
// Each signature will have its own zero-sharing of `alpha` and `beta`
let (zero_sharing_protocol, comm_zero_share) =
super::zero_sharing::Party::init(rng, id, 2 * batch_size, others, protocol_id);
zero_sharing::Party::init(rng, id, 2 * batch_size, others, protocol_id);
Ok((
Self {
id,
Expand Down Expand Up @@ -192,8 +200,7 @@ pub mod tests {
use crate::{
setup::{PublicKeyG2, SecretKey},
threshold::{
base_ot_phase::tests::do_base_ot_for_threshold_sig, multiplication_phase::Phase2,
threshold_bbs_plus::tests::trusted_party_keygen,
multiplication_phase::Phase2, threshold_bbs_plus::tests::trusted_party_keygen,
},
};
use ark_std::{
Expand All @@ -204,6 +211,7 @@ pub mod tests {
use oblivious_transfer_protocols::ot_based_multiplication::{
dkls18_mul_2p::MultiplicationOTEParams, dkls19_batch_mul_2p::GadgetVector,
};
use test_utils::ot::do_pairwise_base_ot;

#[test]
fn signing() {
Expand All @@ -229,7 +237,7 @@ pub mod tests {
trusted_party_keygen::<_, Fr>(&mut rng, threshold_signers, total_signers);

// The signers run OT protocol instances. This is also a one time setup.
let base_ot_outputs = do_base_ot_for_threshold_sig::<BASE_OT_KEY_SIZE>(
let base_ot_outputs = do_pairwise_base_ot::<BASE_OT_KEY_SIZE>(
&mut rng,
ote_params.num_base_ot(),
total_signers,
Expand Down Expand Up @@ -363,8 +371,8 @@ pub mod tests {
// Check that multiplication phase ran successfully, i.e. each signer has an additive share of
// a multiplication with every other signer
for i in 1..=threshold_signers {
for (j, z_A) in &round2_outputs[i as usize - 1].z_A {
let z_B = round2_outputs[*j as usize - 1].z_B.get(&i).unwrap();
for (j, z_A) in &round2_outputs[i as usize - 1].0.z_A {
let z_B = round2_outputs[*j as usize - 1].0.z_B.get(&i).unwrap();
for k in 0..sig_batch_size as usize {
assert_eq!(
z_A.0[k] + z_B.0[k],
Expand Down
30 changes: 18 additions & 12 deletions bbs_plus/src/threshold/threshold_bbs_plus.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::threshold::cointoss::Commitments;
use ark_ec::{pairing::Pairing, AffineRepr, CurveGroup};
use ark_ff::{Field, PrimeField, Zero};

Expand All @@ -10,7 +9,7 @@ use ark_std::{
};
use digest::DynDigest;
use dock_crypto_utils::expect_equality;
use oblivious_transfer_protocols::ParticipantId;
use oblivious_transfer_protocols::{cointoss, zero_sharing, ParticipantId};

use super::{multiplication_phase::Phase2Output, utils::compute_R_and_u};
use crate::{
Expand All @@ -25,6 +24,7 @@ use dock_crypto_utils::signature::MultiMessageSignatureParams;
pub struct Phase1Output<F: PrimeField> {
pub id: ParticipantId,
pub batch_size: u32,
/// Shares of the random `r`, one share for each item in the batch
pub r: Vec<F>,
pub e: Vec<F>,
pub s: Vec<F>,
Expand Down Expand Up @@ -53,17 +53,24 @@ impl<F: PrimeField, const SALT_SIZE: usize> Phase1<F, SALT_SIZE> {
id: ParticipantId,
others: BTreeSet<ParticipantId>,
protocol_id: Vec<u8>,
) -> Result<(Self, Commitments, BTreeMap<ParticipantId, Commitments>), BBSPlusError> {
) -> Result<
(
Self,
cointoss::Commitments,
BTreeMap<ParticipantId, cointoss::Commitments>,
),
BBSPlusError,
> {
if others.contains(&id) {
return Err(BBSPlusError::ParticipantCannotBePresentInOthers(id));
}
let r = (0..batch_size).map(|_| F::rand(rng)).collect();
// 2 because 2 random values `e` and `s` need to be generated per signature
let (commitment_protocol, comm) =
super::cointoss::Party::commit(rng, id, 2 * batch_size, protocol_id.clone());
cointoss::Party::commit(rng, id, 2 * batch_size, protocol_id.clone());
// Each signature will have its own zero-sharing of `alpha` and `beta`
let (zero_sharing_protocol, comm_zero_share) =
super::zero_sharing::Party::init(rng, id, 2 * batch_size, others, protocol_id);
zero_sharing::Party::init(rng, id, 2 * batch_size, others, protocol_id);
Ok((
Self {
id,
Expand Down Expand Up @@ -202,9 +209,7 @@ pub mod tests {

use crate::{
setup::{PublicKeyG2, SecretKey},
threshold::{
base_ot_phase::tests::do_base_ot_for_threshold_sig, multiplication_phase::Phase2,
},
threshold::multiplication_phase::Phase2,
};
use oblivious_transfer_protocols::ot_based_multiplication::{
dkls18_mul_2p::MultiplicationOTEParams, dkls19_batch_mul_2p::GadgetVector,
Expand All @@ -217,6 +222,7 @@ pub mod tests {
use blake2::Blake2b512;

use secret_sharing_and_dkg::shamir_ss::deal_random_secret;
use test_utils::ot::do_pairwise_base_ot;

pub fn trusted_party_keygen<R: RngCore, F: PrimeField>(
rng: &mut R,
Expand Down Expand Up @@ -265,7 +271,7 @@ pub mod tests {

// The signers run OT protocol instances. This is also a one time setup.
let start = Instant::now();
let base_ot_outputs = do_base_ot_for_threshold_sig::<BASE_OT_KEY_SIZE>(
let base_ot_outputs = do_pairwise_base_ot::<BASE_OT_KEY_SIZE>(
rng,
ote_params.num_base_ot(),
total_signers,
Expand Down Expand Up @@ -418,7 +424,7 @@ pub mod tests {
.into_iter()
.map(|p| {
let start = Instant::now();
let i = p.id;
let i = p.0.id;
let o = p.finish();
phase2_times.insert(i, *phase2_times.get(&i).unwrap() + start.elapsed());
o
Expand All @@ -430,8 +436,8 @@ pub mod tests {
// Check that multiplication phase ran successfully, i.e. each signer has an additive share of
// a multiplication with every other signer
for i in 1..=threshold_signers {
for (j, z_A) in &round2_outputs[i as usize - 1].z_A {
let z_B = round2_outputs[*j as usize - 1].z_B.get(&i).unwrap();
for (j, z_A) in &round2_outputs[i as usize - 1].0.z_A {
let z_B = round2_outputs[*j as usize - 1].0.z_B.get(&i).unwrap();
for k in 0..sig_batch_size as usize {
assert_eq!(
z_A.0[k] + z_B.0[k],
Expand Down
8 changes: 5 additions & 3 deletions bbs_plus/src/threshold/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use ark_ff::PrimeField;
use ark_std::{cfg_into_iter, ops::Mul, vec::Vec};
use itertools::Itertools;
use oblivious_transfer_protocols::ParticipantId;
use secret_sharing_and_dkg::error::SSError;

#[cfg(feature = "parallel")]
use rayon::prelude::*;
use secret_sharing_and_dkg::error::SSError;

pub fn compute_masked_arguments_to_multiply<F: PrimeField>(
signing_key: &F,
Expand All @@ -21,6 +21,8 @@ pub fn compute_masked_arguments_to_multiply<F: PrimeField>(
let alphas = zero_shares.drain(0..batch_size).collect::<Vec<_>>();
let betas = zero_shares;
let lambda = secret_sharing_and_dkg::common::lagrange_basis_at_0::<F>(&others, self_id)?;
// masked_signing_key_shares[i] = alphas[i] + (lambda * signing_key)
// masked_r[i] = betas[i] * r[i]
let (masked_signing_key_shares, masked_rs) = cfg_into_iter!(r)
.zip(cfg_into_iter!(alphas).zip(cfg_into_iter!(betas)))
.map(|(r, (alpha, beta))| {
Expand All @@ -45,11 +47,11 @@ pub fn compute_R_and_u<G: AffineRepr>(
) -> (G, G::ScalarField) {
let R = base.mul(r).into_affine();
let mut u = *masked_r * (*e + masked_signing_key_share);
for (_, (a, b)) in &phase2.z_A {
for (_, (a, b)) in &phase2.0.z_A {
u += a[index_in_output as usize];
u += b[index_in_output as usize];
}
for (_, (a, b)) in &phase2.z_B {
for (_, (a, b)) in &phase2.0.z_B {
u += a[index_in_output as usize];
u += b[index_in_output as usize];
}
Expand Down
10 changes: 7 additions & 3 deletions oblivious_transfer/README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
# Oblivious Transfer (OT) and Oblivious Transfer Extensions (OTE)
<!-- cargo-rdme start -->

# Oblivious Transfer (OT), Oblivious Transfer Extensions (OTE) and multi-party protocols based on that.

## Oblivious Transfer protocols

1. [Simplest OT protocol](./src/base_ot/simplest_ot.rs)
2. [Naor Pinkas OT](./src/base_ot/naor_pinkas_ot.rs)
3. [Endemic OT](./src/base_ot/endemic_ot.rs)

## Oblivious Transfer Extensions
## Oblivious Transfer Extensions
1. [ALSZ](./src/ot_extensions/alsz_ote.rs)
2. [KOS](./src/ot_extensions/kos_ote.rs)

## Oblivious Transfer based multiplication
1. [DKLS18](./src/ot_based_multiplication/dkls18_mul_2p.rs) - 2 party multiplication of where each party has a single input
2. [DKLS19](./src/ot_based_multiplication/dkls19_batch_mul_2p.rs) - 2 party batch-multiplication of where each party has multiple inputs, say `n` inputs and those inputs will be multiplied, i.e. a total of `2*n` multiplications will be done with each being between 2 inputs
2. [DKLS19](./src/ot_based_multiplication/dkls19_batch_mul_2p.rs) - 2 party batch-multiplication of where each party has multiple inputs, say `n` inputs and those inputs will be multiplied, i.e. a total of `2*n` multiplications will be done with each being between 2 inputs

<!-- cargo-rdme end -->
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
//! Generate 1 or more random numbers using commit-and-release coin tossing.
//! Called F_com in the paper
//! Called F_com in the paper [Threshold BBS+ Signatures for Distributed Anonymous Credential Issuance](https://eprint.iacr.org/2023/602)

use ark_ff::PrimeField;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::{cfg_into_iter, collections::BTreeMap, rand::RngCore, vec, vec::Vec};
use digest::Digest;
use sha3::Sha3_256;

use oblivious_transfer_protocols::ParticipantId;
use super::ParticipantId;

use crate::error::BBSPlusError;
use crate::error::OTError;

use dock_crypto_utils::expect_equality;

#[cfg(feature = "parallel")]
use rayon::prelude::*;

Expand Down Expand Up @@ -69,19 +70,17 @@ impl<F: PrimeField, const SALT_SIZE: usize> Party<F, SALT_SIZE> {
&mut self,
sender_id: ParticipantId,
commitments: Commitments,
) -> Result<(), BBSPlusError> {
) -> Result<(), OTError> {
if self.id == sender_id {
return Err(BBSPlusError::SenderIdCannotBeSameAsSelf(sender_id, self.id));
return Err(OTError::SenderIdCannotBeSameAsSelf(sender_id, self.id));
}
if self.other_commitments.contains_key(&sender_id) {
return Err(BBSPlusError::AlreadyHaveCommitmentFromParticipant(
sender_id,
));
return Err(OTError::AlreadyHaveCommitmentFromParticipant(sender_id));
}
expect_equality!(
self.own_shares_and_salts.len(),
commitments.0.len(),
BBSPlusError::IncorrectNoOfCommitments
OTError::IncorrectNoOfCommitments
);
self.other_commitments.insert(sender_id, commitments);
Ok(())
Expand All @@ -93,24 +92,24 @@ impl<F: PrimeField, const SALT_SIZE: usize> Party<F, SALT_SIZE> {
&mut self,
sender_id: ParticipantId,
shares_and_salts: Vec<(F, [u8; SALT_SIZE])>,
) -> Result<(), BBSPlusError> {
) -> Result<(), OTError> {
if self.id == sender_id {
return Err(BBSPlusError::SenderIdCannotBeSameAsSelf(sender_id, self.id));
return Err(OTError::SenderIdCannotBeSameAsSelf(sender_id, self.id));
}
if !self.other_commitments.contains_key(&sender_id) {
return Err(BBSPlusError::MissingCommitmentFromParticipant(sender_id));
return Err(OTError::MissingCommitmentFromParticipant(sender_id));
}
if self.other_shares.contains_key(&sender_id) {
return Err(BBSPlusError::AlreadyHaveSharesFromParticipant(sender_id));
return Err(OTError::AlreadyHaveSharesFromParticipant(sender_id));
}
expect_equality!(
self.own_shares_and_salts.len(),
shares_and_salts.len(),
BBSPlusError::IncorrectNoOfShares
OTError::IncorrectNoOfShares
);
let expected_commitments = Self::compute_commitments(&shares_and_salts, &self.protocol_id);
if expected_commitments != self.other_commitments.get(&sender_id).unwrap().0 {
return Err(BBSPlusError::IncorrectCommitment);
return Err(OTError::IncorrectCommitment);
}
self.other_shares.insert(
sender_id,
Expand Down
Loading

0 comments on commit d932a3e

Please sign in to comment.