├── rustfmt.toml ├── .gitignore ├── src ├── lib.rs ├── signature │ ├── utils │ │ ├── mod.rs │ │ ├── tests.rs │ │ ├── errors.rs │ │ └── hash.rs │ ├── mod.rs │ ├── schnorr │ │ ├── srs.rs │ │ └── mod.rs │ ├── bls │ │ ├── srs.rs │ │ └── mod.rs │ ├── algebraic │ │ ├── srs.rs │ │ ├── keypair.rs │ │ ├── public_key.rs │ │ ├── signature.rs │ │ └── mod.rs │ └── scheme │ │ └── mod.rs └── dkg │ ├── mod.rs │ ├── config.rs │ ├── dealer.rs │ ├── srs.rs │ ├── participant.rs │ ├── errors.rs │ ├── pvss.rs │ ├── share.rs │ ├── aggregator.rs │ └── node.rs ├── README.md ├── benches ├── bls.rs ├── signing.rs ├── dkg.rs └── huge_dkg.rs ├── Cargo.toml ├── .github └── workflows │ └── signature.yml ├── examples └── print_sizes.rs ├── LICENSE └── Cargo.lock /rustfmt.toml: -------------------------------------------------------------------------------- 1 | merge_imports = true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | .idea 4 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate ark_std; 3 | 4 | pub mod dkg; 5 | pub mod signature; 6 | -------------------------------------------------------------------------------- /src/signature/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod errors; 2 | pub mod hash; 3 | 4 | #[cfg(test)] 5 | pub mod tests; 6 | -------------------------------------------------------------------------------- /src/signature/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod algebraic; 2 | pub mod bls; 3 | pub mod scheme; 4 | pub mod schnorr; 5 | pub mod utils; 6 | -------------------------------------------------------------------------------- /src/dkg/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod aggregator; 2 | pub mod config; 3 | pub mod dealer; 4 | pub mod errors; 5 | pub mod node; 6 | pub mod participant; 7 | pub mod pvss; 8 | pub mod share; 9 | pub mod srs; 10 | -------------------------------------------------------------------------------- /src/dkg/config.rs: -------------------------------------------------------------------------------- 1 | use super::srs::SRS; 2 | use ark_ec::PairingEngine; 3 | 4 | #[derive(Clone)] 5 | pub struct Config { 6 | pub srs: SRS, 7 | pub u_1: E::G2Affine, 8 | pub degree: usize, 9 | } 10 | -------------------------------------------------------------------------------- /src/dkg/dealer.rs: -------------------------------------------------------------------------------- 1 | use crate::{dkg::participant::Participant, signature::scheme::BatchVerifiableSignatureScheme}; 2 | use ark_ec::PairingEngine; 3 | 4 | #[derive(Clone)] 5 | pub struct Dealer< 6 | E: PairingEngine, 7 | SSIG: BatchVerifiableSignatureScheme, 8 | > { 9 | pub private_key_sig: SSIG::Secret, 10 | pub accumulated_secret: E::G2Affine, 11 | pub participant: Participant, 12 | } 13 | -------------------------------------------------------------------------------- /src/signature/utils/tests.rs: -------------------------------------------------------------------------------- 1 | use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; 2 | use std::io::Cursor; 3 | 4 | pub fn check_serialization< 5 | T: CanonicalSerialize + CanonicalDeserialize + std::fmt::Debug + PartialEq, 6 | >( 7 | obj: T, 8 | ) { 9 | let mut obj_bytes = vec![]; 10 | obj.serialize(&mut obj_bytes).unwrap(); 11 | let deserialized_obj = T::deserialize(&mut Cursor::new(obj_bytes)).unwrap(); 12 | assert_eq!(obj, deserialized_obj); 13 | } 14 | -------------------------------------------------------------------------------- /src/dkg/srs.rs: -------------------------------------------------------------------------------- 1 | use crate::dkg::errors::DKGError; 2 | use ark_ec::{PairingEngine, ProjectiveCurve}; 3 | use ark_ff::UniformRand; 4 | use rand::Rng; 5 | 6 | #[derive(Clone)] 7 | pub struct SRS { 8 | pub g_g1: E::G1Affine, 9 | pub h_g2: E::G2Affine, 10 | } 11 | 12 | impl SRS { 13 | pub fn setup(rng: &mut R) -> Result> { 14 | Ok(Self { 15 | g_g1: E::G1Projective::rand(rng).into_affine(), 16 | h_g2: E::G2Projective::rand(rng).into_affine(), 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/dkg/participant.rs: -------------------------------------------------------------------------------- 1 | use crate::signature::scheme::BatchVerifiableSignatureScheme; 2 | use ark_ec::PairingEngine; 3 | 4 | #[derive(Clone)] 5 | pub enum ParticipantState { 6 | Dealer, 7 | DealerShared, 8 | 9 | Initial, 10 | Verified, 11 | } 12 | 13 | #[derive(Clone)] 14 | pub struct Participant< 15 | E: PairingEngine, 16 | SSIG: BatchVerifiableSignatureScheme, 17 | > { 18 | pub pairing_type: std::marker::PhantomData, 19 | pub id: usize, 20 | pub public_key_sig: SSIG::PublicKey, 21 | pub state: ParticipantState, 22 | } 23 | -------------------------------------------------------------------------------- /src/signature/schnorr/srs.rs: -------------------------------------------------------------------------------- 1 | use crate::signature::utils::errors::SignatureError; 2 | use ark_ec::AffineCurve; 3 | use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write}; 4 | use rand::Rng; 5 | 6 | #[derive(Debug, CanonicalSerialize, CanonicalDeserialize, Clone, PartialEq)] 7 | pub struct SRS { 8 | pub g_public_key: C, 9 | } 10 | 11 | impl SRS { 12 | pub fn setup(_: &mut R) -> Result { 13 | let srs = Self { 14 | g_public_key: C::prime_subgroup_generator(), 15 | }; 16 | Ok(srs) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Aggregatable DKG and VUF 2 | 3 | **WARNING: this code should not be used in production!** 4 | 5 | Implementation of [Aggregatable Distributed Key Generation](https://eprint.iacr.org/2021/005), a distributed key generation (DKG) protocol with aggregatable and publicly verifiable transcripts and a new efficient verifiable unpredictable function (VUF) that can be securely combined with it. 6 | 7 | ## Installation 8 | 9 | Install a recent stable Rust toolchain using [rustup](https://rustup.rs/). 10 | 11 | ## Testing 12 | 13 | Run `cargo test` to test both simple signing and aggregation. 14 | 15 | ## Benchmarks 16 | 17 | Run `cargo bench`. 18 | -------------------------------------------------------------------------------- /src/signature/bls/srs.rs: -------------------------------------------------------------------------------- 1 | use super::BLSSignatureScheme; 2 | use crate::signature::utils::errors::SignatureError; 3 | use ark_ec::AffineCurve; 4 | use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write}; 5 | use rand::Rng; 6 | 7 | #[derive(Debug, CanonicalSerialize, CanonicalDeserialize, Clone, PartialEq)] 8 | pub struct SRS { 9 | pub g_public_key: B::PublicKeyGroup, 10 | pub g_signature: B::SignatureGroup, 11 | } 12 | 13 | impl SRS { 14 | pub fn setup(_: &mut R) -> Result { 15 | let srs = Self { 16 | g_public_key: B::PublicKeyGroup::prime_subgroup_generator(), 17 | g_signature: B::SignatureGroup::prime_subgroup_generator(), 18 | }; 19 | Ok(srs) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/signature/algebraic/srs.rs: -------------------------------------------------------------------------------- 1 | use crate::signature::utils::errors::SignatureError; 2 | use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; 3 | use ark_ff::UniformRand; 4 | use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write}; 5 | use rand::Rng; 6 | 7 | #[derive(Debug, Clone, PartialEq, CanonicalSerialize, CanonicalDeserialize)] 8 | pub struct SRS { 9 | pub g_1_g2: E::G2Affine, 10 | pub h_g1: E::G1Affine, 11 | 12 | pub g_2_g2: E::G2Affine, 13 | pub g_3_g2: E::G2Affine, 14 | pub g_4_g2: E::G2Affine, 15 | } 16 | 17 | impl SRS { 18 | pub fn setup(rng: &mut R) -> Result { 19 | let srs = Self { 20 | g_1_g2: E::G2Affine::prime_subgroup_generator(), 21 | h_g1: E::G1Affine::prime_subgroup_generator(), 22 | 23 | g_2_g2: E::G2Projective::rand(rng).into_affine(), 24 | g_3_g2: E::G2Projective::rand(rng).into_affine(), 25 | g_4_g2: E::G2Projective::rand(rng).into_affine(), 26 | }; 27 | Ok(srs) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /benches/bls.rs: -------------------------------------------------------------------------------- 1 | use aggregatable_dkg::signature::{ 2 | bls::{srs::SRS, BLSSignature, BLSSignatureG1}, 3 | scheme::SignatureScheme, 4 | }; 5 | use ark_bls12_381::Bls12_381; 6 | use criterion::{criterion_group, criterion_main, Criterion}; 7 | use rand::thread_rng; 8 | 9 | pub fn criterion_benchmark(c: &mut Criterion) { 10 | let rng = &mut thread_rng(); 11 | let srs = SRS::>::setup(rng).unwrap(); 12 | let bls = BLSSignature { srs }; 13 | let keypair = bls.generate_keypair(rng).unwrap(); 14 | let message = b"hello"; 15 | 16 | let signature = bls.sign(rng, &keypair.0, &message[..]).unwrap(); 17 | c.bench_function("bls signing", |b| { 18 | b.iter(|| { 19 | let _signature = bls.sign(rng, &keypair.0, &message[..]).unwrap(); 20 | }); 21 | }); 22 | 23 | bls.verify(&keypair.1, &message[..], &signature).unwrap(); 24 | 25 | c.bench_function("bls verification", |b| { 26 | b.iter(|| { 27 | bls.verify(&keypair.1, &message[..], &signature).unwrap(); 28 | }) 29 | }); 30 | } 31 | 32 | criterion_group!(benches, criterion_benchmark); 33 | criterion_main!(benches); 34 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "aggregatable-dkg" 3 | version = "0.1.0" 4 | authors = [] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | ark-ff = { version = "^0.2.0", features = [ "std" ] } 9 | ark-ec = { version = "^0.2.0", features = [ "std" ] } 10 | ark-poly = { version = "^0.2.0", features = [ "std" ] } 11 | ark-serialize = { version = "^0.2.0", features = [ "std" ] } 12 | ark-std = { version = "^0.2.0", features = [ "std" ] } 13 | ark-bls12-381 = { version = "^0.2.0", features = [ "std" ] } 14 | thiserror = "1.0.19" 15 | rand = "0.7.3" 16 | rand_chacha = { version = "0.2.1" } 17 | once_cell = "^1.7" 18 | blake2s_simd = "0.5.10" 19 | 20 | [lib] 21 | bench = false 22 | 23 | [dev-dependencies] 24 | criterion = "0.3" 25 | 26 | [[bench]] 27 | name = "signing" 28 | harness = false 29 | 30 | [[bench]] 31 | name = "dkg" 32 | harness = false 33 | required-features = [ "dkg-bench" ] 34 | 35 | [[bench]] 36 | name = "bls" 37 | harness = false 38 | 39 | [features] 40 | asm = [ "ark-ff/asm" ] 41 | dkg-bench = [] 42 | huge-dkg-bench = [] 43 | print-trace = [ "ark-std/print-trace" ] 44 | 45 | [[bench]] 46 | name = "huge_dkg" 47 | harness = false 48 | required-features = [ "huge-dkg-bench" ] 49 | -------------------------------------------------------------------------------- /src/dkg/errors.rs: -------------------------------------------------------------------------------- 1 | use crate::signature::utils::errors::SignatureError; 2 | use ark_ec::PairingEngine; 3 | use ark_serialize::SerializationError; 4 | use thiserror::Error; 5 | 6 | #[derive(Error, Debug)] 7 | pub enum DKGError { 8 | #[error("Ratio incorrect")] 9 | RatioIncorrect, 10 | #[error("Evaluations are wrong: product = {0}")] 11 | EvaluationsCheckError(E::G1Affine), 12 | #[error("Could not generate evaluation domain")] 13 | EvaluationDomainError, 14 | #[error("Config, dealer and nodes had different SRSes")] 15 | DifferentSRS, 16 | #[error("Signature error: {0}")] 17 | SignatureError(#[from] SignatureError), 18 | #[error("Serialization error: {0}")] 19 | SerializationError(#[from] SerializationError), 20 | #[error("Invalid participant ID: {0}")] 21 | InvalidParticipantId(usize), 22 | #[error("Transcripts have different degree or number of participants: self.degree={0}, other.degree={1}, self.num_participants={2}, self.num_participants={3}")] 23 | TranscriptDifferentConfig(usize, usize, usize, usize), 24 | #[error("Transcripts have different commitments")] 25 | TranscriptDifferentCommitments, 26 | } 27 | -------------------------------------------------------------------------------- /src/signature/utils/errors.rs: -------------------------------------------------------------------------------- 1 | use ark_serialize::SerializationError; 2 | use std::fmt::Display; 3 | use thiserror::Error; 4 | 5 | #[derive(Debug)] 6 | pub enum VerifyProofEquation { 7 | Eq1, 8 | Eq2, 9 | Eq3, 10 | EqAllProbabilistic, 11 | EqProbabilistic, 12 | } 13 | 14 | impl Display for VerifyProofEquation { 15 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { 16 | match *self { 17 | VerifyProofEquation::Eq1 => f.write_str("Eq1"), 18 | VerifyProofEquation::Eq2 => f.write_str("Eq2"), 19 | VerifyProofEquation::Eq3 => f.write_str("Eq3"), 20 | VerifyProofEquation::EqAllProbabilistic => f.write_str("EqAllProbabilistic"), 21 | VerifyProofEquation::EqProbabilistic => f.write_str("EqProbabilistic"), 22 | } 23 | } 24 | } 25 | 26 | #[derive(Error, Debug)] 27 | pub enum SignatureError { 28 | #[error("Could not generate SRS")] 29 | SRSSetupError, 30 | #[error("Failed verifying equation `{0}`")] 31 | AlgebraicVerifyProof(VerifyProofEquation), 32 | #[error("Failed verifying BLS equation")] 33 | BLSVerify, 34 | #[error("Failed verifying Schnorr equation")] 35 | SchnorrVerify, 36 | #[error("Signature doesn't have an inverse")] 37 | SignatureDoesNotHaveInverse, 38 | #[error("SRS is different")] 39 | SRSDifferent, 40 | #[error("SerializationError: {0}")] 41 | SerializationError(#[from] SerializationError), 42 | #[error("Different lengths in batch verification: {0}, {1}, {2}")] 43 | BatchVerification(usize, usize, usize), 44 | } 45 | -------------------------------------------------------------------------------- /src/signature/utils/hash.rs: -------------------------------------------------------------------------------- 1 | use crate::signature::utils::errors::SignatureError; 2 | use ark_ec::AffineCurve; 3 | use ark_ff::{PrimeField, Zero}; 4 | use blake2s_simd::Params; 5 | use rand::{Rng, SeedableRng}; 6 | use rand_chacha::ChaChaRng; 7 | 8 | fn rng_from_message(personalization: &[u8], message: &[u8]) -> ChaChaRng { 9 | let hash = Params::new() 10 | .hash_length(32) 11 | .personal(personalization) 12 | .to_state() 13 | .update(message) 14 | .finalize(); 15 | let mut seed = [0u8; 32]; 16 | seed.copy_from_slice(hash.as_bytes()); 17 | let rng = ChaChaRng::from_seed(seed); 18 | rng 19 | } 20 | 21 | pub fn hash_to_group( 22 | personalization: &[u8], 23 | message: &[u8], 24 | ) -> Result { 25 | let mut rng = rng_from_message(personalization, message); 26 | loop { 27 | let bytes: Vec = (0..C::zero().serialized_size()) 28 | .map(|_| rng.gen()) 29 | .collect(); 30 | if let Some(p) = C::from_random_bytes(&bytes) { 31 | let scaled = p.mul_by_cofactor_to_projective(); 32 | if !scaled.is_zero() { 33 | return Ok(scaled); 34 | } 35 | } 36 | } 37 | } 38 | 39 | pub fn hash_to_field( 40 | personalization: &[u8], 41 | message: &[u8], 42 | ) -> Result { 43 | let mut rng = rng_from_message(personalization, message); 44 | loop { 45 | let bytes: Vec = (0..F::zero().serialized_size()) 46 | .map(|_| rng.gen()) 47 | .collect(); 48 | if let Some(p) = F::from_random_bytes(&bytes) { 49 | return Ok(p); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/dkg/pvss.rs: -------------------------------------------------------------------------------- 1 | use ark_ec::PairingEngine; 2 | use ark_ff::Zero; 3 | use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write}; 4 | 5 | #[derive(Clone, Debug, CanonicalSerialize, CanonicalDeserialize)] 6 | pub struct PVSSShare { 7 | pub f_i: Vec, 8 | pub u_i_2: E::G2Affine, 9 | pub a_i: Vec, 10 | pub y_i: Vec, 11 | } 12 | 13 | impl PVSSShare { 14 | pub fn empty(degree: usize, num_participants: usize) -> Self { 15 | PVSSShare { 16 | f_i: vec![E::G1Affine::zero(); degree + 1], 17 | u_i_2: E::G2Affine::zero(), 18 | a_i: vec![E::G1Affine::zero(); num_participants], 19 | y_i: vec![E::G2Affine::zero(); num_participants], 20 | } 21 | } 22 | 23 | pub fn aggregate(&self, other: &Self) -> Self { 24 | Self { 25 | f_i: self 26 | .f_i 27 | .iter() 28 | .zip(other.f_i.iter()) 29 | .map(|(f1, f2)| *f1 + *f2) 30 | .collect::>(), 31 | u_i_2: self.u_i_2 + other.u_i_2, 32 | a_i: self 33 | .a_i 34 | .iter() 35 | .zip(other.a_i.iter()) 36 | .map(|(a1, a2)| *a1 + *a2) 37 | .collect::>(), 38 | y_i: self 39 | .y_i 40 | .iter() 41 | .zip(other.y_i.iter()) 42 | .map(|(y1, y2)| *y1 + *y2) 43 | .collect::>(), 44 | } 45 | } 46 | } 47 | 48 | pub struct PVSSShareSecrets { 49 | pub f_0: E::Fr, 50 | pub my_secret: E::G2Affine, 51 | } 52 | -------------------------------------------------------------------------------- /src/signature/scheme/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::signature::utils::errors::SignatureError; 2 | use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; 3 | use rand::Rng; 4 | use std::fmt::Debug; 5 | 6 | pub trait SignatureScheme: Debug + Clone + PartialEq + Sized { 7 | type SRS: Clone; 8 | type Secret; 9 | type PublicKey: Clone + CanonicalSerialize + CanonicalDeserialize; 10 | type Signature: Clone + CanonicalSerialize + CanonicalDeserialize; 11 | 12 | fn from_srs(srs: Self::SRS) -> Result; 13 | fn generate_keypair( 14 | &self, 15 | rng: &mut R, 16 | ) -> Result<(Self::Secret, Self::PublicKey), SignatureError>; 17 | fn from_sk(&self, sk: &Self::Secret) 18 | -> Result<(Self::Secret, Self::PublicKey), SignatureError>; 19 | fn sign( 20 | &self, 21 | rng: &mut R, 22 | sk: &Self::Secret, 23 | message: &[u8], 24 | ) -> Result; 25 | fn verify( 26 | &self, 27 | public_key: &Self::PublicKey, 28 | message: &[u8], 29 | signature: &Self::Signature, 30 | ) -> Result<(), SignatureError>; 31 | } 32 | 33 | pub trait AggregatableSignatureScheme: SignatureScheme { 34 | fn aggregate_public_keys( 35 | &self, 36 | public_keys: &[&Self::PublicKey], 37 | ) -> Result; 38 | fn aggregate_signatures( 39 | &self, 40 | signatures: &[&Self::Signature], 41 | ) -> Result; 42 | } 43 | 44 | pub trait BatchVerifiableSignatureScheme: SignatureScheme { 45 | fn batch_verify( 46 | &self, 47 | rng: &mut R, 48 | public_keys: &[&Self::PublicKey], 49 | messages: &[&[u8]], 50 | signatures: &[&Self::Signature], 51 | ) -> Result<(), SignatureError>; 52 | } 53 | -------------------------------------------------------------------------------- /.github/workflows/signature.yml: -------------------------------------------------------------------------------- 1 | name: Signature 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | env: 8 | RUST_BACKTRACE: 1 9 | 10 | jobs: 11 | style: 12 | name: Check Style 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v1 17 | 18 | - name: Install Rust 19 | uses: actions-rs/toolchain@v1 20 | with: 21 | profile: minimal 22 | toolchain: nightly 23 | override: true 24 | components: rustfmt 25 | 26 | - name: cargo fmt --check 27 | uses: actions-rs/cargo@v1 28 | env: 29 | CARGO_NET_GIT_FETCH_WITH_CLI: true 30 | with: 31 | command: fmt 32 | args: --all -- --check 33 | 34 | test: 35 | name: Test 36 | runs-on: ubuntu-latest 37 | env: 38 | RUSTFLAGS: -Dwarnings 39 | strategy: 40 | matrix: 41 | rust: 42 | - stable 43 | # - nightly 44 | steps: 45 | - name: Checkout 46 | uses: actions/checkout@v2 47 | 48 | - name: Install Rust (${{ matrix.rust }}) 49 | uses: actions-rs/toolchain@v1 50 | with: 51 | profile: minimal 52 | toolchain: ${{ matrix.rust }} 53 | override: true 54 | 55 | - name: Check examples 56 | uses: actions-rs/cargo@v1 57 | env: 58 | CARGO_NET_GIT_FETCH_WITH_CLI: true 59 | with: 60 | command: check 61 | args: --examples --all 62 | 63 | - name: Check examples with all features on stable 64 | uses: actions-rs/cargo@v1 65 | with: 66 | command: check 67 | args: --examples --all-features --all 68 | if: matrix.rust == 'stable' 69 | 70 | - name: Test 71 | uses: actions-rs/cargo@v1 72 | with: 73 | command: test 74 | args: --release --all --no-fail-fast 75 | 76 | - name: Bench compile 77 | uses: actions-rs/cargo@v1 78 | with: 79 | command: bench 80 | args: --features huge-dkg-bench dkg-bench --no-run 81 | -------------------------------------------------------------------------------- /benches/signing.rs: -------------------------------------------------------------------------------- 1 | use aggregatable_dkg::signature::algebraic::{keypair::Keypair, srs::SRS}; 2 | use ark_bls12_381::Bls12_381; 3 | use criterion::{criterion_group, criterion_main, Criterion}; 4 | use rand::thread_rng; 5 | 6 | pub fn criterion_benchmark(c: &mut Criterion) { 7 | let rng = &mut thread_rng(); 8 | let srs = SRS::::setup(rng).unwrap(); 9 | let keypair = Keypair::generate_keypair(rng, srs).unwrap(); 10 | let message = b"hello"; 11 | 12 | let proven_public_key = keypair.prove_key().unwrap(); 13 | proven_public_key.verify().unwrap(); 14 | 15 | let signature = keypair.sign(&message[..]).unwrap(); 16 | signature 17 | .verify_and_derive(proven_public_key.clone(), &message[..]) 18 | .unwrap(); 19 | 20 | c.bench_function("signature key proving", |b| { 21 | b.iter(|| keypair.prove_key().unwrap()) 22 | }); 23 | 24 | c.bench_function("signature key verification", |b| { 25 | b.iter(|| { 26 | proven_public_key.verify().unwrap(); 27 | }) 28 | }); 29 | 30 | let mut rng = thread_rng(); 31 | c.bench_function("signature probabilistic key verification", |b| { 32 | b.iter(|| { 33 | proven_public_key 34 | .verify_probabilistically(&mut rng) 35 | .unwrap(); 36 | }) 37 | }); 38 | 39 | c.bench_function("signature signing", |b| { 40 | b.iter(|| { 41 | keypair.sign(&message[..]).unwrap(); 42 | }) 43 | }); 44 | 45 | c.bench_function("signature verification", |b| { 46 | b.iter(|| { 47 | signature 48 | .verify(proven_public_key.clone(), &message[..]) 49 | .unwrap(); 50 | }) 51 | }); 52 | 53 | c.bench_function("signature verification and derivation", |b| { 54 | b.iter(|| { 55 | signature 56 | .verify_and_derive(proven_public_key.clone(), &message[..]) 57 | .unwrap(); 58 | }) 59 | }); 60 | 61 | let mut rng = thread_rng(); 62 | c.bench_function("signature probabilistic all verification", |b| { 63 | b.iter(|| { 64 | signature 65 | .verify_all_probabilistically(&mut rng, proven_public_key.clone(), &message[..]) 66 | .unwrap(); 67 | }) 68 | }); 69 | 70 | c.bench_function( 71 | "signature probabilistic all verification and derivation", 72 | |b| { 73 | b.iter(|| { 74 | signature 75 | .verify_all_probabilistically(&mut rng, proven_public_key.clone(), &message[..]) 76 | .unwrap(); 77 | 78 | signature 79 | .derive(proven_public_key.clone(), &message[..]) 80 | .unwrap(); 81 | }) 82 | }, 83 | ); 84 | } 85 | 86 | criterion_group!(benches, criterion_benchmark); 87 | criterion_main!(benches); 88 | -------------------------------------------------------------------------------- /src/signature/algebraic/keypair.rs: -------------------------------------------------------------------------------- 1 | use super::{ 2 | public_key::{KeyProof, ProvenPublicKey, PublicKey}, 3 | signature::{Signature, SignatureProof}, 4 | srs::SRS, 5 | PERSONALIZATION, 6 | }; 7 | use crate::signature::utils::{errors::SignatureError, hash::hash_to_group}; 8 | use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; 9 | use ark_ff::{PrimeField, UniformRand}; 10 | use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write}; 11 | use rand::Rng; 12 | use std::ops::Neg; 13 | 14 | #[derive(Debug, Clone, PartialEq, CanonicalSerialize, CanonicalDeserialize)] 15 | pub struct PrivateKey { 16 | pub sk: E::G2Affine, 17 | } 18 | 19 | #[derive(Debug, Clone, PartialEq, CanonicalSerialize, CanonicalDeserialize)] 20 | pub struct Keypair { 21 | pub srs: SRS, 22 | pub alpha: E::Fr, 23 | pub beta: E::Fr, 24 | pub private: PrivateKey, 25 | pub public: PublicKey, 26 | } 27 | 28 | impl Keypair { 29 | pub fn generate_keypair(rng: &mut R, srs: SRS) -> Result { 30 | let a = E::Fr::rand(rng); 31 | let a_g2 = srs.g_1_g2.mul(a.clone()); 32 | let private_key = PrivateKey { 33 | sk: a_g2.into_affine(), 34 | }; 35 | let a_g1 = srs.h_g1.mul(a); 36 | let public_key = PublicKey { 37 | srs: srs.clone(), 38 | pk: a_g1.into_affine(), 39 | }; 40 | let keypair = Keypair { 41 | alpha: E::Fr::rand(rng), 42 | beta: E::Fr::rand(rng), 43 | srs: srs.clone(), 44 | private: private_key, 45 | public: public_key, 46 | }; 47 | Ok(keypair) 48 | } 49 | 50 | pub fn refresh_randomness(&self, rng: &mut R) -> Result { 51 | let keypair = Keypair { 52 | alpha: E::Fr::rand(rng), 53 | beta: E::Fr::rand(rng), 54 | srs: self.srs.clone(), 55 | private: self.private.clone(), 56 | public: self.public.clone(), 57 | }; 58 | Ok(keypair) 59 | } 60 | 61 | pub fn sign(&self, message: &[u8]) -> Result, SignatureError> { 62 | let hashed_message = hash_to_group::(PERSONALIZATION, message)?; 63 | let signature_proof = self.prove_signature(hashed_message)?; 64 | 65 | let signature = Signature { signature_proof }; 66 | 67 | Ok(signature) 68 | } 69 | 70 | pub fn prove_key(&self) -> Result, SignatureError> { 71 | let pi_1_g2 = self.srs.g_1_g2.mul(self.alpha.neg()) + &self.srs.g_2_g2.mul(self.beta.neg()); 72 | let pi_2_g2 = self.srs.g_3_g2.mul(self.alpha.neg()) 73 | + &self.srs.g_4_g2.mul(self.beta.neg()) 74 | + &self.private.sk.into_projective(); 75 | let pi_1_g1 = self.srs.h_g1.mul(self.alpha.clone()); 76 | let pi_3_g1 = self.srs.h_g1.mul(self.beta.clone()); 77 | 78 | let key_proof = KeyProof { 79 | pi_1_g2: pi_1_g2.into_affine(), 80 | pi_2_g2: pi_2_g2.into_affine(), 81 | pi_1_g1: pi_1_g1.into_affine(), 82 | pi_3_g1: pi_3_g1.into_affine(), 83 | }; 84 | 85 | let proven_public_key = ProvenPublicKey { 86 | public_key: self.public.clone(), 87 | key_proof, 88 | }; 89 | Ok(proven_public_key) 90 | } 91 | 92 | fn prove_signature( 93 | &self, 94 | hashed_message: E::G1Projective, 95 | ) -> Result, SignatureError> { 96 | let pi_2_g1 = hashed_message.mul(self.alpha.into_repr()); 97 | let pi_4_g1 = hashed_message.mul(self.beta.into_repr()); 98 | 99 | let signature_proof = SignatureProof { 100 | pi_2_g1: pi_2_g1.into_affine(), 101 | pi_4_g1: pi_4_g1.into_affine(), 102 | }; 103 | 104 | Ok(signature_proof) 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/dkg/share.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | dkg::{errors::DKGError, pvss::PVSSShare}, 3 | signature::scheme::BatchVerifiableSignatureScheme, 4 | }; 5 | use ark_ec::PairingEngine; 6 | use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write}; 7 | use ark_std::collections::BTreeMap; 8 | use std::io::Cursor; 9 | 10 | #[derive(CanonicalSerialize, CanonicalDeserialize, Clone)] 11 | pub struct DKGShare< 12 | E: PairingEngine, 13 | SPOK: BatchVerifiableSignatureScheme, 14 | SSIG: BatchVerifiableSignatureScheme, 15 | > { 16 | pub participant_id: usize, 17 | pub pvss_share: PVSSShare, 18 | pub c_i: E::G1Affine, 19 | pub c_i_pok: SPOK::Signature, 20 | pub signature_on_c_i: SSIG::Signature, 21 | } 22 | 23 | #[derive(CanonicalSerialize, CanonicalDeserialize, Clone)] 24 | pub struct DKGTranscriptParticipant< 25 | E: PairingEngine, 26 | SPOK: BatchVerifiableSignatureScheme, 27 | SSIG: BatchVerifiableSignatureScheme, 28 | > { 29 | pub c_i: E::G1Affine, 30 | pub weight: u64, 31 | pub c_i_pok: SPOK::Signature, 32 | pub signature_on_c_i: SSIG::Signature, 33 | } 34 | 35 | #[derive(CanonicalSerialize, CanonicalDeserialize, Clone)] 36 | pub struct DKGTranscript< 37 | E: PairingEngine, 38 | SPOK: BatchVerifiableSignatureScheme, 39 | SSIG: BatchVerifiableSignatureScheme, 40 | > { 41 | pub degree: usize, 42 | pub num_participants: usize, 43 | pub contributions: BTreeMap>, 44 | pub pvss_share: PVSSShare, 45 | } 46 | 47 | pub fn message_from_c_i(c_i: E::G1Affine) -> Result, DKGError> { 48 | let mut message_writer = Cursor::new(vec![]); 49 | c_i.serialize(&mut message_writer)?; 50 | Ok(message_writer.get_ref().to_vec()) 51 | } 52 | 53 | impl< 54 | E: PairingEngine, 55 | SPOK: BatchVerifiableSignatureScheme, 56 | SSIG: BatchVerifiableSignatureScheme, 57 | > DKGTranscript 58 | { 59 | pub fn empty(degree: usize, num_participants: usize) -> Self { 60 | Self { 61 | degree, 62 | num_participants, 63 | contributions: BTreeMap::new(), 64 | pvss_share: PVSSShare::empty(degree, num_participants), 65 | } 66 | } 67 | 68 | pub fn aggregate(&self, other: &Self) -> Result> { 69 | if self.degree != other.degree || self.num_participants != other.num_participants { 70 | return Err(DKGError::TranscriptDifferentConfig( 71 | self.degree, 72 | other.degree, 73 | self.num_participants, 74 | other.num_participants, 75 | )); 76 | } 77 | let contributions = (0..self.num_participants) 78 | .map( 79 | |i| match (self.contributions.get(&i), other.contributions.get(&i)) { 80 | (Some(a), Some(b)) => { 81 | if a.c_i != b.c_i { 82 | return Err(DKGError::TranscriptDifferentCommitments); 83 | } 84 | let transcript_participant = DKGTranscriptParticipant { 85 | c_i: a.c_i, 86 | weight: a.weight + b.weight, 87 | c_i_pok: a.c_i_pok.clone(), 88 | signature_on_c_i: a.signature_on_c_i.clone(), 89 | }; 90 | Ok(Some((i, transcript_participant))) 91 | } 92 | (Some(a), None) => Ok(Some((i, a.clone()))), 93 | (None, Some(b)) => Ok(Some((i, b.clone()))), 94 | (None, None) => Ok(None), 95 | }, 96 | ) 97 | .collect::, _>>()? 98 | .into_iter() 99 | .filter_map(|e| e) 100 | .collect::>(); 101 | let aggregated = Self { 102 | degree: self.degree, 103 | num_participants: self.num_participants, 104 | contributions: contributions.into_iter().collect(), 105 | pvss_share: self.pvss_share.aggregate(&other.pvss_share), 106 | }; 107 | Ok(aggregated) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/signature/algebraic/public_key.rs: -------------------------------------------------------------------------------- 1 | use super::srs::SRS; 2 | use crate::signature::utils::errors::{SignatureError, VerifyProofEquation}; 3 | use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; 4 | use ark_ff::{One, PrimeField, UniformRand, Zero}; 5 | use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write}; 6 | use rand::Rng; 7 | use std::ops::Neg; 8 | 9 | #[derive(Debug, Clone, PartialEq, CanonicalSerialize, CanonicalDeserialize)] 10 | pub struct PublicKey { 11 | pub srs: SRS, 12 | pub pk: E::G1Affine, 13 | } 14 | 15 | #[derive(Debug, Clone, PartialEq, CanonicalSerialize, CanonicalDeserialize)] 16 | pub struct ProvenPublicKey { 17 | pub public_key: PublicKey, 18 | pub key_proof: KeyProof, 19 | } 20 | 21 | #[derive(Debug, Clone, PartialEq, CanonicalSerialize, CanonicalDeserialize)] 22 | pub struct KeyProof { 23 | pub pi_1_g2: E::G2Affine, 24 | pub pi_2_g2: E::G2Affine, 25 | pub pi_1_g1: E::G1Affine, 26 | pub pi_3_g1: E::G1Affine, 27 | } 28 | 29 | impl ProvenPublicKey { 30 | pub fn aggregate(public_keys: &[Self], srs: SRS) -> Result { 31 | let zero_proven_public_key = Self { 32 | public_key: PublicKey { 33 | srs, 34 | pk: E::G1Affine::zero(), 35 | }, 36 | key_proof: KeyProof { 37 | pi_1_g2: E::G2Affine::zero(), 38 | pi_2_g2: E::G2Affine::zero(), 39 | pi_1_g1: E::G1Affine::zero(), 40 | pi_3_g1: E::G1Affine::zero(), 41 | }, 42 | }; 43 | let aggregated_public_key = 44 | public_keys 45 | .into_iter() 46 | .try_fold(zero_proven_public_key, |acc, pk| { 47 | if acc.public_key.srs != pk.public_key.srs { 48 | return Err(SignatureError::SRSDifferent); 49 | } 50 | Ok(ProvenPublicKey { 51 | public_key: PublicKey { 52 | srs: acc.public_key.srs, 53 | pk: acc.public_key.pk + pk.public_key.pk.clone(), 54 | }, 55 | key_proof: KeyProof { 56 | pi_1_g2: acc.key_proof.pi_1_g2 + pk.key_proof.pi_1_g2.clone(), 57 | pi_2_g2: acc.key_proof.pi_2_g2 + pk.key_proof.pi_2_g2.clone(), 58 | pi_1_g1: acc.key_proof.pi_1_g1 + pk.key_proof.pi_1_g1.clone(), 59 | pi_3_g1: acc.key_proof.pi_3_g1 + pk.key_proof.pi_3_g1.clone(), 60 | }, 61 | }) 62 | })?; 63 | 64 | Ok(aggregated_public_key) 65 | } 66 | 67 | pub fn verify(&self) -> Result<(), SignatureError> { 68 | let eq1 = vec![ 69 | ( 70 | self.public_key.srs.h_g1.into(), 71 | self.key_proof.pi_1_g2.into(), 72 | ), 73 | ( 74 | self.key_proof.pi_1_g1.into(), 75 | self.public_key.srs.g_1_g2.into(), 76 | ), 77 | ( 78 | self.key_proof.pi_3_g1.into(), 79 | self.public_key.srs.g_2_g2.into(), 80 | ), 81 | ]; 82 | if !E::product_of_pairings(eq1.iter()).is_one() { 83 | return Err(SignatureError::AlgebraicVerifyProof( 84 | VerifyProofEquation::Eq1, 85 | )); 86 | } 87 | let eq3 = vec![ 88 | ( 89 | self.public_key.srs.h_g1.into(), 90 | self.key_proof.pi_2_g2.into(), 91 | ), 92 | ( 93 | self.key_proof.pi_1_g1.into(), 94 | self.public_key.srs.g_3_g2.into(), 95 | ), 96 | ( 97 | self.key_proof.pi_3_g1.into(), 98 | self.public_key.srs.g_4_g2.into(), 99 | ), 100 | ( 101 | self.public_key.pk.into(), 102 | self.public_key.srs.g_1_g2.neg().into(), 103 | ), 104 | ]; 105 | if !E::product_of_pairings(eq3.iter()).is_one() { 106 | return Err(SignatureError::AlgebraicVerifyProof( 107 | VerifyProofEquation::Eq3, 108 | )); 109 | } 110 | 111 | Ok(()) 112 | } 113 | 114 | pub fn verify_probabilistically(&self, rng: &mut R) -> Result<(), SignatureError> { 115 | let r = E::Fr::rand(rng); 116 | let eq = vec![ 117 | ( 118 | self.public_key 119 | .srs 120 | .h_g1 121 | .mul(r.into_repr()) 122 | .into_affine() 123 | .into(), 124 | self.key_proof.pi_1_g2.into(), 125 | ), 126 | ( 127 | (self.public_key.pk.neg().into_projective() 128 | + &self.key_proof.pi_1_g1.mul(r.into_repr())) 129 | .into_affine() 130 | .into(), 131 | self.public_key.srs.g_1_g2.into(), 132 | ), 133 | ( 134 | self.key_proof 135 | .pi_3_g1 136 | .mul(r.into_repr()) 137 | .into_affine() 138 | .into(), 139 | self.public_key.srs.g_2_g2.into(), 140 | ), 141 | ( 142 | self.public_key.srs.h_g1.into(), 143 | self.key_proof.pi_2_g2.into(), 144 | ), 145 | ( 146 | self.key_proof.pi_1_g1.into(), 147 | self.public_key.srs.g_3_g2.into(), 148 | ), 149 | ( 150 | self.key_proof.pi_3_g1.into(), 151 | self.public_key.srs.g_4_g2.into(), 152 | ), 153 | ]; 154 | if !E::product_of_pairings(eq.iter()).is_one() { 155 | return Err(SignatureError::AlgebraicVerifyProof( 156 | VerifyProofEquation::EqProbabilistic, 157 | )); 158 | } 159 | 160 | Ok(()) 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/signature/algebraic/signature.rs: -------------------------------------------------------------------------------- 1 | use super::{public_key::ProvenPublicKey, PERSONALIZATION}; 2 | use crate::signature::utils::{ 3 | errors::{SignatureError, VerifyProofEquation}, 4 | hash::hash_to_group, 5 | }; 6 | use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; 7 | use ark_ff::{One, PrimeField, UniformRand, Zero}; 8 | use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write}; 9 | use rand::Rng; 10 | use std::ops::Neg; 11 | 12 | #[derive(Debug, Clone, PartialEq, CanonicalSerialize, CanonicalDeserialize)] 13 | pub struct Signature { 14 | pub signature_proof: SignatureProof, 15 | } 16 | 17 | #[derive(Debug, Clone, PartialEq, CanonicalSerialize, CanonicalDeserialize)] 18 | pub struct SignatureProof { 19 | pub pi_2_g1: E::G1Affine, 20 | pub pi_4_g1: E::G1Affine, 21 | } 22 | 23 | impl Default for Signature { 24 | fn default() -> Self { 25 | Signature { 26 | signature_proof: SignatureProof { 27 | pi_2_g1: E::G1Affine::zero(), 28 | pi_4_g1: E::G1Affine::zero(), 29 | }, 30 | } 31 | } 32 | } 33 | 34 | impl Signature { 35 | pub fn verify_and_derive( 36 | &self, 37 | public_key: ProvenPublicKey, 38 | message: &[u8], 39 | ) -> Result { 40 | let hashed_message = hash_to_group::(PERSONALIZATION, message)?; 41 | self.verify_proof(public_key.clone(), hashed_message)?; 42 | 43 | self.derive(public_key, message) 44 | } 45 | 46 | pub fn verify( 47 | &self, 48 | public_key: ProvenPublicKey, 49 | message: &[u8], 50 | ) -> Result<(), SignatureError> { 51 | let hashed_message = hash_to_group::(PERSONALIZATION, message)?; 52 | self.verify_proof(public_key.clone(), hashed_message) 53 | } 54 | 55 | pub fn derive( 56 | &self, 57 | public_key: ProvenPublicKey, 58 | message: &[u8], 59 | ) -> Result { 60 | let hashed_message = hash_to_group::(PERSONALIZATION, message)?; 61 | let sig_elements = vec![ 62 | ( 63 | hashed_message.into_affine().into(), 64 | public_key.key_proof.pi_2_g2.into(), 65 | ), 66 | ( 67 | self.signature_proof.pi_2_g1.into(), 68 | public_key.public_key.srs.g_3_g2.into(), 69 | ), 70 | ( 71 | self.signature_proof.pi_4_g1.into(), 72 | public_key.public_key.srs.g_4_g2.into(), 73 | ), 74 | ]; 75 | let sig = E::product_of_pairings(sig_elements.iter()); 76 | 77 | Ok(sig) 78 | } 79 | 80 | fn verify_proof( 81 | &self, 82 | public_key: ProvenPublicKey, 83 | hashed_message: E::G1Projective, 84 | ) -> Result<(), SignatureError> { 85 | let eq2 = vec![ 86 | ( 87 | hashed_message.into_affine().into(), 88 | public_key.key_proof.pi_1_g2.into(), 89 | ), 90 | ( 91 | self.signature_proof.pi_2_g1.into(), 92 | public_key.public_key.srs.g_1_g2.into(), 93 | ), 94 | ( 95 | self.signature_proof.pi_4_g1.into(), 96 | public_key.public_key.srs.g_2_g2.into(), 97 | ), 98 | ]; 99 | if !E::product_of_pairings(eq2.iter()).is_one() { 100 | return Err(SignatureError::AlgebraicVerifyProof( 101 | VerifyProofEquation::Eq2, 102 | )); 103 | } 104 | 105 | Ok(()) 106 | } 107 | 108 | pub fn verify_all_probabilistically( 109 | &self, 110 | rng: &mut R, 111 | public_key: ProvenPublicKey, 112 | message: &[u8], 113 | ) -> Result<(), SignatureError> { 114 | let hashed_message = hash_to_group::(PERSONALIZATION, message)?; 115 | let r = E::Fr::rand(rng); 116 | let r2 = E::Fr::rand(rng); 117 | let eq = vec![ 118 | ( 119 | (hashed_message.into_affine().mul(r2.into_repr()) 120 | + &public_key.public_key.srs.h_g1.mul(r.into_repr())) 121 | .into_affine() 122 | .into(), 123 | public_key.key_proof.pi_1_g2.into(), 124 | ), 125 | ( 126 | (public_key.public_key.pk.neg().into_projective() 127 | + &self.signature_proof.pi_2_g1.mul(r2.into_repr()) 128 | + &public_key.key_proof.pi_1_g1.mul(r.into_repr())) 129 | .into_affine() 130 | .into(), 131 | public_key.public_key.srs.g_1_g2.into(), 132 | ), 133 | ( 134 | (self.signature_proof.pi_4_g1.mul(r2.into_repr()) 135 | + &public_key.key_proof.pi_3_g1.mul(r.into_repr())) 136 | .into_affine() 137 | .into(), 138 | public_key.public_key.srs.g_2_g2.into(), 139 | ), 140 | ( 141 | public_key.public_key.srs.h_g1.into(), 142 | public_key.key_proof.pi_2_g2.into(), 143 | ), 144 | ( 145 | public_key.key_proof.pi_1_g1.into(), 146 | public_key.public_key.srs.g_3_g2.into(), 147 | ), 148 | ( 149 | public_key.key_proof.pi_3_g1.into(), 150 | public_key.public_key.srs.g_4_g2.into(), 151 | ), 152 | ]; 153 | if !E::product_of_pairings(eq.iter()).is_one() { 154 | return Err(SignatureError::AlgebraicVerifyProof( 155 | VerifyProofEquation::EqAllProbabilistic, 156 | )); 157 | } 158 | 159 | Ok(()) 160 | } 161 | 162 | pub fn aggregate(signatures: &[Self]) -> Result { 163 | let aggregated_signature = 164 | signatures 165 | .into_iter() 166 | .fold(Self::default(), |acc, s| Signature { 167 | signature_proof: SignatureProof { 168 | pi_2_g1: acc.signature_proof.pi_2_g1 + s.signature_proof.pi_2_g1.clone(), 169 | pi_4_g1: acc.signature_proof.pi_4_g1 + s.signature_proof.pi_4_g1.clone(), 170 | }, 171 | }); 172 | Ok(aggregated_signature) 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /examples/print_sizes.rs: -------------------------------------------------------------------------------- 1 | use ark_bls12_381::{Bls12_381, Fr, G1Affine, G2Affine, G2Projective}; 2 | use ark_ec::{AffineCurve, ProjectiveCurve}; 3 | use ark_ff::{PrimeField, UniformRand, Zero}; 4 | use ark_serialize::CanonicalSerialize; 5 | 6 | use aggregatable_dkg::{ 7 | dkg::{ 8 | config::Config, 9 | dealer::Dealer, 10 | errors::DKGError, 11 | participant::{Participant, ParticipantState}, 12 | pvss::PVSSShare, 13 | share::{message_from_c_i, DKGTranscript, DKGTranscriptParticipant}, 14 | srs::SRS as DKGSRS, 15 | }, 16 | signature::{ 17 | algebraic::{keypair::Keypair, srs::SRS}, 18 | bls::{srs::SRS as BLSSRS, BLSSignature, BLSSignatureG1, BLSSignatureG2}, 19 | scheme::{BatchVerifiableSignatureScheme, SignatureScheme}, 20 | schnorr::{srs::SRS as SchnorrSRS, SchnorrSignature}, 21 | }, 22 | }; 23 | use ark_poly::{EvaluationDomain, Radix2EvaluationDomain}; 24 | use rand::thread_rng; 25 | use std::marker::PhantomData; 26 | 27 | fn print_aggregatable_dkg_sizes() { 28 | let rng = &mut thread_rng(); 29 | let srs = SRS::::setup(rng).unwrap(); 30 | let keypair = Keypair::generate_keypair(rng, srs).unwrap(); 31 | let message = b"hello"; 32 | 33 | let proven_public_key = keypair.prove_key().unwrap(); 34 | proven_public_key.verify().unwrap(); 35 | 36 | let signature = keypair.sign(&message[..]).unwrap(); 37 | signature 38 | .verify_and_derive(proven_public_key.clone(), &message[..]) 39 | .unwrap(); 40 | 41 | let mut public_key_bytes = vec![]; 42 | keypair.public.pk.serialize(&mut public_key_bytes).unwrap(); 43 | println!("Algebraic public key size: {}", public_key_bytes.len()); 44 | 45 | let mut key_proof_bytes = vec![]; 46 | proven_public_key 47 | .key_proof 48 | .serialize(&mut key_proof_bytes) 49 | .unwrap(); 50 | println!("Algebraic key proof size: {}", key_proof_bytes.len()); 51 | 52 | let mut signature_bytes = vec![]; 53 | signature 54 | .signature_proof 55 | .serialize(&mut signature_bytes) 56 | .unwrap(); 57 | println!("Algebraic signature size: {}", signature_bytes.len()); 58 | } 59 | 60 | fn print_bls_signature_sizes() { 61 | let rng = &mut thread_rng(); 62 | let srs = BLSSRS::>::setup(rng).unwrap(); 63 | let bls = BLSSignature { srs: srs.clone() }; 64 | let keypair = bls.generate_keypair(rng).unwrap(); 65 | let message = b"hello"; 66 | let signature = bls.sign(rng, &keypair.0, &message[..]).unwrap(); 67 | 68 | let mut public_key_bytes = vec![]; 69 | keypair.1.serialize(&mut public_key_bytes).unwrap(); 70 | println!("BLS public key size: {}", public_key_bytes.len()); 71 | 72 | let mut signature_bytes = vec![]; 73 | signature.serialize(&mut signature_bytes).unwrap(); 74 | println!("BLS signature size: {}", signature_bytes.len()); 75 | } 76 | 77 | fn print_transcript_size< 78 | SPOK: BatchVerifiableSignatureScheme, 79 | SSIG: BatchVerifiableSignatureScheme, 80 | >( 81 | num_nodes: usize, 82 | tag: &str, 83 | srs: DKGSRS, 84 | spok: SPOK, 85 | ssig: SSIG, 86 | ) { 87 | let degree = (2 * num_nodes + 2) / 3; 88 | let rng = &mut thread_rng(); 89 | 90 | let u_1 = G2Projective::rand(rng).into_affine(); 91 | let dkg_config = Config { 92 | srs: srs.clone(), 93 | u_1, 94 | degree, 95 | }; 96 | 97 | let mut dealers = vec![]; 98 | for i in 0..num_nodes { 99 | let dealer_keypair_sig = ssig.generate_keypair(rng).unwrap(); 100 | let participant = Participant { 101 | pairing_type: PhantomData, 102 | id: i, 103 | public_key_sig: dealer_keypair_sig.1, 104 | state: ParticipantState::Dealer, 105 | }; 106 | let dealer = Dealer:: { 107 | private_key_sig: dealer_keypair_sig.0, 108 | accumulated_secret: G2Projective::zero().into_affine(), 109 | participant, 110 | }; 111 | 112 | dealers.push(dealer); 113 | } 114 | 115 | let participants = dealers 116 | .iter() 117 | .map(|d| d.participant.clone()) 118 | .collect::>(); 119 | let num_participants = participants.len(); 120 | 121 | let mut transcript = DKGTranscript::::empty(degree, num_participants); 122 | let mut accumulated_r = Fr::zero(); 123 | for i in 0..num_participants { 124 | let r = Fr::rand(rng); 125 | let c = dkg_config.srs.g_g1.mul(r.into_repr()).into_affine(); 126 | 127 | let pok_keypair = spok.from_sk(&r).unwrap(); 128 | let pok = spok 129 | .sign( 130 | rng, 131 | &pok_keypair.0, 132 | &message_from_c_i::(c.clone()).unwrap(), 133 | ) 134 | .unwrap(); 135 | 136 | let signature_keypair = ssig.from_sk(&(dealers[i].private_key_sig)).unwrap(); 137 | let signature = ssig 138 | .sign( 139 | rng, 140 | &signature_keypair.0, 141 | &message_from_c_i::(c.clone()).unwrap(), 142 | ) 143 | .unwrap(); 144 | 145 | let transcript_participant = DKGTranscriptParticipant:: { 146 | c_i: c.clone(), 147 | weight: 1, 148 | c_i_pok: pok, 149 | signature_on_c_i: signature, 150 | }; 151 | accumulated_r += &r; 152 | 153 | transcript.contributions.insert(i, transcript_participant); 154 | } 155 | 156 | let mut f = (0..=dkg_config.degree) 157 | .map(|_| Fr::rand(rng)) 158 | .collect::>(); 159 | f[0] = accumulated_r; 160 | let domain = Radix2EvaluationDomain::::new(participants.len()) 161 | .ok_or(DKGError::::EvaluationDomainError) 162 | .unwrap(); 163 | let y_eval_i = domain.fft(&mut f); 164 | let f_i = f[1..=dkg_config.degree] 165 | .iter() 166 | .map(|a| dkg_config.srs.g_g1.mul(a.into_repr()).into_affine()) 167 | .collect::>(); 168 | let u_i_2 = dkg_config.u_1.mul(accumulated_r.into_repr()).into_affine(); 169 | let a_i = y_eval_i 170 | .iter() 171 | .map(|a| dkg_config.srs.g_g1.mul(a.into_repr()).into_affine()) 172 | .collect::>(); 173 | let y_i = y_eval_i 174 | .iter() 175 | .enumerate() 176 | .map::>, _>(|(i, a)| { 177 | Ok(participants[i] 178 | .public_key_sig 179 | .mul(a.into_repr()) 180 | .into_affine()) 181 | }) 182 | .collect::>() 183 | .unwrap(); 184 | 185 | transcript.pvss_share = PVSSShare:: { 186 | f_i, 187 | a_i, 188 | y_i, 189 | u_i_2, 190 | }; 191 | 192 | let mut transcript_bytes = vec![]; 193 | transcript.serialize(&mut transcript_bytes).unwrap(); 194 | println!( 195 | "Transcript size for participants={}, scheme={}: {}", 196 | num_nodes, 197 | tag, 198 | transcript_bytes.len() 199 | ); 200 | } 201 | 202 | fn main() { 203 | print_aggregatable_dkg_sizes(); 204 | print_bls_signature_sizes(); 205 | 206 | let rng = &mut thread_rng(); 207 | let srs = DKGSRS::::setup(rng).unwrap(); 208 | 209 | let bls_sig = BLSSignature::> { 210 | srs: BLSSRS { 211 | g_public_key: srs.h_g2, 212 | g_signature: srs.g_g1, 213 | }, 214 | }; 215 | let bls_pok = BLSSignature::> { 216 | srs: BLSSRS { 217 | g_public_key: srs.g_g1, 218 | g_signature: srs.h_g2, 219 | }, 220 | }; 221 | print_transcript_size(64, "bls", srs.clone(), bls_pok.clone(), bls_sig.clone()); 222 | print_transcript_size(128, "bls ", srs.clone(), bls_pok.clone(), bls_sig.clone()); 223 | print_transcript_size(256, "bls ", srs.clone(), bls_pok.clone(), bls_sig.clone()); 224 | print_transcript_size(8192, "bls ", srs.clone(), bls_pok.clone(), bls_sig.clone()); 225 | 226 | let schnorr_sig = SchnorrSignature:: { 227 | srs: SchnorrSRS { 228 | g_public_key: srs.h_g2, 229 | }, 230 | }; 231 | let schnorr_pok = SchnorrSignature:: { 232 | srs: SchnorrSRS { 233 | g_public_key: srs.g_g1, 234 | }, 235 | }; 236 | print_transcript_size( 237 | 64, 238 | "schnorr", 239 | srs.clone(), 240 | schnorr_pok.clone(), 241 | schnorr_sig.clone(), 242 | ); 243 | print_transcript_size( 244 | 128, 245 | "schnorr", 246 | srs.clone(), 247 | schnorr_pok.clone(), 248 | schnorr_sig.clone(), 249 | ); 250 | print_transcript_size( 251 | 256, 252 | "schnorr", 253 | srs.clone(), 254 | schnorr_pok.clone(), 255 | schnorr_sig.clone(), 256 | ); 257 | print_transcript_size( 258 | 8192, 259 | "schnorr", 260 | srs.clone(), 261 | schnorr_pok.clone(), 262 | schnorr_sig.clone(), 263 | ); 264 | } 265 | -------------------------------------------------------------------------------- /benches/dkg.rs: -------------------------------------------------------------------------------- 1 | use aggregatable_dkg::{ 2 | dkg::{ 3 | aggregator::DKGAggregator, 4 | config::Config, 5 | dealer::Dealer, 6 | node::Node, 7 | participant::{Participant, ParticipantState}, 8 | share::DKGTranscript, 9 | srs::SRS, 10 | }, 11 | signature::{ 12 | bls::{srs::SRS as BLSSRS, BLSSignature, BLSSignatureG1, BLSSignatureG2}, 13 | scheme::BatchVerifiableSignatureScheme, 14 | schnorr::{srs::SRS as SchnorrSRS, SchnorrSignature}, 15 | }, 16 | }; 17 | use ark_bls12_381::{Bls12_381, Fr, G1Affine, G2Affine, G2Projective}; 18 | use ark_ec::ProjectiveCurve; 19 | use ark_ff::{UniformRand, Zero}; 20 | use criterion::{criterion_group, criterion_main, Criterion}; 21 | use rand::thread_rng; 22 | use std::marker::PhantomData; 23 | 24 | pub fn criterion_benchmark(c: &mut Criterion) { 25 | let rng = &mut thread_rng(); 26 | let srs = SRS::::setup(rng).unwrap(); 27 | 28 | let schnorr_sig = SchnorrSignature:: { 29 | srs: SchnorrSRS { 30 | g_public_key: srs.h_g2, 31 | }, 32 | }; 33 | let schnorr_pok = SchnorrSignature:: { 34 | srs: SchnorrSRS { 35 | g_public_key: srs.g_g1, 36 | }, 37 | }; 38 | benchmark_with_signature_scheme( 39 | c, 40 | "schnorr", 41 | srs.clone(), 42 | schnorr_pok.clone(), 43 | schnorr_sig.clone(), 44 | ); 45 | 46 | let bls_sig = BLSSignature::> { 47 | srs: BLSSRS { 48 | g_public_key: srs.h_g2, 49 | g_signature: srs.g_g1, 50 | }, 51 | }; 52 | let bls_pok = BLSSignature::> { 53 | srs: BLSSRS { 54 | g_public_key: srs.g_g1, 55 | g_signature: srs.h_g2, 56 | }, 57 | }; 58 | benchmark_with_signature_scheme(c, "bls", srs.clone(), bls_pok.clone(), bls_sig.clone()); 59 | } 60 | 61 | fn benchmark_with_signature_scheme< 62 | SPOK: BatchVerifiableSignatureScheme, 63 | SSIG: BatchVerifiableSignatureScheme, 64 | >( 65 | c: &mut Criterion, 66 | tag: &str, 67 | srs: SRS, 68 | spok: SPOK, 69 | ssig: SSIG, 70 | ) { 71 | for i in 0..10 { 72 | let num_nodes = 1 << i; 73 | for j in 0..i { 74 | let degree = 1 << j; 75 | let rng = &mut thread_rng(); 76 | 77 | let u_1 = G2Projective::rand(rng).into_affine(); 78 | let dkg_config = Config { 79 | srs: srs.clone(), 80 | u_1, 81 | degree, 82 | }; 83 | 84 | let mut dealers = vec![]; 85 | for i in 0..num_nodes { 86 | let dealer_keypair_sig = ssig.generate_keypair(rng).unwrap(); 87 | let participant = Participant { 88 | pairing_type: PhantomData, 89 | id: i, 90 | public_key_sig: dealer_keypair_sig.1, 91 | state: ParticipantState::Dealer, 92 | }; 93 | let dealer = Dealer { 94 | private_key_sig: dealer_keypair_sig.0, 95 | accumulated_secret: G2Projective::zero().into_affine(), 96 | participant, 97 | }; 98 | 99 | dealers.push(dealer); 100 | } 101 | 102 | let participants = dealers 103 | .iter() 104 | .map(|d| d.participant.clone()) 105 | .collect::>(); 106 | let num_participants = participants.len(); 107 | 108 | let mut aggregator = DKGAggregator { 109 | config: dkg_config.clone(), 110 | scheme_pok: spok.clone(), 111 | scheme_sig: ssig.clone(), 112 | participants: participants.clone().into_iter().enumerate().collect(), 113 | transcript: DKGTranscript::empty(dkg_config.degree, num_participants), 114 | }; 115 | 116 | let mut nodes = vec![]; 117 | for i in 0..num_nodes { 118 | let degree = dkg_config.degree; 119 | let node = Node { 120 | aggregator: DKGAggregator { 121 | config: dkg_config.clone(), 122 | scheme_pok: spok.clone(), 123 | scheme_sig: ssig.clone(), 124 | participants: participants.clone().into_iter().enumerate().collect(), 125 | transcript: DKGTranscript::empty(degree, num_participants), 126 | }, 127 | dealer: dealers[i].clone(), 128 | }; 129 | nodes.push(node); 130 | } 131 | for i in 0..num_nodes { 132 | let share = nodes[i].share(rng).unwrap(); 133 | for j in 0..num_nodes { 134 | nodes[j] 135 | .receive_share_and_decrypt(rng, share.clone()) 136 | .unwrap(); 137 | } 138 | aggregator.receive_share(rng, &share.clone()).unwrap(); 139 | if i == 0 { 140 | c.bench_function( 141 | &format!( 142 | "dkg(sig_scheme={}, nodes={}, degree={}) share", 143 | tag, num_nodes, degree 144 | ), 145 | |b| b.iter(|| nodes[i].share(rng).unwrap()), 146 | ); 147 | c.bench_function( 148 | &format!( 149 | "dkg(sig_scheme={}, nodes={}, degree={}) aggregator receive share", 150 | tag, num_nodes, degree 151 | ), 152 | |b| { 153 | b.iter(|| { 154 | let mut aggregator = DKGAggregator { 155 | config: dkg_config.clone(), 156 | scheme_pok: spok.clone(), 157 | scheme_sig: ssig.clone(), 158 | participants: participants 159 | .clone() 160 | .into_iter() 161 | .enumerate() 162 | .collect(), 163 | transcript: DKGTranscript::empty( 164 | dkg_config.degree, 165 | num_participants, 166 | ), 167 | }; 168 | 169 | aggregator.receive_share(rng, &share.clone()).unwrap(); 170 | }) 171 | }, 172 | ); 173 | } 174 | } 175 | 176 | let transcript = aggregator.transcript; 177 | for i in 0..num_nodes { 178 | let degree = dkg_config.degree; 179 | let mut node = Node { 180 | aggregator: DKGAggregator { 181 | config: dkg_config.clone(), 182 | scheme_pok: spok.clone(), 183 | scheme_sig: ssig.clone(), 184 | participants: participants.clone().into_iter().enumerate().collect(), 185 | transcript: DKGTranscript::empty(degree, num_participants), 186 | }, 187 | dealer: dealers[i].clone(), 188 | }; 189 | node.receive_transcript_and_decrypt(rng, transcript.clone()) 190 | .unwrap(); 191 | assert_eq!( 192 | node.dealer.accumulated_secret, 193 | nodes[i].dealer.accumulated_secret 194 | ); 195 | if i == 0 { 196 | c.bench_function( 197 | &format!( 198 | "dkg(sig_scheme={}, nodes={}, degree={}) node receive transcript and decrypt", 199 | tag, num_nodes, degree 200 | ), 201 | |b| { 202 | b.iter(|| { 203 | let mut node = Node { 204 | aggregator: DKGAggregator { 205 | config: dkg_config.clone(), 206 | scheme_pok: spok.clone(), 207 | scheme_sig: ssig.clone(), 208 | participants: participants 209 | .clone() 210 | .into_iter() 211 | .enumerate() 212 | .collect(), 213 | transcript: DKGTranscript::empty(degree, num_participants), 214 | }, 215 | dealer: dealers[i].clone(), 216 | }; 217 | node.receive_transcript_and_decrypt(rng, transcript.clone()) 218 | .unwrap(); 219 | assert_eq!( 220 | node.dealer.accumulated_secret, 221 | nodes[i].dealer.accumulated_secret 222 | ); 223 | }) 224 | }, 225 | ); 226 | } 227 | } 228 | } 229 | } 230 | } 231 | 232 | criterion_group!(benches, criterion_benchmark); 233 | criterion_main!(benches); 234 | -------------------------------------------------------------------------------- /src/signature/schnorr/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::signature::{ 2 | scheme::{BatchVerifiableSignatureScheme, SignatureScheme}, 3 | utils::{errors::SignatureError, hash::hash_to_field}, 4 | }; 5 | use ark_ec::{msm::VariableBaseMSM, AffineCurve, ProjectiveCurve}; 6 | use ark_ff::{One, PrimeField, UniformRand, Zero}; 7 | use rand::Rng; 8 | use srs::SRS; 9 | use std::{fmt::Debug, ops::Neg}; 10 | 11 | pub mod srs; 12 | 13 | const PERSONALIZATION: &[u8] = b"SCHSIGNA"; 14 | 15 | #[derive(Clone, Debug, PartialEq)] 16 | pub struct SchnorrSignature { 17 | pub srs: SRS, 18 | } 19 | 20 | impl SignatureScheme for SchnorrSignature { 21 | type SRS = SRS; 22 | type Secret = C::ScalarField; 23 | type PublicKey = C; 24 | type Signature = (C, C::ScalarField); 25 | 26 | fn from_srs(srs: Self::SRS) -> Result { 27 | Ok(Self { srs }) 28 | } 29 | 30 | fn generate_keypair( 31 | &self, 32 | rng: &mut R, 33 | ) -> Result<(Self::Secret, Self::PublicKey), SignatureError> { 34 | let sk = Self::Secret::rand(rng); 35 | Ok((sk, self.srs.g_public_key.mul(sk.into_repr()).into_affine())) 36 | } 37 | 38 | fn from_sk( 39 | &self, 40 | sk: &Self::Secret, 41 | ) -> Result<(Self::Secret, Self::PublicKey), SignatureError> { 42 | Ok((*sk, self.srs.g_public_key.mul(sk.into_repr()).into_affine())) 43 | } 44 | 45 | fn sign( 46 | &self, 47 | rng: &mut R, 48 | sk: &Self::Secret, 49 | message: &[u8], 50 | ) -> Result { 51 | let v = C::ScalarField::rand(rng); 52 | let v_g = self.srs.g_public_key.mul(v.into_repr()).into_affine(); 53 | let mut v_g_bytes = vec![]; 54 | v_g.serialize(&mut v_g_bytes)?; 55 | let mut g_bytes = vec![]; 56 | self.srs.g_public_key.serialize(&mut g_bytes)?; 57 | 58 | let hashed_message = hash_to_field::( 59 | PERSONALIZATION, 60 | &[message, &v_g_bytes, &g_bytes].concat(), 61 | )?; 62 | let r = v - &(*sk * &hashed_message); 63 | let sig = (v_g, r); 64 | Ok(sig) 65 | } 66 | 67 | fn verify( 68 | &self, 69 | public_key: &Self::PublicKey, 70 | message: &[u8], 71 | signature: &Self::Signature, 72 | ) -> Result<(), SignatureError> { 73 | let mut v_g_bytes = vec![]; 74 | signature.0.serialize(&mut v_g_bytes)?; 75 | let mut g_bytes = vec![]; 76 | self.srs.g_public_key.serialize(&mut g_bytes)?; 77 | 78 | let hashed_message = hash_to_field::( 79 | PERSONALIZATION, 80 | &[message, &v_g_bytes, &g_bytes].concat(), 81 | )?; 82 | 83 | let check = (self.srs.g_public_key.mul(signature.1.into_repr()) 84 | + &public_key.mul(hashed_message.into_repr())) 85 | .into_affine(); 86 | if check != signature.0 { 87 | return Err(SignatureError::SchnorrVerify); 88 | } 89 | 90 | Ok(()) 91 | } 92 | } 93 | 94 | impl BatchVerifiableSignatureScheme for SchnorrSignature { 95 | fn batch_verify( 96 | &self, 97 | rng: &mut R, 98 | public_keys: &[&Self::PublicKey], 99 | messages: &[&[u8]], 100 | signatures: &[&Self::Signature], 101 | ) -> Result<(), SignatureError> { 102 | if public_keys.len() != messages.len() || public_keys.len() != signatures.len() { 103 | return Err(SignatureError::BatchVerification( 104 | public_keys.len(), 105 | messages.len(), 106 | signatures.len(), 107 | )); 108 | } 109 | 110 | let alpha = C::ScalarField::rand(rng); 111 | let mut current_alpha = C::ScalarField::one(); 112 | 113 | let mut g_bytes = vec![]; 114 | self.srs.g_public_key.serialize(&mut g_bytes)?; 115 | 116 | let mut bases = vec![]; 117 | let mut scalars = vec![]; 118 | for i in 0..public_keys.len() { 119 | let mut v_g_bytes = vec![]; 120 | signatures[i].0.serialize(&mut v_g_bytes)?; 121 | 122 | let hashed_message = hash_to_field::( 123 | PERSONALIZATION, 124 | &[messages[i], &v_g_bytes, &g_bytes].concat(), 125 | )?; 126 | 127 | bases.push(self.srs.g_public_key.into_projective()); 128 | scalars.push((signatures[i].1 * ¤t_alpha).into_repr()); 129 | 130 | bases.push(public_keys[i].into_projective()); 131 | scalars.push((hashed_message * ¤t_alpha).into_repr()); 132 | 133 | bases.push(signatures[i].0.into_projective()); 134 | scalars.push(current_alpha.neg().into_repr()); 135 | 136 | current_alpha *= α 137 | } 138 | let bases = C::Projective::batch_normalization_into_affine(&bases); 139 | let accumulated_check = VariableBaseMSM::multi_scalar_mul(&bases, &scalars); 140 | if !accumulated_check.is_zero() { 141 | return Err(SignatureError::SchnorrVerify); 142 | } 143 | Ok(()) 144 | } 145 | } 146 | 147 | #[cfg(test)] 148 | mod test { 149 | use ark_bls12_381::{G1Affine, G2Affine}; 150 | use ark_ec::AffineCurve; 151 | 152 | use super::{SchnorrSignature, SRS}; 153 | use crate::signature::{ 154 | scheme::{BatchVerifiableSignatureScheme, SignatureScheme}, 155 | utils::tests::check_serialization, 156 | }; 157 | 158 | use rand::thread_rng; 159 | 160 | #[test] 161 | fn test_simple_sig_g1() { 162 | test_simple_sig::(); 163 | } 164 | 165 | #[test] 166 | fn test_simple_sig_g2() { 167 | test_simple_sig::(); 168 | } 169 | 170 | fn test_simple_sig() { 171 | let rng = &mut thread_rng(); 172 | let srs = SRS::::setup(rng).unwrap(); 173 | let schnorr = SchnorrSignature { srs }; 174 | let keypair = schnorr.generate_keypair(rng).unwrap(); 175 | let message = b"hello"; 176 | 177 | let signature = schnorr.sign(rng, &keypair.0, &message[..]).unwrap(); 178 | schnorr 179 | .verify(&keypair.1, &message[..], &signature) 180 | .unwrap(); 181 | } 182 | 183 | #[test] 184 | #[should_panic] 185 | fn test_simple_sig_wrong_pk_g1() { 186 | test_simple_sig_wrong_pk::(); 187 | } 188 | #[test] 189 | #[should_panic] 190 | fn test_simple_sig_wrong_pk_g2() { 191 | test_simple_sig_wrong_pk::(); 192 | } 193 | 194 | fn test_simple_sig_wrong_pk() { 195 | let rng = &mut thread_rng(); 196 | let srs = SRS::::setup(rng).unwrap(); 197 | let schnorr = SchnorrSignature { srs }; 198 | let keypair = schnorr.generate_keypair(rng).unwrap(); 199 | let message = b"hello"; 200 | 201 | let signature = schnorr.sign(rng, &keypair.0, &message[..]).unwrap(); 202 | 203 | let keypair2 = schnorr.generate_keypair(rng).unwrap(); 204 | schnorr 205 | .verify(&keypair2.1, &message[..], &signature) 206 | .unwrap(); 207 | } 208 | 209 | #[test] 210 | #[should_panic] 211 | fn test_simple_sig_wrong_message_g1() { 212 | test_simple_sig_wrong_message::(); 213 | } 214 | #[test] 215 | #[should_panic] 216 | fn test_simple_sig_wrong_message_g2() { 217 | test_simple_sig_wrong_message::(); 218 | } 219 | 220 | fn test_simple_sig_wrong_message() { 221 | let rng = &mut thread_rng(); 222 | let srs = SRS::::setup(rng).unwrap(); 223 | let schnorr = SchnorrSignature { srs }; 224 | let keypair = schnorr.generate_keypair(rng).unwrap(); 225 | let message = b"hello"; 226 | 227 | let signature = schnorr.sign(rng, &keypair.0, &message[..]).unwrap(); 228 | 229 | let wrong_message = b"goodbye"; 230 | schnorr 231 | .verify(&keypair.1, &wrong_message[..], &signature) 232 | .unwrap(); 233 | } 234 | 235 | #[test] 236 | fn test_simple_sig_batch_g1() { 237 | test_simple_sig_batch::(); 238 | } 239 | 240 | #[test] 241 | fn test_simple_sig_batch_g2() { 242 | test_simple_sig_batch::(); 243 | } 244 | 245 | fn test_simple_sig_batch() { 246 | let rng = &mut thread_rng(); 247 | let srs = SRS::::setup(rng).unwrap(); 248 | let schnorr = SchnorrSignature { srs }; 249 | let keypair = schnorr.generate_keypair(rng).unwrap(); 250 | let message = b"hello"; 251 | let signature = schnorr.sign(rng, &keypair.0, &message[..]).unwrap(); 252 | let keypair2 = schnorr.generate_keypair(rng).unwrap(); 253 | let message2 = b"hello2"; 254 | let signature2 = schnorr.sign(rng, &keypair2.0, &message2[..]).unwrap(); 255 | schnorr 256 | .batch_verify( 257 | rng, 258 | &[&keypair.1, &keypair2.1], 259 | &[&message[..], &message2[..]], 260 | &[&signature, &signature2], 261 | ) 262 | .unwrap(); 263 | } 264 | 265 | #[test] 266 | fn test_serialization_g1() { 267 | test_serialization::(); 268 | } 269 | #[test] 270 | fn test_serialization_g2() { 271 | test_serialization::(); 272 | } 273 | fn test_serialization() { 274 | let rng = &mut thread_rng(); 275 | let srs = SRS::::setup(rng).unwrap(); 276 | let schnorr = SchnorrSignature { srs: srs.clone() }; 277 | let keypair = schnorr.generate_keypair(rng).unwrap(); 278 | let message = b"hello"; 279 | let signature = schnorr.sign(rng, &keypair.0, &message[..]).unwrap(); 280 | 281 | check_serialization(srs.clone()); 282 | check_serialization(keypair.clone()); 283 | check_serialization(signature.clone()); 284 | } 285 | } 286 | -------------------------------------------------------------------------------- /benches/huge_dkg.rs: -------------------------------------------------------------------------------- 1 | use aggregatable_dkg::{ 2 | dkg::{ 3 | aggregator::DKGAggregator, 4 | config::Config, 5 | dealer::Dealer, 6 | errors::DKGError, 7 | node::Node, 8 | participant::{Participant, ParticipantState}, 9 | pvss::PVSSShare, 10 | share::{message_from_c_i, DKGTranscript, DKGTranscriptParticipant}, 11 | srs::SRS, 12 | }, 13 | signature::{ 14 | bls::{srs::SRS as BLSSRS, BLSSignature, BLSSignatureG1, BLSSignatureG2}, 15 | scheme::BatchVerifiableSignatureScheme, 16 | schnorr::{srs::SRS as SchnorrSRS, SchnorrSignature}, 17 | }, 18 | }; 19 | use ark_bls12_381::{Bls12_381, Fr, G1Affine, G2Affine, G2Projective}; 20 | use ark_ec::{AffineCurve, ProjectiveCurve}; 21 | use ark_ff::{PrimeField, UniformRand, Zero}; 22 | use ark_poly::{EvaluationDomain, Radix2EvaluationDomain}; 23 | use criterion::{criterion_group, criterion_main, Criterion}; 24 | use rand::thread_rng; 25 | use std::marker::PhantomData; 26 | 27 | pub fn criterion_benchmark(c: &mut Criterion) { 28 | let rng = &mut thread_rng(); 29 | let srs = SRS::::setup(rng).unwrap(); 30 | 31 | let bls_sig = BLSSignature::> { 32 | srs: BLSSRS { 33 | g_public_key: srs.h_g2, 34 | g_signature: srs.g_g1, 35 | }, 36 | }; 37 | let bls_pok = BLSSignature::> { 38 | srs: BLSSRS { 39 | g_public_key: srs.g_g1, 40 | g_signature: srs.h_g2, 41 | }, 42 | }; 43 | benchmark_with_signature_scheme(c, "bls", srs.clone(), bls_pok.clone(), bls_sig.clone()); 44 | 45 | let schnorr_sig = SchnorrSignature:: { 46 | srs: SchnorrSRS { 47 | g_public_key: srs.h_g2, 48 | }, 49 | }; 50 | let schnorr_pok = SchnorrSignature:: { 51 | srs: SchnorrSRS { 52 | g_public_key: srs.g_g1, 53 | }, 54 | }; 55 | benchmark_with_signature_scheme( 56 | c, 57 | "schnorr", 58 | srs.clone(), 59 | schnorr_pok.clone(), 60 | schnorr_sig.clone(), 61 | ); 62 | } 63 | 64 | fn benchmark_with_signature_scheme< 65 | SPOK: BatchVerifiableSignatureScheme, 66 | SSIG: BatchVerifiableSignatureScheme, 67 | >( 68 | c: &mut Criterion, 69 | tag: &str, 70 | srs: SRS, 71 | spok: SPOK, 72 | ssig: SSIG, 73 | ) { 74 | let num_nodes = 8192; 75 | let degree = (2 * num_nodes + 2) / 3; 76 | for j in (0..=13).rev() { 77 | let rng = &mut thread_rng(); 78 | 79 | let u_1 = G2Projective::rand(rng).into_affine(); 80 | let dkg_config = Config { 81 | srs: srs.clone(), 82 | u_1, 83 | degree, 84 | }; 85 | 86 | let mut dealers = vec![]; 87 | for i in 0..num_nodes { 88 | let dealer_keypair_sig = ssig.generate_keypair(rng).unwrap(); 89 | let participant = Participant { 90 | pairing_type: PhantomData, 91 | id: i, 92 | public_key_sig: dealer_keypair_sig.1, 93 | state: ParticipantState::Dealer, 94 | }; 95 | let dealer = Dealer { 96 | private_key_sig: dealer_keypair_sig.0, 97 | accumulated_secret: G2Projective::zero().into_affine(), 98 | participant, 99 | }; 100 | 101 | dealers.push(dealer); 102 | } 103 | 104 | let participants = dealers 105 | .iter() 106 | .map(|d| d.participant.clone()) 107 | .collect::>(); 108 | let num_participants = participants.len(); 109 | 110 | c.bench_function( 111 | &format!( 112 | "huge-dkg(j={}, sig_scheme={}, nodes={}, degree={}) share", 113 | j, tag, num_nodes, degree 114 | ), 115 | |b| { 116 | b.iter(|| { 117 | let mut node = Node { 118 | aggregator: DKGAggregator { 119 | config: dkg_config.clone(), 120 | scheme_pok: spok.clone(), 121 | scheme_sig: ssig.clone(), 122 | participants: participants.clone().into_iter().enumerate().collect(), 123 | transcript: DKGTranscript::empty(degree, num_participants), 124 | }, 125 | dealer: dealers[0].clone(), 126 | }; 127 | node.share(rng).unwrap() 128 | }) 129 | }, 130 | ); 131 | 132 | c.bench_function( 133 | &format!( 134 | "huge-dkg(j={}, sig_scheme={}, nodes={}, degree={}) aggregator receive share", 135 | j, tag, num_nodes, degree 136 | ), 137 | |b| { 138 | b.iter(|| { 139 | let mut node = Node { 140 | aggregator: DKGAggregator { 141 | config: dkg_config.clone(), 142 | scheme_pok: spok.clone(), 143 | scheme_sig: ssig.clone(), 144 | participants: participants.clone().into_iter().enumerate().collect(), 145 | transcript: DKGTranscript::empty(degree, num_participants), 146 | }, 147 | dealer: dealers[0].clone(), 148 | }; 149 | let share = node.share(rng).unwrap(); 150 | let mut aggregator = DKGAggregator { 151 | config: dkg_config.clone(), 152 | scheme_pok: spok.clone(), 153 | scheme_sig: ssig.clone(), 154 | participants: participants.clone().into_iter().enumerate().collect(), 155 | transcript: DKGTranscript::empty(dkg_config.degree, num_participants), 156 | }; 157 | 158 | aggregator.receive_share(rng, &share.clone()).unwrap(); 159 | }) 160 | }, 161 | ); 162 | 163 | let mut transcript = 164 | DKGTranscript::::empty(degree, num_participants); 165 | let mut accumulated_r = Fr::zero(); 166 | for i in 0..(1 << j) { 167 | let r = Fr::rand(rng); 168 | let c = dkg_config.srs.g_g1.mul(r.into_repr()).into_affine(); 169 | 170 | let pok_keypair = spok.from_sk(&r).unwrap(); 171 | let pok = spok 172 | .sign( 173 | rng, 174 | &pok_keypair.0, 175 | &message_from_c_i::(c.clone()).unwrap(), 176 | ) 177 | .unwrap(); 178 | 179 | let signature_keypair = ssig.from_sk(&(dealers[i].private_key_sig)).unwrap(); 180 | let signature = ssig 181 | .sign( 182 | rng, 183 | &signature_keypair.0, 184 | &message_from_c_i::(c.clone()).unwrap(), 185 | ) 186 | .unwrap(); 187 | 188 | let transcript_participant = DKGTranscriptParticipant:: { 189 | c_i: c.clone(), 190 | weight: 1, 191 | c_i_pok: pok, 192 | signature_on_c_i: signature, 193 | }; 194 | accumulated_r += &r; 195 | 196 | transcript.contributions.insert(i, transcript_participant); 197 | } 198 | 199 | let mut f = (0..=dkg_config.degree) 200 | .map(|_| Fr::rand(rng)) 201 | .collect::>(); 202 | f[0] = accumulated_r; 203 | let domain = Radix2EvaluationDomain::::new(participants.len()) 204 | .ok_or(DKGError::::EvaluationDomainError) 205 | .unwrap(); 206 | let y_eval_i = domain.fft(&mut f); 207 | let f_i = f[1..=dkg_config.degree] 208 | .iter() 209 | .map(|a| dkg_config.srs.g_g1.mul(a.into_repr()).into_affine()) 210 | .collect::>(); 211 | let u_i_2 = dkg_config.u_1.mul(accumulated_r.into_repr()).into_affine(); 212 | let a_i = y_eval_i 213 | .iter() 214 | .map(|a| dkg_config.srs.g_g1.mul(a.into_repr()).into_affine()) 215 | .collect::>(); 216 | let y_i = y_eval_i 217 | .iter() 218 | .enumerate() 219 | .map::>, _>(|(i, a)| { 220 | Ok(participants[i] 221 | .public_key_sig 222 | .mul(a.into_repr()) 223 | .into_affine()) 224 | }) 225 | .collect::>() 226 | .unwrap(); 227 | 228 | transcript.pvss_share = PVSSShare:: { 229 | f_i, 230 | a_i, 231 | y_i, 232 | u_i_2, 233 | }; 234 | 235 | c.bench_function( 236 | &format!( 237 | "huge-dkg(j={}, sig_scheme={}, nodes={}, degree={}) node receive transcript and decrypt", 238 | j, tag, num_nodes, degree 239 | ), 240 | |b| { 241 | b.iter(|| { 242 | let mut node = Node { 243 | aggregator: DKGAggregator { 244 | config: dkg_config.clone(), 245 | scheme_pok: spok.clone(), 246 | scheme_sig: ssig.clone(), 247 | participants: participants.clone().into_iter().enumerate().collect(), 248 | transcript: DKGTranscript::empty(degree, num_participants), 249 | }, 250 | dealer: dealers[0].clone(), 251 | }; 252 | node.receive_transcript_and_decrypt(rng, transcript.clone()) 253 | .unwrap(); 254 | }) 255 | }, 256 | ); 257 | } 258 | } 259 | 260 | criterion_group!(benches, criterion_benchmark); 261 | criterion_main!(benches); 262 | -------------------------------------------------------------------------------- /src/dkg/aggregator.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | dkg::{ 3 | config::Config, 4 | errors::DKGError, 5 | participant::Participant, 6 | pvss::PVSSShare, 7 | share::{message_from_c_i, DKGShare, DKGTranscript, DKGTranscriptParticipant}, 8 | }, 9 | signature::scheme::BatchVerifiableSignatureScheme, 10 | }; 11 | use ark_ec::{msm::VariableBaseMSM, AffineCurve, PairingEngine, ProjectiveCurve}; 12 | use ark_ff::{One, PrimeField, UniformRand, Zero}; 13 | use ark_poly::{EvaluationDomain, Radix2EvaluationDomain}; 14 | use ark_std::collections::BTreeMap; 15 | use rand::Rng; 16 | use std::ops::Neg; 17 | 18 | pub struct DKGAggregator< 19 | E: PairingEngine, 20 | SPOK: BatchVerifiableSignatureScheme, 21 | SSIG: BatchVerifiableSignatureScheme, 22 | > { 23 | pub config: Config, 24 | pub scheme_pok: SPOK, 25 | pub scheme_sig: SSIG, 26 | pub participants: BTreeMap>, 27 | 28 | pub transcript: DKGTranscript, 29 | } 30 | 31 | impl< 32 | E: PairingEngine, 33 | SPOK: BatchVerifiableSignatureScheme, 34 | SSIG: BatchVerifiableSignatureScheme, 35 | > DKGAggregator 36 | { 37 | pub fn receive_share( 38 | &mut self, 39 | rng: &mut R, 40 | share: &DKGShare, 41 | ) -> Result<(), DKGError> { 42 | self.share_verify(rng, share)?; 43 | let transcript = DKGTranscript { 44 | degree: self.config.degree, 45 | num_participants: self.participants.len(), 46 | contributions: vec![( 47 | share.participant_id, 48 | DKGTranscriptParticipant { 49 | c_i: share.c_i, 50 | weight: 1, 51 | c_i_pok: share.c_i_pok.clone(), 52 | signature_on_c_i: share.signature_on_c_i.clone(), 53 | }, 54 | )] 55 | .into_iter() 56 | .collect(), 57 | pvss_share: share.pvss_share.clone(), 58 | }; 59 | self.transcript = self.transcript.aggregate(&transcript)?; 60 | Ok(()) 61 | } 62 | 63 | pub fn receive_transcript( 64 | &mut self, 65 | rng: &mut R, 66 | transcript: &DKGTranscript, 67 | ) -> Result<(), DKGError> { 68 | let mut c = E::G1Projective::zero(); 69 | let mut public_keys_sig = vec![]; 70 | let mut messages_sig = vec![]; 71 | let mut signatures_sig = vec![]; 72 | 73 | let mut public_keys_pok = vec![]; 74 | let mut messages_pok = vec![]; 75 | let mut signatures_pok = vec![]; 76 | 77 | for (participant_id, contribution) in transcript.contributions.iter() { 78 | let participant = self 79 | .participants 80 | .get(participant_id) 81 | .ok_or(DKGError::::InvalidParticipantId(*participant_id))?; 82 | let message = message_from_c_i(contribution.c_i)?; 83 | 84 | public_keys_sig.push(&participant.public_key_sig); 85 | messages_sig.push(message.clone()); 86 | signatures_sig.push(&contribution.signature_on_c_i); 87 | 88 | public_keys_pok.push(&contribution.c_i); 89 | messages_pok.push(message); 90 | signatures_pok.push(&contribution.c_i_pok); 91 | 92 | c += &contribution 93 | .c_i 94 | .mul(>::from(contribution.weight)); 95 | } 96 | let sig_timer = start_timer!(|| "Signature batch verify"); 97 | self.scheme_sig.batch_verify( 98 | rng, 99 | &public_keys_sig, 100 | &messages_sig 101 | .iter() 102 | .map(|v| v.as_slice()) 103 | .collect::>(), 104 | &signatures_sig, 105 | )?; 106 | end_timer!(sig_timer); 107 | 108 | let pok_timer = start_timer!(|| "POK batch verify"); 109 | self.scheme_pok.batch_verify( 110 | rng, 111 | &public_keys_pok, 112 | &messages_pok 113 | .iter() 114 | .map(|v| v.as_slice()) 115 | .collect::>(), 116 | &signatures_pok, 117 | )?; 118 | end_timer!(pok_timer); 119 | 120 | let pvss_timer = start_timer!(|| "PVSS share verify"); 121 | self.pvss_share_verify(rng, c.into_affine(), &transcript.pvss_share)?; 122 | end_timer!(pvss_timer); 123 | Ok(()) 124 | } 125 | 126 | pub fn pvss_share_verify( 127 | &self, 128 | rng: &mut R, 129 | c_i: E::G1Affine, 130 | share: &PVSSShare, 131 | ) -> Result<(), DKGError> { 132 | // Verify evaluations are correct probabilistically. 133 | let alpha = E::Fr::rand(rng); 134 | let domain = Radix2EvaluationDomain::::new(self.participants.len()) 135 | .ok_or(DKGError::::EvaluationDomainError)?; 136 | let lagrange_coefficients = domain 137 | .evaluate_all_lagrange_coefficients(alpha) 138 | .into_iter() 139 | .map(|c| c.into_repr()) 140 | .collect::>(); 141 | 142 | { 143 | let mut bases = vec![]; 144 | let mut scalars = vec![]; 145 | bases.extend_from_slice(&share.a_i); 146 | scalars.extend_from_slice(&lagrange_coefficients); 147 | let powers_of_alpha = { 148 | let mut current_alpha = E::Fr::one().neg(); 149 | let mut powers = vec![]; 150 | for _ in 0..=self.config.degree { 151 | powers.push(current_alpha.into_repr()); 152 | current_alpha *= α 153 | } 154 | powers 155 | }; 156 | bases.extend_from_slice(&[vec![c_i], share.f_i.clone()].concat()); 157 | scalars.extend_from_slice(&powers_of_alpha); 158 | let product = VariableBaseMSM::multi_scalar_mul(&bases, &scalars); 159 | if !product.is_zero() { 160 | return Err(DKGError::EvaluationsCheckError(product.into())); 161 | } 162 | } 163 | 164 | // Verify same ratio. Need this for security proof. 165 | let pairs = [ 166 | (c_i.into(), self.config.u_1.into()), 167 | (self.config.srs.g_g1.neg().into(), share.u_i_2.into()), 168 | ]; 169 | if !E::product_of_pairings(pairs.iter()).is_one() { 170 | return Err(DKGError::RatioIncorrect); 171 | } 172 | 173 | let powers_of_alpha = { 174 | let mut current_alpha = E::Fr::one(); 175 | let mut powers = vec![]; 176 | for _ in 0..=self.participants.len() { 177 | powers.push(current_alpha.into_repr()); 178 | current_alpha *= α 179 | } 180 | powers 181 | }; 182 | let (batched_a_i, batched_g_1_neg) = { 183 | let g_1_neg = self.config.srs.g_g1.neg(); 184 | let batched_a_i = share 185 | .a_i 186 | .iter() 187 | .zip(powers_of_alpha.iter()) 188 | .map(|(a, power)| a.mul(*power)) 189 | .collect::>(); 190 | let batched_g_1_neg = powers_of_alpha 191 | .iter() 192 | .map(|power| g_1_neg.mul(*power)) 193 | .collect::>(); 194 | let mut batched_all = vec![]; 195 | batched_all.extend_from_slice(&batched_a_i); 196 | batched_all.extend_from_slice(&batched_g_1_neg); 197 | let batched_all = E::G1Projective::batch_normalization_into_affine(&batched_all); 198 | let batched_a_i = batched_all[..batched_a_i.len()] 199 | .into_iter() 200 | .map(|x| x.clone()) 201 | .collect::>(); 202 | let batched_g_1_neg = batched_all[batched_a_i.len()..] 203 | .into_iter() 204 | .map(|x| x.clone()) 205 | .collect::>(); 206 | (batched_a_i, batched_g_1_neg) 207 | }; 208 | // Verify evaluations are encrypted correctly. 209 | let pairs = batched_a_i 210 | .into_iter() 211 | .zip(share.y_i.iter()) 212 | .zip(batched_g_1_neg.into_iter()) 213 | .enumerate() 214 | .map::, DKGError>, _>( 215 | |(i, ((a, y), g_1_neg))| { 216 | let participant = self 217 | .participants 218 | .get(&i) 219 | .ok_or(DKGError::::InvalidParticipantId(i))?; 220 | let pairs = vec![ 221 | (g_1_neg.into(), (*y).into()), 222 | (a.into(), participant.public_key_sig.into()), 223 | ]; 224 | 225 | Ok(pairs) 226 | }, 227 | ) 228 | .collect::, _>>()? 229 | .into_iter() 230 | .flatten() 231 | .collect::>(); 232 | if !E::product_of_pairings(pairs.iter()).is_one() { 233 | return Err(DKGError::RatioIncorrect); 234 | } 235 | Ok(()) 236 | } 237 | 238 | pub fn share_verify( 239 | &mut self, 240 | rng: &mut R, 241 | share: &DKGShare, 242 | ) -> Result<(), DKGError> { 243 | let participant_id = share.participant_id; 244 | let participant = self 245 | .participants 246 | .get(&participant_id) 247 | .ok_or(DKGError::::InvalidParticipantId(participant_id))?; 248 | 249 | self.pvss_share_verify(rng, share.c_i, &share.pvss_share)?; 250 | // Verify signature on C_i by participant i. 251 | self.scheme_sig.verify( 252 | &participant.public_key_sig, 253 | &message_from_c_i(share.c_i)?, 254 | &share.signature_on_c_i, 255 | )?; 256 | 257 | // Verify POK of C_i. 258 | self.scheme_pok 259 | .verify(&share.c_i, &message_from_c_i(share.c_i)?, &share.c_i_pok)?; 260 | 261 | Ok(()) 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /src/signature/algebraic/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod keypair; 2 | pub mod public_key; 3 | pub mod signature; 4 | pub mod srs; 5 | 6 | pub const PERSONALIZATION: &[u8] = b"ALGEBSIG"; 7 | 8 | #[cfg(test)] 9 | mod test { 10 | use ark_bls12_381::Bls12_381; 11 | 12 | use super::{keypair::Keypair, public_key::ProvenPublicKey, signature::Signature, srs::SRS}; 13 | use crate::signature::utils::tests::check_serialization; 14 | 15 | use rand::thread_rng; 16 | 17 | #[test] 18 | fn test_simple_sig() { 19 | let rng = &mut thread_rng(); 20 | let srs = SRS::::setup(rng).unwrap(); 21 | let keypair = Keypair::generate_keypair(rng, srs).unwrap(); 22 | let message = b"hello"; 23 | 24 | let proven_public_key = keypair.prove_key().unwrap(); 25 | proven_public_key.verify().unwrap(); 26 | 27 | let signature = keypair.sign(&message[..]).unwrap(); 28 | signature 29 | .verify_and_derive(proven_public_key, &message[..]) 30 | .unwrap(); 31 | } 32 | 33 | #[test] 34 | #[should_panic] 35 | fn test_simple_sig_wrong_pk() { 36 | let rng = &mut thread_rng(); 37 | let srs = SRS::::setup(rng).unwrap(); 38 | let keypair = Keypair::generate_keypair(rng, srs.clone()).unwrap(); 39 | let message = b"hello"; 40 | 41 | let signature = keypair.sign(&message[..]).unwrap(); 42 | 43 | let keypair2 = Keypair::generate_keypair(rng, srs).unwrap(); 44 | let proven_public_key2 = keypair2.prove_key().unwrap(); 45 | proven_public_key2.verify().unwrap(); 46 | signature 47 | .verify_and_derive(proven_public_key2, &message[..]) 48 | .unwrap(); 49 | } 50 | 51 | #[test] 52 | #[should_panic] 53 | fn test_simple_sig_wrong_message() { 54 | let rng = &mut thread_rng(); 55 | let srs = SRS::::setup(rng).unwrap(); 56 | let keypair = Keypair::generate_keypair(rng, srs).unwrap(); 57 | let message = b"hello"; 58 | 59 | let proven_public_key = keypair.prove_key().unwrap(); 60 | proven_public_key.verify().unwrap(); 61 | 62 | let signature = keypair.sign(&message[..]).unwrap(); 63 | 64 | let wrong_message = b"goodbye"; 65 | signature 66 | .verify_and_derive(proven_public_key, &wrong_message[..]) 67 | .unwrap(); 68 | } 69 | 70 | #[test] 71 | fn test_aggregated_sig() { 72 | let rng = &mut thread_rng(); 73 | let srs = SRS::::setup(rng).unwrap(); 74 | let keypair1 = Keypair::generate_keypair(rng, srs.clone()).unwrap(); 75 | let keypair2 = Keypair::generate_keypair(rng, srs.clone()).unwrap(); 76 | let message = b"hello"; 77 | 78 | let proven_public_key1 = keypair1.prove_key().unwrap(); 79 | proven_public_key1.verify().unwrap(); 80 | 81 | let proven_public_key2 = keypair2.prove_key().unwrap(); 82 | proven_public_key2.verify().unwrap(); 83 | 84 | let signature1 = keypair1.sign(&message[..]).unwrap(); 85 | signature1 86 | .verify_and_derive(proven_public_key1.clone(), &message[..]) 87 | .unwrap(); 88 | 89 | let signature2 = keypair2.sign(&message[..]).unwrap(); 90 | signature2 91 | .verify_and_derive(proven_public_key2.clone(), &message[..]) 92 | .unwrap(); 93 | 94 | let aggregated_pk = 95 | ProvenPublicKey::aggregate(&[proven_public_key1, proven_public_key2], srs.clone()) 96 | .unwrap(); 97 | let aggregated_sig = Signature::aggregate(&[signature1, signature2]).unwrap(); 98 | 99 | aggregated_sig 100 | .verify_and_derive(aggregated_pk, message) 101 | .unwrap(); 102 | } 103 | 104 | #[test] 105 | #[should_panic] 106 | fn test_aggregated_sig_wrong_pk() { 107 | let rng = &mut thread_rng(); 108 | let srs = SRS::::setup(rng).unwrap(); 109 | let keypair1 = Keypair::generate_keypair(rng, srs.clone()).unwrap(); 110 | let keypair2 = Keypair::generate_keypair(rng, srs.clone()).unwrap(); 111 | let message = b"hello"; 112 | 113 | let proven_public_key1 = keypair1.prove_key().unwrap(); 114 | proven_public_key1.verify().unwrap(); 115 | 116 | let proven_public_key2 = keypair2.prove_key().unwrap(); 117 | proven_public_key2.verify().unwrap(); 118 | 119 | let signature1 = keypair1.sign(&message[..]).unwrap(); 120 | signature1 121 | .verify_and_derive(proven_public_key1.clone(), &message[..]) 122 | .unwrap(); 123 | 124 | let signature2 = keypair2.sign(&message[..]).unwrap(); 125 | signature2 126 | .verify_and_derive(proven_public_key2.clone(), &message[..]) 127 | .unwrap(); 128 | 129 | let aggregated_sig = Signature::aggregate(&[signature1, signature2]).unwrap(); 130 | aggregated_sig 131 | .verify_and_derive(proven_public_key1, message) 132 | .unwrap(); 133 | } 134 | 135 | #[test] 136 | #[should_panic] 137 | fn test_aggregated_sig_wrong_message() { 138 | let rng = &mut thread_rng(); 139 | let srs = SRS::::setup(rng).unwrap(); 140 | let keypair1 = Keypair::generate_keypair(rng, srs.clone()).unwrap(); 141 | let keypair2 = Keypair::generate_keypair(rng, srs.clone()).unwrap(); 142 | let message = b"hello"; 143 | 144 | let proven_public_key1 = keypair1.prove_key().unwrap(); 145 | proven_public_key1.verify().unwrap(); 146 | 147 | let proven_public_key2 = keypair2.prove_key().unwrap(); 148 | proven_public_key2.verify().unwrap(); 149 | 150 | let signature1 = keypair1.sign(&message[..]).unwrap(); 151 | signature1 152 | .verify_and_derive(proven_public_key1.clone(), &message[..]) 153 | .unwrap(); 154 | 155 | let signature2 = keypair2.sign(&message[..]).unwrap(); 156 | signature2 157 | .verify_and_derive(proven_public_key2.clone(), &message[..]) 158 | .unwrap(); 159 | 160 | let aggregated_pk = 161 | ProvenPublicKey::aggregate(&[proven_public_key1, proven_public_key2], srs.clone()) 162 | .unwrap(); 163 | let aggregated_sig = Signature::aggregate(&[signature1, signature2]).unwrap(); 164 | 165 | let wrong_message = b"goodbye"; 166 | aggregated_sig 167 | .verify_and_derive(aggregated_pk, wrong_message) 168 | .unwrap(); 169 | } 170 | 171 | #[test] 172 | fn test_refresh_randomness() { 173 | let rng = &mut thread_rng(); 174 | let srs = SRS::::setup(rng).unwrap(); 175 | let keypair = Keypair::generate_keypair(rng, srs).unwrap(); 176 | let message = b"hello"; 177 | 178 | let proven_public_key = keypair.prove_key().unwrap(); 179 | proven_public_key.verify().unwrap(); 180 | 181 | let signature = keypair.sign(&message[..]).unwrap(); 182 | signature 183 | .verify_and_derive(proven_public_key, &message[..]) 184 | .unwrap(); 185 | 186 | let refreshed_keypair = keypair.refresh_randomness(rng).unwrap(); 187 | let proven_refreshed_public_key = refreshed_keypair.prove_key().unwrap(); 188 | proven_refreshed_public_key.verify().unwrap(); 189 | signature 190 | .verify_and_derive(proven_refreshed_public_key.clone(), &message[..]) 191 | .unwrap_err(); 192 | 193 | let signature = refreshed_keypair.sign(&message[..]).unwrap(); 194 | signature 195 | .verify_and_derive(proven_refreshed_public_key, &message[..]) 196 | .unwrap(); 197 | } 198 | 199 | #[test] 200 | fn test_simple_sig_probabilistic() { 201 | let rng = &mut thread_rng(); 202 | let srs = SRS::::setup(rng).unwrap(); 203 | let keypair = Keypair::generate_keypair(rng, srs).unwrap(); 204 | let message = b"hello"; 205 | 206 | let proven_public_key = keypair.prove_key().unwrap(); 207 | proven_public_key.verify().unwrap(); 208 | 209 | let signature = keypair.sign(&message[..]).unwrap(); 210 | proven_public_key.verify_probabilistically(rng).unwrap(); 211 | signature 212 | .verify_and_derive(proven_public_key, &message[..]) 213 | .unwrap(); 214 | } 215 | 216 | #[test] 217 | #[should_panic] 218 | fn test_simple_sig_probabilistic_wrong_pk() { 219 | let rng = &mut thread_rng(); 220 | let srs = SRS::::setup(rng).unwrap(); 221 | let keypair = Keypair::generate_keypair(rng, srs.clone()).unwrap(); 222 | let message = b"hello"; 223 | 224 | let signature = keypair.sign(&message[..]).unwrap(); 225 | 226 | let keypair2 = Keypair::generate_keypair(rng, srs).unwrap(); 227 | let proven_public_key2 = keypair2.prove_key().unwrap(); 228 | proven_public_key2.verify_probabilistically(rng).unwrap(); 229 | proven_public_key2.verify().unwrap(); 230 | signature 231 | .verify_and_derive(proven_public_key2, &message[..]) 232 | .unwrap(); 233 | } 234 | 235 | #[test] 236 | fn test_simple_sig_all_probabilistic() { 237 | let rng = &mut thread_rng(); 238 | let srs = SRS::::setup(rng).unwrap(); 239 | let keypair = Keypair::generate_keypair(rng, srs).unwrap(); 240 | let message = b"hello"; 241 | 242 | let proven_public_key = keypair.prove_key().unwrap(); 243 | proven_public_key.verify().unwrap(); 244 | 245 | let signature = keypair.sign(&message[..]).unwrap(); 246 | signature 247 | .verify_all_probabilistically(rng, proven_public_key.clone(), &message[..]) 248 | .unwrap(); 249 | signature.derive(proven_public_key, &message[..]).unwrap(); 250 | } 251 | 252 | #[test] 253 | #[should_panic] 254 | fn test_simple_sig_all_probabilistic_wrong_pk() { 255 | let rng = &mut thread_rng(); 256 | let srs = SRS::::setup(rng).unwrap(); 257 | let keypair = Keypair::generate_keypair(rng, srs.clone()).unwrap(); 258 | let message = b"hello"; 259 | 260 | let signature = keypair.sign(&message[..]).unwrap(); 261 | 262 | let keypair2 = Keypair::generate_keypair(rng, srs).unwrap(); 263 | let proven_public_key2 = keypair2.prove_key().unwrap(); 264 | proven_public_key2.verify().unwrap(); 265 | signature 266 | .verify_all_probabilistically(rng, proven_public_key2.clone(), &message[..]) 267 | .unwrap(); 268 | signature 269 | .verify_and_derive(proven_public_key2, &message[..]) 270 | .unwrap(); 271 | } 272 | 273 | #[test] 274 | fn test_serialization() { 275 | let rng = &mut thread_rng(); 276 | let srs = SRS::::setup(rng).unwrap(); 277 | let keypair = Keypair::generate_keypair(rng, srs.clone()).unwrap(); 278 | let message = b"hello"; 279 | let signature = keypair.sign(&message[..]).unwrap(); 280 | 281 | check_serialization(srs.clone()); 282 | check_serialization(keypair.clone()); 283 | check_serialization(signature.clone()); 284 | } 285 | } 286 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/signature/bls/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::signature::{ 2 | scheme::{AggregatableSignatureScheme, BatchVerifiableSignatureScheme, SignatureScheme}, 3 | utils::{errors::SignatureError, hash::hash_to_group}, 4 | }; 5 | use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; 6 | use ark_ff::{Field, One, PrimeField, UniformRand, Zero}; 7 | use rand::Rng; 8 | use srs::SRS; 9 | use std::{fmt::Debug, ops::Neg}; 10 | 11 | pub mod srs; 12 | 13 | const PERSONALIZATION: &[u8] = b"BLSSIGNA"; 14 | 15 | pub trait BLSSignatureScheme: Debug + Clone + PartialEq { 16 | type PublicKeyGroup: AffineCurve; 17 | type SignatureGroup: AffineCurve< 18 | ScalarField = ::ScalarField, 19 | Projective = Self::SignatureGroupProjective, 20 | > + From; 21 | type SignatureGroupProjective: ProjectiveCurve< 22 | Affine = Self::SignatureGroup, 23 | ScalarField = ::ScalarField, 24 | BaseField = ::BaseField, 25 | > + From 26 | + Into 27 | + std::ops::MulAssign<::ScalarField>; 28 | type TargetGroup: Field; 29 | 30 | fn product_of_pairings( 31 | pairs: Vec<(Self::PublicKeyGroup, Self::SignatureGroup)>, 32 | ) -> Self::TargetGroup; 33 | 34 | fn batch_product_of_pairings_is_one( 35 | rng: &mut R, 36 | pairs: Vec>, 37 | ) -> bool; 38 | } 39 | 40 | #[derive(Clone, Debug, PartialEq)] 41 | pub struct BLSSignature { 42 | pub srs: SRS, 43 | } 44 | 45 | impl SignatureScheme for BLSSignature { 46 | type SRS = SRS; 47 | type Secret = ::ScalarField; 48 | type PublicKey = B::PublicKeyGroup; 49 | type Signature = B::SignatureGroup; 50 | 51 | fn from_srs(srs: Self::SRS) -> Result { 52 | Ok(Self { srs }) 53 | } 54 | 55 | fn generate_keypair( 56 | &self, 57 | rng: &mut R, 58 | ) -> Result<(Self::Secret, Self::PublicKey), SignatureError> { 59 | let sk = Self::Secret::rand(rng); 60 | Ok((sk, self.srs.g_public_key.mul(sk.into_repr()).into_affine())) 61 | } 62 | 63 | fn from_sk( 64 | &self, 65 | sk: &Self::Secret, 66 | ) -> Result<(Self::Secret, Self::PublicKey), SignatureError> { 67 | Ok((*sk, self.srs.g_public_key.mul(sk.into_repr()).into_affine())) 68 | } 69 | 70 | fn sign( 71 | &self, 72 | _: &mut R, 73 | sk: &Self::Secret, 74 | message: &[u8], 75 | ) -> Result { 76 | let hashed_message = hash_to_group::(PERSONALIZATION, message)?; 77 | let signature = hashed_message.mul(sk.into_repr()); 78 | let sig = signature.into_affine(); 79 | Ok(sig) 80 | } 81 | 82 | fn verify( 83 | &self, 84 | public_key: &Self::PublicKey, 85 | message: &[u8], 86 | signature: &Self::Signature, 87 | ) -> Result<(), SignatureError> { 88 | let hashed_message = hash_to_group::(PERSONALIZATION, message)?; 89 | 90 | let eq = vec![ 91 | (*public_key, hashed_message.into_affine()), 92 | (self.srs.g_public_key.neg(), *signature), 93 | ]; 94 | let sig = B::product_of_pairings(eq); 95 | if !sig.is_one() { 96 | return Err(SignatureError::BLSVerify); 97 | } 98 | 99 | Ok(()) 100 | } 101 | } 102 | 103 | impl AggregatableSignatureScheme for BLSSignature { 104 | fn aggregate_public_keys( 105 | &self, 106 | public_keys: &[&Self::PublicKey], 107 | ) -> Result { 108 | Ok(public_keys 109 | .iter() 110 | .fold(Self::PublicKey::zero(), |acc, &x| acc + *x)) 111 | } 112 | 113 | fn aggregate_signatures( 114 | &self, 115 | signatures: &[&Self::Signature], 116 | ) -> Result { 117 | Ok(signatures 118 | .iter() 119 | .fold(Self::Signature::zero(), |acc, &x| acc + *x)) 120 | } 121 | } 122 | 123 | impl BatchVerifiableSignatureScheme for BLSSignature { 124 | fn batch_verify( 125 | &self, 126 | rng: &mut R, 127 | public_keys: &[&Self::PublicKey], 128 | messages: &[&[u8]], 129 | signatures: &[&Self::Signature], 130 | ) -> Result<(), SignatureError> { 131 | if public_keys.len() != messages.len() || public_keys.len() != signatures.len() { 132 | return Err(SignatureError::BatchVerification( 133 | public_keys.len(), 134 | messages.len(), 135 | signatures.len(), 136 | )); 137 | } 138 | let mut pairs = vec![]; 139 | for i in 0..public_keys.len() { 140 | let hashed_message = hash_to_group::(PERSONALIZATION, messages[i])?; 141 | 142 | let eq = vec![ 143 | (*public_keys[i], hashed_message.into_affine()), 144 | (self.srs.g_public_key.neg(), *signatures[i]), 145 | ]; 146 | 147 | pairs.push(eq); 148 | } 149 | 150 | if !B::batch_product_of_pairings_is_one(rng, pairs) { 151 | return Err(SignatureError::BLSVerify); 152 | } 153 | 154 | Ok(()) 155 | } 156 | } 157 | 158 | #[derive(Clone, Debug, PartialEq)] 159 | pub struct BLSSignatureG1 { 160 | pairing_type: std::marker::PhantomData, 161 | } 162 | impl BLSSignatureScheme for BLSSignatureG1 { 163 | type PublicKeyGroup = E::G2Affine; 164 | type SignatureGroup = E::G1Affine; 165 | type SignatureGroupProjective = E::G1Projective; 166 | type TargetGroup = E::Fqk; 167 | 168 | fn product_of_pairings( 169 | pairs: Vec<(Self::PublicKeyGroup, Self::SignatureGroup)>, 170 | ) -> Self::TargetGroup { 171 | let pairs = pairs 172 | .into_iter() 173 | .map(|p| (p.1.into(), p.0.into())) 174 | .collect::>(); 175 | E::product_of_pairings(pairs.iter()) 176 | } 177 | 178 | fn batch_product_of_pairings_is_one( 179 | rng: &mut R, 180 | pairs_list: Vec>, 181 | ) -> bool { 182 | let alpha = E::Fr::rand(rng); 183 | 184 | let mut current_alpha = E::Fr::one(); 185 | let mut batch_elements = vec![]; 186 | let mut other_elements = vec![]; 187 | for pairs in pairs_list { 188 | for pair in pairs { 189 | batch_elements.push(pair.1.mul(current_alpha.into_repr())); 190 | other_elements.push(pair.0); 191 | } 192 | current_alpha *= α 193 | } 194 | let batch_elements_affine = 195 | E::G1Projective::batch_normalization_into_affine(&batch_elements); 196 | let batch_pairs = other_elements 197 | .into_iter() 198 | .zip(batch_elements_affine.into_iter()) 199 | .collect::>(); 200 | 201 | Self::product_of_pairings(batch_pairs).is_one() 202 | } 203 | } 204 | 205 | #[derive(Clone, Debug, PartialEq)] 206 | pub struct BLSSignatureG2 { 207 | pairing_type: std::marker::PhantomData, 208 | } 209 | impl BLSSignatureScheme for BLSSignatureG2 { 210 | type PublicKeyGroup = E::G1Affine; 211 | type SignatureGroup = E::G2Affine; 212 | type SignatureGroupProjective = E::G2Projective; 213 | type TargetGroup = E::Fqk; 214 | 215 | fn product_of_pairings( 216 | pairs: Vec<(Self::PublicKeyGroup, Self::SignatureGroup)>, 217 | ) -> Self::TargetGroup { 218 | let pairs = pairs 219 | .into_iter() 220 | .map(|p| (p.0.into(), p.1.into())) 221 | .collect::>(); 222 | E::product_of_pairings(pairs.iter()) 223 | } 224 | 225 | fn batch_product_of_pairings_is_one( 226 | rng: &mut R, 227 | pairs_list: Vec>, 228 | ) -> bool { 229 | let alpha = E::Fr::rand(rng); 230 | 231 | let mut current_alpha = E::Fr::one(); 232 | let mut batch_elements = vec![]; 233 | let mut other_elements = vec![]; 234 | for pairs in pairs_list { 235 | for pair in pairs { 236 | batch_elements.push(pair.0.mul(current_alpha.into_repr())); 237 | other_elements.push(pair.1); 238 | } 239 | current_alpha *= α 240 | } 241 | let batch_elements_affine = 242 | E::G1Projective::batch_normalization_into_affine(&batch_elements); 243 | let batch_pairs = batch_elements_affine 244 | .into_iter() 245 | .zip(other_elements.into_iter()) 246 | .collect::>(); 247 | 248 | Self::product_of_pairings(batch_pairs).is_one() 249 | } 250 | } 251 | 252 | #[cfg(test)] 253 | mod test { 254 | use ark_bls12_381::Bls12_381; 255 | 256 | use super::{BLSSignatureG1, BLSSignatureG2, BLSSignatureScheme, SRS}; 257 | use crate::signature::{ 258 | scheme::{AggregatableSignatureScheme, SignatureScheme}, 259 | utils::tests::check_serialization, 260 | }; 261 | 262 | use crate::signature::{bls::BLSSignature, scheme::BatchVerifiableSignatureScheme}; 263 | use rand::thread_rng; 264 | 265 | #[test] 266 | fn test_simple_sig_g1() { 267 | test_simple_sig::>(); 268 | } 269 | 270 | #[test] 271 | fn test_simple_sig_g2() { 272 | test_simple_sig::>(); 273 | } 274 | 275 | fn test_simple_sig() { 276 | let rng = &mut thread_rng(); 277 | let srs = SRS::::setup(rng).unwrap(); 278 | let bls = BLSSignature { srs }; 279 | let keypair = bls.generate_keypair(rng).unwrap(); 280 | let message = b"hello"; 281 | 282 | let signature = bls.sign(rng, &keypair.0, &message[..]).unwrap(); 283 | bls.verify(&keypair.1, &message[..], &signature).unwrap(); 284 | } 285 | 286 | #[test] 287 | #[should_panic] 288 | fn test_simple_sig_wrong_pk_g1() { 289 | test_simple_sig_wrong_pk::>(); 290 | } 291 | #[test] 292 | #[should_panic] 293 | fn test_simple_sig_wrong_pk_g2() { 294 | test_simple_sig_wrong_pk::>(); 295 | } 296 | 297 | fn test_simple_sig_wrong_pk() { 298 | let rng = &mut thread_rng(); 299 | let srs = SRS::::setup(rng).unwrap(); 300 | let bls = BLSSignature { srs }; 301 | let keypair = bls.generate_keypair(rng).unwrap(); 302 | let message = b"hello"; 303 | 304 | let signature = bls.sign(rng, &keypair.0, &message[..]).unwrap(); 305 | 306 | let keypair2 = bls.generate_keypair(rng).unwrap(); 307 | bls.verify(&keypair2.1, &message[..], &signature).unwrap(); 308 | } 309 | 310 | #[test] 311 | #[should_panic] 312 | fn test_simple_sig_wrong_message_g1() { 313 | test_simple_sig_wrong_message::>(); 314 | } 315 | #[test] 316 | #[should_panic] 317 | fn test_simple_sig_wrong_message_g2() { 318 | test_simple_sig_wrong_message::>(); 319 | } 320 | 321 | fn test_simple_sig_wrong_message() { 322 | let rng = &mut thread_rng(); 323 | let srs = SRS::::setup(rng).unwrap(); 324 | let bls = BLSSignature { srs }; 325 | let keypair = bls.generate_keypair(rng).unwrap(); 326 | let message = b"hello"; 327 | 328 | let signature = bls.sign(rng, &keypair.0, &message[..]).unwrap(); 329 | 330 | let wrong_message = b"goodbye"; 331 | bls.verify(&keypair.1, &wrong_message[..], &signature) 332 | .unwrap(); 333 | } 334 | 335 | #[test] 336 | fn test_aggregated_sig_g1() { 337 | test_aggregated_sig::>(); 338 | } 339 | 340 | #[test] 341 | fn test_aggregated_sig_g2() { 342 | test_aggregated_sig::>(); 343 | } 344 | 345 | fn test_aggregated_sig() { 346 | let rng = &mut thread_rng(); 347 | let srs = SRS::::setup(rng).unwrap(); 348 | let bls = BLSSignature { srs }; 349 | let keypair1 = bls.generate_keypair(rng).unwrap(); 350 | let keypair2 = bls.generate_keypair(rng).unwrap(); 351 | let message = b"hello"; 352 | 353 | let signature1 = bls.sign(rng, &keypair1.0, &message[..]).unwrap(); 354 | bls.verify(&keypair1.1, &message[..], &signature1).unwrap(); 355 | 356 | let signature2 = bls.sign(rng, &keypair2.0, &message[..]).unwrap(); 357 | bls.verify(&keypair2.1, &message[..], &signature2).unwrap(); 358 | 359 | let aggregated_pk = bls 360 | .aggregate_public_keys(&[&keypair1.1, &keypair2.1]) 361 | .unwrap(); 362 | let aggregated_sig = bls 363 | .aggregate_signatures(&[&signature1, &signature2]) 364 | .unwrap(); 365 | 366 | bls.verify(&aggregated_pk, message, &aggregated_sig) 367 | .unwrap(); 368 | } 369 | 370 | #[test] 371 | #[should_panic] 372 | fn test_aggregated_sig_wrong_pk_g1() { 373 | test_aggregated_sig_wrong_pk::>(); 374 | } 375 | #[test] 376 | #[should_panic] 377 | fn test_aggregated_sig_wrong_pk_g2() { 378 | test_aggregated_sig_wrong_pk::>(); 379 | } 380 | fn test_aggregated_sig_wrong_pk() { 381 | let rng = &mut thread_rng(); 382 | let srs = SRS::::setup(rng).unwrap(); 383 | let bls = BLSSignature { srs }; 384 | let keypair1 = bls.generate_keypair(rng).unwrap(); 385 | let keypair2 = bls.generate_keypair(rng).unwrap(); 386 | let message = b"hello"; 387 | 388 | let signature1 = bls.sign(rng, &keypair1.0, &message[..]).unwrap(); 389 | bls.verify(&keypair1.1, &message[..], &signature1).unwrap(); 390 | 391 | let signature2 = bls.sign(rng, &keypair2.0, &message[..]).unwrap(); 392 | bls.verify(&keypair1.1, &message[..], &signature2).unwrap(); 393 | 394 | let aggregated_sig = bls 395 | .aggregate_signatures(&[&signature1, &signature2]) 396 | .unwrap(); 397 | bls.verify(&keypair1.1, message, &aggregated_sig).unwrap(); 398 | } 399 | 400 | #[test] 401 | #[should_panic] 402 | fn test_aggregated_sig_wrong_message_g1() { 403 | test_aggregated_sig_wrong_message::>(); 404 | } 405 | #[test] 406 | #[should_panic] 407 | fn test_aggregated_sig_wrong_message_g2() { 408 | test_aggregated_sig_wrong_message::>(); 409 | } 410 | fn test_aggregated_sig_wrong_message() { 411 | let rng = &mut thread_rng(); 412 | let srs = SRS::::setup(rng).unwrap(); 413 | let bls = BLSSignature { srs }; 414 | let keypair1 = bls.generate_keypair(rng).unwrap(); 415 | let keypair2 = bls.generate_keypair(rng).unwrap(); 416 | let message = b"hello"; 417 | 418 | let signature1 = bls.sign(rng, &keypair1.0, &message[..]).unwrap(); 419 | bls.verify(&keypair1.1, &message[..], &signature1).unwrap(); 420 | 421 | let signature2 = bls.sign(rng, &keypair2.0, &message[..]).unwrap(); 422 | bls.verify(&keypair2.1, &message[..], &signature2).unwrap(); 423 | 424 | let aggregated_pk = bls 425 | .aggregate_public_keys(&[&keypair1.1, &keypair2.1]) 426 | .unwrap(); 427 | let aggregated_sig = bls 428 | .aggregate_signatures(&[&signature1, &signature2]) 429 | .unwrap(); 430 | 431 | let wrong_message = b"goodbye"; 432 | bls.verify(&aggregated_pk, wrong_message, &aggregated_sig) 433 | .unwrap(); 434 | } 435 | 436 | #[test] 437 | fn test_simple_sig_batch_g1() { 438 | test_simple_sig_batch::>(); 439 | } 440 | 441 | #[test] 442 | fn test_simple_sig_batch_g2() { 443 | test_simple_sig_batch::>(); 444 | } 445 | 446 | fn test_simple_sig_batch() { 447 | let rng = &mut thread_rng(); 448 | let srs = SRS::::setup(rng).unwrap(); 449 | let bls = BLSSignature { srs }; 450 | let keypair = bls.generate_keypair(rng).unwrap(); 451 | let message = b"hello"; 452 | let signature = bls.sign(rng, &keypair.0, &message[..]).unwrap(); 453 | let keypair2 = bls.generate_keypair(rng).unwrap(); 454 | let message2 = b"hello2"; 455 | let signature2 = bls.sign(rng, &keypair2.0, &message2[..]).unwrap(); 456 | bls.batch_verify( 457 | rng, 458 | &[&keypair.1, &keypair2.1], 459 | &[&message[..], &message2[..]], 460 | &[&signature, &signature2], 461 | ) 462 | .unwrap(); 463 | } 464 | 465 | #[test] 466 | fn test_serialization_g1() { 467 | test_serialization::>(); 468 | } 469 | #[test] 470 | fn test_serialization_g2() { 471 | test_serialization::>(); 472 | } 473 | fn test_serialization() { 474 | let rng = &mut thread_rng(); 475 | let srs = SRS::::setup(rng).unwrap(); 476 | let bls = BLSSignature { srs: srs.clone() }; 477 | let keypair = bls.generate_keypair(rng).unwrap(); 478 | let message = b"hello"; 479 | let signature = bls.sign(rng, &keypair.0, &message[..]).unwrap(); 480 | 481 | check_serialization(srs.clone()); 482 | check_serialization(keypair.clone()); 483 | check_serialization(signature.clone()); 484 | } 485 | } 486 | -------------------------------------------------------------------------------- /src/dkg/node.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | dkg::{ 3 | aggregator::DKGAggregator, 4 | config::Config, 5 | dealer::Dealer, 6 | errors::DKGError, 7 | participant::{Participant, ParticipantState}, 8 | pvss::{PVSSShare, PVSSShareSecrets}, 9 | share::{message_from_c_i, DKGShare, DKGTranscript}, 10 | }, 11 | signature::scheme::BatchVerifiableSignatureScheme, 12 | }; 13 | use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; 14 | use ark_ff::{Field, PrimeField, UniformRand}; 15 | use ark_poly::{EvaluationDomain, Radix2EvaluationDomain}; 16 | use rand::Rng; 17 | use std::collections::BTreeMap; 18 | 19 | pub struct Node< 20 | E: PairingEngine, 21 | SPOK: BatchVerifiableSignatureScheme, 22 | SSIG: BatchVerifiableSignatureScheme, 23 | > { 24 | pub aggregator: DKGAggregator, 25 | pub dealer: Dealer, 26 | } 27 | 28 | impl< 29 | E: PairingEngine, 30 | SPOK: BatchVerifiableSignatureScheme, 31 | SSIG: BatchVerifiableSignatureScheme, 32 | > Node 33 | { 34 | pub fn new( 35 | config: Config, 36 | scheme_pok: SPOK, 37 | scheme_sig: SSIG, 38 | dealer: Dealer, 39 | participants: BTreeMap>, 40 | ) -> Result> { 41 | let degree = config.degree; 42 | let num_participants = participants.len(); 43 | let node = Node { 44 | aggregator: DKGAggregator { 45 | config, 46 | scheme_pok, 47 | scheme_sig, 48 | participants, 49 | transcript: DKGTranscript::empty(degree, num_participants), 50 | }, 51 | dealer, 52 | }; 53 | Ok(node) 54 | } 55 | 56 | pub fn share_pvss( 57 | &mut self, 58 | rng: &mut R, 59 | ) -> Result<(PVSSShare, PVSSShareSecrets), DKGError> { 60 | let mut f = (0..=self.aggregator.config.degree) 61 | .map(|_| E::Fr::rand(rng)) 62 | .collect::>(); 63 | let domain = Radix2EvaluationDomain::::new(self.aggregator.participants.len()) 64 | .ok_or(DKGError::::EvaluationDomainError)?; 65 | let y_eval_i = domain.fft(&mut f); 66 | 67 | let f_i = f[1..=self.aggregator.config.degree] 68 | .iter() 69 | .map(|a| { 70 | self.aggregator 71 | .config 72 | .srs 73 | .g_g1 74 | .mul(a.into_repr()) 75 | .into_affine() 76 | }) 77 | .collect::>(); 78 | let u_i_2 = self 79 | .aggregator 80 | .config 81 | .u_1 82 | .mul(f[0].into_repr()) 83 | .into_affine(); 84 | let a_i = y_eval_i 85 | .iter() 86 | .map(|a| { 87 | self.aggregator 88 | .config 89 | .srs 90 | .g_g1 91 | .mul(a.into_repr()) 92 | .into_affine() 93 | }) 94 | .collect::>(); 95 | let y_i = y_eval_i 96 | .iter() 97 | .enumerate() 98 | .map::>, _>(|(i, a)| { 99 | Ok(self 100 | .aggregator 101 | .participants 102 | .get(&i) 103 | .ok_or(DKGError::::InvalidParticipantId(i))? 104 | .public_key_sig 105 | .mul(a.into_repr()) 106 | .into_affine()) 107 | }) 108 | .collect::>()?; 109 | let pvss_share = PVSSShare { 110 | f_i, 111 | u_i_2, 112 | a_i, 113 | y_i, 114 | }; 115 | 116 | let my_secret = self 117 | .aggregator 118 | .config 119 | .srs 120 | .h_g2 121 | .mul(y_eval_i[self.dealer.participant.id].into_repr()) 122 | .into_affine(); 123 | 124 | let pvss_share_secrets = PVSSShareSecrets { 125 | f_0: f[0], 126 | my_secret, 127 | }; 128 | 129 | Ok((pvss_share, pvss_share_secrets)) 130 | } 131 | 132 | pub fn share(&mut self, rng: &mut R) -> Result, DKGError> { 133 | let (pvss_share, pvss_share_secrets) = self.share_pvss(rng)?; 134 | let c_i = self 135 | .aggregator 136 | .config 137 | .srs 138 | .g_g1 139 | .mul(pvss_share_secrets.f_0.into_repr()) 140 | .into_affine(); 141 | 142 | let pok_keypair = self 143 | .aggregator 144 | .scheme_pok 145 | .from_sk(&pvss_share_secrets.f_0)?; 146 | let pok = self 147 | .aggregator 148 | .scheme_pok 149 | .sign(rng, &pok_keypair.0, &message_from_c_i(c_i)?)?; 150 | 151 | let signature_keypair = self 152 | .aggregator 153 | .scheme_sig 154 | .from_sk(&(self.dealer.private_key_sig))?; 155 | let signature = 156 | self.aggregator 157 | .scheme_sig 158 | .sign(rng, &signature_keypair.0, &message_from_c_i(c_i)?)?; 159 | 160 | let share = DKGShare { 161 | participant_id: self.dealer.participant.id, 162 | c_i, 163 | pvss_share, 164 | c_i_pok: pok, 165 | signature_on_c_i: signature, 166 | }; 167 | 168 | self.dealer.participant.state = ParticipantState::DealerShared; 169 | Ok(share) 170 | } 171 | 172 | // Assumes that the participant id has been authenticated. 173 | pub fn receive_share_and_decrypt( 174 | &mut self, 175 | rng: &mut R, 176 | share: DKGShare, 177 | ) -> Result<(), DKGError> { 178 | let participant_id = share.participant_id; 179 | 180 | match (|| -> Result> { 181 | self.aggregator.receive_share(rng, &share)?; 182 | 183 | let secret = share.pvss_share.y_i[self.dealer.participant.id] 184 | .mul(self.dealer.private_key_sig.inverse().unwrap().into_repr()) 185 | .into_affine(); 186 | 187 | Ok(secret) 188 | })() { 189 | Ok(secret) => { 190 | self.dealer.accumulated_secret = self.dealer.accumulated_secret + secret; 191 | let participant = self 192 | .aggregator 193 | .participants 194 | .get_mut(&participant_id) 195 | .ok_or(DKGError::::InvalidParticipantId(participant_id))?; 196 | participant.state = ParticipantState::Verified; 197 | } 198 | Err(_) => {} 199 | }; 200 | 201 | Ok(()) 202 | } 203 | 204 | // Assumes that the participant id has been authenticated. 205 | pub fn receive_transcript_and_decrypt( 206 | &mut self, 207 | rng: &mut R, 208 | transcript: DKGTranscript, 209 | ) -> Result<(), DKGError> { 210 | self.aggregator.receive_transcript(rng, &transcript)?; 211 | 212 | let secret = transcript.pvss_share.y_i[self.dealer.participant.id] 213 | .mul(self.dealer.private_key_sig.inverse().unwrap().into_repr()) 214 | .into_affine(); 215 | 216 | for (participant_id, _) in transcript.contributions { 217 | let participant = self 218 | .aggregator 219 | .participants 220 | .get_mut(&participant_id) 221 | .ok_or(DKGError::::InvalidParticipantId(participant_id))?; 222 | participant.state = ParticipantState::Verified; 223 | } 224 | self.dealer.accumulated_secret = self.dealer.accumulated_secret + secret; 225 | 226 | Ok(()) 227 | } 228 | } 229 | 230 | #[cfg(test)] 231 | mod test { 232 | use crate::{ 233 | dkg::{ 234 | aggregator::DKGAggregator, 235 | config::Config, 236 | dealer::Dealer, 237 | node::Node, 238 | participant::{Participant, ParticipantState}, 239 | share::DKGTranscript, 240 | srs::SRS, 241 | }, 242 | signature::{ 243 | bls::{srs::SRS as BLSSRS, BLSSignature, BLSSignatureG1, BLSSignatureG2}, 244 | scheme::{BatchVerifiableSignatureScheme, SignatureScheme}, 245 | schnorr::{srs::SRS as SchnorrSRS, SchnorrSignature}, 246 | }, 247 | }; 248 | use ark_bls12_381::{Bls12_381, Fr, G1Affine, G1Projective, G2Affine, G2Projective}; 249 | use ark_ec::ProjectiveCurve; 250 | use ark_ff::{UniformRand, Zero}; 251 | use rand::thread_rng; 252 | 253 | use std::marker::PhantomData; 254 | 255 | #[test] 256 | fn test_one() { 257 | let rng = &mut thread_rng(); 258 | let srs = SRS::::setup(rng).unwrap(); 259 | let bls_sig = BLSSignature::> { 260 | srs: BLSSRS { 261 | g_public_key: srs.h_g2, 262 | g_signature: srs.g_g1, 263 | }, 264 | }; 265 | let bls_pok = BLSSignature::> { 266 | srs: BLSSRS { 267 | g_public_key: srs.g_g1, 268 | g_signature: srs.h_g2, 269 | }, 270 | }; 271 | let dealer_keypair_sig = bls_sig.generate_keypair(rng).unwrap(); 272 | let dealer = Dealer { 273 | private_key_sig: dealer_keypair_sig.0, 274 | accumulated_secret: G2Projective::zero().into_affine(), 275 | participant: Participant { 276 | pairing_type: PhantomData, 277 | id: 0, 278 | public_key_sig: dealer_keypair_sig.1, 279 | state: ParticipantState::Dealer, 280 | }, 281 | }; 282 | 283 | let u_1 = G2Projective::rand(rng).into_affine(); 284 | let dkg_config = Config { 285 | srs: srs.clone(), 286 | u_1, 287 | degree: 10, 288 | }; 289 | 290 | let participants = vec![dealer.participant.clone()]; 291 | let degree = dkg_config.degree; 292 | let num_participants = participants.len(); 293 | 294 | let mut node = Node { 295 | aggregator: DKGAggregator { 296 | config: dkg_config.clone(), 297 | scheme_pok: bls_pok.clone(), 298 | scheme_sig: bls_sig.clone(), 299 | participants: participants.clone().into_iter().enumerate().collect(), 300 | transcript: DKGTranscript::empty(degree, num_participants), 301 | }, 302 | dealer, 303 | }; 304 | 305 | node.share(rng).unwrap(); 306 | } 307 | 308 | #[test] 309 | fn test_2_nodes_verify() { 310 | const NODES: usize = 4; 311 | 312 | let rng = &mut thread_rng(); 313 | let srs = SRS::::setup(rng).unwrap(); 314 | let bls_sig = BLSSignature::> { 315 | srs: BLSSRS { 316 | g_public_key: srs.h_g2, 317 | g_signature: srs.g_g1, 318 | }, 319 | }; 320 | let bls_pok = BLSSignature::> { 321 | srs: BLSSRS { 322 | g_public_key: srs.g_g1, 323 | g_signature: srs.h_g2, 324 | }, 325 | }; 326 | 327 | let u_1 = G2Projective::rand(rng).into_affine(); 328 | let dkg_config = Config { 329 | srs: srs.clone(), 330 | u_1, 331 | degree: 2, 332 | }; 333 | 334 | let mut dealers = vec![]; 335 | for i in 0..NODES { 336 | let dealer_keypair_sig = bls_sig.generate_keypair(rng).unwrap(); 337 | let participant = Participant { 338 | pairing_type: PhantomData, 339 | id: i, 340 | public_key_sig: dealer_keypair_sig.1, 341 | state: ParticipantState::Dealer, 342 | }; 343 | let dealer = Dealer { 344 | private_key_sig: dealer_keypair_sig.0, 345 | accumulated_secret: G2Projective::zero().into_affine(), 346 | participant, 347 | }; 348 | 349 | dealers.push(dealer); 350 | } 351 | 352 | let participants = dealers 353 | .iter() 354 | .map(|d| d.participant.clone()) 355 | .collect::>(); 356 | let mut nodes = vec![]; 357 | for i in 0..NODES { 358 | let degree = dkg_config.degree; 359 | let num_participants = participants.len(); 360 | let node = Node { 361 | aggregator: DKGAggregator { 362 | config: dkg_config.clone(), 363 | scheme_pok: bls_pok.clone(), 364 | scheme_sig: bls_sig.clone(), 365 | participants: participants.clone().into_iter().enumerate().collect(), 366 | transcript: DKGTranscript::empty(degree, num_participants), 367 | }, 368 | dealer: dealers[i].clone(), 369 | }; 370 | nodes.push(node); 371 | } 372 | for i in 0..NODES { 373 | let node = &mut nodes[i]; 374 | let share = node.share(rng).unwrap(); 375 | for j in 0..NODES { 376 | nodes[j] 377 | .receive_share_and_decrypt(rng, share.clone()) 378 | .unwrap(); 379 | } 380 | } 381 | } 382 | 383 | #[test] 384 | fn test_2_nodes_and_aggregator_bls() { 385 | let rng = &mut thread_rng(); 386 | let srs = SRS::::setup(rng).unwrap(); 387 | let bls_sig = BLSSignature::> { 388 | srs: BLSSRS { 389 | g_public_key: srs.h_g2, 390 | g_signature: srs.g_g1, 391 | }, 392 | }; 393 | let bls_pok = BLSSignature::> { 394 | srs: BLSSRS { 395 | g_public_key: srs.g_g1, 396 | g_signature: srs.h_g2, 397 | }, 398 | }; 399 | test_2_nodes_and_aggregator_with_signature_scheme(srs, bls_pok, bls_sig); 400 | } 401 | #[test] 402 | fn test_2_nodes_and_aggregator_schnorr() { 403 | let rng = &mut thread_rng(); 404 | let srs = SRS::::setup(rng).unwrap(); 405 | let schnorr_sig = SchnorrSignature:: { 406 | srs: SchnorrSRS { 407 | g_public_key: srs.h_g2, 408 | }, 409 | }; 410 | let schnorr_pok = SchnorrSignature:: { 411 | srs: SchnorrSRS { 412 | g_public_key: srs.g_g1, 413 | }, 414 | }; 415 | test_2_nodes_and_aggregator_with_signature_scheme(srs, schnorr_pok, schnorr_sig); 416 | } 417 | 418 | fn test_2_nodes_and_aggregator_with_signature_scheme< 419 | SPOK: BatchVerifiableSignatureScheme, 420 | SSIG: BatchVerifiableSignatureScheme, 421 | >( 422 | srs: SRS, 423 | spok: SPOK, 424 | ssig: SSIG, 425 | ) { 426 | const NODES: usize = 4; 427 | 428 | let rng = &mut thread_rng(); 429 | 430 | let u_1 = G2Projective::rand(rng).into_affine(); 431 | let dkg_config = Config { 432 | srs: srs.clone(), 433 | u_1, 434 | degree: 2, 435 | }; 436 | 437 | let mut dealers = vec![]; 438 | for i in 0..NODES { 439 | let dealer_keypair_sig = ssig.generate_keypair(rng).unwrap(); 440 | let participant = Participant { 441 | pairing_type: PhantomData, 442 | id: i, 443 | public_key_sig: dealer_keypair_sig.1, 444 | state: ParticipantState::Dealer, 445 | }; 446 | let dealer = Dealer { 447 | private_key_sig: dealer_keypair_sig.0, 448 | accumulated_secret: G2Projective::zero().into_affine(), 449 | participant, 450 | }; 451 | 452 | dealers.push(dealer); 453 | } 454 | 455 | let participants = dealers 456 | .iter() 457 | .map(|d| d.participant.clone()) 458 | .collect::>(); 459 | let num_participants = participants.len(); 460 | 461 | let mut aggregator = DKGAggregator { 462 | config: dkg_config.clone(), 463 | scheme_pok: spok.clone(), 464 | scheme_sig: ssig.clone(), 465 | participants: participants.clone().into_iter().enumerate().collect(), 466 | transcript: DKGTranscript::empty(dkg_config.degree, num_participants), 467 | }; 468 | 469 | let mut nodes = vec![]; 470 | for i in 0..NODES { 471 | let degree = dkg_config.degree; 472 | let node = Node { 473 | aggregator: DKGAggregator { 474 | config: dkg_config.clone(), 475 | scheme_pok: spok.clone(), 476 | scheme_sig: ssig.clone(), 477 | participants: participants.clone().into_iter().enumerate().collect(), 478 | transcript: DKGTranscript::empty(degree, num_participants), 479 | }, 480 | dealer: dealers[i].clone(), 481 | }; 482 | nodes.push(node); 483 | } 484 | // Make participant 0 have weight 2. 485 | // Should ignore participant 1, since we modify its share to be bad. 486 | for i in 0..NODES { 487 | let node = &mut nodes[i]; 488 | let mut share = node.share(rng).unwrap(); 489 | for j in 0..NODES { 490 | if i == 1 { 491 | share.c_i = G1Projective::rand(rng).into_affine(); 492 | } 493 | 494 | nodes[j] 495 | .receive_share_and_decrypt(rng, share.clone()) 496 | .unwrap(); 497 | if i == 0 { 498 | nodes[j] 499 | .receive_share_and_decrypt(rng, share.clone()) 500 | .unwrap(); 501 | } 502 | } 503 | if i != 1 { 504 | aggregator.receive_share(rng, &share.clone()).unwrap(); 505 | if i == 0 { 506 | aggregator.receive_share(rng, &share.clone()).unwrap(); 507 | } 508 | } else { 509 | aggregator.receive_share(rng, &share.clone()).unwrap_err(); 510 | } 511 | } 512 | 513 | let transcript = aggregator.transcript; 514 | for i in 0..NODES { 515 | let degree = dkg_config.degree; 516 | let mut node = Node { 517 | aggregator: DKGAggregator { 518 | config: dkg_config.clone(), 519 | scheme_pok: spok.clone(), 520 | scheme_sig: ssig.clone(), 521 | participants: participants.clone().into_iter().enumerate().collect(), 522 | transcript: DKGTranscript::empty(degree, num_participants), 523 | }, 524 | dealer: dealers[i].clone(), 525 | }; 526 | node.receive_transcript_and_decrypt(rng, transcript.clone()) 527 | .unwrap(); 528 | assert_eq!( 529 | node.dealer.accumulated_secret, 530 | nodes[i].dealer.accumulated_secret 531 | ); 532 | if i == 0 { 533 | assert_eq!(transcript.contributions[&i].weight, 2); 534 | } else if i == 1 { 535 | assert!(transcript.contributions.get(&i).is_none()); 536 | } else { 537 | assert_eq!(transcript.contributions[&i].weight, 1); 538 | } 539 | } 540 | } 541 | } 542 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "aggregatable-dkg" 5 | version = "0.1.0" 6 | dependencies = [ 7 | "ark-bls12-381", 8 | "ark-ec", 9 | "ark-ff", 10 | "ark-poly", 11 | "ark-serialize", 12 | "ark-std", 13 | "blake2s_simd", 14 | "criterion", 15 | "once_cell", 16 | "rand", 17 | "rand_chacha", 18 | "thiserror", 19 | ] 20 | 21 | [[package]] 22 | name = "ahash" 23 | version = "0.7.2" 24 | source = "registry+https://github.com/rust-lang/crates.io-index" 25 | checksum = "7f200cbb1e856866d9eade941cf3aa0c5d7dd36f74311c4273b494f4ef036957" 26 | dependencies = [ 27 | "getrandom 0.2.2", 28 | "once_cell", 29 | "version_check", 30 | ] 31 | 32 | [[package]] 33 | name = "ark-bls12-381" 34 | version = "0.2.0" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "70e1c2ad76c4f725520440b981df3ce2d635f2baa1122750c757c0cf0f3d4b74" 37 | dependencies = [ 38 | "ark-ec", 39 | "ark-ff", 40 | "ark-std", 41 | ] 42 | 43 | [[package]] 44 | name = "ark-ec" 45 | version = "0.2.0" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "c56006994f509d76fbce6f6ffe3108f7191b4f3754ecd00bbae7cac20ec05020" 48 | dependencies = [ 49 | "ark-ff", 50 | "ark-serialize", 51 | "ark-std", 52 | "derivative", 53 | "num-traits", 54 | "zeroize", 55 | ] 56 | 57 | [[package]] 58 | name = "ark-ff" 59 | version = "0.2.0" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | checksum = "a4d8802d40fce9212c5c09be08f75c4b3becc0c488e87f60fff787b01250ce33" 62 | dependencies = [ 63 | "ark-ff-asm", 64 | "ark-ff-macros", 65 | "ark-serialize", 66 | "ark-std", 67 | "derivative", 68 | "num-traits", 69 | "rustc_version 0.3.3", 70 | "zeroize", 71 | ] 72 | 73 | [[package]] 74 | name = "ark-ff-asm" 75 | version = "0.2.0" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "3e8cb28c2137af1ef058aa59616db3f7df67dbb70bf2be4ee6920008cc30d98c" 78 | dependencies = [ 79 | "quote", 80 | "syn", 81 | ] 82 | 83 | [[package]] 84 | name = "ark-ff-macros" 85 | version = "0.2.0" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "0b9c256a93a10ed9708c16a517d6dcfaba3d215c0d7fab44d29a9affefb5eeb8" 88 | dependencies = [ 89 | "num-bigint", 90 | "num-traits", 91 | "quote", 92 | "syn", 93 | ] 94 | 95 | [[package]] 96 | name = "ark-poly" 97 | version = "0.2.0" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "72d6683d21645a2abb94034f6a14e708405e55d9597687952d54b2269922857a" 100 | dependencies = [ 101 | "ark-ff", 102 | "ark-serialize", 103 | "ark-std", 104 | "derivative", 105 | "hashbrown", 106 | ] 107 | 108 | [[package]] 109 | name = "ark-serialize" 110 | version = "0.2.0" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "c3e9b59329dc9b92086b3dc619f31cef4a0c802f10829b575a3666d48a48387d" 113 | dependencies = [ 114 | "ark-serialize-derive", 115 | "ark-std", 116 | ] 117 | 118 | [[package]] 119 | name = "ark-serialize-derive" 120 | version = "0.2.0" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | checksum = "5ac3d78c750b01f5df5b2e76d106ed31487a93b3868f14a7f0eb3a74f45e1d8a" 123 | dependencies = [ 124 | "proc-macro2", 125 | "quote", 126 | "syn", 127 | ] 128 | 129 | [[package]] 130 | name = "ark-std" 131 | version = "0.2.0" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "fb5b856a29bea7b810858116a596beee3d20fc4c5aeb240e8e5a8bca4845a470" 134 | dependencies = [ 135 | "colored", 136 | "rand", 137 | "rand_xorshift", 138 | ] 139 | 140 | [[package]] 141 | name = "arrayref" 142 | version = "0.3.6" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" 145 | 146 | [[package]] 147 | name = "arrayvec" 148 | version = "0.5.2" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" 151 | 152 | [[package]] 153 | name = "atty" 154 | version = "0.2.14" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 157 | dependencies = [ 158 | "hermit-abi", 159 | "libc", 160 | "winapi", 161 | ] 162 | 163 | [[package]] 164 | name = "autocfg" 165 | version = "1.0.1" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 168 | 169 | [[package]] 170 | name = "bitflags" 171 | version = "1.2.1" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 174 | 175 | [[package]] 176 | name = "blake2s_simd" 177 | version = "0.5.11" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "9e461a7034e85b211a4acb57ee2e6730b32912b06c08cc242243c39fc21ae6a2" 180 | dependencies = [ 181 | "arrayref", 182 | "arrayvec", 183 | "constant_time_eq", 184 | ] 185 | 186 | [[package]] 187 | name = "bstr" 188 | version = "0.2.15" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "a40b47ad93e1a5404e6c18dec46b628214fee441c70f4ab5d6942142cc268a3d" 191 | dependencies = [ 192 | "lazy_static", 193 | "memchr", 194 | "regex-automata", 195 | "serde", 196 | ] 197 | 198 | [[package]] 199 | name = "bumpalo" 200 | version = "3.6.1" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" 203 | 204 | [[package]] 205 | name = "byteorder" 206 | version = "1.4.3" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 209 | 210 | [[package]] 211 | name = "cast" 212 | version = "0.2.3" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" 215 | dependencies = [ 216 | "rustc_version 0.2.3", 217 | ] 218 | 219 | [[package]] 220 | name = "cfg-if" 221 | version = "1.0.0" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 224 | 225 | [[package]] 226 | name = "clap" 227 | version = "2.33.3" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" 230 | dependencies = [ 231 | "bitflags", 232 | "textwrap", 233 | "unicode-width", 234 | ] 235 | 236 | [[package]] 237 | name = "colored" 238 | version = "2.0.0" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" 241 | dependencies = [ 242 | "atty", 243 | "lazy_static", 244 | "winapi", 245 | ] 246 | 247 | [[package]] 248 | name = "constant_time_eq" 249 | version = "0.1.5" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" 252 | 253 | [[package]] 254 | name = "criterion" 255 | version = "0.3.4" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "ab327ed7354547cc2ef43cbe20ef68b988e70b4b593cbd66a2a61733123a3d23" 258 | dependencies = [ 259 | "atty", 260 | "cast", 261 | "clap", 262 | "criterion-plot", 263 | "csv", 264 | "itertools 0.10.0", 265 | "lazy_static", 266 | "num-traits", 267 | "oorandom", 268 | "plotters", 269 | "rayon", 270 | "regex", 271 | "serde", 272 | "serde_cbor", 273 | "serde_derive", 274 | "serde_json", 275 | "tinytemplate", 276 | "walkdir", 277 | ] 278 | 279 | [[package]] 280 | name = "criterion-plot" 281 | version = "0.4.3" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "e022feadec601fba1649cfa83586381a4ad31c6bf3a9ab7d408118b05dd9889d" 284 | dependencies = [ 285 | "cast", 286 | "itertools 0.9.0", 287 | ] 288 | 289 | [[package]] 290 | name = "crossbeam-channel" 291 | version = "0.5.0" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" 294 | dependencies = [ 295 | "cfg-if", 296 | "crossbeam-utils", 297 | ] 298 | 299 | [[package]] 300 | name = "crossbeam-deque" 301 | version = "0.8.0" 302 | source = "registry+https://github.com/rust-lang/crates.io-index" 303 | checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" 304 | dependencies = [ 305 | "cfg-if", 306 | "crossbeam-epoch", 307 | "crossbeam-utils", 308 | ] 309 | 310 | [[package]] 311 | name = "crossbeam-epoch" 312 | version = "0.9.3" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "2584f639eb95fea8c798496315b297cf81b9b58b6d30ab066a75455333cf4b12" 315 | dependencies = [ 316 | "cfg-if", 317 | "crossbeam-utils", 318 | "lazy_static", 319 | "memoffset", 320 | "scopeguard", 321 | ] 322 | 323 | [[package]] 324 | name = "crossbeam-utils" 325 | version = "0.8.3" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" 328 | dependencies = [ 329 | "autocfg", 330 | "cfg-if", 331 | "lazy_static", 332 | ] 333 | 334 | [[package]] 335 | name = "csv" 336 | version = "1.1.6" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" 339 | dependencies = [ 340 | "bstr", 341 | "csv-core", 342 | "itoa", 343 | "ryu", 344 | "serde", 345 | ] 346 | 347 | [[package]] 348 | name = "csv-core" 349 | version = "0.1.10" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" 352 | dependencies = [ 353 | "memchr", 354 | ] 355 | 356 | [[package]] 357 | name = "derivative" 358 | version = "2.2.0" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" 361 | dependencies = [ 362 | "proc-macro2", 363 | "quote", 364 | "syn", 365 | ] 366 | 367 | [[package]] 368 | name = "either" 369 | version = "1.6.1" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 372 | 373 | [[package]] 374 | name = "getrandom" 375 | version = "0.1.16" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" 378 | dependencies = [ 379 | "cfg-if", 380 | "libc", 381 | "wasi 0.9.0+wasi-snapshot-preview1", 382 | ] 383 | 384 | [[package]] 385 | name = "getrandom" 386 | version = "0.2.2" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" 389 | dependencies = [ 390 | "cfg-if", 391 | "libc", 392 | "wasi 0.10.2+wasi-snapshot-preview1", 393 | ] 394 | 395 | [[package]] 396 | name = "half" 397 | version = "1.7.1" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" 400 | 401 | [[package]] 402 | name = "hashbrown" 403 | version = "0.11.2" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 406 | dependencies = [ 407 | "ahash", 408 | ] 409 | 410 | [[package]] 411 | name = "hermit-abi" 412 | version = "0.1.18" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" 415 | dependencies = [ 416 | "libc", 417 | ] 418 | 419 | [[package]] 420 | name = "itertools" 421 | version = "0.9.0" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" 424 | dependencies = [ 425 | "either", 426 | ] 427 | 428 | [[package]] 429 | name = "itertools" 430 | version = "0.10.0" 431 | source = "registry+https://github.com/rust-lang/crates.io-index" 432 | checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319" 433 | dependencies = [ 434 | "either", 435 | ] 436 | 437 | [[package]] 438 | name = "itoa" 439 | version = "0.4.7" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" 442 | 443 | [[package]] 444 | name = "js-sys" 445 | version = "0.3.50" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c" 448 | dependencies = [ 449 | "wasm-bindgen", 450 | ] 451 | 452 | [[package]] 453 | name = "lazy_static" 454 | version = "1.4.0" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 457 | 458 | [[package]] 459 | name = "libc" 460 | version = "0.2.91" 461 | source = "registry+https://github.com/rust-lang/crates.io-index" 462 | checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7" 463 | 464 | [[package]] 465 | name = "log" 466 | version = "0.4.14" 467 | source = "registry+https://github.com/rust-lang/crates.io-index" 468 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 469 | dependencies = [ 470 | "cfg-if", 471 | ] 472 | 473 | [[package]] 474 | name = "memchr" 475 | version = "2.3.4" 476 | source = "registry+https://github.com/rust-lang/crates.io-index" 477 | checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" 478 | 479 | [[package]] 480 | name = "memoffset" 481 | version = "0.6.3" 482 | source = "registry+https://github.com/rust-lang/crates.io-index" 483 | checksum = "f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d" 484 | dependencies = [ 485 | "autocfg", 486 | ] 487 | 488 | [[package]] 489 | name = "num-bigint" 490 | version = "0.4.0" 491 | source = "registry+https://github.com/rust-lang/crates.io-index" 492 | checksum = "4e0d047c1062aa51e256408c560894e5251f08925980e53cf1aa5bd00eec6512" 493 | dependencies = [ 494 | "autocfg", 495 | "num-integer", 496 | "num-traits", 497 | ] 498 | 499 | [[package]] 500 | name = "num-integer" 501 | version = "0.1.44" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 504 | dependencies = [ 505 | "autocfg", 506 | "num-traits", 507 | ] 508 | 509 | [[package]] 510 | name = "num-traits" 511 | version = "0.2.14" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 514 | dependencies = [ 515 | "autocfg", 516 | ] 517 | 518 | [[package]] 519 | name = "num_cpus" 520 | version = "1.13.0" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 523 | dependencies = [ 524 | "hermit-abi", 525 | "libc", 526 | ] 527 | 528 | [[package]] 529 | name = "once_cell" 530 | version = "1.7.2" 531 | source = "registry+https://github.com/rust-lang/crates.io-index" 532 | checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" 533 | 534 | [[package]] 535 | name = "oorandom" 536 | version = "11.1.3" 537 | source = "registry+https://github.com/rust-lang/crates.io-index" 538 | checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" 539 | 540 | [[package]] 541 | name = "pest" 542 | version = "2.1.3" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" 545 | dependencies = [ 546 | "ucd-trie", 547 | ] 548 | 549 | [[package]] 550 | name = "plotters" 551 | version = "0.3.0" 552 | source = "registry+https://github.com/rust-lang/crates.io-index" 553 | checksum = "45ca0ae5f169d0917a7c7f5a9c1a3d3d9598f18f529dd2b8373ed988efea307a" 554 | dependencies = [ 555 | "num-traits", 556 | "plotters-backend", 557 | "plotters-svg", 558 | "wasm-bindgen", 559 | "web-sys", 560 | ] 561 | 562 | [[package]] 563 | name = "plotters-backend" 564 | version = "0.3.0" 565 | source = "registry+https://github.com/rust-lang/crates.io-index" 566 | checksum = "b07fffcddc1cb3a1de753caa4e4df03b79922ba43cf882acc1bdd7e8df9f4590" 567 | 568 | [[package]] 569 | name = "plotters-svg" 570 | version = "0.3.0" 571 | source = "registry+https://github.com/rust-lang/crates.io-index" 572 | checksum = "b38a02e23bd9604b842a812063aec4ef702b57989c37b655254bb61c471ad211" 573 | dependencies = [ 574 | "plotters-backend", 575 | ] 576 | 577 | [[package]] 578 | name = "ppv-lite86" 579 | version = "0.2.10" 580 | source = "registry+https://github.com/rust-lang/crates.io-index" 581 | checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" 582 | 583 | [[package]] 584 | name = "proc-macro2" 585 | version = "1.0.24" 586 | source = "registry+https://github.com/rust-lang/crates.io-index" 587 | checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" 588 | dependencies = [ 589 | "unicode-xid", 590 | ] 591 | 592 | [[package]] 593 | name = "quote" 594 | version = "1.0.9" 595 | source = "registry+https://github.com/rust-lang/crates.io-index" 596 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 597 | dependencies = [ 598 | "proc-macro2", 599 | ] 600 | 601 | [[package]] 602 | name = "rand" 603 | version = "0.7.3" 604 | source = "registry+https://github.com/rust-lang/crates.io-index" 605 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 606 | dependencies = [ 607 | "getrandom 0.1.16", 608 | "libc", 609 | "rand_chacha", 610 | "rand_core", 611 | "rand_hc", 612 | ] 613 | 614 | [[package]] 615 | name = "rand_chacha" 616 | version = "0.2.2" 617 | source = "registry+https://github.com/rust-lang/crates.io-index" 618 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" 619 | dependencies = [ 620 | "ppv-lite86", 621 | "rand_core", 622 | ] 623 | 624 | [[package]] 625 | name = "rand_core" 626 | version = "0.5.1" 627 | source = "registry+https://github.com/rust-lang/crates.io-index" 628 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 629 | dependencies = [ 630 | "getrandom 0.1.16", 631 | ] 632 | 633 | [[package]] 634 | name = "rand_hc" 635 | version = "0.2.0" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 638 | dependencies = [ 639 | "rand_core", 640 | ] 641 | 642 | [[package]] 643 | name = "rand_xorshift" 644 | version = "0.2.0" 645 | source = "registry+https://github.com/rust-lang/crates.io-index" 646 | checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" 647 | dependencies = [ 648 | "rand_core", 649 | ] 650 | 651 | [[package]] 652 | name = "rayon" 653 | version = "1.5.0" 654 | source = "registry+https://github.com/rust-lang/crates.io-index" 655 | checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674" 656 | dependencies = [ 657 | "autocfg", 658 | "crossbeam-deque", 659 | "either", 660 | "rayon-core", 661 | ] 662 | 663 | [[package]] 664 | name = "rayon-core" 665 | version = "1.9.0" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" 668 | dependencies = [ 669 | "crossbeam-channel", 670 | "crossbeam-deque", 671 | "crossbeam-utils", 672 | "lazy_static", 673 | "num_cpus", 674 | ] 675 | 676 | [[package]] 677 | name = "regex" 678 | version = "1.4.5" 679 | source = "registry+https://github.com/rust-lang/crates.io-index" 680 | checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" 681 | dependencies = [ 682 | "regex-syntax", 683 | ] 684 | 685 | [[package]] 686 | name = "regex-automata" 687 | version = "0.1.9" 688 | source = "registry+https://github.com/rust-lang/crates.io-index" 689 | checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" 690 | dependencies = [ 691 | "byteorder", 692 | ] 693 | 694 | [[package]] 695 | name = "regex-syntax" 696 | version = "0.6.23" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" 699 | 700 | [[package]] 701 | name = "rustc_version" 702 | version = "0.2.3" 703 | source = "registry+https://github.com/rust-lang/crates.io-index" 704 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 705 | dependencies = [ 706 | "semver 0.9.0", 707 | ] 708 | 709 | [[package]] 710 | name = "rustc_version" 711 | version = "0.3.3" 712 | source = "registry+https://github.com/rust-lang/crates.io-index" 713 | checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" 714 | dependencies = [ 715 | "semver 0.11.0", 716 | ] 717 | 718 | [[package]] 719 | name = "ryu" 720 | version = "1.0.5" 721 | source = "registry+https://github.com/rust-lang/crates.io-index" 722 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 723 | 724 | [[package]] 725 | name = "same-file" 726 | version = "1.0.6" 727 | source = "registry+https://github.com/rust-lang/crates.io-index" 728 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 729 | dependencies = [ 730 | "winapi-util", 731 | ] 732 | 733 | [[package]] 734 | name = "scopeguard" 735 | version = "1.1.0" 736 | source = "registry+https://github.com/rust-lang/crates.io-index" 737 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 738 | 739 | [[package]] 740 | name = "semver" 741 | version = "0.9.0" 742 | source = "registry+https://github.com/rust-lang/crates.io-index" 743 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 744 | dependencies = [ 745 | "semver-parser 0.7.0", 746 | ] 747 | 748 | [[package]] 749 | name = "semver" 750 | version = "0.11.0" 751 | source = "registry+https://github.com/rust-lang/crates.io-index" 752 | checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" 753 | dependencies = [ 754 | "semver-parser 0.10.2", 755 | ] 756 | 757 | [[package]] 758 | name = "semver-parser" 759 | version = "0.7.0" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 762 | 763 | [[package]] 764 | name = "semver-parser" 765 | version = "0.10.2" 766 | source = "registry+https://github.com/rust-lang/crates.io-index" 767 | checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" 768 | dependencies = [ 769 | "pest", 770 | ] 771 | 772 | [[package]] 773 | name = "serde" 774 | version = "1.0.125" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" 777 | 778 | [[package]] 779 | name = "serde_cbor" 780 | version = "0.11.1" 781 | source = "registry+https://github.com/rust-lang/crates.io-index" 782 | checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" 783 | dependencies = [ 784 | "half", 785 | "serde", 786 | ] 787 | 788 | [[package]] 789 | name = "serde_derive" 790 | version = "1.0.125" 791 | source = "registry+https://github.com/rust-lang/crates.io-index" 792 | checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" 793 | dependencies = [ 794 | "proc-macro2", 795 | "quote", 796 | "syn", 797 | ] 798 | 799 | [[package]] 800 | name = "serde_json" 801 | version = "1.0.64" 802 | source = "registry+https://github.com/rust-lang/crates.io-index" 803 | checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" 804 | dependencies = [ 805 | "itoa", 806 | "ryu", 807 | "serde", 808 | ] 809 | 810 | [[package]] 811 | name = "syn" 812 | version = "1.0.67" 813 | source = "registry+https://github.com/rust-lang/crates.io-index" 814 | checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702" 815 | dependencies = [ 816 | "proc-macro2", 817 | "quote", 818 | "unicode-xid", 819 | ] 820 | 821 | [[package]] 822 | name = "synstructure" 823 | version = "0.12.4" 824 | source = "registry+https://github.com/rust-lang/crates.io-index" 825 | checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" 826 | dependencies = [ 827 | "proc-macro2", 828 | "quote", 829 | "syn", 830 | "unicode-xid", 831 | ] 832 | 833 | [[package]] 834 | name = "textwrap" 835 | version = "0.11.0" 836 | source = "registry+https://github.com/rust-lang/crates.io-index" 837 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 838 | dependencies = [ 839 | "unicode-width", 840 | ] 841 | 842 | [[package]] 843 | name = "thiserror" 844 | version = "1.0.24" 845 | source = "registry+https://github.com/rust-lang/crates.io-index" 846 | checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" 847 | dependencies = [ 848 | "thiserror-impl", 849 | ] 850 | 851 | [[package]] 852 | name = "thiserror-impl" 853 | version = "1.0.24" 854 | source = "registry+https://github.com/rust-lang/crates.io-index" 855 | checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" 856 | dependencies = [ 857 | "proc-macro2", 858 | "quote", 859 | "syn", 860 | ] 861 | 862 | [[package]] 863 | name = "tinytemplate" 864 | version = "1.2.1" 865 | source = "registry+https://github.com/rust-lang/crates.io-index" 866 | checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" 867 | dependencies = [ 868 | "serde", 869 | "serde_json", 870 | ] 871 | 872 | [[package]] 873 | name = "ucd-trie" 874 | version = "0.1.3" 875 | source = "registry+https://github.com/rust-lang/crates.io-index" 876 | checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" 877 | 878 | [[package]] 879 | name = "unicode-width" 880 | version = "0.1.8" 881 | source = "registry+https://github.com/rust-lang/crates.io-index" 882 | checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" 883 | 884 | [[package]] 885 | name = "unicode-xid" 886 | version = "0.2.1" 887 | source = "registry+https://github.com/rust-lang/crates.io-index" 888 | checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" 889 | 890 | [[package]] 891 | name = "version_check" 892 | version = "0.9.3" 893 | source = "registry+https://github.com/rust-lang/crates.io-index" 894 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 895 | 896 | [[package]] 897 | name = "walkdir" 898 | version = "2.3.2" 899 | source = "registry+https://github.com/rust-lang/crates.io-index" 900 | checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" 901 | dependencies = [ 902 | "same-file", 903 | "winapi", 904 | "winapi-util", 905 | ] 906 | 907 | [[package]] 908 | name = "wasi" 909 | version = "0.9.0+wasi-snapshot-preview1" 910 | source = "registry+https://github.com/rust-lang/crates.io-index" 911 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 912 | 913 | [[package]] 914 | name = "wasi" 915 | version = "0.10.2+wasi-snapshot-preview1" 916 | source = "registry+https://github.com/rust-lang/crates.io-index" 917 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 918 | 919 | [[package]] 920 | name = "wasm-bindgen" 921 | version = "0.2.73" 922 | source = "registry+https://github.com/rust-lang/crates.io-index" 923 | checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9" 924 | dependencies = [ 925 | "cfg-if", 926 | "wasm-bindgen-macro", 927 | ] 928 | 929 | [[package]] 930 | name = "wasm-bindgen-backend" 931 | version = "0.2.73" 932 | source = "registry+https://github.com/rust-lang/crates.io-index" 933 | checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae" 934 | dependencies = [ 935 | "bumpalo", 936 | "lazy_static", 937 | "log", 938 | "proc-macro2", 939 | "quote", 940 | "syn", 941 | "wasm-bindgen-shared", 942 | ] 943 | 944 | [[package]] 945 | name = "wasm-bindgen-macro" 946 | version = "0.2.73" 947 | source = "registry+https://github.com/rust-lang/crates.io-index" 948 | checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" 949 | dependencies = [ 950 | "quote", 951 | "wasm-bindgen-macro-support", 952 | ] 953 | 954 | [[package]] 955 | name = "wasm-bindgen-macro-support" 956 | version = "0.2.73" 957 | source = "registry+https://github.com/rust-lang/crates.io-index" 958 | checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" 959 | dependencies = [ 960 | "proc-macro2", 961 | "quote", 962 | "syn", 963 | "wasm-bindgen-backend", 964 | "wasm-bindgen-shared", 965 | ] 966 | 967 | [[package]] 968 | name = "wasm-bindgen-shared" 969 | version = "0.2.73" 970 | source = "registry+https://github.com/rust-lang/crates.io-index" 971 | checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489" 972 | 973 | [[package]] 974 | name = "web-sys" 975 | version = "0.3.50" 976 | source = "registry+https://github.com/rust-lang/crates.io-index" 977 | checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be" 978 | dependencies = [ 979 | "js-sys", 980 | "wasm-bindgen", 981 | ] 982 | 983 | [[package]] 984 | name = "winapi" 985 | version = "0.3.9" 986 | source = "registry+https://github.com/rust-lang/crates.io-index" 987 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 988 | dependencies = [ 989 | "winapi-i686-pc-windows-gnu", 990 | "winapi-x86_64-pc-windows-gnu", 991 | ] 992 | 993 | [[package]] 994 | name = "winapi-i686-pc-windows-gnu" 995 | version = "0.4.0" 996 | source = "registry+https://github.com/rust-lang/crates.io-index" 997 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 998 | 999 | [[package]] 1000 | name = "winapi-util" 1001 | version = "0.1.5" 1002 | source = "registry+https://github.com/rust-lang/crates.io-index" 1003 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1004 | dependencies = [ 1005 | "winapi", 1006 | ] 1007 | 1008 | [[package]] 1009 | name = "winapi-x86_64-pc-windows-gnu" 1010 | version = "0.4.0" 1011 | source = "registry+https://github.com/rust-lang/crates.io-index" 1012 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1013 | 1014 | [[package]] 1015 | name = "zeroize" 1016 | version = "1.2.0" 1017 | source = "registry+https://github.com/rust-lang/crates.io-index" 1018 | checksum = "81a974bcdd357f0dca4d41677db03436324d45a4c9ed2d0b873a5a360ce41c36" 1019 | dependencies = [ 1020 | "zeroize_derive", 1021 | ] 1022 | 1023 | [[package]] 1024 | name = "zeroize_derive" 1025 | version = "1.0.1" 1026 | source = "registry+https://github.com/rust-lang/crates.io-index" 1027 | checksum = "c3f369ddb18862aba61aa49bf31e74d29f0f162dec753063200e1dc084345d16" 1028 | dependencies = [ 1029 | "proc-macro2", 1030 | "quote", 1031 | "syn", 1032 | "synstructure", 1033 | ] 1034 | --------------------------------------------------------------------------------