Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
a083f74
- add `ed-by-bls12-381` sub crate
drskalman Sep 3, 2025
063ed2c
fix `SchnorrPop::verify` so schnorr_bls_pop_sign_and_verify passes
drskalman Sep 3, 2025
c5dacff
Add `ed_by_bls12_381` as a dependency of `w3f-bls`
drskalman Sep 3, 2025
2b91801
Implement NuggetBLS with 3rd public key in the sister group
drskalman Sep 12, 2025
5751457
- Implement Nugget BLS with generic CP group.
drskalman Sep 23, 2025
5f5d154
Fix DoubleNuggetBLS tests
drskalman Sep 23, 2025
1de7d1d
- Pass `triple_nugget::tests::test_single_bls_message_double_signatur…
drskalman Sep 23, 2025
5e079ff
Do cargo fmt
drskalman Sep 24, 2025
c1a22d2
Enable benches for triple nugget
drskalman Sep 24, 2025
fa44729
- Implement Strauss-Shamir optimiation for CP signature verification
drskalman Dec 6, 2025
a2fbf0a
Implement bench for strauss shamir in cp
drskalman Dec 9, 2025
5f9dd0d
make Cargo tomel by add extra tesst curves
drskalman Dec 9, 2025
3e9898a
Implement:
drskalman Jan 27, 2026
4cfeed1
- Implement `into_nugget_double_public_key` to get `NuggetDoublePubli…
drskalman Jan 27, 2026
09ebfbe
- cargo fmt
drskalman Feb 4, 2026
19281f7
Move all experimental modules to w3f-bls-experimental crate.
drskalman Feb 13, 2026
b19cb4b
Update README.md 's example from experimental code + fmt.
drskalman Feb 15, 2026
a52b7f6
remove redundant hash to curve from CP verification
drskalman Feb 15, 2026
0f9706a
- gatekeeping for benchmark messages and measure.
drskalman Feb 15, 2026
1520acf
- Removed depricated double_pop.rs (now double_nugget.rs).
drskalman Apr 1, 2026
0bd2e4b
- bump to version 0.2.0
drskalman Apr 3, 2026
1ffa617
Move bench.rs to experimental
drskalman Apr 3, 2026
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/target/
**/*.rs.bk
**/*.rs~
.#*
Cargo.lock
nohup.out
54 changes: 45 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,37 @@ homepage = "https://github.com/w3f/bls"
license = "MIT/Apache-2.0"
name = "w3f-bls"
repository = "https://github.com/w3f/bls"
version = "0.1.9"
edition = "2018"
version = "0.2.0"
edition = "2024"

[workspace]
members = [
".",
"experimental_curves/ed_by_bls12_381",
"experimental_curves/sw_by_bls12_381",
]

[workspace.package]
edition = "2024"
repository = "https://github.com/w3f/bls"

[workspace.dependencies]

ark-ff = { version = "0.5.0", default-features = false }
ark-ec = { version = "0.5.0", default-features = false }
ark-serialize = { version = "0.5.0", default-features = false, features = [ "derive" ] }
ark-serialize-derive = { version = "0.5.0", default-features = false }
ark-std = { version = "0.5.0", default-features = false }

ark-bls12-381 = { version = "0.5.0", default-features = false, features = [ "curve" ] }
ark-bls12-377 = { version = "0.5.0", default-features = false, features = [ "curve" ] }

[dependencies]
ark-ff = { workspace = true }
ark-ec = { workspace = true }
ark-serialize = { workspace = true }
ark-serialize-derive = { workspace = true }

arrayref = { version = "0.3", default-features = false }
rand = { version = "0.8.5", default-features = false}
rand_core = { version = "0.6", default-features = false }
Expand All @@ -18,20 +45,29 @@ sha3 = { version = "0.10", default-features = false }
sha2 = { version = "0.10", default-features = false }
digest = { version = "0.10", default-features = false }

ark-ff = { version = "0.4.0", default-features = false }
ark-ec = { version = "0.4.0", default-features = false }
ark-serialize = { version = "0.4.0", default-features = false, features = [ "derive" ] }
ark-serialize-derive = { version = "0.4.0", default-features = false }

