Notes on the chilldkg module API ================================ This module implements ChillDKG, a distributed key generation (DKG) protocol for FROST, as specified by the bip-frost-dkg BIP draft (https://github.com/BlockstreamResearch/bip-frost-dkg, version 0.3.0-dev). In a ChillDKG session, n participants jointly generate a threshold key with the help of an untrusted coordinator, such that no party (including the coordinator) learns more than its own secret share, and every participant obtains the threshold public key and the public shares of all participants. The output is designed to feed directly into the frost module (`include/secp256k1_frost.h`), which implements FROST signing (BIP 445) and explicitly leaves DKG out of scope. The implementation and its test vectors (`tools/test_vectors_chilldkg_generate.py`) are validated against the pinned reference commit `a91896883f85b159415ecf298d5e844879af112d` (v0.3.0-dev). **This module is experimental.** Do not use it in production. The API should not be considered stable. The underlying BIP is still a draft (v0.3.0-dev): tagged hashes, wire formats, and protocol details may change in future BIP versions. The module depends on the schnorrsig module (for the CertEq certificate and proofs of possession) and the ecdh module (for encrypted share distribution). A usage example can be found in `examples/chilldkg.c`. Protocol summary ---------------- Participants are identified by identifiers 0..n-1; participant i sits at polynomial x-coordinate i + 1 (the same convention as the frost module). The threshold t is the number of participants required to sign. The number of participants must not exceed SECP256K1_CHILLDKG_MAX_PARTICIPANTS (128); the state objects are fixed-size and the library does not allocate memory, so all message buffers are caller-allocated (use the `secp256k1_chilldkg_*_msg1_len`, `secp256k1_chilldkg_*_msg2_len`, `secp256k1_chilldkg_recovery_data_len` and `secp256k1_chilldkg_investigation_msg_len` helpers to size them). The coordinator is untrusted: it routes and aggregates messages but learns nothing about the secret shares, and it cannot forge the outcome — all its messages are verified by the participants. All coordinator sends are broadcasts to all participants. | Step | Function | Message | Size | Contents | |---|---|---|---|---| | participant step 1 | `secp256k1_chilldkg_participant_step1` | pmsg1 | 33t + 32n + 97 | VSS commitment, PoP, pubnonce, encrypted shares | | coordinator step 1 | `secp256k1_chilldkg_coordinator_step1` | cmsg1 | 162n + 33(t-1) | commitments, pops, pubnonces, summed encrypted shares | | participant step 2 | `secp256k1_chilldkg_participant_step2` | pmsg2 | 64 | CertEq signature over the transcript | | coordinator finalize | `secp256k1_chilldkg_coordinator_finalize` | cmsg2 | 64n | certificate (the n CertEq signatures) | | participant finalize | `secp256k1_chilldkg_participant_finalize` | — | — | DKG output + recovery data | The resulting threshold public key is tweaked with a TapTweak-style tweak such that the BIP 341 script path is unspendable; the tweak is already included in the (secret and public) shares output by this module, so the outputs can be used with the frost module directly (initialize the frost tweak cache from the threshold public key and apply no further tweaks, unless the application wants additional tweaks). Blame taxonomy -------------- Protocol functions report faults via the `secp256k1_chilldkg_fault` enum plus a `fault_index` output: - `SECP256K1_CHILLDKG_FAULTY_COORDINATOR`: the coordinator deviated from the protocol (detected by a participant). - `SECP256K1_CHILLDKG_FAULTY_PARTICIPANT(i)`: participant i deviated from the protocol (detected by the coordinator, or an invalid recovery acknowledgment of participant i). - `SECP256K1_CHILLDKG_FAULTY_PARTICIPANT_OR_COORDINATOR(i)`: participant i appears to be faulty, but the coordinator may have framed them (detected by a participant). - `SECP256K1_CHILLDKG_UNKNOWN_FAULTY_PARTICIPANT_OR_COORDINATOR`: a fault was detected but cannot be attributed without the investigation procedure; call `secp256k1_chilldkg_coordinator_investigate` (coordinator) and `secp256k1_chilldkg_participant_investigate` (participant, with the `inv_data` output by `secp256k1_chilldkg_participant_step2`) to attribute the fault. - `SECP256K1_CHILLDKG_INVALID_INPUT`: the caller provided invalid input (bad host secret key, invalid session parameters, invalid recovery data). Recovery -------- `secp256k1_chilldkg_participant_finalize` and `secp256k1_chilldkg_coordinator_finalize` output the recovery data (`eq_input || certificate`). It is self-delimiting and self-authenticating: anyone holding it can verify that the session succeeded, and a participant can recover its DKG output at any time from the recovery data and its host secret key (`secp256k1_chilldkg_participant_recover`; the coordinator uses `secp256k1_chilldkg_coordinator_recover`). This also covers the case where some participants never receive cmsg2: they can be convinced of the success of the session later by being presented with the recovery data. Callers SHOULD ensure that all participants deem the session successful before using the threshold public key (e.g., before sending funds to it). The recommended way is to collect recovery acknowledgments from all participants (`secp256k1_chilldkg_recovery_ack_sign` and `secp256k1_chilldkg_recovery_acks_verify`). Security notes -------------- - The host secret key is the participant's long-term identity and the basis of all session secrets. The same host key pair may be reused in multiple sessions. Do NOT erase the host secret key after a session, even a failed one: another participant may have succeeded, and this participant can recover its output later from the recovery data. - `random32` in `secp256k1_chilldkg_participant_step1` must be FRESH cryptographically secure randomness for every session; reusing it across sessions can leak the host secret key. The function rejects all-zero randomness as a guard against a malfunctioning RNG. - `state2` and `inv_data` contain secret key material (the secret share and decryption pads); keep them secret and do not copy them. `state1` and the coordinator state contain no secrets and can be copied (e.g., to persist them). - Each state object must not be reused: pass `state1` to at most one `participant_step2` call, `state2` to at most one `participant_finalize` call, and the coordinator state to at most one `coordinator_finalize` call. - The recovery data does not reveal the secret shares (they are encrypted), but it commits to the session's participants and outcome; treat it as sensitive metadata.