use crate::{
error::SyraError,
setup::{IssuerSecretKey, PreparedSetupParams, UserSecretKey},
vrf::{Output, Proof},
};
use ark_ec::{pairing::Pairing, CurveGroup};
use ark_ff::{Field, PrimeField, Zero};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::{collections::BTreeMap, ops::Mul, rand::RngCore, vec::Vec};
use digest::{DynDigest, ExtendableOutput, Update};
use dock_crypto_utils::serde_utils::ArkObjectBytes;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use short_group_sig::threshold_weak_bb_sig::{
BaseOTOutput, GadgetVector, Message1, Message2, MultiplicationOTEParams, ParticipantId,
SigShare,
};
pub use short_group_sig::threshold_weak_bb_sig::{Phase1, Phase1Output};
use zeroize::{Zeroize, ZeroizeOnDrop};
#[derive(Clone, CanonicalSerialize, CanonicalDeserialize)]
pub struct Phase2<F: PrimeField, const KAPPA: u16, const STATISTICAL_SECURITY_PARAMETER: u16>(
pub short_group_sig::threshold_weak_bb_sig::Phase2<F, KAPPA, STATISTICAL_SECURITY_PARAMETER>,
);
#[serde_as]
#[derive(
Clone,
PartialEq,
Eq,
Debug,
CanonicalSerialize,
CanonicalDeserialize,
Serialize,
Deserialize,
Zeroize,
ZeroizeOnDrop,
)]
pub struct UserSecretKeyShare<E: Pairing> {
pub signer_id: ParticipantId,
#[serde_as(as = "ArkObjectBytes")]
pub R: E::G1Affine,
#[serde_as(as = "ArkObjectBytes")]
pub R_hat: E::G2Affine,
#[serde_as(as = "ArkObjectBytes")]
pub u: E::ScalarField,
}
impl<F: PrimeField, const KAPPA: u16, const STATISTICAL_SECURITY_PARAMETER: u16>
Phase2<F, KAPPA, STATISTICAL_SECURITY_PARAMETER>
{
pub fn init_for_user_id<R: RngCore, X: Default + Update + ExtendableOutput>(
rng: &mut R,
id: ParticipantId,
issuer_sk: &IssuerSecretKey<F>,
user_id: F,
phase_1_output: Phase1Output<F>,
base_ot_output: BaseOTOutput,
ote_params: MultiplicationOTEParams<KAPPA, STATISTICAL_SECURITY_PARAMETER>,
gadget_vector: &GadgetVector<F, KAPPA, STATISTICAL_SECURITY_PARAMETER>,
label: &'static [u8],
) -> Result<(Self, BTreeMap<ParticipantId, Message1<F>>), SyraError> {
let (inner, m) = short_group_sig::threshold_weak_bb_sig::Phase2::<
F,
KAPPA,
STATISTICAL_SECURITY_PARAMETER,
>::init_for_known_message::<R, X>(
rng,
id,
issuer_sk.0,
user_id,
phase_1_output,
base_ot_output,
ote_params,
gadget_vector,
label,
)?;
Ok((Self(inner), m))
}
pub fn init_for_shared_user_id<R: RngCore, X: Default + Update + ExtendableOutput>(
rng: &mut R,
id: ParticipantId,
issuer_sk: &IssuerSecretKey<F>,
user_id_share: F,
phase_1_output: Phase1Output<F>,
base_ot_output: BaseOTOutput,
ote_params: MultiplicationOTEParams<KAPPA, STATISTICAL_SECURITY_PARAMETER>,
gadget_vector: &GadgetVector<F, KAPPA, STATISTICAL_SECURITY_PARAMETER>,
label: &'static [u8],
) -> Result<(Self, BTreeMap<ParticipantId, Message1<F>>), SyraError> {
let (inner, m) = short_group_sig::threshold_weak_bb_sig::Phase2::<
F,
KAPPA,
STATISTICAL_SECURITY_PARAMETER,
>::init_for_shared_message::<R, X>(
rng,
id,
issuer_sk.0,
user_id_share,
phase_1_output,
base_ot_output,
ote_params,
gadget_vector,
label,
)?;
Ok((Self(inner), m))
}
pub fn receive_message1<
D: Default + DynDigest + Clone,
X: Default + Update + ExtendableOutput,
>(
&mut self,
sender_id: ParticipantId,
message: Message1<F>,
gadget_vector: &GadgetVector<F, KAPPA, STATISTICAL_SECURITY_PARAMETER>,
) -> Result<Message2<F>, SyraError> {
self.0
.receive_message1::<D, X>(sender_id, message, gadget_vector)
.map_err(|e| e.into())
}
pub fn receive_message2<D: Default + DynDigest + Clone>(
&mut self,
sender_id: ParticipantId,
message: Message2<F>,
gadget_vector: &GadgetVector<F, KAPPA, STATISTICAL_SECURITY_PARAMETER>,
) -> Result<(), SyraError> {
self.0
.receive_message2::<D>(sender_id, message, gadget_vector)
.map_err(|e| e.into())
}
pub fn finish<E: Pairing<ScalarField = F>>(
self,
params: impl Into<PreparedSetupParams<E>>,
) -> UserSecretKeyShare<E> {
let params = params.into();
let r = self.0.r;
let R_hat = params.g_hat.mul(r).into_affine();
let SigShare { signer_id, R, u } = self.0.finish::<E::G1Affine>(¶ms.g);
UserSecretKeyShare {
signer_id,
R,
R_hat,
u,
}
}
}
impl<E: Pairing> UserSecretKeyShare<E> {
pub fn aggregate(
shares: Vec<Self>,
params: impl Into<PreparedSetupParams<E>>,
) -> UserSecretKey<E> {
let params = params.into();
let mut sum_R = E::G1::zero();
let mut sum_R_hat = E::G2::zero();
let mut sum_u = E::ScalarField::zero();
for share in shares {
sum_R += share.R;
sum_R_hat += share.R_hat;
sum_u += share.u;
}
let u_inv = sum_u.inverse().unwrap();
let R = (sum_R * u_inv).into_affine();
let R_hat = (sum_R_hat * u_inv).into_affine();
let T = E::pairing(R, params.g_hat_prepared);
UserSecretKey(Output(T), Proof(R, R_hat))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::setup::{IssuerPublicKey, IssuerSecretKey, SetupParams};
use ark_bls12_381::{Bls12_381, Fr};
use ark_std::rand::{rngs::StdRng, SeedableRng};
use blake2::Blake2b512;
use schnorr_pok::compute_random_oracle_challenge;
use secret_sharing_and_dkg::shamir_ss::{deal_random_secret, deal_secret};
use sha3::Shake256;
use short_group_sig::threshold_weak_bb_sig::Phase1;
use std::{collections::BTreeSet, time::Instant};
use test_utils::ot::do_pairwise_base_ot;
const BASE_OT_KEY_SIZE: u16 = 128;
const KAPPA: u16 = 256;
const STATISTICAL_SECURITY_PARAMETER: u16 = 80;
const OTE_PARAMS: MultiplicationOTEParams<KAPPA, STATISTICAL_SECURITY_PARAMETER> =
MultiplicationOTEParams::<KAPPA, STATISTICAL_SECURITY_PARAMETER> {};
pub fn trusted_party_keygen(
rng: &mut StdRng,
threshold: ParticipantId,
total: ParticipantId,
) -> (Fr, Vec<Fr>) {
let (secret, shares, _) = deal_random_secret(rng, threshold, total).unwrap();
(secret, shares.0.into_iter().map(|s| s.share).collect())
}
fn do_phase1(
rng: &mut StdRng,
threshold_signers: ParticipantId,
protocol_id: Vec<u8>,
) -> Vec<Phase1Output<Fr>> {
let threshold_party_set = (1..=threshold_signers).into_iter().collect::<BTreeSet<_>>();
let mut phase1s = vec![];
let mut commitments_zero_share = vec![];
for i in 1..=threshold_signers {
let mut others = threshold_party_set.clone();
others.remove(&i);
let (round1, comm_zero) =
Phase1::<Fr, 256>::init::<_, Blake2b512>(rng, i, others, protocol_id.clone())
.unwrap();
phase1s.push(round1);
commitments_zero_share.push(comm_zero);
}
for i in 1..=threshold_signers {
for j in 1..=threshold_signers {
if i != j {
phase1s[i as usize - 1]
.receive_commitment(
j,
commitments_zero_share[j as usize - 1]
.get(&i)
.unwrap()
.clone(),
)
.unwrap();
}
}
}
for i in 1..=threshold_signers {
for j in 1..=threshold_signers {
if i != j {
let zero_share = phase1s[j as usize - 1]
.get_comm_shares_and_salts_for_zero_sharing_protocol_with_other(&i);
phase1s[i as usize - 1]
.receive_shares::<Blake2b512>(j, zero_share)
.unwrap();
}
}
}
let phase1_outputs = phase1s
.into_iter()
.map(|p| p.finish::<Blake2b512>().unwrap())
.collect::<Vec<_>>();
phase1_outputs
}
fn do_phase2(
rng: &mut StdRng,
threshold_signers: ParticipantId,
gadget_vector: &GadgetVector<Fr, KAPPA, STATISTICAL_SECURITY_PARAMETER>,
params: impl Into<PreparedSetupParams<Bls12_381>>,
base_ot_outputs: &[BaseOTOutput],
phase1_outs: &[Phase1Output<Fr>],
expected_sk_term: Fr,
secret_key_shares: &[IssuerSecretKey<Fr>],
user_id: Option<Fr>,
user_id_shares: Option<Vec<Fr>>,
) -> Vec<UserSecretKeyShare<Bls12_381>> {
let mut phase2s = vec![];
let mut all_msg_1s = vec![];
let label = b"test";
let known_id = user_id.is_some();
let user_id = user_id.unwrap_or_default();
let user_id_shares = user_id_shares.unwrap_or_default();
for i in 1..=threshold_signers {
let (phase, msgs) = if known_id {
Phase2::init_for_user_id::<_, Shake256>(
rng,
i,
&secret_key_shares[i as usize - 1],
user_id,
phase1_outs[i as usize - 1].clone(),
base_ot_outputs[i as usize - 1].clone(),
OTE_PARAMS,
&gadget_vector,
label,
)
.unwrap()
} else {
Phase2::init_for_shared_user_id::<_, Shake256>(
rng,
i,
&secret_key_shares[i as usize - 1],
user_id_shares[i as usize - 1],
phase1_outs[i as usize - 1].clone(),
base_ot_outputs[i as usize - 1].clone(),
OTE_PARAMS,
&gadget_vector,
label,
)
.unwrap()
};
phase2s.push(phase);
all_msg_1s.push((i, msgs));
}
let mut sk_term = Fr::zero();
for p in &phase2s {
sk_term += p.0.masked_sk_term_share
}
assert_eq!(expected_sk_term, sk_term);
let mut all_msg_2s = vec![];
for (sender_id, msg_1s) in all_msg_1s {
for (receiver_id, m) in msg_1s {
let m2 = phase2s[receiver_id as usize - 1]
.receive_message1::<Blake2b512, Shake256>(sender_id, m, &gadget_vector)
.unwrap();
all_msg_2s.push((receiver_id, sender_id, m2));
}
}
for (sender_id, receiver_id, m2) in all_msg_2s {
phase2s[receiver_id as usize - 1]
.receive_message2::<Blake2b512>(sender_id, m2, &gadget_vector)
.unwrap();
}
let params = params.into();
let usk_shares = phase2s
.into_iter()
.map(|p| p.finish::<Bls12_381>(params.clone()))
.collect::<Vec<_>>();
usk_shares
}
#[test]
fn issue_with_known_user_id() {
let mut rng = StdRng::seed_from_u64(0u64);
let params = SetupParams::<Bls12_381>::new::<Blake2b512>(b"test");
let prepared_params = PreparedSetupParams::<Bls12_381>::from(params.clone());
let gadget_vector = GadgetVector::<Fr, KAPPA, STATISTICAL_SECURITY_PARAMETER>::new::<
Blake2b512,
>(OTE_PARAMS, b"test-gadget-vector");
for (threshold_signers, total_signers) in [(5, 8), (6, 15), (15, 20), (20, 30), (25, 40)] {
println!("\n\nFor {}-of-{}", threshold_signers, total_signers);
let all_party_set = (1..=total_signers).into_iter().collect::<BTreeSet<_>>();
let (sk, sk_shares) = trusted_party_keygen(&mut rng, threshold_signers, total_signers);
let isk_shares = sk_shares
.into_iter()
.map(|s| IssuerSecretKey(s))
.collect::<Vec<_>>();
let threshold_ipk = IssuerPublicKey::new(&mut rng, &IssuerSecretKey(sk), ¶ms);
let base_ot_outputs = do_pairwise_base_ot::<BASE_OT_KEY_SIZE>(
&mut rng,
OTE_PARAMS.num_base_ot(),
total_signers,
all_party_set.clone(),
);
let protocol_id = b"test".to_vec();
let phase1_outs = do_phase1(&mut rng, threshold_signers, protocol_id.clone());
let user_id = compute_random_oracle_challenge::<Fr, Blake2b512>(b"low entropy user-id");
let usk_shares = do_phase2(
&mut rng,
threshold_signers,
&gadget_vector,
prepared_params.clone(),
&base_ot_outputs,
&phase1_outs,
sk,
&isk_shares,
Some(user_id),
None,
);
let start = Instant::now();
let usk = UserSecretKeyShare::aggregate(usk_shares, prepared_params.clone());
println!(
"Aggregating {} shares took {:.2?}",
threshold_signers,
start.elapsed()
);
usk.verify(user_id, &threshold_ipk, prepared_params.clone())
.unwrap();
}
}
#[test]
fn issue_with_shared_user_id() {
let mut rng = StdRng::seed_from_u64(0u64);
let params = SetupParams::<Bls12_381>::new::<Blake2b512>(b"test");
let prepared_params = PreparedSetupParams::<Bls12_381>::from(params.clone());
let gadget_vector = GadgetVector::<Fr, KAPPA, STATISTICAL_SECURITY_PARAMETER>::new::<
Blake2b512,
>(OTE_PARAMS, b"test-gadget-vector");
for (threshold_signers, total_signers) in [(5, 8), (6, 15), (15, 20), (20, 30), (25, 40)] {
println!("\n\nFor {}-of-{}", threshold_signers, total_signers);
let all_party_set = (1..=total_signers).into_iter().collect::<BTreeSet<_>>();
let (sk, sk_shares) = trusted_party_keygen(&mut rng, threshold_signers, total_signers);
let isk_shares = sk_shares
.into_iter()
.map(|s| IssuerSecretKey(s))
.collect::<Vec<_>>();
let threshold_ipk = IssuerPublicKey::new(&mut rng, &IssuerSecretKey(sk), ¶ms);
let base_ot_outputs = do_pairwise_base_ot::<BASE_OT_KEY_SIZE>(
&mut rng,
OTE_PARAMS.num_base_ot(),
total_signers,
all_party_set.clone(),
);
let protocol_id = b"test".to_vec();
let phase1_outs = do_phase1(&mut rng, threshold_signers, protocol_id.clone());
let user_id = compute_random_oracle_challenge::<Fr, Blake2b512>(b"low entropy user-id");
let (user_id_shares, _) =
deal_secret::<StdRng, Fr>(&mut rng, user_id, threshold_signers, total_signers)
.unwrap();
let usk_shares = do_phase2(
&mut rng,
threshold_signers,
&gadget_vector,
prepared_params.clone(),
&base_ot_outputs,
&phase1_outs,
sk + user_id,
&isk_shares,
None,
Some(
user_id_shares
.0
.into_iter()
.map(|share| share.share)
.collect(),
),
);
let start = Instant::now();
let usk = UserSecretKeyShare::aggregate(usk_shares, prepared_params.clone());
println!(
"Aggregating {} shares took {:.2?}",
threshold_signers,
start.elapsed()
);
usk.verify(user_id, &threshold_ipk, prepared_params.clone())
.unwrap();
}
}
}