ark-bls12-381 = { version = "0.4.0", default-features = false, features = [ "curve" ] }
ark-bls12-377 = { version = "0.4.0", default-features = false, features = [ "curve" ] }
ark-bls12-381 = { workspace = true }
ark-bls12-377 = { workspace = true }

zeroize = { version = "1.0", default-features = false, features = [ "zeroize_derive" ] }

[dev-dependencies]
hex-literal = "0.3.4"
ark-ed-by-bls12-381 = {path = "./experimental_curves/ed_by_bls12_381"}
ark-sw-by-bls12-381 = {path = "./experimental_curves/sw_by_bls12_381"}

[features]
default = ["std"]
std = ["rand/std"]
experimental = []
benchmark = ["std"]
experimental = ["std"]

[[example]]
name = "aggregated"
path = "examples/experimental/aggregated.rs"
required-features = ["experimental"]

[[example]]
name = "aggregated_with_pop"
path = "examples/experimental/aggregated_with_pop.rs"
required-features = ["experimental"]
85 changes: 42 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,48 +28,46 @@ Aggregated and blind signatures are almost the only reasons anyone would conside
As a rule, aggregation that requires distinct messages still requires one miller loop step per message, so aggregate signatures have rather slow verification times. You can nevertheless achieve quite small signature sizes like

```rust
#[cfg(feature = "experimental")]
use w3f_bls::{distinct::DistinctMessages, Keypair, Message, Signed, ZBLS};

#[cfg(feature = "experimental")]
{
let mut keypairs = [
Keypair::<ZBLS>::generate(::rand::thread_rng()),
Keypair::<ZBLS>::generate(::rand::thread_rng()),
];
let msgs = [
"The ships",
"hung in the sky",
"in much the same way",
"that bricks don’t.",
]
use w3f_bls::{Keypair, Message, Signed, ZBLS};
use w3f_bls::experimental::distinct::DistinctMessages;
use rand::{SeedableRng, rngs::StdRng};

let mut keypairs = [
Keypair::<ZBLS>::generate(StdRng::from_seed([0u8; 32])),
Keypair::<ZBLS>::generate(StdRng::from_seed([1u8; 32])),
];
let msgs = [
"The ships",
"hung in the sky",
"in much the same way",
"that bricks don't.",
]
.iter()
.map(|m| Message::new(b"Some context", m.as_bytes()))
.collect::<Vec<_>>();
let sigs = msgs
.iter()
.map(|m| Message::new(b"Some context", m.as_bytes()))
.zip(keypairs.iter_mut())
.map(|(m, k)| k.signed_message(m))
.collect::<Vec<_>>();
let sigs = msgs
.iter()
.zip(keypairs.iter_mut())
.map(|(m, k)| k.signed_message(m))
.collect::<Vec<_>>();

let dms = sigs
.iter()
.try_fold(DistinctMessages::<ZBLS>::new(), |dm, sig| dm.add(sig))
.unwrap();
let signature = <&DistinctMessages<ZBLS> as Signed>::signature(&&dms);

let publickeys = keypairs.iter().map(|k| k.public).collect::<Vec<_>>();
let mut dms = msgs
.into_iter()
.zip(publickeys)
.try_fold(
DistinctMessages::<ZBLS>::new(),
|dm, (message, publickey)| dm.add_message_n_publickey(message, publickey),
)
.unwrap();
dms.add_signature(&signature);
assert!(dms.verify())
}

let dms = sigs
.iter()
.try_fold(DistinctMessages::<ZBLS>::new(), |dm, sig| dm.add(sig))
.unwrap();
let signature = <&DistinctMessages<ZBLS> as Signed>::signature(&&dms);

let publickeys = keypairs.iter().map(|k| k.public).collect::<Vec<_>>();
let mut dms = msgs
.into_iter()
.zip(publickeys)
.try_fold(
DistinctMessages::<ZBLS>::new(),
|dm, (message, publickey)| dm.add_message_n_publickey(message, publickey),
)
.unwrap();
dms.add_signature(&signature);
assert!(dms.verify())
```
Anyone who receives the already aggregated signature along with a list of messages and public keys might reconstruct the signature as shown in the above example.

