A Rust CLI for threshold ECDSA signing built on silence-laboratories/dkls23 and peer-to-peer networking by n0-computer/iroh.
Each instance is a peer; instances find each other on the LAN via iroh's mDNS-based local discovery and exchange dkls23 protocol messages over QUIC streams. There is no server and no leader.
keygen -t T [-n N] --peer-id ID --key-id KID
pubkey --key-id KID
sign --key-id KID --peer-id ID --msg MSG
reshare -t T [-n N] --peer-id ID --key-id KID
verify --key-id KID --msg MSG --signature HEX
-n defaults to -t. Threshold t = 1 produces a plain (singleton) ECDSA key
for which signing happens locally with no networking.
Key shares live under ./.secrets/<key_id>/<peer_id>.json.
| from \ to | (1,1) | (t', n) same n | (t, n) same params |
|---|---|---|---|
| (1,1) | n/a | split via ecdsa_secret_shares + key_refresh |
n/a |
| (t, n) | not implemented (would use key_export) |
quorum_change |
key_refresh |
Resharing to a different new committee size (-n ≠ old -n) is rejected
explicitly; the more general quorum_change flow with mixed old/new committees
is left for a follow-up.
cargo build
cargo test --test integration # in-process dkls23 round-trip
bash scripts/run_all.sh # build + cargo tests + multi-process QA
iroh::address_lookup::MdnsAddressLookup is set up with
service_name = "dkls23-<blake3(tool_id|key_id)[..6]>", scoping discovery to
peers running this tool against the same key_id. Lower-id peers dial higher
ones; both sides exchange a hello carrying (peer_id, key_id, aux) before any
protocol traffic.
Each peer holds a sl_mpc_mate::coord::SimpleMessageRelay locally. The dkls23
protocol task talks to a connection from this relay (Stream + Sink). Outbound
publishes are tee'd to a fan-out task that broadcasts them to every peer; the
remote side pushes whatever it receives back into its own relay via
coord.send. Asks (header-only requests) stay local.