Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ members = [
"crates/testutil",
"crates/tracing",
"crates/peerinfo",
"crates/frost",
]
resolver = "3"

Expand Down Expand Up @@ -115,6 +116,7 @@ pluto-testutil = { path = "crates/testutil" }
pluto-tracing = { path = "crates/tracing" }
pluto-p2p = { path = "crates/p2p" }
pluto-peerinfo = { path = "crates/peerinfo" }
pluto-frost = { path = "crates/frost" }

[workspace.lints.rust]
missing_docs = "deny"
Expand Down
34 changes: 34 additions & 0 deletions crates/frost/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[package]
name = "pluto-frost"
version.workspace = true
edition.workspace = true
repository.workspace = true
license.workspace = true
publish.workspace = true

[dependencies]
blst.workspace = true
rand_core.workspace = true
sha2.workspace = true

[dev-dependencies]
hex.workspace = true
rand.workspace = true
serde.workspace = true
serde_json.workspace = true

[lints.rust]
missing_docs = "deny"
# Allow unsafe code for blst C bindings (overrides workspace forbid)
unsafe_code = "allow"

[lints.clippy]
arithmetic_side_effects = "deny"
cast_lossless = "deny"
cast_possible_truncation = "deny"
cast_possible_wrap = "deny"
cast_precision_loss = "deny"
cast_sign_loss = "deny"
needless_return = "deny"
panicking_overflow_checks = "deny"
unwrap_used = "deny"
72 changes: 72 additions & 0 deletions crates/frost/dkg.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Kryptology-Compatible Distributed Key Generation (DKG)

The kryptology DKG module supports generating FROST key shares in a distributed
manner compatible with Go's Coinbase Kryptology FROST DKG.

The output types ([`KeyPackage`], [`PublicKeyPackage`]) are standard frost-core
types. The key shares can be used for BLS threshold signing via the
`bls_partial_sign`, `bls_combine_signatures`, and `bls_verify` functions.

## Wire contract

The supported cross-language contract is the raw field encoding used by the
fixtures and round helpers in this module:

- Scalars are 32-byte big-endian field elements.
- G1 points are 48-byte compressed encodings.
- Participant identifiers are transported as `u32` values.
- The DKG context is transported as a single `u8` byte.

Gob encoding is not part of this interoperability contract.

## Example

```rust
use std::collections::BTreeMap;

use pluto_frost::kryptology;

let mut rng = rand::rngs::OsRng;

let threshold = 3u16;
let max_signers = 5u16;
let ctx = 0u8;

// Round 1: each participant generates broadcast data and shares.
let mut bcasts: BTreeMap<u32, kryptology::Round1Bcast> = BTreeMap::new();
let mut all_shares: BTreeMap<u32, BTreeMap<u32, kryptology::ShamirShare>> = BTreeMap::new();
let mut secrets: BTreeMap<u32, kryptology::Round1Secret> = BTreeMap::new();

for id in 1..=max_signers as u32 {
let (bcast, shares, secret) =
kryptology::round1(id, threshold, max_signers, ctx, &mut rng)
.expect("round1 should succeed");
bcasts.insert(id, bcast);
secrets.insert(id, secret);
for (&target_id, share) in &shares {
all_shares.entry(target_id).or_default().insert(id, share.clone());
}
}

// Round 2: each participant verifies broadcasts and aggregates shares.
let mut key_packages = BTreeMap::new();
let mut public_key_packages = Vec::new();

for id in 1..=max_signers as u32 {
let received_bcasts: BTreeMap<_, _> = bcasts
.iter()
.filter(|(k, _)| **k != id)
.map(|(k, v)| (*k, v.clone()))
.collect();
let received_shares = all_shares.remove(&id).unwrap();
let secret = secrets.remove(&id).unwrap();

let (_r2_bcast, key_package, pub_package) =
kryptology::round2(secret, &received_bcasts, &received_shares)
.expect("round2 should succeed");
key_packages.insert(id, key_package);
public_key_packages.push(pub_package);
}

// Each participant now has a KeyPackage and PublicKeyPackage for BLS threshold signing.
```
Loading
Loading