Expand All @@ -80,7 +78,7 @@ Assuming you already have proofs-of-possession, then you'll want to do aggregati
The library offers method for generating and verifying proof of positions both based on BLS and [Schnorr Signature](https://en.wikipedia.org/wiki/Schnorr_signature) which is faster to verify than when using BLS signature itself as proof of position. The following example demonstrate how to generate and verify proof of positions and then using `SignatureAggregatorAssumingPoP` to batch and verify multiple BLS signatures.

```rust
use w3f_bls::{Keypair,PublicKey,ZBLS,Message,Signed, ProofOfPossessionGenerator, ProofOfPossession, schnorr_pop::{SchnorrPoP}, multi_pop_aggregator::MultiMessageSignatureAggregatorAssumingPoP};
use w3f_bls::{Keypair,PublicKey,ZBLS,Message,Signed, ProofOfPossessionGenerator, ProofOfPossession, experimental::schnorr_pop::{SchnorrPoP}, multi_pop_aggregator::MultiMessageSignatureAggregatorAssumingPoP};
use sha2::Sha256;

let mut keypairs = [Keypair::<ZBLS>::generate(::rand::thread_rng()), Keypair::<ZBLS>::generate(::rand::thread_rng())];
Expand Down Expand Up @@ -112,7 +110,8 @@ use ark_ff::Zero;
use rand::thread_rng;

use w3f_bls::{
single_pop_aggregator::SignatureAggregatorAssumingPoP, DoublePublicKeyScheme, EngineBLS, Keypair, Message, PublicKey, PublicKeyInSignatureGroup, Signed, TinyBLS, TinyBLS377,
single_pop_aggregator::SignatureAggregatorAssumingPoP, DoubleNuggetBLS, EngineBLS, Keypair,
Message, NuggetPublicKey, PublicKey, PublicKeyInSignatureGroup, Signed, TinyBLS, TinyBLS377,
};


Expand All @@ -123,7 +122,7 @@ let mut keypairs: Vec<_> = (0..3)
.collect();
let pub_keys_in_sig_grp: Vec<PublicKeyInSignatureGroup<TinyBLS377>> = keypairs
.iter()
.map(|k| k.into_public_key_in_signature_group())
.map(|k| DoubleNuggetBLS::<TinyBLS377>::into_nugget_double_public_key(k).into_public_key_in_signature_group())
.collect();

let mut prover_aggregator =
Expand Down
8 changes: 5 additions & 3 deletions examples/aggregate_with_public_key_in_signature_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
use sha2::Sha256;
#[cfg(feature = "std")]
use w3f_bls::{
single_pop_aggregator::SignatureAggregatorAssumingPoP, DoublePublicKeyScheme, EngineBLS,
Keypair, Message, PublicKey, PublicKeyInSignatureGroup, Signed, TinyBLS, TinyBLS377,
single_pop_aggregator::SignatureAggregatorAssumingPoP, EngineBLS, Keypair, Message, NuggetBLS,
PublicKey, PublicKeyInSignatureGroup, Signed, TinyBLS, TinyBLS377,
};

#[cfg(feature = "std")]
Expand All @@ -20,14 +20,16 @@ use rand::thread_rng;
fn main() {
#[cfg(feature = "std")]
{
type EB = TinyBLS<Bls12_377, ark_bls12_377::Config>;

let message = Message::new(b"ctx", b"I'd far rather be happy than right any day.");
let mut keypairs: Vec<_> = (0..3)
.into_iter()
.map(|_| Keypair::<TinyBLS<Bls12_377, ark_bls12_377::Config>>::generate(thread_rng()))
.collect();
let pub_keys_in_sig_grp: Vec<PublicKeyInSignatureGroup<TinyBLS377>> = keypairs
.iter()
.map(|k| k.into_public_key_in_signature_group())
.map(|k| NuggetBLS::<_, <EB as EngineBLS>::SignatureGroup>::into_public_key_in_signature_group(k))
.collect();
let mut prover_aggregator =
SignatureAggregatorAssumingPoP::<TinyBLS377>::new(message.clone());
Expand Down
48 changes: 0 additions & 48 deletions examples/aggregated.rs

This file was deleted.

45 changes: 45 additions & 0 deletions examples/experimental/aggregated.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use w3f_bls::experimental::distinct::DistinctMessages;
use w3f_bls::{Keypair, Message, Signed, ZBLS};

/// Run using
/// ```sh
/// cargo run --features experimental --example aggregated
/// ```
fn main() {
let mut keypairs = [
Keypair::<ZBLS>::generate(::rand::thread_rng()),
Keypair::<ZBLS>::generate(::rand::thread_rng()),
];
let msgs = [
"The ships",
"hung in the sky",
"in much the same way",
"that bricks don't.",
]
.iter()
.map(|m| Message::new(b"Some context", m.as_bytes()))
.collect::<Vec<_>>();
let sigs = msgs
.iter()
.zip(keypairs.iter_mut())
.map(|(m, k)| k.signed_message(m))
.collect::<Vec<_>>();

let dms = sigs
.iter()
.try_fold(DistinctMessages::<ZBLS>::new(), |dm, sig| dm.add(sig))
.unwrap();
let signature = <&DistinctMessages<ZBLS> as Signed>::signature(&&dms);

let publickeys = keypairs.iter().map(|k| k.public).collect::<Vec<_>>();
let mut dms = msgs
.into_iter()
.zip(publickeys)
.try_fold(
DistinctMessages::<ZBLS>::new(),
|dm, (message, publickey)| dm.add_message_n_publickey(message, publickey),
)
.unwrap();
dms.add_signature(&signature);
assert!(dms.verify())
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
use sha2::Sha256;
#[cfg(feature = "std")]
use w3f_bls::{
multi_pop_aggregator::MultiMessageSignatureAggregatorAssumingPoP, schnorr_pop::SchnorrPoP,
experimental::schnorr_pop::SchnorrPoP,
multi_pop_aggregator::MultiMessageSignatureAggregatorAssumingPoP,
Keypair, Message, ProofOfPossession, ProofOfPossessionGenerator, PublicKey, Signed, ZBLS,
};

Expand Down Expand Up @@ -36,7 +37,7 @@ fn main() {
.iter()
.map(|k| k.public.clone())
.collect::<Vec<_>>();
let pops = keypairs.iter_mut().map(|k|(ProofOfPossessionGenerator::<ZBLS, Sha256, PublicKey<ZBLS>, SchnorrPoP<ZBLS>>::generate_pok(k))).collect::<Vec<_>>();
let pops = keypairs.iter_mut().map(|k|ProofOfPossessionGenerator::<ZBLS, Sha256, PublicKey<ZBLS>, SchnorrPoP<ZBLS>>::generate_pok(k)).collect::<Vec<_>>();

//first make sure public keys have valid pop
let publickeys = publickeys
Expand All @@ -50,6 +51,7 @@ fn main() {
})
.collect::<Vec<_>>();

//now that we have confidence in keys we can verify the batched signature
let batch_poped = msgs.iter().zip(publickeys).zip(sigs).fold(
MultiMessageSignatureAggregatorAssumingPoP::<ZBLS>::new(),
|mut bpop, ((message, publickey), sig)| {
Expand Down
6 changes: 3 additions & 3 deletions examples/nugget_pop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use sha2::Sha256;
#[cfg(feature = "std")]
use w3f_bls::{
DoublePublicKey, Keypair, NuggetBLSPoP, NuggetBLSnCPPoP, ProofOfPossessionGenerator,
Keypair, NuggetBLSPoP, NuggetBLSnCPPoP, NuggetDoublePublicKey, ProofOfPossessionGenerator,
SerializableToBytes, TinyBLS381,
};

Expand All @@ -22,7 +22,7 @@ fn main() {
let proof_pair = <dyn ProofOfPossessionGenerator<
TinyBLS381,
Sha256,
DoublePublicKey<TinyBLS381>,
NuggetDoublePublicKey<TinyBLS381>,
NuggetBLSPoP<TinyBLS381>,
>>::generate_pok(&mut keypair);

Expand All @@ -36,7 +36,7 @@ fn main() {
let proof_pair = <dyn ProofOfPossessionGenerator<
TinyBLS381,
Sha256,
DoublePublicKey<TinyBLS381>,
NuggetDoublePublicKey<TinyBLS381>,
NuggetBLSnCPPoP<TinyBLS381>,
>>::generate_pok(&mut keypair);

Expand Down
Loading