diff --git a/bbs_plus/src/error.rs b/bbs_plus/src/error.rs index 136977e6..9ea13a83 100644 --- a/bbs_plus/src/error.rs +++ b/bbs_plus/src/error.rs @@ -8,6 +8,7 @@ use dock_crypto_utils::{ }; use oblivious_transfer_protocols::{error::OTError, ParticipantId}; use schnorr_pok::error::SchnorrError; +use secret_sharing_and_dkg::error::SSError; use serde::Serialize; #[derive(Debug, Serialize)] @@ -57,6 +58,7 @@ pub enum BBSPlusError { AlreadyHaveChallengesFrom(ParticipantId), SenderEitherNotReadyForResponseOrAlreadySentIt(ParticipantId), ReceiverEitherNotReadyForHashedKeysOrAlreadyVerifiedIt(ParticipantId), + SSError(SSError), } impl From for BBSPlusError { @@ -88,3 +90,9 @@ impl From for BBSPlusError { Self::OTError(e) } } + +impl From for BBSPlusError { + fn from(e: SSError) -> Self { + Self::SSError(e) + } +} diff --git a/bbs_plus/src/threshold/base_ot_phase.rs b/bbs_plus/src/threshold/base_ot_phase.rs index c604ec8d..eaea8f45 100644 --- a/bbs_plus/src/threshold/base_ot_phase.rs +++ b/bbs_plus/src/threshold/base_ot_phase.rs @@ -247,7 +247,6 @@ pub mod tests { UniformRand, }; use blake2::Blake2b512; - use std::time::Instant; pub fn check_base_ot_keys( choices: &[Bit], diff --git a/bbs_plus/src/threshold/randomness_generation_phase.rs b/bbs_plus/src/threshold/randomness_generation_phase.rs index f75d0ba3..83540905 100644 --- a/bbs_plus/src/threshold/randomness_generation_phase.rs +++ b/bbs_plus/src/threshold/randomness_generation_phase.rs @@ -86,7 +86,7 @@ impl Phase1 { zero_shares, self.id, &others, - ); + )?; Ok((others, randomness, masked_signing_key_share, masked_r)) } diff --git a/bbs_plus/src/threshold/utils.rs b/bbs_plus/src/threshold/utils.rs index 0cc8a448..3eddef35 100644 --- a/bbs_plus/src/threshold/utils.rs +++ b/bbs_plus/src/threshold/utils.rs @@ -7,6 +7,7 @@ use oblivious_transfer_protocols::ParticipantId; #[cfg(feature = "parallel")] use rayon::prelude::*; +use secret_sharing_and_dkg::error::SSError; pub fn compute_masked_arguments_to_multiply( signing_key: &F, @@ -14,12 +15,12 @@ pub fn compute_masked_arguments_to_multiply( mut zero_shares: Vec, self_id: ParticipantId, others: &[ParticipantId], -) -> (Vec, Vec) { +) -> Result<(Vec, Vec), SSError> { let batch_size = r.len(); debug_assert_eq!(zero_shares.len(), 2 * batch_size); let alphas = zero_shares.drain(0..batch_size).collect::>(); let betas = zero_shares; - let lambda = secret_sharing_and_dkg::common::lagrange_basis_at_0::(&others, self_id); + let lambda = secret_sharing_and_dkg::common::lagrange_basis_at_0::(&others, self_id)?; 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))| { @@ -30,7 +31,7 @@ pub fn compute_masked_arguments_to_multiply( .collect::>() .into_iter() .multiunzip::<(Vec, Vec)>(); - (masked_signing_key_shares, masked_rs) + Ok((masked_signing_key_shares, masked_rs)) } pub fn compute_R_and_u( diff --git a/coconut/src/signature/aggregated_signature.rs b/coconut/src/signature/aggregated_signature.rs index f2a745a3..86c444cf 100644 --- a/coconut/src/signature/aggregated_signature.rs +++ b/coconut/src/signature/aggregated_signature.rs @@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize}; use ark_ec::pairing::Pairing; use ark_serialize::*; +use ark_std::cfg_iter; use utils::iter::validate; use super::{error::AggregatedPSError, ps_signature::Signature}; @@ -49,7 +50,9 @@ impl AggregatedSignature { if s.is_empty() { Err(AggregatedPSError::NoSignatures)? } - + if cfg_iter!(participant_ids).any(|p| *p == 0) { + return Err(AggregatedPSError::ParticipantIdCantBeZero); + } let l = lagrange_basis_at_0(participant_ids) .map(::into_bigint) .collect(); @@ -171,4 +174,18 @@ mod aggregated_signature_tests { Err(AggregatedPSError::NoSignatures) ); } + + #[test] + fn zero_participant_id() { + let mut rng = StdRng::seed_from_u64(0u64); + let h = G1::rand(&mut rng).into_affine(); + + let sig1 = Signature::::combine(h.clone(), G1::rand(&mut rng).into_affine()); + let sig2 = Signature::::combine(h.clone(), G1::rand(&mut rng).into_affine()); + let aggr_sigs = vec![(0, &sig1), (1, &sig2)]; + assert_eq!( + AggregatedSignature::new(aggr_sigs, &h), + Err(AggregatedPSError::ParticipantIdCantBeZero) + ) + } } diff --git a/coconut/src/signature/error.rs b/coconut/src/signature/error.rs index bc95493b..c25446a7 100644 --- a/coconut/src/signature/error.rs +++ b/coconut/src/signature/error.rs @@ -60,6 +60,7 @@ pub enum AggregatedPSError { InvalidSigma1For(ParticipantId), ParticipantIdsMustBeUniqueAndSorted(InvalidPair), PSError(PSError), + ParticipantIdCantBeZero, } impl From> for AggregatedPSError { diff --git a/legogroth16/Cargo.toml b/legogroth16/Cargo.toml index 03466abb..bd25e97d 100644 --- a/legogroth16/Cargo.toml +++ b/legogroth16/Cargo.toml @@ -23,7 +23,7 @@ ark-r1cs-std = { workspace = true, optional = true } tracing = { version = "0.1", default-features = false, features = [ "attributes" ], optional = true } derivative = { version = "2.0", features = ["use_core"], optional = true } rayon = { workspace = true, optional = true } -wasmer = { version = "4.3.0", optional = true, default-features = false } +wasmer = { version = "3.3.0", optional = true, default-features = false } fnv = { version = "1.0.3", default-features = false, optional = true } num-bigint = { version = "0.4", default-features = false, optional = true } log = "0.4" diff --git a/secret_sharing_and_dkg/src/common.rs b/secret_sharing_and_dkg/src/common.rs index 794d095b..a1952a0c 100644 --- a/secret_sharing_and_dkg/src/common.rs +++ b/secret_sharing_and_dkg/src/common.rs @@ -8,11 +8,14 @@ use serde::{Deserialize, Serialize}; use serde_with::serde_as; use zeroize::{Zeroize, ZeroizeOnDrop}; +use crate::error::SSError; #[cfg(feature = "parallel")] use rayon::prelude::*; +/// ShareId must be greater than 0 pub type ShareId = u16; +/// ParticipantId must be greater than 0 pub type ParticipantId = u16; /// Share used in Shamir secret sharing and Feldman verifiable secret sharing @@ -81,7 +84,7 @@ pub struct VerifiableShare { #[serde(bound = "")] pub struct VerifiableShares(pub Vec>); -/// Commitments to coefficients of the of the polynomial created during secret sharing. Each commitment +/// Commitments to coefficients of the polynomial created during secret sharing. Each commitment /// in the vector could be a Pedersen commitment or a computationally hiding and computationally binding /// commitment (scalar multiplication of the coefficient with a public group element). The former is used /// in Pedersen secret sharing and the latter in Feldman @@ -155,11 +158,15 @@ impl PublicKeyBase { /// Return the Lagrange basis polynomial at x = 0 given the `x` coordinates /// `(x_coords[0]) * (x_coords[1]) * ... / ((x_coords[0] - i) * (x_coords[1] - i) * ...)` /// Assumes all `x` coordinates are distinct and appropriate number of coordinates are provided -pub fn lagrange_basis_at_0(x_coords: &[ShareId], i: ShareId) -> F { +pub fn lagrange_basis_at_0(x_coords: &[ShareId], i: ShareId) -> Result { let mut numerator = F::one(); let mut denominator = F::one(); let i_f = F::from(i as u64); for x in x_coords { + // Ensure no x-coordinate can be 0 since we are evaluating basis polynomial at 0 + if *x == 0 { + return Err(SSError::XCordCantBeZero); + } if *x == i { continue; } @@ -168,20 +175,26 @@ pub fn lagrange_basis_at_0(x_coords: &[ShareId], i: ShareId) -> F denominator *= x - i_f; } denominator.inverse_in_place().unwrap(); - numerator * denominator + Ok(numerator * denominator) } /// Return the Lagrange basis polynomial at x = 0 for each of the given `x` coordinates. Faster than /// doing multiple calls to `lagrange_basis_at_0` -pub fn lagrange_basis_at_0_for_all(x_coords: Vec) -> Vec { +pub fn lagrange_basis_at_0_for_all( + x_coords: Vec, +) -> Result, SSError> { let x = cfg_into_iter!(x_coords.as_slice()) .map(|x| F::from(*x as u64)) .collect::>(); + // Ensure no x-coordinate can be 0 since we are evaluating basis polynomials at 0 + if cfg_iter!(x).any(|x_i| x_i.is_zero()) { + return Err(SSError::XCordCantBeZero); + } // Product of all `x`, i.e. \prod_{i}(x_i} let product = cfg_iter!(x).product::(); - cfg_into_iter!(x.clone()) + let r = cfg_into_iter!(x.clone()) .map(move |i| { let mut denominator = cfg_iter!(x) .filter(|&j| &i != j) @@ -195,21 +208,27 @@ pub fn lagrange_basis_at_0_for_all(x_coords: Vec) -> Vec denominator * numerator }) - .collect::>() + .collect::>(); + Ok(r) } #[cfg(test)] pub mod tests { use super::*; - use ark_bls12_381::Bls12_381; - use ark_ec::pairing::Pairing; + use ark_bls12_381::Fr; use ark_std::{ rand::{prelude::StdRng, SeedableRng}, UniformRand, }; use std::time::Instant; - type Fr = ::ScalarField; + #[test] + fn cannot_compute_lagrange_basis_at_0_with_0_as_x_coordinate() { + assert!(lagrange_basis_at_0::(&[0, 1, 2, 4], 2).is_err()); + assert!(lagrange_basis_at_0::(&[1, 0, 2, 4], 2).is_err()); + assert!(lagrange_basis_at_0_for_all::(vec![1, 0, 2, 4]).is_err()); + assert!(lagrange_basis_at_0_for_all::(vec![1, 3, 0, 4]).is_err()); + } #[test] fn compare_lagrange_basis_at_0() { @@ -222,12 +241,12 @@ pub mod tests { let start = Instant::now(); let single = cfg_iter!(x) - .map(|i| lagrange_basis_at_0(&x, *i)) + .map(|i| lagrange_basis_at_0(&x, *i).unwrap()) .collect::>(); println!("For {} x, single took {:?}", count, start.elapsed()); let start = Instant::now(); - let multiple = lagrange_basis_at_0_for_all(x); + let multiple = lagrange_basis_at_0_for_all(x).unwrap(); println!("For {} x, multiple took {:?}", count, start.elapsed()); assert_eq!(single, multiple); diff --git a/secret_sharing_and_dkg/src/distributed_dlog_check/maliciously_secure.rs b/secret_sharing_and_dkg/src/distributed_dlog_check/maliciously_secure.rs index 6386001f..9c120f46 100644 --- a/secret_sharing_and_dkg/src/distributed_dlog_check/maliciously_secure.rs +++ b/secret_sharing_and_dkg/src/distributed_dlog_check/maliciously_secure.rs @@ -209,16 +209,12 @@ macro_rules! impl_protocol { if threshold > len { return Err(SSError::BelowThreshold(threshold, len)); } - let share_ids = &shares[0..threshold as usize] + let share_ids = shares[0..threshold as usize] .iter() .map(|s| s.id) .collect::>(); - let result = cfg_into_iter!(&shares[0..threshold as usize]) - .map(|s| { - s.share * common::lagrange_basis_at_0::(&share_ids, s.id) - }) - .sum::>(); - Ok(result) + let basis = common::lagrange_basis_at_0_for_all::(share_ids)?; + Ok(cfg_into_iter!(basis).zip(cfg_into_iter!(shares)).map(|(b, s)| s.share * b).sum::>()) } } diff --git a/secret_sharing_and_dkg/src/distributed_dlog_check/semi_honest.rs b/secret_sharing_and_dkg/src/distributed_dlog_check/semi_honest.rs index f8ee5c67..52e08542 100644 --- a/secret_sharing_and_dkg/src/distributed_dlog_check/semi_honest.rs +++ b/secret_sharing_and_dkg/src/distributed_dlog_check/semi_honest.rs @@ -7,7 +7,7 @@ use crate::{ }; use ark_ec::{AffineRepr, CurveGroup, VariableBaseMSM}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use ark_std::{cfg_into_iter, rand::RngCore, vec, vec::Vec, UniformRand}; +use ark_std::{rand::RngCore, vec, vec::Vec, UniformRand}; use digest::Digest; use dock_crypto_utils::serde_utils::ArkObjectBytes; use schnorr_pok::{ @@ -122,13 +122,11 @@ impl ComputationShare { if threshold > len { return Err(SSError::BelowThreshold(threshold, len)); } - let share_ids = &shares[0..threshold as usize] + let share_ids = shares[0..threshold as usize] .iter() .map(|s| s.id) .collect::>(); - let basis = cfg_into_iter!(&shares[0..threshold as usize]) - .map(|s| common::lagrange_basis_at_0::(&share_ids, s.id)) - .collect::>(); + let basis = common::lagrange_basis_at_0_for_all::(share_ids)?; let shares = &shares[0..threshold as usize] .iter() .map(|s| s.share) diff --git a/secret_sharing_and_dkg/src/error.rs b/secret_sharing_and_dkg/src/error.rs index 5f401bf2..a67bd3d2 100644 --- a/secret_sharing_and_dkg/src/error.rs +++ b/secret_sharing_and_dkg/src/error.rs @@ -1,7 +1,8 @@ use crate::common::{ParticipantId, ShareId}; use schnorr_pok::error::SchnorrError; +use serde::Serialize; -#[derive(Debug)] +#[derive(Debug, Serialize)] pub enum SSError { InvalidThresholdOrTotal(ShareId, ShareId), BelowThreshold(ShareId, ShareId), @@ -22,6 +23,7 @@ pub enum SSError { InvalidComputationShareProof(ShareId), UnequalNoOfProofsAndShares(usize, usize), UnequalNoOfProofsAndCommitments(usize, usize), + XCordCantBeZero, } impl From for SSError { diff --git a/secret_sharing_and_dkg/src/feldman_dvss_dkg.rs b/secret_sharing_and_dkg/src/feldman_dvss_dkg.rs index 24da7afe..5b25bd31 100644 --- a/secret_sharing_and_dkg/src/feldman_dvss_dkg.rs +++ b/secret_sharing_and_dkg/src/feldman_dvss_dkg.rs @@ -1,6 +1,7 @@ //! Feldman Distributed Verifiable secret sharing and distributed key generation. use crate::{ + common, common::{lagrange_basis_at_0, CommitmentToCoefficients, ParticipantId, Share, ShareId}, error::SSError, }; @@ -181,9 +182,7 @@ pub fn reconstruct_threshold_public_key( let pkt = &public_keys[0..threshold as usize]; let pk_ids = pkt.iter().map(|(i, _)| *i).collect::>(); let pks = pkt.iter().map(|(_, pk)| *pk).collect::>(); - let lcs = cfg_iter!(pk_ids) - .map(|i| lagrange_basis_at_0::(&pk_ids, *i)) - .collect::>(); + let lcs = common::lagrange_basis_at_0_for_all::(pk_ids)?; Ok(G::Group::msm_unchecked(&pks, &lcs).into_affine()) } diff --git a/secret_sharing_and_dkg/src/shamir_ss.rs b/secret_sharing_and_dkg/src/shamir_ss.rs index a36df7c7..a5caf3cb 100644 --- a/secret_sharing_and_dkg/src/shamir_ss.rs +++ b/secret_sharing_and_dkg/src/shamir_ss.rs @@ -61,8 +61,10 @@ impl Shares { } let shares = &self.0[0..threshold as usize]; let share_ids = shares.iter().map(|s| s.id).collect::>(); - Ok(cfg_iter!(shares) - .map(|s| common::lagrange_basis_at_0::(&share_ids, s.id) * s.share) + let basis = common::lagrange_basis_at_0_for_all::(share_ids)?; + Ok(cfg_into_iter!(basis) + .zip(cfg_into_iter!(shares)) + .map(|(b, s)| b * s.share) .sum::()) } } @@ -71,11 +73,19 @@ impl Shares { pub mod tests { use super::*; use crate::common::Share; - use ark_bls12_381::{Bls12_381, Fr}; + use ark_bls12_381::Fr; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::rand::{rngs::StdRng, SeedableRng}; use test_utils::test_serialization; + #[test] + fn invalid_recombine_zero_id() { + let mut rng = StdRng::seed_from_u64(0u64); + let (_, mut shares, _) = deal_random_secret::<_, Fr>(&mut rng, 2, 3).unwrap(); + shares.0[0].id = 0; + assert!(shares.reconstruct_secret().is_err()); + } + #[test] fn shamir_secret_sharing() { let mut rng = StdRng::seed_from_u64(0u64);