Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fiono11's OLAF #110

Open
wants to merge 63 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
b93d5ea
Implementation of SimplPedPoP
Fiono11 May 6, 2024
0229035
Improvements
Fiono11 May 6, 2024
059b601
Add tests
Fiono11 May 6, 2024
bbb6b74
Fix tests
Fiono11 May 6, 2024
9f64544
WIP
Fiono11 May 6, 2024
2e557c9
Return keys from simplpedpop_recipient_all instead of points and scalars
Fiono11 May 6, 2024
999f299
WIP
Fiono11 May 6, 2024
5fc364a
Replace pub(crate) with pub(super)
Fiono11 May 6, 2024
1a2b54d
WIP
Fiono11 May 6, 2024
9b775b9
WIP
Fiono11 May 6, 2024
75dd78b
WIP
Fiono11 May 6, 2024
1b387d2
Fix in ciphertexts loop
Fiono11 May 7, 2024
cf308ba
Add wrapper types
Fiono11 May 7, 2024
ff8d132
Implement SecretShare and EncryptedSecretShare types
Fiono11 May 8, 2024
2e9b153
Implement SecretPolynomial and PolynomialCommitment types
Fiono11 May 8, 2024
9420ff4
Restructuring of files
Fiono11 May 8, 2024
69473c4
Remove derive_key_from_scalar
Fiono11 May 8, 2024
51d16cd
Remove ephemeral key
Fiono11 May 8, 2024
0be043a
Add Identifier type
Fiono11 May 8, 2024
cc2fd93
Add identifiers to dkg_output
Fiono11 May 8, 2024
d7d061d
Remove proof of possession signature
Fiono11 May 8, 2024
9ed307f
Improvements
Fiono11 May 8, 2024
8b9726e
Fix deserialization of dkg output
Fiono11 May 8, 2024
3771fd5
Remove unwrap
Fiono11 May 9, 2024
04546ed
Improve errors
Fiono11 May 9, 2024
030ce7a
Add polynomial tests
Fiono11 May 9, 2024
ec189f5
Merge final_simplpedpop branch
Fiono11 May 9, 2024
443a40f
Reimplement ephemeral key and proof of possession
Fiono11 May 10, 2024
e1c24d1
Implementation of FROST
Fiono11 May 9, 2024
d8308e0
Add test
Fiono11 May 14, 2024
3bf17d1
Add test
Fiono11 May 14, 2024
f5b0f41
Add frost benchmarks
Fiono11 May 14, 2024
8e779fc
Refractoring
Fiono11 May 14, 2024
206d051
Improvements
Fiono11 May 16, 2024
c4484b6
Implement SigningPackage
Fiono11 May 16, 2024
e3b1c63
Add (de)serialization of SigningPackage test
Fiono11 May 16, 2024
4020137
Fix frost benchmark
Fiono11 May 16, 2024
d830b7b
Implement cheater detection
Fiono11 May 16, 2024
8e091d3
Improvements
Fiono11 May 16, 2024
b0a0ed9
Improvements
Fiono11 May 17, 2024
f67a4f3
Improvements
Fiono11 May 17, 2024
524b01e
Merge changes from final_frost branch to simplpedpop
Fiono11 May 17, 2024
1a9c024
Undo formatting
Fiono11 May 17, 2024
20d539f
Undo formatting
Fiono11 May 17, 2024
1402b1e
Implementation of SimplPedPoP
Fiono11 May 6, 2024
e5b1f7b
Improvements
Fiono11 May 18, 2024
3d67f38
Sign the whole message with the secret of the polynomial
Fiono11 May 18, 2024
689bfed
Merge remote-tracking branch 'fiono/final_simplpedpop' into final_sim…
Fiono11 May 19, 2024
63cbcdf
Sign the whole message with the secret of the polynomial
Fiono11 May 18, 2024
86c8bee
Fixes
Fiono11 May 20, 2024
4835946
Complete serialization of frost
Fiono11 May 20, 2024
35518c6
Fixes
Fiono11 May 20, 2024
d8ca0dd
Use system randomness in frost
Fiono11 May 21, 2024
46b7d30
Small improvements
Fiono11 Jun 1, 2024
fddd002
Make tpk content pub
Fiono11 Jun 5, 2024
df2f948
Merge branch 'Fiono11-final_frost' into Fiono11-final
burdges Jul 30, 2024
b0741a9
Upgrade curve25519-dalek
burdges Jul 30, 2024
1cfc580
Make aead a default feature now
burdges Jul 30, 2024
6829d16
Not FROST since removing 1-round version
burdges Jul 30, 2024
f4d26d6
Again not FROST since removing 1-round version
burdges Jul 30, 2024
3940595
Remove the FRO of FROST aka the dangerous 1-round
burdges Jul 30, 2024
fa7989b
rand_chacha fix maybe?
burdges Jul 30, 2024
bde258e
Ahh maybe this
burdges Jul 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 33 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ aead = { version = "0.5.2", default-features = false, optional = true }
arrayref = { version = "0.3.7", default-features = false }
# needs to match parity-scale-code which is "=0.7.0"
arrayvec = { version = "0.7.4", default-features = false }
curve25519-dalek = { version = "4.1.0", default-features = false, features = [
curve25519-dalek = { version = "4.1.3", default-features = false, features = [
"digest",
"zeroize",
"precomputed-tables",
"legacy_compatibility",
"rand_core",
] }
subtle = { version = "2.4.1", default-features = false }
merlin = { version = "3.0.0", default-features = false }
Expand All @@ -32,11 +33,14 @@ serde_bytes = { version = "0.11.5", default-features = false, optional = true }
cfg-if = { version = "1.0.0", optional = true }
sha2 = { version = "0.10.7", default-features = false }
failure = { version = "0.1.8", default-features = false, optional = true }
zeroize = { version = "1.6", default-features = false, features = ["zeroize_derive"] }
zeroize = { version = "1.6", default-features = false, features = [
"zeroize_derive",
] }
chacha20poly1305 = { version = "0.10.1", default-features = false }
rand_chacha = { version = "0.3.1", default-features = false }

[dev-dependencies]
rand = "0.8.5"
rand_chacha = { version = "0.3.1", default-features = false }
hex-literal = "0.4.1"
sha3 = "0.10.8"
bincode = "1.3.3"
Expand All @@ -47,17 +51,39 @@ serde_json = "1.0.68"
name = "schnorr_benchmarks"
harness = false

[[bench]]
name = "olaf_benchmarks"
required-features = ["alloc", "aead"]
harness = false

[features]
default = ["std", "getrandom"]
default = ["std", "getrandom", "aead"]
rand_chacha = []
preaudit_deprecated = []
nightly = []
alloc = ["curve25519-dalek/alloc", "rand_core/alloc", "getrandom_or_panic/alloc", "serde_bytes/alloc"]
std = ["alloc", "getrandom", "serde_bytes/std", "rand_core/std", "getrandom_or_panic/std"]
alloc = [
"curve25519-dalek/alloc",
"rand_core/alloc",
"getrandom_or_panic/alloc",
"serde_bytes/alloc",
]
std = [
"alloc",
"getrandom",
"serde_bytes/std",
"rand_core/std",
"getrandom_or_panic/std",
"chacha20poly1305/std",
]
asm = ["sha2/asm"]
serde = ["serde_crate", "serde_bytes", "cfg-if"]
# We cannot make getrandom a direct dependency because rand_core makes
# getrandom a feature name, which requires forwarding.
getrandom = ["rand_core/getrandom", "getrandom_or_panic/getrandom", "aead?/getrandom"]
getrandom = [
"rand_core/getrandom",
"getrandom_or_panic/getrandom",
"aead?/getrandom",
]
# We thus cannot forward the wasm-bindgen feature of getrandom,
# but our consumers could depend upon getrandom and activate its
# wasm-bindgen feature themselve, which works due to cargo features
Expand Down
145 changes: 145 additions & 0 deletions benches/olaf_benchmarks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
use criterion::criterion_main;

mod olaf_benches {
use criterion::{criterion_group, BenchmarkId, Criterion};
use schnorrkel::olaf::multisig::aggregate;
use schnorrkel::keys::{PublicKey, Keypair};
use schnorrkel::olaf::multisig::{SigningPackage, SigningNonces, SigningCommitments};
use schnorrkel::olaf::simplpedpop::AllMessage;

fn benchmark_simplpedpop(c: &mut Criterion) {
let mut group = c.benchmark_group("SimplPedPoP");

group.sample_size(10);

for &n in [3, 10, 100, 1000].iter() {
let participants = n;
let threshold = (n * 2 + 2) / 3;

let keypairs: Vec<Keypair> = (0..participants).map(|_| Keypair::generate()).collect();
let public_keys: Vec<PublicKey> = keypairs.iter().map(|kp| kp.public).collect();

let mut all_messages: Vec<AllMessage> = Vec::new();

for i in 0..participants {
let message = keypairs[i]
.simplpedpop_contribute_all(threshold as u16, public_keys.clone())
.unwrap();
all_messages.push(message);
}

group.bench_function(BenchmarkId::new("round1", participants), |b| {
b.iter(|| {
keypairs[0]
.simplpedpop_contribute_all(threshold as u16, public_keys.clone())
.unwrap();
})
});

group.bench_function(BenchmarkId::new("round2", participants), |b| {
b.iter(|| {
keypairs[0].simplpedpop_recipient_all(&all_messages).unwrap();
})
});
}

group.finish();
}

fn benchmark_multisig(c: &mut Criterion) {
let mut group = c.benchmark_group("multisig");

group.sample_size(10);

for &n in [3, 10, 100, 1000].iter() {
let participants = n;
let threshold = (n * 2 + 2) / 3;

let keypairs: Vec<Keypair> = (0..participants).map(|_| Keypair::generate()).collect();
let public_keys: Vec<PublicKey> = keypairs.iter().map(|kp| kp.public).collect();

let mut all_messages = Vec::new();
for i in 0..participants {
let message = keypairs[i]
.simplpedpop_contribute_all(threshold as u16, public_keys.clone())
.unwrap();
all_messages.push(message);
}

let mut spp_outputs = Vec::new();

for kp in keypairs.iter() {
let spp_output = kp.simplpedpop_recipient_all(&all_messages).unwrap();
spp_outputs.push(spp_output);
}

let mut all_signing_commitments: Vec<SigningCommitments> = Vec::new();
let mut all_signing_nonces: Vec<SigningNonces> = Vec::new();

for spp_output in &spp_outputs {
let (signing_nonces, signing_commitments) = spp_output.1.commit();
all_signing_nonces.push(signing_nonces);
all_signing_commitments.push(signing_commitments);
}

group.bench_function(BenchmarkId::new("round1", participants), |b| {
b.iter(|| {
spp_outputs[0].1.commit();
})
});

let mut signing_packages: Vec<SigningPackage> = Vec::new();

let message = b"message";
let context = b"context";

group.bench_function(BenchmarkId::new("round2", participants), |b| {
b.iter(|| {
spp_outputs[0]
.1
.sign(
context.to_vec(),
message.to_vec(),
spp_outputs[0].0.clone().spp_output(),
all_signing_commitments.clone(),
&all_signing_nonces[0],
)
.unwrap();
})
});

for (i, spp_output) in spp_outputs.iter().enumerate() {
let signing_package: SigningPackage = spp_output
.1
.sign(
context.to_vec(),
message.to_vec(),
spp_output.0.clone().spp_output(),
all_signing_commitments.clone(),
&all_signing_nonces[i],
)
.unwrap();

signing_packages.push(signing_package);
}

group.bench_function(BenchmarkId::new("aggregate", participants), |b| {
b.iter(|| {
aggregate(&signing_packages).unwrap();
})
});
}

group.finish();
}

criterion_group! {
name = olaf_benches;
config = Criterion::default();
targets =
benchmark_simplpedpop,
benchmark_multisig,
}
}

criterion_main!(olaf_benches::olaf_benches);
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,9 @@ pub mod derive;
pub mod cert;
pub mod errors;

#[cfg(all(feature = "alloc", feature = "aead"))]
pub mod olaf;

#[cfg(all(feature = "aead", feature = "getrandom"))]
pub mod aead;

Expand Down
76 changes: 76 additions & 0 deletions src/olaf/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//! Implementation of the Olaf protocol (<https://eprint.iacr.org/2023/899>), which is composed of the Distributed
//! Key Generation (DKG) protocol SimplPedPoP and the Threshold Signing protocol FROST.

/// Implementation of the SimplPedPoP protocol.
pub mod simplpedpop;

/// Implementation of the two-round non-deterministic multisig protocol.
pub mod multisig;

use curve25519_dalek::{constants::RISTRETTO_BASEPOINT_POINT, RistrettoPoint, Scalar};
use merlin::Transcript;
use zeroize::ZeroizeOnDrop;
use crate::{context::SigningTranscript, Keypair, PublicKey, SignatureError, KEYPAIR_LENGTH};

pub(super) const MINIMUM_THRESHOLD: u16 = 2;
pub(super) const GENERATOR: RistrettoPoint = RISTRETTO_BASEPOINT_POINT;
pub(super) const COMPRESSED_RISTRETTO_LENGTH: usize = 32;
pub(crate) const SCALAR_LENGTH: usize = 32;

/// The threshold public key generated in the SimplPedPoP protocol, used to validate the threshold signatures of the FROST protocol.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ThresholdPublicKey(pub PublicKey);

/// The verifying share of a participant generated in the SimplPedPoP protocol, used to verify its signatures shares in the FROST protocol.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct VerifyingShare(pub(crate) PublicKey);

/// The signing keypair of a participant generated in the SimplPedPoP protocol, used to produce its signatures shares in the FROST protocol.
#[derive(Clone, Debug, ZeroizeOnDrop)]
pub struct SigningKeypair(pub(crate) Keypair);

impl SigningKeypair {
/// Serializes `SigningKeypair` to bytes.
pub fn to_bytes(&self) -> [u8; KEYPAIR_LENGTH] {
self.0.to_bytes()
}

/// Deserializes a `SigningKeypair` from bytes.
pub fn from_bytes(bytes: &[u8]) -> Result<SigningKeypair, SignatureError> {
let keypair = Keypair::from_bytes(bytes)?;
Ok(SigningKeypair(keypair))
}
}

/// The identifier of a participant, which must be the same in the SimplPedPoP protocol and in the FROST protocol.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Identifier(pub(crate) Scalar);

impl Identifier {
pub(super) fn generate(recipients_hash: &[u8; 16], index: u16) -> Identifier {
let mut pos = Transcript::new(b"Identifier");
pos.append_message(b"RecipientsHash", recipients_hash);
pos.append_message(b"i", &index.to_le_bytes()[..]);

Identifier(pos.challenge_scalar(b"evaluation position"))
}
}

#[cfg(test)]
pub(crate) mod test_utils {
use rand::{thread_rng, Rng};
use crate::olaf::simplpedpop::Parameters;

const MAXIMUM_PARTICIPANTS: u16 = 10;
const MINIMUM_PARTICIPANTS: u16 = 2;

pub(crate) fn generate_parameters() -> Parameters {
use super::MINIMUM_THRESHOLD;

let mut rng = thread_rng();
let participants = rng.gen_range(MINIMUM_PARTICIPANTS..=MAXIMUM_PARTICIPANTS);
let threshold = rng.gen_range(MINIMUM_THRESHOLD..=participants);

Parameters { participants, threshold }
}
}
Loading
Loading