Skip to content

Commit a1be7a4

Browse files
feat(dkg): FROST implementation (#328)
* Move code as-is from private repo * Rename dir * Add crate * Fix crate toml * Fix imports and compiler issues - Adjust `&` handling in patterns * Apply formatting * Apply clippy suggestions * Adjust docs * Inline readme * Remove bench-specific configs * Reduce attribute usage * Use std imports * Add proper permalinks * Adjust test names * Enable lints * Use derive macros when possible - Replaces custom deserialization code * Inline const * Simplify fixture parsing - Use vec directly * Fix clippy lints - Infallible conversions - Disable arithmetic checks * Assert conversions - Use `assert!` over `debug_assert!` - Reference RFC when required * Update lockfile * fix: address comments / review on frost, more tests (#364) * fix: address comments and reviews in FROST impl * fix: refine error * fix: more tests on frost core * fix: add tests for curve * fix: add and refactor tests on kryptology * fix: simplify tests * fix: address comments * fix: ignore RUSTSEC-2026-0118 and RUSTSEC-2026-0119 because libp2p --------- Co-authored-by: Quang Le <iamquang95@gmail.com>
1 parent 8546ddd commit a1be7a4

15 files changed

Lines changed: 2969 additions & 0 deletions

Cargo.lock

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ members = [
1818
"crates/testutil",
1919
"crates/tracing",
2020
"crates/peerinfo",
21+
"crates/frost",
2122
]
2223
resolver = "3"
2324

@@ -69,6 +70,7 @@ pbkdf2 = "0.12.2"
6970
pin-project = "1"
7071
sha2 = "0.10.9"
7172
scrypt = "0.11.0"
73+
subtle = "2.6"
7274
unicode-normalization = "0.1.25"
7375
zeroize = "1.8.2"
7476
uuid = { version = "1.19", features = ["serde", "v4"] }
@@ -123,6 +125,7 @@ pluto-testutil = { path = "crates/testutil" }
123125
pluto-tracing = { path = "crates/tracing" }
124126
pluto-p2p = { path = "crates/p2p" }
125127
pluto-peerinfo = { path = "crates/peerinfo" }
128+
pluto-frost = { path = "crates/frost" }
126129

127130
[workspace.lints.rust]
128131
missing_docs = "deny"

crates/frost/Cargo.toml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
[package]
2+
name = "pluto-frost"
3+
version.workspace = true
4+
edition.workspace = true
5+
repository.workspace = true
6+
license.workspace = true
7+
publish.workspace = true
8+
9+
[dependencies]
10+
blst.workspace = true
11+
rand_core.workspace = true
12+
sha2.workspace = true
13+
subtle.workspace = true
14+
thiserror.workspace = true
15+
zeroize = { workspace = true, features = ["derive"] }
16+
17+
[dev-dependencies]
18+
hex.workspace = true
19+
rand.workspace = true
20+
serde.workspace = true
21+
serde_json.workspace = true
22+
23+
[lints.rust]
24+
missing_docs = "deny"
25+
# Allow unsafe code for blst C bindings (overrides workspace forbid)
26+
unsafe_code = "allow"
27+
28+
[lints.clippy]
29+
arithmetic_side_effects = "deny"
30+
cast_lossless = "deny"
31+
cast_possible_truncation = "deny"
32+
cast_possible_wrap = "deny"
33+
cast_precision_loss = "deny"
34+
cast_sign_loss = "deny"
35+
needless_return = "deny"
36+
panicking_overflow_checks = "deny"
37+
unwrap_used = "deny"

crates/frost/dkg.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Kryptology-Compatible Distributed Key Generation (DKG)
2+
3+
The kryptology DKG module supports generating FROST key shares in a distributed
4+
manner compatible with Go's Coinbase Kryptology FROST DKG.
5+
6+
The output types ([`KeyPackage`], [`PublicKeyPackage`]) are standard frost-core
7+
types. The key shares can be used for BLS threshold signing via the
8+
`bls_partial_sign`, `bls_combine_signatures`, and `bls_verify` functions.
9+
10+
## Wire contract
11+
12+
The supported cross-language contract is the raw field encoding used by the
13+
fixtures and round helpers in this module:
14+
15+
- Scalars are 32-byte big-endian field elements.
16+
- G1 points are 48-byte compressed encodings.
17+
- Participant identifiers are transported as `u32` values.
18+
- The DKG context is transported as a single `u8` byte.
19+
20+
Gob encoding is not part of this interoperability contract.
21+
22+
## Example
23+
24+
```rust
25+
use std::collections::BTreeMap;
26+
27+
use pluto_frost::kryptology;
28+
29+
let mut rng = rand::rngs::OsRng;
30+
31+
let threshold = 3u16;
32+
let max_signers = 5u16;
33+
let ctx = 0u8;
34+
35+
// Round 1: each participant generates broadcast data and shares.
36+
let mut bcasts: BTreeMap<u32, kryptology::Round1Bcast> = BTreeMap::new();
37+
let mut all_shares: BTreeMap<u32, BTreeMap<u32, kryptology::ShamirShare>> = BTreeMap::new();
38+
let mut secrets: BTreeMap<u32, kryptology::Round1Secret> = BTreeMap::new();
39+
40+
for id in 1..=max_signers as u32 {
41+
let (bcast, shares, secret) =
42+
kryptology::round1(id, threshold, max_signers, ctx, &mut rng)
43+
.expect("round1 should succeed");
44+
bcasts.insert(id, bcast);
45+
secrets.insert(id, secret);
46+
for (&target_id, share) in &shares {
47+
all_shares.entry(target_id).or_default().insert(id, share.clone());
48+
}
49+
}
50+
51+
// Round 2: each participant verifies broadcasts and aggregates shares.
52+
let mut key_packages = BTreeMap::new();
53+
let mut public_key_packages = Vec::new();
54+
55+
for id in 1..=max_signers as u32 {
56+
let received_bcasts: BTreeMap<_, _> = bcasts
57+
.iter()
58+
.filter(|(k, _)| **k != id)
59+
.map(|(k, v)| (*k, v.clone()))
60+
.collect();
61+
let received_shares = all_shares.remove(&id).unwrap();
62+
let secret = secrets.remove(&id).unwrap();
63+
64+
let (_r2_bcast, key_package, pub_package) =
65+
kryptology::round2(secret, &received_bcasts, &received_shares)
66+
.expect("round2 should succeed");
67+
key_packages.insert(id, key_package);
68+
public_key_packages.push(pub_package);
69+
}
70+
71+
// Each participant now has a KeyPackage and PublicKeyPackage for BLS threshold signing.
72+
```

0 commit comments

Comments
 (0)