chilldkg: Phase 4 - public coordinator API
Add the coordinator side of the ChillDKG protocol (bip-frost-dkg v0.3.0-dev, reference commit a91896883f85b159415ecf298d5e844879af112d), as thin wrappers over the Phase 2 encpedpop coordinator internals (whose cmsg1 output was already verified byte-identical to the reference coordinator_step1). Public API: - secp256k1_chilldkg_coordinator_step1: takes an array of pointers to the n participant pmsg1 messages (musig/frost-style convention), parses each with checked scalar parse, aggregates SimplPedPop and EncPedPop, builds eq_input (including the enc_secshares suffix, mirroring the reference) and emits cmsg1 (162n + 33(t-1) bytes). PoPs are not verified coordinator-side, exactly as the reference. - secp256k1_chilldkg_coordinator_finalize: concatenates the n CertEq pmsg2 signatures into the 64n-byte certificate, verifies all of them via certeq_verify (hostpubkeys recovered from eq_input at offset 4+33t), and outputs the coordinator-side DKG result: threshold pubkey, pubshares and recovery data -- no secshare. - secp256k1_chilldkg_coordinator_state: opaque, 21041 bytes, magic-validated, holds only t, n, eq_input, thresh_pk and pubshares -- no secret material, documented as freely copyable/persistable so a stateless coordinator is possible. Blame mapping (verified against chilldkg.py): - malformed pmsg1 (bad commitment encoding, overflowing encrypted share) -> FAULTY_PARTICIPANT(sender index), - invalid CertEq signature -> FAULTY_PARTICIPANT(failing index) (deliberately different from participant_finalize, which maps the same failure to FAULTY_COORDINATOR -- matching the reference), - invalid session params -> INVALID_INPUT; all outputs zeroed on failure. tests_impl.h: chilldkg_coordinator_api_test runs a full n=3,t=2 session through only the public APIs on both sides, byte-exact against the Python reference vectors and cross-checked against every participant's finalize outputs; blame cases (malformed pmsg1 and overflowing share -> FAULTY_PARTICIPANT with the right index, bad CertEq sig -> FAULTY_PARTICIPANT(2), zeroed outputs); misuse coverage (NULL args, corrupted state magic). Verified: make check 3/3 (incl. noverify); CMake ctest 365/365; ./tests --target=chilldkg green.
This commit is contained in:
@@ -32,12 +32,13 @@ extern "C" {
|
||||
* not exceed SECP256K1_CHILLDKG_MAX_PARTICIPANTS. The message flow is:
|
||||
* 1. Every participant runs secp256k1_chilldkg_participant_step1 and sends
|
||||
* the resulting pmsg1 to the coordinator.
|
||||
* 2. The coordinator aggregates the pmsg1s into a single cmsg1 broadcast
|
||||
* to all participants (coordinator API is not available yet).
|
||||
* 2. The coordinator runs secp256k1_chilldkg_coordinator_step1 on all
|
||||
* pmsg1s and broadcasts the resulting cmsg1 to all participants.
|
||||
* 3. Every participant runs secp256k1_chilldkg_participant_step2 and sends
|
||||
* the resulting signature (pmsg2) to the coordinator.
|
||||
* 4. The coordinator collects the n signatures into a certificate (cmsg2)
|
||||
* broadcast to all participants.
|
||||
* 4. The coordinator runs secp256k1_chilldkg_coordinator_finalize on all
|
||||
* pmsg2s and broadcasts the resulting certificate (cmsg2) to all
|
||||
* participants.
|
||||
* 5. Every participant runs secp256k1_chilldkg_participant_finalize to
|
||||
* obtain the DKG output and the recovery data.
|
||||
*
|
||||
@@ -111,6 +112,19 @@ typedef struct secp256k1_chilldkg_participant_state2 {
|
||||
unsigned char data[12 + 4 + 131 * SECP256K1_CHILLDKG_MAX_PARTICIPANTS + 32 + 33 + 33 * SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
|
||||
} secp256k1_chilldkg_participant_state2;
|
||||
|
||||
/** Opaque data structure that holds the coordinator's session state after
|
||||
* secp256k1_chilldkg_coordinator_step1, to be passed to
|
||||
* secp256k1_chilldkg_coordinator_finalize (it must not be reused).
|
||||
*
|
||||
* This structure contains no secret key material; it can be copied freely
|
||||
* (e.g., to persist it between the two coordinator steps).
|
||||
*
|
||||
* Guaranteed to be 21041 bytes in size.
|
||||
*/
|
||||
typedef struct secp256k1_chilldkg_coordinator_state {
|
||||
unsigned char data[12 + 4 + 131 * SECP256K1_CHILLDKG_MAX_PARTICIPANTS + 33 + 33 * SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
|
||||
} secp256k1_chilldkg_coordinator_state;
|
||||
|
||||
/** Compute the participant's host public key from the host secret key.
|
||||
*
|
||||
* The host public key is the long-term cryptographic identity of the
|
||||
@@ -307,6 +321,85 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_chilldkg_fault secp256k1_ch
|
||||
const unsigned char *cmsg2
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8);
|
||||
|
||||
/** Perform the coordinator's first step of a ChillDKG session.
|
||||
*
|
||||
* Parses all n participant messages and aggregates them into the message to
|
||||
* broadcast to all participants. The proofs of possession contained in the
|
||||
* pmsg1s are NOT verified here; the participants verify them in step 2 (this
|
||||
* mirrors the reference implementation).
|
||||
*
|
||||
* Returns: SECP256K1_CHILLDKG_OK on success,
|
||||
* SECP256K1_CHILLDKG_INVALID_INPUT on invalid session parameters,
|
||||
* or SECP256K1_CHILLDKG_FAULTY_PARTICIPANT (with fault_index set to
|
||||
* the sender) if a participant message is malformed (invalid
|
||||
* commitment encoding, or an encrypted share that overflows the
|
||||
* group order). On failure, cmsg1 and the state are set to zero.
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: state: pointer to a coordinator_state object to be passed
|
||||
* to secp256k1_chilldkg_coordinator_finalize (must not
|
||||
* be reused)
|
||||
* cmsg1: pointer to a 162*n + 33*(t-1) byte array (see
|
||||
* secp256k1_chilldkg_coordinator_msg1_len) to store
|
||||
* the message to be broadcast to all participants
|
||||
* fault_index: pointer to a uint32 that receives the identifier of
|
||||
* the faulty participant where applicable, and
|
||||
* UINT32_MAX otherwise
|
||||
* In: pmsgs1: array of n pointers to the participants' first
|
||||
* messages (33*t + 32*n + 97 bytes each)
|
||||
* hostpubkeys33: pointer to an array of n host public keys (33 bytes
|
||||
* each); must be identical (in content and order) to
|
||||
* the arrays used by the participants
|
||||
* n_participants: total number of participants n
|
||||
* threshold: threshold t
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_chilldkg_fault secp256k1_chilldkg_coordinator_step1(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_chilldkg_coordinator_state *state,
|
||||
unsigned char *cmsg1,
|
||||
uint32_t *fault_index,
|
||||
const unsigned char *const *pmsgs1,
|
||||
const unsigned char *hostpubkeys33,
|
||||
size_t n_participants,
|
||||
uint32_t threshold
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
|
||||
|
||||
/** Perform the coordinator's final step of a ChillDKG session.
|
||||
*
|
||||
* Collects the n CertEq signatures into the certificate and verifies all of
|
||||
* them. If this function returns SECP256K1_CHILLDKG_OK, the coordinator
|
||||
* deems the DKG session successful.
|
||||
*
|
||||
* Returns: SECP256K1_CHILLDKG_OK on success, or
|
||||
* SECP256K1_CHILLDKG_FAULTY_PARTICIPANT (with fault_index set to
|
||||
* the signer) if a CertEq signature is invalid. On failure, all
|
||||
* outputs are set to zero.
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: cmsg2: pointer to a 64*n byte array to store the
|
||||
* certificate, to be broadcast to all participants
|
||||
* thresh_pk33: pointer to a 33-byte array to store the threshold
|
||||
* public key (compressed serialization)
|
||||
* pubshares33: pointer to an array of n 33-byte elements to store
|
||||
* the public shares of all participants
|
||||
* recovery: pointer to a 4 + 33*t + 162*n byte array (see
|
||||
* secp256k1_chilldkg_recovery_data_len) to store the
|
||||
* recovery data
|
||||
* fault_index: pointer to a uint32 (see above)
|
||||
* In: state: pointer to the coordinator_state object output by
|
||||
* secp256k1_chilldkg_coordinator_step1
|
||||
* pmsgs2: array of n pointers to the participants' second
|
||||
* messages (64 bytes each)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_chilldkg_fault secp256k1_chilldkg_coordinator_finalize(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *cmsg2,
|
||||
unsigned char *thresh_pk33,
|
||||
unsigned char *pubshares33,
|
||||
unsigned char *recovery,
|
||||
uint32_t *fault_index,
|
||||
const secp256k1_chilldkg_coordinator_state *state,
|
||||
const unsigned char *const *pmsgs2
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user