{"id":13531483,"url":"https://github.com/w3f/bls","last_synced_at":"2025-04-01T19:32:09.829Z","repository":{"id":47750542,"uuid":"139057605","full_name":"w3f/bls","owner":"w3f","description":"Aggregatable BLS sigantures","archived":false,"fork":false,"pushed_at":"2024-10-30T07:12:25.000Z","size":637,"stargazers_count":71,"open_issues_count":19,"forks_count":16,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-03-27T22:18:22.080Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/w3f.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-06-28T18:59:58.000Z","updated_at":"2025-03-09T11:45:31.000Z","dependencies_parsed_at":"2024-06-21T13:06:14.295Z","dependency_job_id":"c833fe80-36fd-4aa0-9f61-fd8243312a6f","html_url":"https://github.com/w3f/bls","commit_stats":{"total_commits":189,"total_committers":5,"mean_commits":37.8,"dds":0.4285714285714286,"last_synced_commit":"08081fec582ea3d2ff615494f149704d2fdff658"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/w3f%2Fbls","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/w3f%2Fbls/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/w3f%2Fbls/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/w3f%2Fbls/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/w3f","download_url":"https://codeload.github.com/w3f/bls/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246700618,"owners_count":20819904,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T07:01:03.357Z","updated_at":"2025-04-01T19:32:08.486Z","avatar_url":"https://github.com/w3f.png","language":"Rust","funding_links":[],"categories":["Cryptography"],"sub_categories":["Digital Signature"],"readme":"# bls [![Crates.io](https://img.shields.io/crates/v/w3f-bls.svg)](https://crates.io/crates/w3f-bls) #\n\nBoneh-Lynn-Shacham (BLS) signatures have slow signing, very slow verification, require slow and much less secure pairing friendly curves, and tend towards dangerous malleability.  Yet, BLS permits a diverse array of signature aggregation options far beyond any other known signature scheme, which makes BLS a preferred scheme for voting in consensus algorithms and for threshold signatures. \n\nIn this crate, we take a largely unified approach to aggregation techniques and verifier optimisations for BLS signature:  We support the [BLS12-381](https://z.cash/blog/new-snark-curve.html) and [BLS12-377](https://eprint.iacr.org/2018/962.pdf) (Barreto-Lynn-Scott) curves via Arkworks traits, but abstract the pairing so that developers can choose their preferred orientation for BLS signatures. We provide aggregation techniques based on messages being distinct, on proofs-of-possession, and on delinearization, although we do not provide all known optimisations for delinearization.\n\nWe provide implementation of generation and verification proof-of-possession based on Schnorr Signature which is faster than using BLS Signature itself for this task.\n\nWe cannot claim these abstractions provide miss-use resistance, but they at least structure the problem, provide some guidlines, and maximize the relevance of warnings present in the documentation.\n\n## Documentation\n\nYou first bring the `bls` crate into your project just as you normally would.\n\n```rust\nuse w3f_bls::{Keypair,ZBLS,Message,Signed};\n\nlet mut keypair = Keypair::\u003cZBLS\u003e::generate(::rand::thread_rng());\nlet message = Message::new(b\"Some context\",b\"Some message\");\nlet sig = keypair.sign(\u0026message);\nassert!( sig.verify(\u0026message,\u0026keypair.public) );\n```\n\nIn this example, `sig` is a `Signature\u003cZBLS\u003e` which only contains signature. One can use `Keypair::signed_message` method which returns a `SignedMessage` struct that contains the message hash, the signer's public key, and of course the signature, but one should usually detach these constituents for wire formats.\n\nAggregated and blind signatures are almost the only reasons anyone would consider using BLS signatures, so we focus on aggregation here.  We assume for brevity that `sigs` is an array of `SignedMessage`s, as one might construct like \n\nAs 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\n\n```rust\n#[cfg(feature = \"experimental\")]\nuse w3f_bls::{distinct::DistinctMessages, Keypair, Message, Signed, ZBLS};\n\n#[cfg(feature = \"experimental\")]\n{\n\tlet mut keypairs = [\n\t\tKeypair::\u003cZBLS\u003e::generate(::rand::thread_rng()),\n\t\tKeypair::\u003cZBLS\u003e::generate(::rand::thread_rng()),\n\t];\n\tlet msgs = [\n\t\t\"The ships\",\n\t\t\"hung in the sky\",\n\t\t\"in much the same way\",\n\t\t\"that bricks don’t.\",\n\t]\n\t.iter()\n\t.map(|m| Message::new(b\"Some context\", m.as_bytes()))\n\t.collect::\u003cVec\u003c_\u003e\u003e();\n\tlet sigs = msgs\n\t\t.iter()\n\t\t.zip(keypairs.iter_mut())\n\t\t.map(|(m, k)| k.signed_message(m))\n\t\t.collect::\u003cVec\u003c_\u003e\u003e();\n\n\t\tlet dms = sigs\n\t\t.iter()\n\t\t.try_fold(DistinctMessages::\u003cZBLS\u003e::new(), |dm, sig| dm.add(sig))\n\t\t.unwrap();\n\tlet signature = \u003c\u0026DistinctMessages\u003cZBLS\u003e as Signed\u003e::signature(\u0026\u0026dms);\n\n\t\tlet publickeys = keypairs.iter().map(|k| k.public).collect::\u003cVec\u003c_\u003e\u003e();\n\tlet mut dms = msgs\n\t\t.into_iter()\n\t\t.zip(publickeys)\n\t\t.try_fold(\n\t\t\tDistinctMessages::\u003cZBLS\u003e::new(),\n\t\t\t|dm, (message, publickey)| dm.add_message_n_publickey(message, publickey),\n\t\t)\n\t\t.unwrap();\n\tdms.add_signature(\u0026signature);\n\tassert!(dms.verify())\n}\n```\nAnyone 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.\n\nWe recommend distinct message aggregation like this primarily for verifying proofs-of-possession, meaning checking the self certificates for numerous keys.\n\nAssuming you already have proofs-of-possession, then you'll want to do aggregation with `BitPoPSignedMessage` or some variant tuned to your use case.  We recommend more care when using `SignatureAggregatorAssumingPoP` because it provides no mechanism for checking a proof-of-possession table.\n\nThe 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.\n\n```rust\nuse w3f_bls::{Keypair,PublicKey,ZBLS,Message,Signed, ProofOfPossessionGenerator, ProofOfPossession, schnorr_pop::{SchnorrPoP}, multi_pop_aggregator::MultiMessageSignatureAggregatorAssumingPoP};\nuse sha2::Sha256;\n\nlet mut keypairs = [Keypair::\u003cZBLS\u003e::generate(::rand::thread_rng()), Keypair::\u003cZBLS\u003e::generate(::rand::thread_rng())];\nlet 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::\u003cVec\u003c_\u003e\u003e();\nlet sigs = msgs.iter().zip(keypairs.iter_mut()).map(|(m,k)| k.sign(m)).collect::\u003cVec\u003c_\u003e\u003e();\n\nlet publickeys = keypairs.iter().map(|k|k.public.clone()).collect::\u003cVec\u003c_\u003e\u003e();\nlet pops = keypairs.iter_mut().map(|k|(ProofOfPossessionGenerator::\u003cZBLS, Sha256, PublicKey\u003cZBLS\u003e, SchnorrPoP\u003cZBLS\u003e\u003e::generate_pok(k))).collect::\u003cVec\u003c_\u003e\u003e();\n\n//first make sure public keys have valid pop\nlet publickeys = publickeys.iter().zip(pops.iter()).map(|(publickey, pop) | {assert!(ProofOfPossession::\u003cZBLS, Sha256, PublicKey\u003cZBLS\u003e\u003e::verify(pop,publickey)); publickey}).collect::\u003cVec\u003c_\u003e\u003e();\n\nlet batch_poped = msgs.iter().zip(publickeys).zip(sigs).fold(\n    MultiMessageSignatureAggregatorAssumingPoP::\u003cZBLS\u003e::new(),\n    |mut bpop,((message, publickey),sig)| { bpop.add_message_n_publickey(message, \u0026publickey); bpop.add_signature(\u0026sig); bpop }\n);\nassert!(batch_poped.verify())\n```\n\nIf you lack proofs-of-possesion, then delinearized approaches are provided in the `delinear` module, but such schemes might require a more customised approach. However, note that currently only aggeration assuming proof of possession is maintained and the other strategies are experimental. \n\n### Efficient Aggregatable BLS Signatures with Chaum-Pedersen Proofs\n\nThe scheme introduced in [`our recent paper`](https://eprint.iacr.org/2022/1611) is implemented in [`chaum_pederson_signature.rs`](src/chaum_pederson_signature.rs) using `ChaumPedersonSigner` and `ChaumPedersonVerifier` traits and in [`pop.rs`](src/pop.rs) using `add_auxiliary_public_key` and `verify_using_aggregated_auxiliary_public_keys` functions which is demonestrated in the following example:\n```rust\nuse sha2::Sha256;\nuse ark_bls12_377::Bls12_377;\nuse ark_ff::Zero;\nuse rand::thread_rng;\n\nuse w3f_bls::{\n    single_pop_aggregator::SignatureAggregatorAssumingPoP, DoublePublicKeyScheme, EngineBLS, Keypair, Message, PublicKey, PublicKeyInSignatureGroup, Signed, TinyBLS, TinyBLS377,\n};\n\n\nlet message = Message::new(b\"ctx\", b\"I'd far rather be happy than right any day.\");\nlet mut keypairs: Vec\u003c_\u003e = (0..3)\n    .into_iter()\n    .map(|_| Keypair::\u003cTinyBLS\u003cBls12_377, ark_bls12_377::Config\u003e\u003e::generate(thread_rng()))\n    .collect();\nlet pub_keys_in_sig_grp: Vec\u003cPublicKeyInSignatureGroup\u003cTinyBLS377\u003e\u003e = keypairs\n    .iter()\n    .map(|k| k.into_public_key_in_signature_group())\n    .collect();\n\nlet mut prover_aggregator =\n    SignatureAggregatorAssumingPoP::\u003cTinyBLS377\u003e::new(message.clone());\nlet mut aggregated_public_key =\n    PublicKey::\u003cTinyBLS377\u003e(\u003cTinyBLS377 as EngineBLS\u003e::PublicKeyGroup::zero());\n\n//sign and aggegate\nlet _ = keypairs\n    .iter_mut()\n    .map(|k| {\n        prover_aggregator.add_signature(\u0026k.sign(\u0026message));\n        aggregated_public_key.0 += k.public.0;\n    })\n    .count();\n\nlet mut verifier_aggregator = SignatureAggregatorAssumingPoP::\u003cTinyBLS377\u003e::new(message);\n\nverifier_aggregator.add_signature(\u0026(\u0026prover_aggregator).signature());\n\n//aggregate public keys in signature group\nverifier_aggregator.add_publickey(\u0026aggregated_public_key);\n\npub_keys_in_sig_grp.iter().for_each(|pk| {verifier_aggregator.add_auxiliary_public_key(pk);});\n\nassert!(\n    verifier_aggregator.verify_using_aggregated_auxiliary_public_keys::\u003cSha256\u003e(),\n    \"verifying with honest auxilary public key should pass\"\n);\n```\n\n### Hash to Curve\n\nIn order to sign a message, the library needs to hash the message as a point on the signature curve. While `BLSEngine` trait is agnostic about `MapToSignatureCurve` method, our implementation of BLS12-381 (`ZBLS`) and BLS12-377(`BLS377`) specifically uses Wahby and Boneh hash to curve method described in Section of 6.6.3 of https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/.\n\n## Security Warnings\n\nThis library does not make any guarantees about constant-time operations, memory access patterns, or resistance to side-channel attacks.\n\n## License\n\nLicensed under either of\n\n * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)\n * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)\n\nat your option.\n\n### Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally\nsubmitted for inclusion in the work by you, as defined in the Apache-2.0\nlicense, shall be dual licensed as above, without any additional terms or\nconditions.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fw3f%2Fbls","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fw3f%2Fbls","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fw3f%2Fbls/lists"}