Threshold sign with CMP20
Problem: You want a 2-of-3 threshold ECDSA signature over P-256, where any 2 of 3 parties can sign and the 3rd party can be offline.
Solution
# 1. Generate 3 shares with threshold 2 via CMP20 DKG
confium threshold dkg \
--threshold 2 \
--parties 3 \
--scheme cmp20 \
--out shares.json
# 2. Sign a message with all 3 shares available
# (the threshold is 2, so any 2 of 3 would suffice; the CLI takes all)
confium threshold sign \
--shares shares.json \
--message "payload to sign" \
--out signature.hex
# 3. Verify with openssl (Confium outputs standard P-256 ECDSA):
openssl pkeyutl -verify -pubin \
-inkey <(jq -r .public_key shares.json | openssl pkey -pubin -inform DER) \
-sigfile <(xxd -r -p signature.hex) \
-in <(printf 'payload to sign' | openssl dgst -sha256 -binary)
What’s happening
-
DKG runs the CMP20 distributed key generation. Each party contributes randomness; the joint public key is
Y = Σ x_i · G. No party ever holds the full secretx = Σ x_i. -
Sign runs the CMP20 signing protocol. Each signing party contributes a partial signature; the protocol combines them via Lagrange interpolation. The output is a standard ECDSA-P256
(r, s)pair. -
Verify is a standard ECDSA verification. Any verifier (OpenSSL, browser, the
p256crate) accepts Confium signatures — they look identical to single-key ECDSA signatures from the verifier’s perspective.
Edge cases
- Nonce reuse: CMP20 nonces MUST be unique per signing session. Confium derives them deterministically per RFC 8941 so accidental reuse is impossible.
- Share theft: If one party’s share is stolen, the attacker still needs
T-1more shares to forge. With T=2 and N=3, one stolen share doesn’t compromise the key. - Refresh: Run
confium threshold refreshperiodically to redistribute shares without changing the public key. See refresh-shares.mdx.