chilldkg: Phase 2 - SimplPedPop and EncPedPop layers
Port the two sub-protocol layers of the ChillDKG reference
implementation (bip-frost-dkg v0.3.0-dev, upstream commit
a91896883f85b159415ecf298d5e844879af112d) to C, keeping the same
function decomposition as simplpedpop.py / encpedpop.py so the code
stays diffable against the reference.
simplpedpop.h / simplpedpop_impl.h (mirrors simplpedpop.py):
- simplpedpop_participant_step1: VSS coefficient generation and
commitment, per-participant shares, proof of possession. The PoP is
a BIP-340 signature with custom tag prefix "BIP DKG/pop message"
over u32be(participant_id), signed with the constant coefficient
f(0), using TH("BIP DKG/simplpedpop aux", simpl_seed) as aux_rand.
- simplpedpop_coordinator_step / assemble_sum_coms: echo per-dealer
constant-term commitments, sum non-constant-term commitments,
collect PoPs (not verified by the coordinator, as in the reference).
- simplpedpop_participant_step2: own-commitment echo check, per-dealer
infinity rejection and PoP verification against the x-only
coms_to_secrets[i], TapTweak applied before share verification
(secshare vs pubshare check on tweaked values), eq_input =
u32be(t) || sum_coms committing to the UNTWEAKED summed commitment.
encpedpop.h / encpedpop_impl.h (mirrors encpedpop.py):
- simpl_seed / aux / secnonce derivations from (hostseckey, random,
enc_context) via "BIP DKG/encpedpop seed", "BIP DKG/simplpedpop aux"
and "BIP DKG/encpedpop secnonce"; pubnonce = pubkey_gen_plain(secnonce).
- encaps_multi / encrypt_multi: per-recipient pad context
u32be(i) || enc_context, self-pad at the own index (no ECDH),
libsecp256k1-style ECDH pad otherwise with sender-first ordering;
encryption is additive mod n so the coordinator can sum encrypted
shares per recipient.
- decaps_multi / decrypt_sum: receiver-side pads, invalid or infinity
pubnonce maps to FAULTY_PARTICIPANT_OR_COORDINATOR(sender).
- coordinator_step: checked scalar parse of encrypted shares
(overflow blames the sender), per-recipient summation.
- participant_step2: pubnonce echo check (mismatch ->
FAULTY_COORDINATOR), decrypt, delegate to simplpedpop step2,
eq_input extended with enckeys || pubnonces.
util.h: add SECP256K1_CHILLDKG_MAX_PARTICIPANTS (128, matching frost)
and the internal fault enum mirroring the reference's exception
taxonomy (FAULTY_COORDINATOR, FAULTY_PARTICIPANT,
FAULTY_PARTICIPANT_OR_COORDINATOR,
UNKNOWN_FAULTY_PARTICIPANT_OR_COORDINATOR, INVALID_INPUT). The public
blame-reporting enum arrives with the Phase 3 API.
State structs are fixed-size (no malloc, cap 128 participants). All
secret temporaries are cleared; negligible-probability secret-
dependent failures are declassified before branching.
Documented deviations where the reference crashes with non-protocol
errors: infinity sum_coms[0] in invalid_taproot_commit (unreachable
after PoP verification) and tweak-hash overflow (negligible) return
UNKNOWN_FAULTY_PARTICIPANT_OR_COORDINATOR; a wrong cmsg length maps
to FAULTY_COORDINATOR. Investigation procedures are deferred to
Phase 5 per the plan.
tests_impl.h: byte-exact n=3/t=2 happy-path vectors for both layers
generated from the Python reference (pmsg/cmsg/eq_input/enc_secshares
and all DKG outputs), plus PoP reject cases (tampered, wrong index,
infinity commitment, wrong echo, tampered non-constant-term sum),
coordinator blame (bad commitment, overflowing encrypted share),
encaps/decaps pad symmetry for all sender/receiver pairs including
self-pad, encrypt->sum->decrypt_sum roundtrip, tampered encrypted
share, invalid pubnonce blame, and input-validation rejects.
Verified: make check 3/3 suites pass (incl. noverify_tests running the
module); CMake ctest 361/361; ./tests --target=chilldkg runs all 9
module tests green.
This commit is contained in:
@@ -4,4 +4,8 @@ noinst_HEADERS += src/modules/chilldkg/util.h
|
||||
noinst_HEADERS += src/modules/chilldkg/util_impl.h
|
||||
noinst_HEADERS += src/modules/chilldkg/vss.h
|
||||
noinst_HEADERS += src/modules/chilldkg/vss_impl.h
|
||||
noinst_HEADERS += src/modules/chilldkg/simplpedpop.h
|
||||
noinst_HEADERS += src/modules/chilldkg/simplpedpop_impl.h
|
||||
noinst_HEADERS += src/modules/chilldkg/encpedpop.h
|
||||
noinst_HEADERS += src/modules/chilldkg/encpedpop_impl.h
|
||||
noinst_HEADERS += src/modules/chilldkg/tests_impl.h
|
||||
|
||||
126
src/modules/chilldkg/encpedpop.h
Normal file
126
src/modules/chilldkg/encpedpop.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/***********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_CHILLDKG_ENCPEDPOP_H
|
||||
#define SECP256K1_MODULE_CHILLDKG_ENCPEDPOP_H
|
||||
|
||||
#include "../../../include/secp256k1.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "simplpedpop.h"
|
||||
#include "../../group.h"
|
||||
#include "../../scalar.h"
|
||||
|
||||
/* This file contains the internal EncPedPop sub-protocol of the ChillDKG
|
||||
* module, mirroring chilldkg_ref/encpedpop.py of the bip-frost-dkg reference
|
||||
* implementation. EncPedPop wraps SimplPedPop and encrypts the partial secret
|
||||
* shares towards their recipients with an additively homomorphic "Hashed
|
||||
* ElGamal" multi-recipient KEM, so that an untrusted coordinator can aggregate
|
||||
* the encrypted shares per recipient.
|
||||
*
|
||||
* Messages are byte strings:
|
||||
* pmsg (participant -> coordinator): simpl_pmsg (33*t + 64) || pubnonce (33)
|
||||
* || enc_shares (32*n)
|
||||
* cmsg (coordinator -> participants): simpl_cmsg (97*n + 33*(t-1)) ||
|
||||
* pubnonces (33*n)
|
||||
* The EncPedPop contribution to the equality-check input appends to the
|
||||
* SimplPedPop contribution:
|
||||
* eq_input = ... || enckeys (33*n) || pubnonces (33*n) */
|
||||
|
||||
/* Serialize the encryption context (encpedpop.py serialize_enc_context):
|
||||
* out = u32be(t) || enckeys[0] || ... || enckeys[n-1]
|
||||
* enckeys33 is an array of n 33-byte compressed host public keys; out must
|
||||
* hold 4 + 33*n bytes. */
|
||||
static void secp256k1_chilldkg_encpedpop_serialize_enc_context(unsigned char *out, uint32_t t, const unsigned char *enckeys33, size_t n);
|
||||
|
||||
/* Compute the pads for encrypting to all n recipients (encpedpop.py
|
||||
* encaps_multi): for recipient i, the context is u32be(i) || enc_context; the
|
||||
* pad for our own index is the symmetric self pad (no ECDH), the others are
|
||||
* ECDH pads between the one-time secnonce and the recipient's host public key
|
||||
* (sender-side ordering in the pad hash).
|
||||
*
|
||||
* enc_context must be at most 4 + 33*SECP256K1_CHILLDKG_MAX_PARTICIPANTS
|
||||
* bytes. Returns 1 on success and 0 if some host public key is invalid
|
||||
* (caller input error; the session parameters must be validated beforehand).
|
||||
* On failure, all pads are cleared. */
|
||||
static int secp256k1_chilldkg_encpedpop_encaps_multi(const secp256k1_context *ctx, secp256k1_scalar *pads, const secp256k1_scalar *secnonce, const unsigned char *pubnonce33, const unsigned char *deckey32, const unsigned char *enckeys33, const unsigned char *enc_context, size_t enc_context_len, uint32_t participant_id, size_t n);
|
||||
|
||||
/* Encrypt the n plaintext shares towards the n recipients (encpedpop.py
|
||||
* encrypt_multi): ciphertexts[i] = plaintexts[i] + pad[i]. The encryption is
|
||||
* additively homomorphic modulo the group order, so the coordinator can sum
|
||||
* the ciphertexts per recipient. Returns 1 on success, 0 on invalid host
|
||||
* public keys (see encaps_multi). */
|
||||
static int secp256k1_chilldkg_encpedpop_encrypt_multi(const secp256k1_context *ctx, secp256k1_scalar *ciphertexts, const secp256k1_scalar *secnonce, const unsigned char *pubnonce33, const unsigned char *deckey32, const unsigned char *enckeys33, const unsigned char *enc_context, size_t enc_context_len, uint32_t participant_id, const secp256k1_scalar *plaintexts, size_t n);
|
||||
|
||||
/* Compute the pads for decrypting the shares received from all n senders
|
||||
* (encpedpop.py decaps_multi): the context is u32be(participant_id) ||
|
||||
* enc_context for every sender; the pad for our own index is the symmetric
|
||||
* self pad, the others are ECDH pads between our deckey and the sender's
|
||||
* pubnonce (receiver-side ordering in the pad hash). deckey32 is our host
|
||||
* secret key and enckey33 our host public key.
|
||||
*
|
||||
* Returns SECP256K1_CHILLDKG_SUCCESS on success,
|
||||
* SECP256K1_CHILLDKG_FAULTY_PARTICIPANT_OR_COORDINATOR (with *fault_index) if
|
||||
* some sender's pubnonce is invalid, and SECP256K1_CHILLDKG_INVALID_INPUT if
|
||||
* deckey32 is invalid. On failure, all pads are cleared. */
|
||||
static secp256k1_chilldkg_fault secp256k1_chilldkg_encpedpop_decaps_multi(const secp256k1_context *ctx, secp256k1_scalar *pads, uint32_t *fault_index, const unsigned char *deckey32, const unsigned char *enckey33, const unsigned char *pubnonces33, const unsigned char *enc_context, size_t enc_context_len, uint32_t participant_id, size_t n);
|
||||
|
||||
/* Decrypt the sum of the encrypted shares addressed to us (encpedpop.py
|
||||
* decrypt_sum): out = sum_ciphertexts - sum of the n pads. Returns like
|
||||
* decaps_multi. */
|
||||
static secp256k1_chilldkg_fault secp256k1_chilldkg_encpedpop_decrypt_sum(const secp256k1_context *ctx, secp256k1_scalar *out, uint32_t *fault_index, const unsigned char *deckey32, const unsigned char *enckey33, const unsigned char *pubnonces33, const unsigned char *enc_context, size_t enc_context_len, uint32_t participant_id, const secp256k1_scalar *sum_ciphertexts, size_t n);
|
||||
|
||||
/* Participant state (encpedpop.py ParticipantState). The enckeys are kept
|
||||
* because participant_step2 needs them to recompute the encryption context
|
||||
* and the pads. */
|
||||
typedef struct {
|
||||
secp256k1_chilldkg_simplpedpop_participant_state simpl_state;
|
||||
unsigned char pubnonce33[33];
|
||||
unsigned char enckeys33[SECP256K1_CHILLDKG_MAX_PARTICIPANTS][33];
|
||||
} secp256k1_chilldkg_encpedpop_participant_state;
|
||||
|
||||
/* Participant step 1 (encpedpop.py participant_step1). Derives
|
||||
* simpl_seed = TH("BIP DKG/encpedpop seed", seed32 || random32 || enc_context)
|
||||
* aux_rand = TH("BIP DKG/simplpedpop aux", simpl_seed)
|
||||
* secnonce = TH("BIP DKG/encpedpop secnonce", simpl_seed)
|
||||
* pubnonce = pubkey_gen_plain(secnonce)
|
||||
* (in ChillDKG, both seed32 and deckey32 are the host secret key), runs
|
||||
* SimplPedPop participant_step1 on simpl_seed, encrypts the shares, and
|
||||
* outputs the participant message pmsg (33*t + 64 + 33 + 32*n bytes).
|
||||
*
|
||||
* Returns 1 on success and 0 on invalid input (t < 1, t > n, n exceeding
|
||||
* SECP256K1_CHILLDKG_MAX_PARTICIPANTS, participant_id >= n, invalid host
|
||||
* public keys) or on negligible-probability derivation failures. */
|
||||
static int secp256k1_chilldkg_encpedpop_participant_step1(const secp256k1_context *ctx, secp256k1_chilldkg_encpedpop_participant_state *state, unsigned char *pmsg, const unsigned char *seed32, const unsigned char *deckey32, const unsigned char *enckeys33, uint32_t t, uint32_t participant_id, const unsigned char *random32, size_t n);
|
||||
|
||||
/* Participant step 2 (encpedpop.py participant_step2): verify that the
|
||||
* coordinator echoed our pubnonce, decrypt our secshare from the summed
|
||||
* encrypted secshare, and run SimplPedPop participant_step2. Outputs the DKG
|
||||
* output and the EncPedPop eq_input (4 + 33*t + 33*n + 33*n bytes).
|
||||
*
|
||||
* cmsg must be exactly 97*n + 33*(t-1) + 33*n bytes. Returns
|
||||
* SECP256K1_CHILLDKG_SUCCESS on success; otherwise a fault code (with
|
||||
* *fault_index set when applicable): FAULTY_COORDINATOR if cmsg is malformed
|
||||
* or the pubnonce echo is wrong, FAULTY_PARTICIPANT_OR_COORDINATOR(i) if
|
||||
* sender i's pubnonce is invalid or their pop/commitment is bad, and
|
||||
* UNKNOWN_FAULTY_PARTICIPANT_OR_COORDINATOR if the decrypted secshare does
|
||||
* not match the pubshare. */
|
||||
static secp256k1_chilldkg_fault secp256k1_chilldkg_encpedpop_participant_step2(const secp256k1_context *ctx, secp256k1_chilldkg_simplpedpop_dkg_output *dkg_output, unsigned char *eq_input, uint32_t *fault_index, const secp256k1_chilldkg_encpedpop_participant_state *state, const unsigned char *deckey32, const unsigned char *cmsg, size_t cmsg_len, const secp256k1_scalar *enc_secshare);
|
||||
|
||||
/* Coordinator step (encpedpop.py coordinator_step): parse the n participant
|
||||
* messages (each 33*t + 64 + 33 + 32*n bytes), aggregate SimplPedPop, and sum
|
||||
* the encrypted shares per recipient (exploiting the additive homomorphism).
|
||||
* Outputs cmsg (97*n + 33*(t-1) + 33*n bytes), the coordinator's DKG output
|
||||
* (no secshare), the EncPedPop eq_input (4 + 33*t + 33*n + 33*n bytes) and
|
||||
* the n summed encrypted secshares. (In pure EncPedPop the coordinator would
|
||||
* send enc_secshares[i] to participant i only; ChillDKG broadcasts them.)
|
||||
*
|
||||
* Returns SECP256K1_CHILLDKG_SUCCESS on success and
|
||||
* SECP256K1_CHILLDKG_FAULTY_PARTICIPANT (with *fault_index) if a participant
|
||||
* message is malformed (invalid commitment, or an encrypted share that
|
||||
* overflows the group order). */
|
||||
static secp256k1_chilldkg_fault secp256k1_chilldkg_encpedpop_coordinator_step(const secp256k1_context *ctx, unsigned char *cmsg, secp256k1_chilldkg_simplpedpop_dkg_output *dkg_output, unsigned char *eq_input, secp256k1_scalar *enc_secshares, uint32_t *fault_index, const unsigned char *const *pmsgs, uint32_t t, const unsigned char *enckeys33, size_t n);
|
||||
|
||||
#endif
|
||||
378
src/modules/chilldkg/encpedpop_impl.h
Normal file
378
src/modules/chilldkg/encpedpop_impl.h
Normal file
@@ -0,0 +1,378 @@
|
||||
/***********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_CHILLDKG_ENCPEDPOP_IMPL_H
|
||||
#define SECP256K1_MODULE_CHILLDKG_ENCPEDPOP_IMPL_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "../../../include/secp256k1.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "vss.h"
|
||||
#include "simplpedpop.h"
|
||||
#include "encpedpop.h"
|
||||
#include "../../ecmult.h"
|
||||
#include "../../util.h"
|
||||
|
||||
/* The buffer size for u32be(index) || enc_context. */
|
||||
#define SECP256K1_CHILLDKG_ENCPEDPOP_MAX_CONTEXT_LEN (8 + 33 * SECP256K1_CHILLDKG_MAX_PARTICIPANTS)
|
||||
|
||||
static void secp256k1_chilldkg_encpedpop_serialize_enc_context(unsigned char *out, uint32_t t, const unsigned char *enckeys33, size_t n) {
|
||||
secp256k1_write_be32(out, t);
|
||||
memcpy(out + 4, enckeys33, 33 * n);
|
||||
}
|
||||
|
||||
static int secp256k1_chilldkg_encpedpop_encaps_multi(const secp256k1_context *ctx, secp256k1_scalar *pads, const secp256k1_scalar *secnonce, const unsigned char *pubnonce33, const unsigned char *deckey32, const unsigned char *enckeys33, const unsigned char *enc_context, size_t enc_context_len, uint32_t participant_id, size_t n) {
|
||||
const secp256k1_hash_ctx *hash_ctx;
|
||||
unsigned char context_[SECP256K1_CHILLDKG_ENCPEDPOP_MAX_CONTEXT_LEN];
|
||||
size_t i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
VERIFY_CHECK(enc_context_len + 4 <= sizeof(context_));
|
||||
hash_ctx = secp256k1_get_hash_context(ctx);
|
||||
|
||||
/* This is effectively the "Hashed ElGamal" multi-recipient KEM described
|
||||
* in Section 5 of "Multi-recipient encryption, revisited" by Alexandre
|
||||
* Pinto, Bertram Poettering, Jacob C. N. Schuldt (AsiaCCS 2014). */
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_write_be32(context_, (uint32_t)i);
|
||||
memcpy(context_ + 4, enc_context, enc_context_len);
|
||||
if (i == participant_id) {
|
||||
/* We're encrypting to ourselves, so we use a symmetrically
|
||||
* derived pad to save the ECDH computation. */
|
||||
secp256k1_chilldkg_encpedpop_self_pad(hash_ctx, &pads[i], deckey32, pubnonce33, context_, 4 + enc_context_len);
|
||||
} else {
|
||||
secp256k1_ge enckey;
|
||||
if (!secp256k1_chilldkg_point_load(&enckey, enckeys33 + 33 * i) || secp256k1_ge_is_infinity(&enckey)) {
|
||||
/* Invalid host public key: caller input error (the session
|
||||
* parameters must be validated beforehand). */
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar_clear(&pads[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
secp256k1_chilldkg_encpedpop_ecdh(ctx, &pads[i], secnonce, &enckey, pubnonce33, enckeys33 + 33 * i, context_, 4 + enc_context_len, 1);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_chilldkg_encpedpop_encrypt_multi(const secp256k1_context *ctx, secp256k1_scalar *ciphertexts, const secp256k1_scalar *secnonce, const unsigned char *pubnonce33, const unsigned char *deckey32, const unsigned char *enckeys33, const unsigned char *enc_context, size_t enc_context_len, uint32_t participant_id, const secp256k1_scalar *plaintexts, size_t n) {
|
||||
secp256k1_scalar pads[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
|
||||
size_t i;
|
||||
int ret;
|
||||
|
||||
VERIFY_CHECK(n <= SECP256K1_CHILLDKG_MAX_PARTICIPANTS);
|
||||
ret = secp256k1_chilldkg_encpedpop_encaps_multi(ctx, pads, secnonce, pubnonce33, deckey32, enckeys33, enc_context, enc_context_len, participant_id, n);
|
||||
if (ret) {
|
||||
/* The encryption is additively homomorphic modulo the group order. */
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar_add(&ciphertexts[i], &plaintexts[i], &pads[i]);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar_clear(&pads[i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static secp256k1_chilldkg_fault secp256k1_chilldkg_encpedpop_decaps_multi(const secp256k1_context *ctx, secp256k1_scalar *pads, uint32_t *fault_index, const unsigned char *deckey32, const unsigned char *enckey33, const unsigned char *pubnonces33, const unsigned char *enc_context, size_t enc_context_len, uint32_t participant_id, size_t n) {
|
||||
const secp256k1_hash_ctx *hash_ctx;
|
||||
unsigned char context_[SECP256K1_CHILLDKG_ENCPEDPOP_MAX_CONTEXT_LEN];
|
||||
secp256k1_scalar deckey;
|
||||
size_t i;
|
||||
int overflow;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
VERIFY_CHECK(enc_context_len + 4 <= sizeof(context_));
|
||||
VERIFY_CHECK(participant_id < n);
|
||||
hash_ctx = secp256k1_get_hash_context(ctx);
|
||||
|
||||
/* The receiver index in the context is our own participant id for every
|
||||
* sender. */
|
||||
secp256k1_write_be32(context_, participant_id);
|
||||
memcpy(context_ + 4, enc_context, enc_context_len);
|
||||
|
||||
secp256k1_scalar_set_b32(&deckey, deckey32, &overflow);
|
||||
overflow |= secp256k1_scalar_is_zero(&deckey);
|
||||
/* deckey32 is the caller's own host secret key; a failure is an input
|
||||
* error, not a protocol fault. */
|
||||
secp256k1_declassify(ctx, &overflow, sizeof(overflow));
|
||||
if (overflow) {
|
||||
return SECP256K1_CHILLDKG_INVALID_INPUT;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (i == participant_id) {
|
||||
/* The pad for the share from ourselves is derived symmetrically
|
||||
* (the sender side of the pad does the same). */
|
||||
secp256k1_chilldkg_encpedpop_self_pad(hash_ctx, &pads[i], deckey32, pubnonces33 + 33 * i, context_, 4 + enc_context_len);
|
||||
} else {
|
||||
secp256k1_ge pubnonce;
|
||||
if (!secp256k1_chilldkg_point_load(&pubnonce, pubnonces33 + 33 * i) || secp256k1_ge_is_infinity(&pubnonce)) {
|
||||
/* Since deckey and enckey are well-formed, the error must
|
||||
* have been caused by an invalid public nonce. */
|
||||
secp256k1_scalar_clear(&deckey);
|
||||
*fault_index = (uint32_t)i;
|
||||
return SECP256K1_CHILLDKG_FAULTY_PARTICIPANT_OR_COORDINATOR;
|
||||
}
|
||||
secp256k1_chilldkg_encpedpop_ecdh(ctx, &pads[i], &deckey, &pubnonce, enckey33, pubnonces33 + 33 * i, context_, 4 + enc_context_len, 0);
|
||||
}
|
||||
}
|
||||
secp256k1_scalar_clear(&deckey);
|
||||
return SECP256K1_CHILLDKG_SUCCESS;
|
||||
}
|
||||
|
||||
static secp256k1_chilldkg_fault secp256k1_chilldkg_encpedpop_decrypt_sum(const secp256k1_context *ctx, secp256k1_scalar *out, uint32_t *fault_index, const unsigned char *deckey32, const unsigned char *enckey33, const unsigned char *pubnonces33, const unsigned char *enc_context, size_t enc_context_len, uint32_t participant_id, const secp256k1_scalar *sum_ciphertexts, size_t n) {
|
||||
secp256k1_scalar pads[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
|
||||
secp256k1_chilldkg_fault fault;
|
||||
size_t i;
|
||||
|
||||
VERIFY_CHECK(n <= SECP256K1_CHILLDKG_MAX_PARTICIPANTS);
|
||||
fault = secp256k1_chilldkg_encpedpop_decaps_multi(ctx, pads, fault_index, deckey32, enckey33, pubnonces33, enc_context, enc_context_len, participant_id, n);
|
||||
if (fault == SECP256K1_CHILLDKG_SUCCESS) {
|
||||
secp256k1_scalar_set_int(out, 0);
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar_add(out, out, &pads[i]);
|
||||
}
|
||||
secp256k1_scalar_negate(out, out);
|
||||
secp256k1_scalar_add(out, out, sum_ciphertexts);
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar_clear(&pads[i]);
|
||||
}
|
||||
return fault;
|
||||
}
|
||||
|
||||
static int secp256k1_chilldkg_encpedpop_participant_step1(const secp256k1_context *ctx, secp256k1_chilldkg_encpedpop_participant_state *state, unsigned char *pmsg, const unsigned char *seed32, const unsigned char *deckey32, const unsigned char *enckeys33, uint32_t t, uint32_t participant_id, const unsigned char *random32, size_t n) {
|
||||
const secp256k1_hash_ctx *hash_ctx;
|
||||
unsigned char enc_context[4 + 33 * SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
|
||||
unsigned char simpl_seed[32];
|
||||
unsigned char simpl_aux_rand[32];
|
||||
unsigned char secnonce32[32];
|
||||
unsigned char pubnonce33[33];
|
||||
secp256k1_scalar secnonce;
|
||||
secp256k1_scalar shares[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
|
||||
secp256k1_scalar enc_shares[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
|
||||
secp256k1_sha256 sha;
|
||||
uint32_t i;
|
||||
int overflow;
|
||||
int ret = 0;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(state != NULL);
|
||||
ARG_CHECK(pmsg != NULL);
|
||||
ARG_CHECK(seed32 != NULL);
|
||||
ARG_CHECK(deckey32 != NULL);
|
||||
ARG_CHECK(enckeys33 != NULL);
|
||||
ARG_CHECK(random32 != NULL);
|
||||
hash_ctx = secp256k1_get_hash_context(ctx);
|
||||
|
||||
if (t < 1 || n < 1 || t > n || participant_id >= n || n > SECP256K1_CHILLDKG_MAX_PARTICIPANTS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Derive an encryption nonce and a seed for SimplPedPop.
|
||||
*
|
||||
* SimplPedPop will use its seed to derive the secret shares, which we
|
||||
* will encrypt using the encryption nonce. That means that all entropy
|
||||
* used in the derivation of simpl_seed should also be in the derivation
|
||||
* of the pubnonce, to ensure that we never encrypt different secret
|
||||
* shares with the same encryption pads. The foolproof way to achieve this
|
||||
* is to simply derive the nonce from simpl_seed. */
|
||||
secp256k1_chilldkg_encpedpop_serialize_enc_context(enc_context, t, enckeys33, n);
|
||||
secp256k1_chilldkg_sha256_tagged_encpedpop_seed(hash_ctx, &sha);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, seed32, 32);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, random32, 32);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, enc_context, 4 + 33 * n);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, simpl_seed);
|
||||
|
||||
secp256k1_chilldkg_sha256_tagged_simplpedpop_aux(hash_ctx, &sha);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, simpl_seed, 32);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, simpl_aux_rand);
|
||||
|
||||
secp256k1_chilldkg_sha256_tagged_encpedpop_secnonce(hash_ctx, &sha);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, simpl_seed, 32);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, secnonce32);
|
||||
secp256k1_sha256_clear(&sha);
|
||||
|
||||
/* pubnonce = pubkey_gen_plain(secnonce); fails only if secnonce is not in
|
||||
* range 1..n-1 (negligible probability). */
|
||||
secp256k1_scalar_set_b32(&secnonce, secnonce32, &overflow);
|
||||
overflow |= secp256k1_scalar_is_zero(&secnonce);
|
||||
secp256k1_declassify(ctx, &overflow, sizeof(overflow));
|
||||
if (!overflow) {
|
||||
secp256k1_gej pubnoncej;
|
||||
secp256k1_ge pubnonce_ge;
|
||||
secp256k1_ecmult_gen_gej(&ctx->ecmult_gen_ctx, &pubnoncej, &secnonce);
|
||||
secp256k1_ge_set_gej(&pubnonce_ge, &pubnoncej);
|
||||
secp256k1_chilldkg_point_save(pubnonce33, &pubnonce_ge);
|
||||
secp256k1_gej_clear(&pubnoncej);
|
||||
|
||||
if (secp256k1_chilldkg_simplpedpop_participant_step1(ctx, &state->simpl_state, pmsg, shares, simpl_seed, t, (uint32_t)n, participant_id, simpl_aux_rand)) {
|
||||
if (secp256k1_chilldkg_encpedpop_encrypt_multi(ctx, enc_shares, &secnonce, pubnonce33, deckey32, enckeys33, enc_context, 4 + 33 * n, participant_id, shares, n)) {
|
||||
/* pmsg = ParticipantMsg(simpl_pmsg, pubnonce, enc_shares).to_bytes() */
|
||||
memcpy(pmsg + 33 * t + 64, pubnonce33, 33);
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar_get_b32(pmsg + 33 * t + 97 + 32 * i, &enc_shares[i]);
|
||||
}
|
||||
memcpy(state->pubnonce33, pubnonce33, 33);
|
||||
memcpy(&state->enckeys33[0][0], enckeys33, 33 * n);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
secp256k1_scalar_clear(&secnonce);
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar_clear(&shares[i]);
|
||||
secp256k1_scalar_clear(&enc_shares[i]);
|
||||
}
|
||||
secp256k1_memclear_explicit(simpl_seed, sizeof(simpl_seed));
|
||||
secp256k1_memclear_explicit(simpl_aux_rand, sizeof(simpl_aux_rand));
|
||||
secp256k1_memclear_explicit(secnonce32, sizeof(secnonce32));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static secp256k1_chilldkg_fault secp256k1_chilldkg_encpedpop_participant_step2(const secp256k1_context *ctx, secp256k1_chilldkg_simplpedpop_dkg_output *dkg_output, unsigned char *eq_input, uint32_t *fault_index, const secp256k1_chilldkg_encpedpop_participant_state *state, const unsigned char *deckey32, const unsigned char *cmsg, size_t cmsg_len, const secp256k1_scalar *enc_secshare) {
|
||||
const uint32_t t = state->simpl_state.t;
|
||||
const uint32_t n = state->simpl_state.n;
|
||||
const uint32_t participant_id = state->simpl_state.participant_id;
|
||||
const size_t simpl_cmsg_len = 97 * (size_t)n + 33 * (size_t)(t - 1);
|
||||
const unsigned char *pubnonces;
|
||||
unsigned char enc_context[4 + 33 * SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
|
||||
secp256k1_scalar pads[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
|
||||
secp256k1_scalar padsum;
|
||||
secp256k1_scalar secshare;
|
||||
secp256k1_chilldkg_fault fault;
|
||||
uint32_t i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(dkg_output != NULL);
|
||||
ARG_CHECK(eq_input != NULL);
|
||||
ARG_CHECK(state != NULL);
|
||||
ARG_CHECK(deckey32 != NULL);
|
||||
ARG_CHECK(cmsg != NULL);
|
||||
ARG_CHECK(enc_secshare != NULL);
|
||||
|
||||
/* CoordinatorMsg.from_bytes; the simpl_cmsg prefix is parsed (again) by
|
||||
* the SimplPedPop participant_step2 below. */
|
||||
if (cmsg_len != simpl_cmsg_len + 33 * (size_t)n) {
|
||||
return SECP256K1_CHILLDKG_FAULTY_COORDINATOR;
|
||||
}
|
||||
pubnonces = cmsg + simpl_cmsg_len;
|
||||
|
||||
/* The coordinator must echo our own pubnonce. */
|
||||
if (secp256k1_memcmp_var(pubnonces + 33 * participant_id, state->pubnonce33, 33) != 0) {
|
||||
return SECP256K1_CHILLDKG_FAULTY_COORDINATOR;
|
||||
}
|
||||
|
||||
/* secshare = enc_secshare - sum of the pads (decrypt_sum). */
|
||||
secp256k1_chilldkg_encpedpop_serialize_enc_context(enc_context, t, &state->enckeys33[0][0], n);
|
||||
fault = secp256k1_chilldkg_encpedpop_decaps_multi(ctx, pads, fault_index, deckey32, state->enckeys33[participant_id], pubnonces, enc_context, 4 + 33 * (size_t)n, participant_id, n);
|
||||
if (fault != SECP256K1_CHILLDKG_SUCCESS) {
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar_clear(&pads[i]);
|
||||
}
|
||||
return fault;
|
||||
}
|
||||
secp256k1_scalar_set_int(&padsum, 0);
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar_add(&padsum, &padsum, &pads[i]);
|
||||
}
|
||||
secp256k1_scalar_negate(&secshare, &padsum);
|
||||
secp256k1_scalar_add(&secshare, &secshare, enc_secshare);
|
||||
|
||||
fault = secp256k1_chilldkg_simplpedpop_participant_step2(ctx, dkg_output, eq_input, fault_index, &state->simpl_state, cmsg, simpl_cmsg_len, &secshare);
|
||||
|
||||
secp256k1_scalar_clear(&secshare);
|
||||
secp256k1_scalar_clear(&padsum);
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar_clear(&pads[i]);
|
||||
}
|
||||
if (fault != SECP256K1_CHILLDKG_SUCCESS) {
|
||||
return fault;
|
||||
}
|
||||
|
||||
/* eq_input += enckeys || pubnonces */
|
||||
memcpy(eq_input + 4 + 33 * t, &state->enckeys33[0][0], 33 * (size_t)n);
|
||||
memcpy(eq_input + 4 + 33 * t + 33 * (size_t)n, pubnonces, 33 * (size_t)n);
|
||||
return SECP256K1_CHILLDKG_SUCCESS;
|
||||
}
|
||||
|
||||
static secp256k1_chilldkg_fault secp256k1_chilldkg_encpedpop_coordinator_step(const secp256k1_context *ctx, unsigned char *cmsg, secp256k1_chilldkg_simplpedpop_dkg_output *dkg_output, unsigned char *eq_input, secp256k1_scalar *enc_secshares, uint32_t *fault_index, const unsigned char *const *pmsgs, uint32_t t, const unsigned char *enckeys33, size_t n) {
|
||||
const size_t simpl_pmsg_len = 33 * (size_t)t + 64;
|
||||
const size_t simpl_cmsg_len = 97 * n + 33 * (size_t)(t - 1);
|
||||
secp256k1_ge scratch;
|
||||
secp256k1_scalar share;
|
||||
secp256k1_chilldkg_fault fault;
|
||||
size_t i;
|
||||
size_t j;
|
||||
int overflow;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(cmsg != NULL);
|
||||
ARG_CHECK(dkg_output != NULL);
|
||||
ARG_CHECK(eq_input != NULL);
|
||||
ARG_CHECK(enc_secshares != NULL);
|
||||
ARG_CHECK(pmsgs != NULL);
|
||||
ARG_CHECK(enckeys33 != NULL);
|
||||
|
||||
if (t < 1 || n < 1 || t > n || n > SECP256K1_CHILLDKG_MAX_PARTICIPANTS) {
|
||||
return SECP256K1_CHILLDKG_INVALID_INPUT;
|
||||
}
|
||||
|
||||
/* Parse the participant messages (ParticipantMsg.from_bytes). A malformed
|
||||
* message blames its sender. The pubnonces are not parsed (they are plain
|
||||
* byte strings in the reference); the participants parse them when
|
||||
* decrypting. */
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar_set_int(&enc_secshares[i], 0);
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
const unsigned char *pmsg = pmsgs[i];
|
||||
/* Validate the SimplPedPop commitment (the actual aggregation happens
|
||||
* in the SimplPedPop coordinator step below). */
|
||||
for (j = 0; j < t; j++) {
|
||||
if (!secp256k1_chilldkg_point_load(&scratch, pmsg + 33 * j)) {
|
||||
*fault_index = (uint32_t)i;
|
||||
return SECP256K1_CHILLDKG_FAULTY_PARTICIPANT;
|
||||
}
|
||||
}
|
||||
/* Collect the pubnonces in the coordinator message. */
|
||||
memcpy(cmsg + simpl_cmsg_len + 33 * i, pmsg + simpl_pmsg_len, 33);
|
||||
/* Sum the encrypted shares per recipient (the encryption is
|
||||
* additively homomorphic). Wire scalars are parsed checked; an
|
||||
* overflow blames the sender. */
|
||||
for (j = 0; j < n; j++) {
|
||||
secp256k1_scalar_set_b32(&share, pmsg + simpl_pmsg_len + 33 + 32 * j, &overflow);
|
||||
if (overflow) {
|
||||
secp256k1_scalar_clear(&share);
|
||||
*fault_index = (uint32_t)i;
|
||||
return SECP256K1_CHILLDKG_FAULTY_PARTICIPANT;
|
||||
}
|
||||
secp256k1_scalar_add(&enc_secshares[j], &enc_secshares[j], &share);
|
||||
}
|
||||
}
|
||||
secp256k1_scalar_clear(&share);
|
||||
|
||||
fault = secp256k1_chilldkg_simplpedpop_coordinator_step(ctx, cmsg, dkg_output, eq_input, fault_index, pmsgs, t, (uint32_t)n);
|
||||
if (fault != SECP256K1_CHILLDKG_SUCCESS) {
|
||||
return fault;
|
||||
}
|
||||
|
||||
/* eq_input += enckeys || pubnonces */
|
||||
memcpy(eq_input + 4 + 33 * t, enckeys33, 33 * n);
|
||||
memcpy(eq_input + 4 + 33 * t + 33 * n, cmsg + simpl_cmsg_len, 33 * n);
|
||||
return SECP256K1_CHILLDKG_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -10,5 +10,7 @@
|
||||
|
||||
#include "util_impl.h"
|
||||
#include "vss_impl.h"
|
||||
#include "simplpedpop_impl.h"
|
||||
#include "encpedpop_impl.h"
|
||||
|
||||
#endif
|
||||
|
||||
117
src/modules/chilldkg/simplpedpop.h
Normal file
117
src/modules/chilldkg/simplpedpop.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/***********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_CHILLDKG_SIMPLPEDPOP_H
|
||||
#define SECP256K1_MODULE_CHILLDKG_SIMPLPEDPOP_H
|
||||
|
||||
#include "../../../include/secp256k1.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "vss.h"
|
||||
#include "../../group.h"
|
||||
#include "../../scalar.h"
|
||||
|
||||
/* This file contains the internal SimplPedPop sub-protocol of the ChillDKG
|
||||
* module, mirroring chilldkg_ref/simplpedpop.py of the bip-frost-dkg
|
||||
* reference implementation. Function decomposition and naming follow the
|
||||
* reference so that the two stay diffable.
|
||||
*
|
||||
* SimplPedPop is a non-interactive Pedersen VSS with a proof of possession
|
||||
* (pop) per participant. Messages are byte strings:
|
||||
* pmsg (participant -> coordinator): com (33*t) || pop (64)
|
||||
* cmsg (coordinator -> participants): coms_to_secrets (33*n) ||
|
||||
* sum_coms_to_nonconst_terms (33*(t-1)) || pops (64*n)
|
||||
* The SimplPedPop contribution to the equality-check input is
|
||||
* eq_input = u32be(t) || sum_coms (33*t) [sum_coms is UNTWEAKED]
|
||||
* and is extended by the EncPedPop layer. */
|
||||
|
||||
/* The message over which a proof of possession is computed is
|
||||
* u32be(participant_id) (simplpedpop.py pop_msg); the tag prefix is
|
||||
* "BIP DKG/pop message" (POP_MSG_TAG). */
|
||||
|
||||
/* Compute a proof of possession (simplpedpop.py pop_prove): a BIP 340
|
||||
* signature with tag prefix "BIP DKG/pop message" over u32be(participant_id),
|
||||
* created with the given 32-byte secret key and aux_rand. Returns 1 on success
|
||||
* and 0 if the secret key is invalid (negligible probability for VSS
|
||||
* coefficients). */
|
||||
static int secp256k1_chilldkg_simplpedpop_pop_prove(const secp256k1_context *ctx, unsigned char *pop64, const unsigned char *seckey32, uint32_t participant_id, const unsigned char *aux_rand32);
|
||||
|
||||
/* Verify a proof of possession (simplpedpop.py pop_verify) against the x-only
|
||||
* encoding of the commitment to the secret of the claimed participant.
|
||||
* Returns 1 if the pop is valid and 0 otherwise. */
|
||||
static int secp256k1_chilldkg_simplpedpop_pop_verify(const secp256k1_context *ctx, const unsigned char *pop64, const unsigned char *pubkey32, uint32_t participant_id);
|
||||
|
||||
/* Participant state (simplpedpop.py ParticipantState). */
|
||||
typedef struct {
|
||||
uint32_t t;
|
||||
uint32_t n;
|
||||
uint32_t participant_id;
|
||||
secp256k1_ge com_to_secret;
|
||||
} secp256k1_chilldkg_simplpedpop_participant_state;
|
||||
|
||||
/* DKG output (simplpedpop.py DKGOutput). secshare32 and the pubshares are the
|
||||
* TWEAKED values (after invalid_taproot_commit). The coordinator has no
|
||||
* secshare; in its output secshare32 is zero (None in the reference). Only
|
||||
* the first n entries of pubshares33 are filled. */
|
||||
typedef struct {
|
||||
unsigned char secshare32[32];
|
||||
unsigned char thresh_pk33[33];
|
||||
unsigned char pubshares33[SECP256K1_CHILLDKG_MAX_PARTICIPANTS][33];
|
||||
} secp256k1_chilldkg_simplpedpop_dkg_output;
|
||||
|
||||
/* Participant step 1 (simplpedpop.py participant_step1): derive the VSS
|
||||
* coefficients from seed32, compute the commitment and the shares for all n
|
||||
* participants, and prove possession of the secret (the constant coefficient
|
||||
* f(0)) with aux_rand32 as aux_rand.
|
||||
*
|
||||
* Outputs the state, the participant message msg (33*t + 64 bytes) and the n
|
||||
* partial secret shares (the caller must clear them after use). Returns 1 on
|
||||
* success and 0 on invalid input (t < 1, t > n, n or t exceeding
|
||||
* SECP256K1_CHILLDKG_MAX_PARTICIPANTS, participant_id >= n) or if the
|
||||
* seed-derived coefficients overflow the group order or the secret is zero
|
||||
* (negligible probability). */
|
||||
static int secp256k1_chilldkg_simplpedpop_participant_step1(const secp256k1_context *ctx, secp256k1_chilldkg_simplpedpop_participant_state *state, unsigned char *msg, secp256k1_scalar *partial_secshares, const unsigned char *seed32, uint32_t t, uint32_t n, uint32_t participant_id, const unsigned char *aux_rand32);
|
||||
|
||||
/* Sum the partial secshares received from all participants
|
||||
* (simplpedpop.py participant_step2_prepare_secshare). */
|
||||
static void secp256k1_chilldkg_simplpedpop_participant_step2_prepare_secshare(secp256k1_scalar *out, const secp256k1_scalar *partial_secshares, size_t n);
|
||||
|
||||
/* Participant step 2 (simplpedpop.py participant_step2): verify the
|
||||
* coordinator message, i.e., check that our own commitment to the secret was
|
||||
* echoed correctly, verify the pops of all other participants against the
|
||||
* x-only encodings of their commitments to the secrets, and check the tweaked
|
||||
* secshare against the tweaked pubshare (the tweak is applied before the share
|
||||
* verification). Outputs the DKG output and the SimplPedPop contribution to
|
||||
* eq_input (4 + 33*t bytes).
|
||||
*
|
||||
* cmsg must be exactly 97*n + 33*(t-1) bytes. Returns SECP256K1_CHILLDKG_SUCCESS
|
||||
* on success; otherwise a fault code (with *fault_index set when applicable):
|
||||
* - FAULTY_COORDINATOR if cmsg is malformed or the echo of our own
|
||||
* commitment to the secret is wrong;
|
||||
* - FAULTY_PARTICIPANT_OR_COORDINATOR(i) if participant i sent the point at
|
||||
* infinity as commitment to their secret or an invalid pop;
|
||||
* - UNKNOWN_FAULTY_PARTICIPANT_OR_COORDINATOR if the tweaked secshare does
|
||||
* not match the tweaked pubshare (the investigation procedure of a later
|
||||
* phase can attribute the fault). */
|
||||
static secp256k1_chilldkg_fault secp256k1_chilldkg_simplpedpop_participant_step2(const secp256k1_context *ctx, secp256k1_chilldkg_simplpedpop_dkg_output *dkg_output, unsigned char *eq_input, uint32_t *fault_index, const secp256k1_chilldkg_simplpedpop_participant_state *state, const unsigned char *cmsg, size_t cmsg_len, const secp256k1_scalar *secshare);
|
||||
|
||||
/* Assemble the summed VSS commitment (simplpedpop.py assemble_sum_coms):
|
||||
* sum_coms[0] = sum of the n coms_to_secrets, sum_coms[j] =
|
||||
* sum_coms_to_nonconst_terms[j-1] for j > 0. All inputs are public. */
|
||||
static void secp256k1_chilldkg_simplpedpop_assemble_sum_coms(secp256k1_ge *sum_coms, const secp256k1_ge *coms_to_secrets, const secp256k1_ge *sum_coms_to_nonconst_terms, size_t n, size_t t);
|
||||
|
||||
/* Coordinator step (simplpedpop.py coordinator_step): parse the n participant
|
||||
* messages (each 33*t + 64 bytes), echo the per-participant commitments to
|
||||
* the secrets, sum the commitments to the non-constant terms, and compute the
|
||||
* tweaked DKG output (no secshare) and the SimplPedPop contribution to
|
||||
* eq_input (4 + 33*t bytes). The pops are NOT verified here (participants
|
||||
* verify them in step 2).
|
||||
*
|
||||
* Outputs cmsg (97*n + 33*(t-1) bytes). Returns SECP256K1_CHILLDKG_SUCCESS on
|
||||
* success and SECP256K1_CHILLDKG_FAULTY_PARTICIPANT (with *fault_index) if a
|
||||
* participant message is malformed. */
|
||||
static secp256k1_chilldkg_fault secp256k1_chilldkg_simplpedpop_coordinator_step(const secp256k1_context *ctx, unsigned char *cmsg, secp256k1_chilldkg_simplpedpop_dkg_output *dkg_output, unsigned char *eq_input, uint32_t *fault_index, const unsigned char *const *pmsgs, uint32_t t, uint32_t n);
|
||||
|
||||
#endif
|
||||
356
src/modules/chilldkg/simplpedpop_impl.h
Normal file
356
src/modules/chilldkg/simplpedpop_impl.h
Normal file
@@ -0,0 +1,356 @@
|
||||
/***********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_CHILLDKG_SIMPLPEDPOP_IMPL_H
|
||||
#define SECP256K1_MODULE_CHILLDKG_SIMPLPEDPOP_IMPL_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "../../../include/secp256k1.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "vss.h"
|
||||
#include "simplpedpop.h"
|
||||
#include "../../ecmult.h"
|
||||
#include "../../util.h"
|
||||
|
||||
/* The tag prefix of the proof-of-possession signatures (POP_MSG_TAG in
|
||||
* simplpedpop.py). */
|
||||
#define SECP256K1_CHILLDKG_POP_MSG_TAG "BIP DKG/pop message"
|
||||
|
||||
static int secp256k1_chilldkg_simplpedpop_pop_prove(const secp256k1_context *ctx, unsigned char *pop64, const unsigned char *seckey32, uint32_t participant_id, const unsigned char *aux_rand32) {
|
||||
/* pop_msg: the message is u32be(participant_id). */
|
||||
unsigned char msg[4];
|
||||
int ret;
|
||||
|
||||
secp256k1_write_be32(msg, participant_id);
|
||||
ret = secp256k1_chilldkg_schnorrsig_sign(ctx, pop64, msg, sizeof(msg), seckey32, aux_rand32, SECP256K1_CHILLDKG_POP_MSG_TAG);
|
||||
secp256k1_memclear_explicit(msg, sizeof(msg));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int secp256k1_chilldkg_simplpedpop_pop_verify(const secp256k1_context *ctx, const unsigned char *pop64, const unsigned char *pubkey32, uint32_t participant_id) {
|
||||
unsigned char msg[4];
|
||||
int ret;
|
||||
|
||||
secp256k1_write_be32(msg, participant_id);
|
||||
ret = secp256k1_chilldkg_schnorrsig_verify(ctx, pop64, msg, sizeof(msg), pubkey32, SECP256K1_CHILLDKG_POP_MSG_TAG);
|
||||
secp256k1_memclear_explicit(msg, sizeof(msg));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int secp256k1_chilldkg_simplpedpop_participant_step1(const secp256k1_context *ctx, secp256k1_chilldkg_simplpedpop_participant_state *state, unsigned char *msg, secp256k1_scalar *partial_secshares, const unsigned char *seed32, uint32_t t, uint32_t n, uint32_t participant_id, const unsigned char *aux_rand32) {
|
||||
const secp256k1_hash_ctx *hash_ctx;
|
||||
secp256k1_scalar coeffs[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
|
||||
secp256k1_ge coms[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
|
||||
unsigned char seckey32[32];
|
||||
unsigned char pop[64];
|
||||
uint32_t i;
|
||||
size_t j;
|
||||
int coeffs_ok;
|
||||
int ret = 0;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(state != NULL);
|
||||
ARG_CHECK(msg != NULL);
|
||||
ARG_CHECK(partial_secshares != NULL);
|
||||
ARG_CHECK(seed32 != NULL);
|
||||
ARG_CHECK(aux_rand32 != NULL);
|
||||
hash_ctx = secp256k1_get_hash_context(ctx);
|
||||
|
||||
/* Input validation, mirroring the ValueError/IndexError checks of the
|
||||
* reference. The reference would fail on t == 0 when accessing the
|
||||
* constant coefficient; reject it here instead. */
|
||||
if (t < 1 || n < 1 || t > n || participant_id >= n || n > SECP256K1_CHILLDKG_MAX_PARTICIPANTS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* VSS.generate(seed, t). */
|
||||
coeffs_ok = secp256k1_chilldkg_vss_gen_coeffs(hash_ctx, coeffs, t, seed32);
|
||||
/* The failure depends on the secret seed but occurs with negligible
|
||||
* probability only (the reference raises OverflowError in this case). */
|
||||
secp256k1_declassify(ctx, &coeffs_ok, sizeof(coeffs_ok));
|
||||
if (coeffs_ok) {
|
||||
/* vss.secshares(n): the partial secret shares from us to all
|
||||
* participants. */
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_chilldkg_vss_secshare_for(&partial_secshares[i], coeffs, t, i);
|
||||
}
|
||||
/* com = vss.commit(). */
|
||||
secp256k1_chilldkg_vss_commit(ctx, coms, coeffs, t);
|
||||
/* pop = pop_prove(vss.secret(), participant_id, aux_rand); the secret
|
||||
* is the constant coefficient f(0) = coeffs[0]. Fails only if the
|
||||
* secret is zero (negligible probability). */
|
||||
secp256k1_scalar_get_b32(seckey32, &coeffs[0]);
|
||||
if (secp256k1_chilldkg_simplpedpop_pop_prove(ctx, pop, seckey32, participant_id, aux_rand32)) {
|
||||
/* msg = ParticipantMsg(com, pop).to_bytes() */
|
||||
for (j = 0; j < t; j++) {
|
||||
secp256k1_chilldkg_point_save(msg + 33 * j, &coms[j]);
|
||||
}
|
||||
memcpy(msg + 33 * t, pop, 64);
|
||||
state->t = t;
|
||||
state->n = n;
|
||||
state->participant_id = participant_id;
|
||||
/* com_to_secret = com.commitment_to_secret() */
|
||||
state->com_to_secret = coms[0];
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < t; j++) {
|
||||
secp256k1_scalar_clear(&coeffs[j]);
|
||||
}
|
||||
secp256k1_memclear_explicit(seckey32, sizeof(seckey32));
|
||||
secp256k1_memclear_explicit(pop, sizeof(pop));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void secp256k1_chilldkg_simplpedpop_participant_step2_prepare_secshare(secp256k1_scalar *out, const secp256k1_scalar *partial_secshares, size_t n) {
|
||||
size_t i;
|
||||
|
||||
secp256k1_scalar_set_int(out, 0);
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar_add(out, out, &partial_secshares[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static secp256k1_chilldkg_fault secp256k1_chilldkg_simplpedpop_participant_step2(const secp256k1_context *ctx, secp256k1_chilldkg_simplpedpop_dkg_output *dkg_output, unsigned char *eq_input, uint32_t *fault_index, const secp256k1_chilldkg_simplpedpop_participant_state *state, const unsigned char *cmsg, size_t cmsg_len, const secp256k1_scalar *secshare) {
|
||||
const uint32_t t = state->t;
|
||||
const uint32_t n = state->n;
|
||||
const uint32_t participant_id = state->participant_id;
|
||||
secp256k1_ge coms_to_secrets[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
|
||||
secp256k1_ge sum_coms_to_nonconst_terms[SECP256K1_CHILLDKG_MAX_PARTICIPANTS - 1];
|
||||
secp256k1_ge sum_coms[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
|
||||
secp256k1_ge sum_coms_tweaked[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
|
||||
secp256k1_ge pubtweak;
|
||||
secp256k1_ge pubshare;
|
||||
secp256k1_ge pubshare_i;
|
||||
secp256k1_gej pubsharej;
|
||||
secp256k1_scalar tweak;
|
||||
secp256k1_scalar secshare_tweaked;
|
||||
const unsigned char *pops;
|
||||
unsigned char buf33[33];
|
||||
unsigned char buf33b[33];
|
||||
unsigned char xonly32[32];
|
||||
uint32_t i;
|
||||
size_t j;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(dkg_output != NULL);
|
||||
ARG_CHECK(eq_input != NULL);
|
||||
ARG_CHECK(state != NULL);
|
||||
ARG_CHECK(cmsg != NULL);
|
||||
ARG_CHECK(secshare != NULL);
|
||||
|
||||
/* CoordinatorMsg.from_bytes; parse errors blame the coordinator. */
|
||||
if (cmsg_len != 97 * (size_t)n + 33 * (size_t)(t - 1)) {
|
||||
return SECP256K1_CHILLDKG_FAULTY_COORDINATOR;
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
if (!secp256k1_chilldkg_point_load(&coms_to_secrets[i], cmsg + 33 * i)) {
|
||||
return SECP256K1_CHILLDKG_FAULTY_COORDINATOR;
|
||||
}
|
||||
}
|
||||
/* Parse the summed commitments to the non-constant terms. */
|
||||
for (j = 1; j < t; j++) {
|
||||
if (!secp256k1_chilldkg_point_load(&sum_coms_to_nonconst_terms[j - 1], cmsg + 33 * n + 33 * (j - 1))) {
|
||||
return SECP256K1_CHILLDKG_FAULTY_COORDINATOR;
|
||||
}
|
||||
}
|
||||
pops = cmsg + 33 * n + 33 * (t - 1);
|
||||
|
||||
/* The coordinator must echo our own commitment to the secret. Compare the
|
||||
* canonical serializations so that the point at infinity (which cannot
|
||||
* occur here in practice, see participant_step1) is handled, too. */
|
||||
secp256k1_chilldkg_point_save(buf33, &state->com_to_secret);
|
||||
secp256k1_chilldkg_point_save(buf33b, &coms_to_secrets[participant_id]);
|
||||
if (secp256k1_memcmp_var(buf33, buf33b, 33) != 0) {
|
||||
return SECP256K1_CHILLDKG_FAULTY_COORDINATOR;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (i == participant_id) {
|
||||
/* No need to check our own pop. */
|
||||
continue;
|
||||
}
|
||||
if (secp256k1_ge_is_infinity(&coms_to_secrets[i])) {
|
||||
/* "Participant sent invalid commitment": the x-only serialization
|
||||
* needed for the pop verification does not exist. */
|
||||
*fault_index = i;
|
||||
return SECP256K1_CHILLDKG_FAULTY_PARTICIPANT_OR_COORDINATOR;
|
||||
}
|
||||
secp256k1_chilldkg_xonly_save(xonly32, &coms_to_secrets[i]);
|
||||
if (!secp256k1_chilldkg_simplpedpop_pop_verify(ctx, pops + 64 * i, xonly32, i)) {
|
||||
/* "Participant sent invalid proof-of-knowledge". */
|
||||
*fault_index = i;
|
||||
return SECP256K1_CHILLDKG_FAULTY_PARTICIPANT_OR_COORDINATOR;
|
||||
}
|
||||
}
|
||||
|
||||
secp256k1_chilldkg_simplpedpop_assemble_sum_coms(sum_coms, coms_to_secrets, sum_coms_to_nonconst_terms, n, t);
|
||||
|
||||
if (!secp256k1_chilldkg_vss_invalid_taproot_commit(ctx, sum_coms_tweaked, &tweak, &pubtweak, sum_coms, t)) {
|
||||
/* Unreachable in practice: sum_coms[0] can only be the point at
|
||||
* infinity if some pop is invalid (checked above), and a tweak hash
|
||||
* overflow has negligible probability. The reference raises a
|
||||
* non-protocol error here. */
|
||||
*fault_index = UINT32_MAX;
|
||||
return SECP256K1_CHILLDKG_UNKNOWN_FAULTY_PARTICIPANT_OR_COORDINATOR;
|
||||
}
|
||||
|
||||
/* Verifying the tweaked secshare against the tweaked pubshare is
|
||||
* equivalent to verifying the untweaked values, but avoids computing the
|
||||
* untweaked pubshare in the happy path. */
|
||||
secp256k1_chilldkg_vss_pubshare(&pubsharej, sum_coms_tweaked, t, participant_id);
|
||||
secp256k1_ge_set_gej_var(&pubshare, &pubsharej);
|
||||
secp256k1_scalar_add(&secshare_tweaked, secshare, &tweak);
|
||||
if (!secp256k1_chilldkg_vss_verify_secshare(ctx, &secshare_tweaked, &pubshare)) {
|
||||
/* "Received invalid secshare"; the investigation procedure (a later
|
||||
* phase) can determine the faulty party. */
|
||||
*fault_index = UINT32_MAX;
|
||||
secp256k1_scalar_clear(&tweak);
|
||||
secp256k1_scalar_clear(&secshare_tweaked);
|
||||
return SECP256K1_CHILLDKG_UNKNOWN_FAULTY_PARTICIPANT_OR_COORDINATOR;
|
||||
}
|
||||
|
||||
/* dkg_output: tweaked secshare, threshold public key (the tweaked
|
||||
* commitment to the secret), and the tweaked pubshares of all
|
||||
* participants. */
|
||||
secp256k1_scalar_get_b32(dkg_output->secshare32, &secshare_tweaked);
|
||||
secp256k1_chilldkg_point_save(dkg_output->thresh_pk33, &sum_coms_tweaked[0]);
|
||||
for (i = 0; i < n; i++) {
|
||||
if (i != participant_id) {
|
||||
/* We have computed our own pubshare already. */
|
||||
secp256k1_chilldkg_vss_pubshare(&pubsharej, sum_coms_tweaked, t, i);
|
||||
secp256k1_ge_set_gej_var(&pubshare_i, &pubsharej);
|
||||
secp256k1_chilldkg_point_save(dkg_output->pubshares33[i], &pubshare_i);
|
||||
} else {
|
||||
secp256k1_chilldkg_point_save(dkg_output->pubshares33[i], &pubshare);
|
||||
}
|
||||
}
|
||||
|
||||
/* eq_input = u32be(t) || sum_coms.to_bytes() (UNTWEAKED commitment). */
|
||||
secp256k1_write_be32(eq_input, t);
|
||||
for (j = 0; j < t; j++) {
|
||||
secp256k1_chilldkg_point_save(eq_input + 4 + 33 * j, &sum_coms[j]);
|
||||
}
|
||||
|
||||
secp256k1_scalar_clear(&tweak);
|
||||
secp256k1_scalar_clear(&secshare_tweaked);
|
||||
return SECP256K1_CHILLDKG_SUCCESS;
|
||||
}
|
||||
|
||||
static void secp256k1_chilldkg_simplpedpop_assemble_sum_coms(secp256k1_ge *sum_coms, const secp256k1_ge *coms_to_secrets, const secp256k1_ge *sum_coms_to_nonconst_terms, size_t n, size_t t) {
|
||||
secp256k1_gej accj, termj;
|
||||
size_t i, j;
|
||||
|
||||
/* Sum the commitments to the secrets. */
|
||||
secp256k1_gej_set_infinity(&accj);
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_gej_set_ge(&termj, &coms_to_secrets[i]);
|
||||
secp256k1_gej_add_var(&accj, &accj, &termj, NULL);
|
||||
}
|
||||
secp256k1_ge_set_gej_var(&sum_coms[0], &accj);
|
||||
for (j = 1; j < t; j++) {
|
||||
sum_coms[j] = sum_coms_to_nonconst_terms[j - 1];
|
||||
}
|
||||
}
|
||||
|
||||
static secp256k1_chilldkg_fault secp256k1_chilldkg_simplpedpop_coordinator_step(const secp256k1_context *ctx, unsigned char *cmsg, secp256k1_chilldkg_simplpedpop_dkg_output *dkg_output, unsigned char *eq_input, uint32_t *fault_index, const unsigned char *const *pmsgs, uint32_t t, uint32_t n) {
|
||||
secp256k1_ge coms_to_secrets[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
|
||||
secp256k1_ge com[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
|
||||
secp256k1_ge sum_coms_to_nonconst_terms[SECP256K1_CHILLDKG_MAX_PARTICIPANTS - 1];
|
||||
secp256k1_ge sum_coms[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
|
||||
secp256k1_ge sum_coms_tweaked[SECP256K1_CHILLDKG_MAX_PARTICIPANTS];
|
||||
secp256k1_ge pubtweak;
|
||||
secp256k1_ge pubshare;
|
||||
secp256k1_gej pubsharej;
|
||||
secp256k1_scalar tweak;
|
||||
uint32_t i;
|
||||
size_t j;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(cmsg != NULL);
|
||||
ARG_CHECK(dkg_output != NULL);
|
||||
ARG_CHECK(eq_input != NULL);
|
||||
ARG_CHECK(pmsgs != NULL);
|
||||
|
||||
if (t < 1 || n < 1 || t > n || n > SECP256K1_CHILLDKG_MAX_PARTICIPANTS) {
|
||||
return SECP256K1_CHILLDKG_INVALID_INPUT;
|
||||
}
|
||||
|
||||
/* Parse the participant messages. A malformed message blames its sender.
|
||||
* The pops are not verified here; the participants verify them in step 2. */
|
||||
for (j = 1; j < t; j++) {
|
||||
secp256k1_ge_set_infinity(&sum_coms_to_nonconst_terms[j - 1]);
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
for (j = 0; j < t; j++) {
|
||||
if (!secp256k1_chilldkg_point_load(&com[j], pmsgs[i] + 33 * j)) {
|
||||
*fault_index = i;
|
||||
return SECP256K1_CHILLDKG_FAULTY_PARTICIPANT;
|
||||
}
|
||||
}
|
||||
/* Echo the commitment to the secret ... */
|
||||
coms_to_secrets[i] = com[0];
|
||||
/* ... and sum the commitments to the non-constant terms (Pedersen,
|
||||
* Section 5.1 of "Non-Interactive and Information-Theoretic Secure
|
||||
* Verifiable Secret Sharing"). All inputs are public. */
|
||||
for (j = 1; j < t; j++) {
|
||||
secp256k1_gej aj, bj, sumj;
|
||||
secp256k1_gej_set_ge(&aj, &sum_coms_to_nonconst_terms[j - 1]);
|
||||
secp256k1_gej_set_ge(&bj, &com[j]);
|
||||
secp256k1_gej_add_var(&sumj, &aj, &bj, NULL);
|
||||
secp256k1_ge_set_gej_var(&sum_coms_to_nonconst_terms[j - 1], &sumj);
|
||||
}
|
||||
/* Collect the pops in the coordinator message. */
|
||||
memcpy(cmsg + 33 * n + 33 * (t - 1) + 64 * i, pmsgs[i] + 33 * t, 64);
|
||||
}
|
||||
|
||||
/* cmsg = CoordinatorMsg(coms_to_secrets, sum_coms_to_nonconst_terms, pops).to_bytes() */
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_chilldkg_point_save(cmsg + 33 * i, &coms_to_secrets[i]);
|
||||
}
|
||||
for (j = 1; j < t; j++) {
|
||||
secp256k1_chilldkg_point_save(cmsg + 33 * n + 33 * (j - 1), &sum_coms_to_nonconst_terms[j - 1]);
|
||||
}
|
||||
|
||||
secp256k1_chilldkg_simplpedpop_assemble_sum_coms(sum_coms, coms_to_secrets, sum_coms_to_nonconst_terms, n, t);
|
||||
|
||||
if (!secp256k1_chilldkg_vss_invalid_taproot_commit(ctx, sum_coms_tweaked, &tweak, &pubtweak, sum_coms, t)) {
|
||||
/* A participant can make the sum of the commitments to the secrets
|
||||
* the point at infinity (the coordinator does not verify the pops),
|
||||
* or the tweak hash overflows (negligible probability). The faulty
|
||||
* participant cannot be identified without verifying the pops, which
|
||||
* is the participants' job in step 2. The reference raises a
|
||||
* non-protocol error here. */
|
||||
*fault_index = UINT32_MAX;
|
||||
secp256k1_scalar_clear(&tweak);
|
||||
return SECP256K1_CHILLDKG_UNKNOWN_FAULTY_PARTICIPANT_OR_COORDINATOR;
|
||||
}
|
||||
|
||||
/* The coordinator's DKG output has no secshare (None in the reference). */
|
||||
memset(dkg_output->secshare32, 0, 32);
|
||||
secp256k1_chilldkg_point_save(dkg_output->thresh_pk33, &sum_coms_tweaked[0]);
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_chilldkg_vss_pubshare(&pubsharej, sum_coms_tweaked, t, i);
|
||||
secp256k1_ge_set_gej_var(&pubshare, &pubsharej);
|
||||
secp256k1_chilldkg_point_save(dkg_output->pubshares33[i], &pubshare);
|
||||
}
|
||||
|
||||
/* eq_input = u32be(t) || sum_coms.to_bytes() (UNTWEAKED commitment). */
|
||||
secp256k1_write_be32(eq_input, t);
|
||||
for (j = 0; j < t; j++) {
|
||||
secp256k1_chilldkg_point_save(eq_input + 4 + 33 * j, &sum_coms[j]);
|
||||
}
|
||||
|
||||
secp256k1_scalar_clear(&tweak);
|
||||
return SECP256K1_CHILLDKG_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
#include "util.h"
|
||||
#include "vss.h"
|
||||
#include "simplpedpop.h"
|
||||
#include "encpedpop.h"
|
||||
#include "../../group.h"
|
||||
#include "../../hash.h"
|
||||
#include "../../scalar.h"
|
||||
@@ -113,6 +115,92 @@ static const unsigned char vec_vss_coms_tweaked[3][33] = {
|
||||
};
|
||||
/* all python-side sanity checks passed */
|
||||
|
||||
static const unsigned char vec_simpl_seeds[3][32] = {
|
||||
{ 0xa6, 0xf4, 0xe5, 0xf2, 0x7b, 0xdd, 0xce, 0xa7, 0x26, 0xb2, 0x34, 0xfb, 0x7b, 0xde, 0x82, 0x98, 0xa5, 0x43, 0xc2, 0x51, 0x45, 0xa9, 0x7a, 0xd2, 0x34, 0x3d, 0xb5, 0x22, 0x5b, 0x29, 0x31, 0x14 },
|
||||
{ 0xb3, 0xa1, 0xef, 0xa6, 0x69, 0xc6, 0x9c, 0xa8, 0xdd, 0x58, 0x0a, 0xfe, 0x92, 0x0b, 0x8c, 0x00, 0xcc, 0x6e, 0x92, 0x2f, 0xd0, 0x7b, 0x88, 0x13, 0x80, 0x20, 0x9b, 0x86, 0x78, 0x2b, 0x3b, 0x9b },
|
||||
{ 0xe9, 0x9e, 0xe7, 0xeb, 0x84, 0xe2, 0x22, 0xca, 0x0a, 0xcc, 0x8a, 0x88, 0x24, 0x9b, 0x94, 0x28, 0xbd, 0xd9, 0xfd, 0x7e, 0x86, 0x45, 0xb5, 0xb3, 0xb9, 0xc0, 0x90, 0x7d, 0x20, 0x4d, 0x55, 0x61 },
|
||||
};
|
||||
static const unsigned char vec_simpl_auxs[3][32] = {
|
||||
{ 0x33, 0x0e, 0x6c, 0x54, 0x12, 0x16, 0x2a, 0xc7, 0x24, 0x63, 0x4e, 0x89, 0x6a, 0x05, 0x86, 0xcb, 0x00, 0x7c, 0xa4, 0xf9, 0x87, 0xf7, 0x13, 0x85, 0x5d, 0x29, 0xc4, 0xbb, 0x41, 0x8d, 0x28, 0xdf },
|
||||
{ 0xf8, 0xfd, 0xb8, 0x21, 0xbc, 0x3d, 0x58, 0x44, 0xea, 0x95, 0x03, 0x73, 0x85, 0xf3, 0x9e, 0xab, 0x9f, 0x31, 0x77, 0xbe, 0x40, 0x81, 0x63, 0x73, 0x85, 0xeb, 0xdd, 0x8d, 0x0e, 0xaf, 0xde, 0xac },
|
||||
{ 0xe4, 0x6d, 0x0d, 0x20, 0x61, 0x82, 0xee, 0x3c, 0x90, 0xb7, 0xdf, 0xb2, 0x9a, 0x78, 0x5e, 0x8d, 0x6b, 0xb5, 0x37, 0x1d, 0x4f, 0x0d, 0x84, 0xe4, 0xe0, 0xe8, 0x0d, 0xe5, 0x65, 0x04, 0x31, 0x34 },
|
||||
};
|
||||
static const unsigned char vec_simpl_pmsgs[3][130] = {
|
||||
{ 0x03, 0x8c, 0xb4, 0x5f, 0x49, 0xf0, 0x01, 0x02, 0xf9, 0x84, 0x09, 0x9c, 0xe4, 0x1b, 0x85, 0xed, 0x90, 0x2e, 0xb8, 0x67, 0x69, 0x7a, 0x07, 0x88, 0x62, 0x34, 0xb7, 0x66, 0x32, 0xd2, 0x9b, 0xbe, 0xbc, 0x03, 0x9f, 0x74, 0xfc, 0x67, 0x4f, 0x91, 0xb6, 0x7d, 0xaf, 0x76, 0xb5, 0x25, 0x47, 0xb4, 0x4d, 0x60, 0xf6, 0x06, 0xef, 0x1d, 0x3a, 0xa8, 0x64, 0x8f, 0x68, 0x2d, 0xc6, 0xd3, 0x71, 0x75, 0x63, 0x4c, 0x72, 0x78, 0x3a, 0x94, 0xd6, 0x86, 0x8a, 0x58, 0x61, 0x22, 0x4f, 0xda, 0x99, 0x0d, 0x70, 0x38, 0x88, 0xa8, 0x7b, 0x00, 0xc0, 0x2a, 0x27, 0xca, 0x52, 0x66, 0x4a, 0x99, 0x36, 0xb1, 0x3c, 0xc1, 0xaf, 0xe6, 0x59, 0x12, 0x3c, 0xfe, 0xcb, 0x3b, 0x7a, 0x77, 0x85, 0x0d, 0x96, 0x32, 0x4a, 0x3f, 0x7e, 0xd9, 0x66, 0x22, 0x3b, 0x30, 0x36, 0x73, 0xdf, 0x16, 0x78, 0xd0, 0x76, 0xa6, 0xf8, 0x2f },
|
||||
{ 0x03, 0xc6, 0x5d, 0x00, 0x8d, 0xd5, 0x1c, 0x5f, 0xe9, 0x64, 0x38, 0x62, 0xbe, 0x0e, 0x7f, 0x6f, 0xcf, 0x08, 0x98, 0x90, 0xe9, 0x2d, 0x9e, 0x6e, 0xc3, 0x3d, 0x62, 0x44, 0xbf, 0x77, 0x7e, 0x7a, 0x1b, 0x03, 0x19, 0xe5, 0x0b, 0xbb, 0x2a, 0xb2, 0xd4, 0x65, 0x36, 0xd9, 0xbf, 0xef, 0x5c, 0x04, 0xa1, 0x09, 0xb3, 0x07, 0x47, 0x17, 0xc4, 0x5c, 0x2f, 0xdf, 0xc8, 0x21, 0x52, 0x1f, 0x3f, 0x84, 0xae, 0x11, 0xe9, 0xbd, 0xcd, 0xb3, 0xba, 0x31, 0x72, 0xe5, 0x04, 0xc1, 0x51, 0xc2, 0x59, 0xfa, 0x8d, 0x05, 0xb7, 0xe1, 0x75, 0x98, 0x35, 0xd3, 0xb9, 0x47, 0xf0, 0x57, 0x5b, 0xe4, 0x37, 0xfc, 0x91, 0x1e, 0x61, 0xe7, 0x4b, 0x1d, 0x5c, 0x07, 0x18, 0x94, 0x5f, 0x33, 0x79, 0x55, 0x64, 0x35, 0x6d, 0x3e, 0x69, 0x92, 0x0f, 0xc0, 0x7a, 0x03, 0xc0, 0x33, 0x7f, 0x26, 0xb5, 0xfd, 0xc3, 0x3e, 0x47, 0x5c },
|
||||
{ 0x02, 0x99, 0xad, 0x8e, 0x28, 0xa8, 0x4c, 0x91, 0x5e, 0xc8, 0x19, 0x03, 0xc3, 0x1b, 0xb4, 0x0f, 0xc5, 0xa5, 0xd4, 0xad, 0x06, 0xdf, 0xd0, 0xaa, 0x77, 0xd1, 0xf4, 0x62, 0x8e, 0x07, 0xf4, 0x58, 0xee, 0x03, 0x43, 0x6e, 0x96, 0x90, 0x01, 0x45, 0x43, 0xb7, 0x27, 0x3f, 0xa4, 0xd8, 0x86, 0x17, 0x63, 0x70, 0x2b, 0x50, 0x97, 0xaa, 0x1b, 0x8c, 0x71, 0x91, 0x9d, 0x55, 0x5c, 0x59, 0xbe, 0x54, 0x05, 0x9d, 0x54, 0x08, 0x18, 0x4a, 0x80, 0xbd, 0x80, 0x31, 0x49, 0x0d, 0xef, 0x23, 0x98, 0xb2, 0x1a, 0x4f, 0x59, 0x20, 0x29, 0x72, 0xbd, 0x3d, 0xb3, 0xeb, 0x7e, 0x9e, 0xec, 0x9c, 0x4c, 0xe9, 0x56, 0x7a, 0x97, 0xab, 0x0b, 0xc9, 0x90, 0xd9, 0x7f, 0xb9, 0xc5, 0x6f, 0x67, 0x74, 0x29, 0x8b, 0x32, 0x41, 0x05, 0xf5, 0xe0, 0x4f, 0xa2, 0xbe, 0x68, 0x84, 0x43, 0xe6, 0x13, 0xd1, 0xbb, 0xe9, 0x8d, 0x6b },
|
||||
};
|
||||
static const unsigned char vec_simpl_cmsg[324] = { 0x03, 0x8c, 0xb4, 0x5f, 0x49, 0xf0, 0x01, 0x02, 0xf9, 0x84, 0x09, 0x9c, 0xe4, 0x1b, 0x85, 0xed, 0x90, 0x2e, 0xb8, 0x67, 0x69, 0x7a, 0x07, 0x88, 0x62, 0x34, 0xb7, 0x66, 0x32, 0xd2, 0x9b, 0xbe, 0xbc, 0x03, 0xc6, 0x5d, 0x00, 0x8d, 0xd5, 0x1c, 0x5f, 0xe9, 0x64, 0x38, 0x62, 0xbe, 0x0e, 0x7f, 0x6f, 0xcf, 0x08, 0x98, 0x90, 0xe9, 0x2d, 0x9e, 0x6e, 0xc3, 0x3d, 0x62, 0x44, 0xbf, 0x77, 0x7e, 0x7a, 0x1b, 0x02, 0x99, 0xad, 0x8e, 0x28, 0xa8, 0x4c, 0x91, 0x5e, 0xc8, 0x19, 0x03, 0xc3, 0x1b, 0xb4, 0x0f, 0xc5, 0xa5, 0xd4, 0xad, 0x06, 0xdf, 0xd0, 0xaa, 0x77, 0xd1, 0xf4, 0x62, 0x8e, 0x07, 0xf4, 0x58, 0xee, 0x02, 0x64, 0xcc, 0x1f, 0x7a, 0x2d, 0x27, 0xbb, 0x89, 0xf0, 0x68, 0xb1, 0x80, 0xfe, 0xe6, 0x9a, 0x6c, 0xd6, 0xce, 0x69, 0x93, 0x58, 0x6c, 0x61, 0x2b, 0x8b, 0x2e, 0x31, 0x08, 0xb9, 0x20, 0xf5, 0xac, 0x72, 0x78, 0x3a, 0x94, 0xd6, 0x86, 0x8a, 0x58, 0x61, 0x22, 0x4f, 0xda, 0x99, 0x0d, 0x70, 0x38, 0x88, 0xa8, 0x7b, 0x00, 0xc0, 0x2a, 0x27, 0xca, 0x52, 0x66, 0x4a, 0x99, 0x36, 0xb1, 0x3c, 0xc1, 0xaf, 0xe6, 0x59, 0x12, 0x3c, 0xfe, 0xcb, 0x3b, 0x7a, 0x77, 0x85, 0x0d, 0x96, 0x32, 0x4a, 0x3f, 0x7e, 0xd9, 0x66, 0x22, 0x3b, 0x30, 0x36, 0x73, 0xdf, 0x16, 0x78, 0xd0, 0x76, 0xa6, 0xf8, 0x2f, 0xe9, 0xbd, 0xcd, 0xb3, 0xba, 0x31, 0x72, 0xe5, 0x04, 0xc1, 0x51, 0xc2, 0x59, 0xfa, 0x8d, 0x05, 0xb7, 0xe1, 0x75, 0x98, 0x35, 0xd3, 0xb9, 0x47, 0xf0, 0x57, 0x5b, 0xe4, 0x37, 0xfc, 0x91, 0x1e, 0x61, 0xe7, 0x4b, 0x1d, 0x5c, 0x07, 0x18, 0x94, 0x5f, 0x33, 0x79, 0x55, 0x64, 0x35, 0x6d, 0x3e, 0x69, 0x92, 0x0f, 0xc0, 0x7a, 0x03, 0xc0, 0x33, 0x7f, 0x26, 0xb5, 0xfd, 0xc3, 0x3e, 0x47, 0x5c, 0x54, 0x08, 0x18, 0x4a, 0x80, 0xbd, 0x80, 0x31, 0x49, 0x0d, 0xef, 0x23, 0x98, 0xb2, 0x1a, 0x4f, 0x59, 0x20, 0x29, 0x72, 0xbd, 0x3d, 0xb3, 0xeb, 0x7e, 0x9e, 0xec, 0x9c, 0x4c, 0xe9, 0x56, 0x7a, 0x97, 0xab, 0x0b, 0xc9, 0x90, 0xd9, 0x7f, 0xb9, 0xc5, 0x6f, 0x67, 0x74, 0x29, 0x8b, 0x32, 0x41, 0x05, 0xf5, 0xe0, 0x4f, 0xa2, 0xbe, 0x68, 0x84, 0x43, 0xe6, 0x13, 0xd1, 0xbb, 0xe9, 0x8d, 0x6b };
|
||||
static const unsigned char vec_simpl_eq_input[70] = { 0x00, 0x00, 0x00, 0x02, 0x02, 0xd0, 0x90, 0x3c, 0xe9, 0x3d, 0xa3, 0x13, 0x95, 0x1e, 0x45, 0xd4, 0xa1, 0xb3, 0x84, 0x79, 0xbe, 0x50, 0x00, 0xc0, 0xd0, 0x6b, 0xec, 0xbc, 0x9a, 0xb3, 0xdf, 0x19, 0x56, 0x14, 0xd2, 0x15, 0x4c, 0x02, 0x64, 0xcc, 0x1f, 0x7a, 0x2d, 0x27, 0xbb, 0x89, 0xf0, 0x68, 0xb1, 0x80, 0xfe, 0xe6, 0x9a, 0x6c, 0xd6, 0xce, 0x69, 0x93, 0x58, 0x6c, 0x61, 0x2b, 0x8b, 0x2e, 0x31, 0x08, 0xb9, 0x20, 0xf5, 0xac };
|
||||
static const unsigned char vec_simpl_untweaked_secshares[3][32] = {
|
||||
{ 0x59, 0x2f, 0xa6, 0x21, 0xe3, 0xf7, 0xb2, 0xd2, 0x8d, 0x65, 0x4b, 0x93, 0xc2, 0xfd, 0x3f, 0xae, 0xe9, 0x58, 0x56, 0xf6, 0xde, 0x20, 0xb4, 0xc9, 0x24, 0xae, 0x60, 0x9a, 0x5f, 0x95, 0xaf, 0x91 },
|
||||
{ 0x19, 0xd3, 0x87, 0xab, 0x70, 0xd1, 0x17, 0x08, 0x5e, 0xbd, 0x0e, 0xae, 0x69, 0x96, 0xe3, 0x1b, 0x12, 0x93, 0x8b, 0x7b, 0x74, 0xd6, 0xe9, 0xbd, 0xdc, 0xe8, 0x49, 0x12, 0x89, 0xdc, 0xf9, 0x9a },
|
||||
{ 0xda, 0x77, 0x69, 0x34, 0xfd, 0xaa, 0x7b, 0x3e, 0x30, 0x14, 0xd1, 0xc9, 0x10, 0x30, 0x86, 0x85, 0xf6, 0x7d, 0x9c, 0xe6, 0xba, 0xd5, 0xbe, 0xee, 0x54, 0xf4, 0x90, 0x17, 0x84, 0x5a, 0x84, 0xe4 },
|
||||
};
|
||||
static const unsigned char vec_simpl_secshares[3][32] = {
|
||||
{ 0x3b, 0x3a, 0x99, 0x94, 0x6a, 0x23, 0x46, 0xb0, 0xd2, 0xf6, 0x9f, 0x20, 0xb0, 0xa6, 0x93, 0x0c, 0x0d, 0x10, 0x96, 0xc7, 0x7b, 0x07, 0xd8, 0x34, 0x5c, 0xc4, 0x54, 0x36, 0x2c, 0xfd, 0xc6, 0x6d },
|
||||
{ 0xfb, 0xde, 0x7b, 0x1d, 0xf6, 0xfc, 0xaa, 0xe6, 0xa4, 0x4e, 0x62, 0x3b, 0x57, 0x40, 0x36, 0x76, 0xf0, 0xfa, 0xa8, 0x32, 0xc1, 0x06, 0xad, 0x64, 0xd4, 0xd0, 0x9b, 0x3b, 0x27, 0x7b, 0x51, 0xb7 },
|
||||
{ 0xbc, 0x82, 0x5c, 0xa7, 0x83, 0xd6, 0x0f, 0x1c, 0x75, 0xa6, 0x25, 0x55, 0xfd, 0xd9, 0xd9, 0xe3, 0x1a, 0x35, 0xdc, 0xb7, 0x57, 0xbc, 0xe2, 0x59, 0x8d, 0x0a, 0x83, 0xb3, 0x51, 0xc2, 0x9b, 0xc0 },
|
||||
};
|
||||
static const unsigned char vec_simpl_thresh_pk[33] = { 0x03, 0x40, 0x04, 0x9c, 0x23, 0x3f, 0xcd, 0xc0, 0xed, 0x61, 0xe5, 0xc0, 0x2b, 0x69, 0xc2, 0xd8, 0x87, 0x6e, 0x78, 0xe9, 0xb3, 0xd4, 0x6d, 0x00, 0x7e, 0x26, 0x99, 0x8e, 0xeb, 0xfe, 0xa0, 0xdd, 0xc2 };
|
||||
static const unsigned char vec_simpl_pubshares[3][33] = {
|
||||
{ 0x02, 0xe4, 0x79, 0xc9, 0x2f, 0x41, 0xe8, 0x17, 0xef, 0x02, 0xa0, 0xa7, 0x50, 0x72, 0xb5, 0x9c, 0xce, 0xcd, 0xc5, 0xbf, 0xae, 0x56, 0x23, 0x19, 0x14, 0x97, 0x58, 0x9f, 0x80, 0xcd, 0x8c, 0x0b, 0x66 },
|
||||
{ 0x03, 0xc2, 0x2e, 0x8e, 0x3b, 0x79, 0xff, 0xa2, 0x98, 0xb3, 0xc6, 0x26, 0xdd, 0x32, 0xdb, 0x4d, 0xad, 0xd6, 0xca, 0xeb, 0xae, 0xb3, 0x21, 0xb2, 0x0e, 0xc3, 0x7e, 0x80, 0xce, 0x55, 0x26, 0xdd, 0xed },
|
||||
{ 0x03, 0x47, 0xef, 0x6d, 0x6b, 0x08, 0x3c, 0x91, 0xe2, 0x0a, 0xb0, 0x09, 0xa9, 0x1e, 0xa0, 0x40, 0x0c, 0x45, 0x19, 0x04, 0x53, 0x4a, 0xa3, 0x7f, 0x12, 0x1f, 0x22, 0xcb, 0xbf, 0x5c, 0x80, 0xcb, 0xf5 },
|
||||
};
|
||||
/* simplpedpop n = 3, t = 2 */
|
||||
static const unsigned char vec_enc_hostseckeys[3][32] = {
|
||||
{ 0xdb, 0x3d, 0x72, 0xeb, 0x38, 0x03, 0x1d, 0x5e, 0x7e, 0x83, 0xd7, 0x23, 0x30, 0xe2, 0xd0, 0xb9, 0x41, 0x77, 0xcb, 0x4c, 0x35, 0x65, 0x59, 0xee, 0x41, 0xca, 0xd5, 0x61, 0x52, 0x58, 0xd5, 0x00 },
|
||||
{ 0xe8, 0x12, 0xb0, 0xff, 0x5b, 0xb8, 0xf0, 0x8a, 0xfc, 0x87, 0xd7, 0xc3, 0x5b, 0x92, 0x17, 0x22, 0xab, 0x4d, 0x89, 0x76, 0x87, 0x45, 0x7a, 0x27, 0x2f, 0x71, 0x0c, 0xfb, 0x0a, 0xc9, 0x94, 0x50 },
|
||||
{ 0xff, 0x64, 0xf0, 0x9b, 0xb5, 0x03, 0xb5, 0x66, 0x29, 0x6e, 0xb6, 0xb2, 0x69, 0x09, 0x60, 0xab, 0x8b, 0x42, 0x13, 0x2d, 0x64, 0xdb, 0x9d, 0x4d, 0x27, 0x74, 0xc1, 0x19, 0x15, 0x74, 0x49, 0xba },
|
||||
};
|
||||
static const unsigned char vec_enc_hostpubkeys[3][33] = {
|
||||
{ 0x03, 0x30, 0x45, 0x46, 0x1f, 0xd4, 0xb4, 0xe8, 0xbc, 0xd2, 0x88, 0x8b, 0xc0, 0x5d, 0x2f, 0x8c, 0x86, 0x10, 0x53, 0x43, 0x10, 0x2e, 0x42, 0x5f, 0x18, 0xae, 0x64, 0xe0, 0x03, 0x2a, 0xba, 0xe1, 0xe3 },
|
||||
{ 0x03, 0x5c, 0x1f, 0xe2, 0x1b, 0xce, 0x62, 0x99, 0x2a, 0xe0, 0x66, 0x67, 0x7e, 0xc0, 0x4f, 0x68, 0xfc, 0x1b, 0x25, 0x79, 0x5f, 0x1a, 0x33, 0x62, 0x9a, 0xfb, 0x00, 0x24, 0x90, 0x60, 0x02, 0x85, 0x37 },
|
||||
{ 0x02, 0x19, 0xd6, 0xb1, 0x40, 0xab, 0x84, 0xa2, 0x5a, 0x49, 0x38, 0xcd, 0x62, 0xb2, 0x63, 0xd1, 0xd9, 0x85, 0x5e, 0xa4, 0x1e, 0x1e, 0xbc, 0x19, 0x56, 0x85, 0x47, 0x7f, 0xed, 0xd6, 0xd6, 0xa1, 0x38 },
|
||||
};
|
||||
static const unsigned char vec_enc_randoms[3][32] = {
|
||||
{ 0x95, 0xd1, 0xe5, 0x58, 0xb0, 0xba, 0x91, 0x29, 0x56, 0xfc, 0x6a, 0x07, 0xf1, 0xc1, 0xb5, 0x7a, 0x79, 0x98, 0x04, 0x26, 0xf7, 0x62, 0xfd, 0x70, 0x56, 0x46, 0x27, 0xab, 0x00, 0x05, 0xb1, 0x57 },
|
||||
{ 0x5d, 0xec, 0x98, 0x69, 0xa0, 0xf1, 0x7d, 0xbb, 0x48, 0x07, 0x10, 0x1d, 0x39, 0xe7, 0x77, 0x67, 0x24, 0xeb, 0xb1, 0xfe, 0x67, 0x36, 0x55, 0xd8, 0xd9, 0x29, 0xe1, 0x42, 0x4b, 0x74, 0x78, 0x4c },
|
||||
{ 0x7a, 0x98, 0x6c, 0xf5, 0x5d, 0xfa, 0xfc, 0x25, 0x0b, 0xa4, 0xb9, 0x51, 0x8a, 0x86, 0x9f, 0xfc, 0xb9, 0x84, 0x5a, 0x02, 0x0e, 0x46, 0xcd, 0xeb, 0xfd, 0xd8, 0x69, 0xf0, 0x96, 0x1b, 0xe1, 0x33 },
|
||||
};
|
||||
static const unsigned char vec_enc_context[103] = { 0x00, 0x00, 0x00, 0x02, 0x03, 0x30, 0x45, 0x46, 0x1f, 0xd4, 0xb4, 0xe8, 0xbc, 0xd2, 0x88, 0x8b, 0xc0, 0x5d, 0x2f, 0x8c, 0x86, 0x10, 0x53, 0x43, 0x10, 0x2e, 0x42, 0x5f, 0x18, 0xae, 0x64, 0xe0, 0x03, 0x2a, 0xba, 0xe1, 0xe3, 0x03, 0x5c, 0x1f, 0xe2, 0x1b, 0xce, 0x62, 0x99, 0x2a, 0xe0, 0x66, 0x67, 0x7e, 0xc0, 0x4f, 0x68, 0xfc, 0x1b, 0x25, 0x79, 0x5f, 0x1a, 0x33, 0x62, 0x9a, 0xfb, 0x00, 0x24, 0x90, 0x60, 0x02, 0x85, 0x37, 0x02, 0x19, 0xd6, 0xb1, 0x40, 0xab, 0x84, 0xa2, 0x5a, 0x49, 0x38, 0xcd, 0x62, 0xb2, 0x63, 0xd1, 0xd9, 0x85, 0x5e, 0xa4, 0x1e, 0x1e, 0xbc, 0x19, 0x56, 0x85, 0x47, 0x7f, 0xed, 0xd6, 0xd6, 0xa1, 0x38 };
|
||||
static const unsigned char vec_enc_secnonces[3][32] = {
|
||||
{ 0xe0, 0x4c, 0x21, 0xfc, 0x3d, 0xe8, 0x14, 0x0b, 0xa5, 0x69, 0x1b, 0xd8, 0x95, 0x74, 0xb5, 0x39, 0x13, 0x62, 0x7e, 0x30, 0x4a, 0x57, 0x9e, 0xa3, 0x78, 0x27, 0x48, 0x67, 0xb2, 0x17, 0x02, 0xd7 },
|
||||
{ 0x40, 0x32, 0xd6, 0xcc, 0x81, 0x70, 0xca, 0x6c, 0xcd, 0x31, 0x18, 0xa6, 0x07, 0xc0, 0x68, 0x45, 0x6b, 0x3e, 0x91, 0x28, 0xd5, 0x99, 0x65, 0xbe, 0x57, 0x02, 0x11, 0xd4, 0x2a, 0x3f, 0x28, 0xdb },
|
||||
{ 0x34, 0x10, 0x60, 0x33, 0x60, 0x32, 0xc1, 0xc5, 0x8a, 0x76, 0x9a, 0xcb, 0xcd, 0xee, 0x2d, 0x78, 0xe7, 0x41, 0x89, 0x7f, 0xe0, 0xdb, 0xda, 0x5a, 0x8f, 0xf5, 0xa0, 0x1c, 0x4f, 0x01, 0x26, 0x36 },
|
||||
};
|
||||
static const unsigned char vec_enc_pubnonces[3][33] = {
|
||||
{ 0x02, 0xb4, 0x37, 0x07, 0x73, 0x50, 0x98, 0x00, 0xf2, 0x22, 0x91, 0x6a, 0x54, 0x79, 0x78, 0x41, 0xd6, 0xcf, 0xc5, 0xb7, 0x00, 0x88, 0x0b, 0xcf, 0xb0, 0x39, 0xfb, 0x00, 0x08, 0x49, 0x41, 0x5f, 0x3f },
|
||||
{ 0x03, 0x97, 0x21, 0xcb, 0xf9, 0xbe, 0xde, 0xbf, 0x1b, 0xd5, 0x53, 0x0a, 0x04, 0x8d, 0x9d, 0x5b, 0x08, 0xf4, 0x6b, 0xb6, 0x1e, 0x6e, 0x7f, 0xf6, 0xc9, 0x96, 0x12, 0x9b, 0x14, 0x9e, 0xf3, 0xa0, 0x2d },
|
||||
{ 0x02, 0x12, 0xab, 0xc1, 0x3e, 0x84, 0x05, 0xa3, 0x3f, 0xcb, 0x4c, 0x43, 0x77, 0x43, 0xf8, 0x65, 0x20, 0x37, 0xf1, 0x4b, 0x67, 0x0e, 0x8d, 0x57, 0x42, 0xea, 0x26, 0x33, 0xa6, 0xec, 0x5e, 0x42, 0x37 },
|
||||
};
|
||||
static const unsigned char vec_enc_pmsgs[3][259] = {
|
||||
{ 0x03, 0xec, 0x16, 0x3c, 0xbf, 0xfc, 0x00, 0x8b, 0xf2, 0x5b, 0x99, 0x89, 0x8f, 0x5c, 0x4c, 0x0b, 0x5b, 0x00, 0xf3, 0xeb, 0xf8, 0xb2, 0xde, 0x73, 0x0d, 0x78, 0xdb, 0xef, 0xcb, 0xad, 0x01, 0xf9, 0x12, 0x03, 0xf2, 0x85, 0xe9, 0xd4, 0x54, 0x84, 0x8b, 0x3e, 0xc0, 0xaa, 0x4b, 0x14, 0xd5, 0x9c, 0x40, 0x8c, 0xd4, 0xa2, 0xed, 0x0a, 0x7d, 0x12, 0xf6, 0x4d, 0xed, 0xa7, 0xb7, 0x46, 0x0b, 0xee, 0xe4, 0xd1, 0xc0, 0x01, 0xd9, 0x1f, 0x98, 0x64, 0x8c, 0xa5, 0x81, 0xe0, 0x48, 0xef, 0x5b, 0xb8, 0xaa, 0x8f, 0x17, 0xe7, 0x05, 0xc8, 0x78, 0x4b, 0xaa, 0xe1, 0xbe, 0xc1, 0x2e, 0x9f, 0xc8, 0x16, 0x79, 0x1d, 0x2e, 0x54, 0xde, 0xef, 0x4b, 0x3a, 0xba, 0xcf, 0x76, 0x71, 0x63, 0x53, 0x42, 0xd5, 0x78, 0xfb, 0x32, 0x18, 0xce, 0x70, 0x27, 0xe1, 0x6e, 0x1e, 0x3c, 0x55, 0x10, 0x11, 0x62, 0xcf, 0xfa, 0x7c, 0x02, 0xb4, 0x37, 0x07, 0x73, 0x50, 0x98, 0x00, 0xf2, 0x22, 0x91, 0x6a, 0x54, 0x79, 0x78, 0x41, 0xd6, 0xcf, 0xc5, 0xb7, 0x00, 0x88, 0x0b, 0xcf, 0xb0, 0x39, 0xfb, 0x00, 0x08, 0x49, 0x41, 0x5f, 0x3f, 0x01, 0x0c, 0xd2, 0xc2, 0xfe, 0xe8, 0x28, 0x59, 0xf3, 0xe8, 0x8c, 0xe9, 0x34, 0x4e, 0x90, 0x48, 0xd2, 0x45, 0xe2, 0xb1, 0xdc, 0x31, 0x06, 0x46, 0x7e, 0xf6, 0xda, 0xc6, 0x9b, 0xa9, 0x7b, 0xfb, 0xd6, 0xf0, 0xef, 0x8e, 0x90, 0x8d, 0xa1, 0x43, 0x18, 0x4b, 0xd1, 0x3a, 0x7d, 0xa1, 0x96, 0x19, 0x34, 0x98, 0xb5, 0xcf, 0x50, 0x0c, 0x96, 0x5b, 0xe3, 0xba, 0x60, 0x75, 0xac, 0x39, 0x79, 0x00, 0xcc, 0x77, 0x7c, 0x7f, 0xb5, 0x43, 0x4f, 0x27, 0x2e, 0x17, 0xdb, 0xf6, 0x2f, 0xcb, 0xe2, 0x1e, 0x39, 0x14, 0x18, 0x24, 0x87, 0x11, 0x8c, 0x5f, 0x82, 0xe0, 0xbc, 0x49, 0xed, 0x36, 0xea, 0xd9 },
|
||||
{ 0x02, 0xba, 0x32, 0x18, 0xa3, 0xd4, 0xd6, 0x53, 0xcc, 0x8a, 0xb6, 0x1d, 0x4b, 0xea, 0x1f, 0xc9, 0xfd, 0x08, 0xa5, 0x1b, 0x5f, 0xb1, 0x93, 0xba, 0xa8, 0x3d, 0x37, 0x81, 0x16, 0x20, 0x5d, 0x52, 0xb9, 0x02, 0x22, 0xd4, 0x83, 0xee, 0x97, 0x61, 0x5a, 0x68, 0x49, 0x5e, 0x87, 0xaa, 0x1a, 0xad, 0x0d, 0x42, 0x38, 0x8f, 0x6f, 0xd6, 0x93, 0x24, 0xca, 0x13, 0x3a, 0x0b, 0x8f, 0x38, 0xbd, 0x7b, 0xb0, 0x37, 0x71, 0x7d, 0xe1, 0xc6, 0xd8, 0xf7, 0x14, 0x89, 0x65, 0x7c, 0xa4, 0xab, 0x22, 0x6b, 0xfe, 0x00, 0x72, 0x39, 0x03, 0xbf, 0xbc, 0x17, 0x3f, 0x53, 0x06, 0x1a, 0xae, 0x44, 0xba, 0x0d, 0x10, 0xa4, 0x1a, 0x13, 0xf1, 0xcc, 0x25, 0xa6, 0x1a, 0xf0, 0x53, 0xc4, 0x29, 0x66, 0xf9, 0x7f, 0x3e, 0xc6, 0x88, 0x32, 0xac, 0xd5, 0xe8, 0x28, 0x06, 0x47, 0xf1, 0x04, 0x43, 0xae, 0xdb, 0x90, 0x00, 0x3a, 0x03, 0x97, 0x21, 0xcb, 0xf9, 0xbe, 0xde, 0xbf, 0x1b, 0xd5, 0x53, 0x0a, 0x04, 0x8d, 0x9d, 0x5b, 0x08, 0xf4, 0x6b, 0xb6, 0x1e, 0x6e, 0x7f, 0xf6, 0xc9, 0x96, 0x12, 0x9b, 0x14, 0x9e, 0xf3, 0xa0, 0x2d, 0x10, 0x95, 0x16, 0x68, 0xd3, 0x2a, 0xa7, 0x04, 0xcf, 0xf5, 0x60, 0xb9, 0x10, 0x40, 0xc7, 0x67, 0xdd, 0x3d, 0x36, 0x9d, 0x47, 0x18, 0x2e, 0x39, 0xe8, 0xc1, 0x1b, 0x38, 0xb3, 0xc6, 0x86, 0x04, 0x68, 0x83, 0x1f, 0xeb, 0x67, 0x8c, 0xff, 0xca, 0x77, 0x53, 0x51, 0x62, 0x4e, 0x9e, 0x9f, 0x3b, 0x88, 0xe0, 0x51, 0x94, 0xd8, 0x0b, 0xf8, 0x47, 0xe3, 0xe8, 0x8b, 0xe8, 0x32, 0xa4, 0x5e, 0xdc, 0x9d, 0x77, 0x5b, 0x9a, 0x7b, 0x71, 0x96, 0xca, 0xb9, 0x2c, 0x3b, 0xff, 0x7b, 0x94, 0x46, 0x24, 0x4a, 0x08, 0x23, 0x2d, 0x32, 0x8f, 0xb9, 0x4c, 0x30, 0x8c, 0x2f, 0xea, 0x3b, 0x47, 0xf9, 0xc6 },
|
||||
{ 0x03, 0x58, 0x20, 0x38, 0x53, 0xa3, 0x8b, 0x1c, 0xa3, 0x49, 0x5f, 0x78, 0xfb, 0x4a, 0xcb, 0x67, 0x95, 0x30, 0xa5, 0xe6, 0xe9, 0x12, 0xfc, 0x6f, 0x49, 0x7e, 0x4f, 0x6c, 0x9d, 0x29, 0xf3, 0x1a, 0x5e, 0x03, 0xf4, 0xb1, 0x99, 0xf5, 0x2a, 0x56, 0x5b, 0x7e, 0x06, 0xc8, 0x5b, 0x4c, 0xd9, 0xc4, 0x8f, 0x14, 0xa0, 0x22, 0xbd, 0x95, 0x33, 0x6a, 0x8d, 0xa0, 0xf5, 0x53, 0x5c, 0x62, 0xd6, 0x1d, 0x24, 0x2f, 0x3e, 0xea, 0x96, 0xeb, 0xd9, 0xb0, 0x64, 0x21, 0x6a, 0x1b, 0x3d, 0x4d, 0x34, 0xc0, 0x20, 0xc8, 0x5f, 0x03, 0xf2, 0xe9, 0x3d, 0x13, 0x6d, 0x74, 0x97, 0xe8, 0x26, 0xf9, 0x0c, 0xef, 0x4e, 0xfe, 0xd3, 0x68, 0x5f, 0x01, 0x91, 0x0a, 0x1c, 0x72, 0x4f, 0xbc, 0x97, 0xfc, 0x66, 0x8d, 0x76, 0x62, 0xde, 0x33, 0xdb, 0x70, 0x58, 0x2f, 0x73, 0xd3, 0xc1, 0x19, 0xe1, 0x98, 0xe0, 0x6b, 0x3a, 0x4d, 0x02, 0x12, 0xab, 0xc1, 0x3e, 0x84, 0x05, 0xa3, 0x3f, 0xcb, 0x4c, 0x43, 0x77, 0x43, 0xf8, 0x65, 0x20, 0x37, 0xf1, 0x4b, 0x67, 0x0e, 0x8d, 0x57, 0x42, 0xea, 0x26, 0x33, 0xa6, 0xec, 0x5e, 0x42, 0x37, 0x57, 0x28, 0x52, 0x4e, 0xb1, 0x88, 0xcb, 0xa5, 0xc5, 0xda, 0x24, 0x60, 0x44, 0x7a, 0xa8, 0x1b, 0xc7, 0x3f, 0x6b, 0x53, 0x2e, 0x75, 0xc9, 0xf6, 0xd7, 0x54, 0x9b, 0x7f, 0xdc, 0xe9, 0xee, 0x7f, 0x04, 0xae, 0xb4, 0x62, 0xdd, 0x76, 0x6c, 0x4f, 0x09, 0xaf, 0xa9, 0x8c, 0x91, 0x63, 0x49, 0x4f, 0x3c, 0x97, 0x4a, 0xa6, 0x8c, 0xb7, 0x8a, 0xf3, 0x0b, 0x09, 0xe7, 0xc5, 0x09, 0x93, 0x38, 0x81, 0x2e, 0x5e, 0xa8, 0x9d, 0xeb, 0xc5, 0xfd, 0xf2, 0xfc, 0xae, 0x0c, 0x3a, 0xbf, 0x94, 0x6f, 0x3e, 0xce, 0xd5, 0x8a, 0xa4, 0xf4, 0xfa, 0x39, 0x4a, 0x92, 0xa2, 0xe1, 0xe7, 0x83, 0x9f, 0xd2, 0xc8 },
|
||||
};
|
||||
static const unsigned char vec_enc_cmsg[423] = { 0x03, 0xec, 0x16, 0x3c, 0xbf, 0xfc, 0x00, 0x8b, 0xf2, 0x5b, 0x99, 0x89, 0x8f, 0x5c, 0x4c, 0x0b, 0x5b, 0x00, 0xf3, 0xeb, 0xf8, 0xb2, 0xde, 0x73, 0x0d, 0x78, 0xdb, 0xef, 0xcb, 0xad, 0x01, 0xf9, 0x12, 0x02, 0xba, 0x32, 0x18, 0xa3, 0xd4, 0xd6, 0x53, 0xcc, 0x8a, 0xb6, 0x1d, 0x4b, 0xea, 0x1f, 0xc9, 0xfd, 0x08, 0xa5, 0x1b, 0x5f, 0xb1, 0x93, 0xba, 0xa8, 0x3d, 0x37, 0x81, 0x16, 0x20, 0x5d, 0x52, 0xb9, 0x03, 0x58, 0x20, 0x38, 0x53, 0xa3, 0x8b, 0x1c, 0xa3, 0x49, 0x5f, 0x78, 0xfb, 0x4a, 0xcb, 0x67, 0x95, 0x30, 0xa5, 0xe6, 0xe9, 0x12, 0xfc, 0x6f, 0x49, 0x7e, 0x4f, 0x6c, 0x9d, 0x29, 0xf3, 0x1a, 0x5e, 0x03, 0x14, 0x72, 0x50, 0xbc, 0x22, 0x95, 0xb2, 0x46, 0x18, 0x25, 0x31, 0x7a, 0x10, 0x01, 0x12, 0x09, 0x32, 0xf4, 0xea, 0x0c, 0x8a, 0xaa, 0xba, 0xc3, 0x24, 0xa4, 0x35, 0x5f, 0x6e, 0xf2, 0x85, 0xb6, 0xc0, 0x01, 0xd9, 0x1f, 0x98, 0x64, 0x8c, 0xa5, 0x81, 0xe0, 0x48, 0xef, 0x5b, 0xb8, 0xaa, 0x8f, 0x17, 0xe7, 0x05, 0xc8, 0x78, 0x4b, 0xaa, 0xe1, 0xbe, 0xc1, 0x2e, 0x9f, 0xc8, 0x16, 0x79, 0x1d, 0x2e, 0x54, 0xde, 0xef, 0x4b, 0x3a, 0xba, 0xcf, 0x76, 0x71, 0x63, 0x53, 0x42, 0xd5, 0x78, 0xfb, 0x32, 0x18, 0xce, 0x70, 0x27, 0xe1, 0x6e, 0x1e, 0x3c, 0x55, 0x10, 0x11, 0x62, 0xcf, 0xfa, 0x7c, 0x71, 0x7d, 0xe1, 0xc6, 0xd8, 0xf7, 0x14, 0x89, 0x65, 0x7c, 0xa4, 0xab, 0x22, 0x6b, 0xfe, 0x00, 0x72, 0x39, 0x03, 0xbf, 0xbc, 0x17, 0x3f, 0x53, 0x06, 0x1a, 0xae, 0x44, 0xba, 0x0d, 0x10, 0xa4, 0x1a, 0x13, 0xf1, 0xcc, 0x25, 0xa6, 0x1a, 0xf0, 0x53, 0xc4, 0x29, 0x66, 0xf9, 0x7f, 0x3e, 0xc6, 0x88, 0x32, 0xac, 0xd5, 0xe8, 0x28, 0x06, 0x47, 0xf1, 0x04, 0x43, 0xae, 0xdb, 0x90, 0x00, 0x3a, 0x3e, 0xea, 0x96, 0xeb, 0xd9, 0xb0, 0x64, 0x21, 0x6a, 0x1b, 0x3d, 0x4d, 0x34, 0xc0, 0x20, 0xc8, 0x5f, 0x03, 0xf2, 0xe9, 0x3d, 0x13, 0x6d, 0x74, 0x97, 0xe8, 0x26, 0xf9, 0x0c, 0xef, 0x4e, 0xfe, 0xd3, 0x68, 0x5f, 0x01, 0x91, 0x0a, 0x1c, 0x72, 0x4f, 0xbc, 0x97, 0xfc, 0x66, 0x8d, 0x76, 0x62, 0xde, 0x33, 0xdb, 0x70, 0x58, 0x2f, 0x73, 0xd3, 0xc1, 0x19, 0xe1, 0x98, 0xe0, 0x6b, 0x3a, 0x4d, 0x02, 0xb4, 0x37, 0x07, 0x73, 0x50, 0x98, 0x00, 0xf2, 0x22, 0x91, 0x6a, 0x54, 0x79, 0x78, 0x41, 0xd6, 0xcf, 0xc5, 0xb7, 0x00, 0x88, 0x0b, 0xcf, 0xb0, 0x39, 0xfb, 0x00, 0x08, 0x49, 0x41, 0x5f, 0x3f, 0x03, 0x97, 0x21, 0xcb, 0xf9, 0xbe, 0xde, 0xbf, 0x1b, 0xd5, 0x53, 0x0a, 0x04, 0x8d, 0x9d, 0x5b, 0x08, 0xf4, 0x6b, 0xb6, 0x1e, 0x6e, 0x7f, 0xf6, 0xc9, 0x96, 0x12, 0x9b, 0x14, 0x9e, 0xf3, 0xa0, 0x2d, 0x02, 0x12, 0xab, 0xc1, 0x3e, 0x84, 0x05, 0xa3, 0x3f, 0xcb, 0x4c, 0x43, 0x77, 0x43, 0xf8, 0x65, 0x20, 0x37, 0xf1, 0x4b, 0x67, 0x0e, 0x8d, 0x57, 0x42, 0xea, 0x26, 0x33, 0xa6, 0xec, 0x5e, 0x42, 0x37 };
|
||||
static const unsigned char vec_enc_secshares[3][32] = {
|
||||
{ 0x68, 0xca, 0x3b, 0x7a, 0x83, 0x9b, 0x9b, 0x04, 0x89, 0xb8, 0x12, 0x02, 0x89, 0x09, 0xff, 0xcc, 0x76, 0xc2, 0x84, 0xa2, 0x51, 0xbe, 0xfe, 0x77, 0x3f, 0x0c, 0x91, 0x7f, 0x2c, 0x59, 0xf0, 0x7e },
|
||||
{ 0x44, 0x22, 0xc3, 0xdc, 0xd5, 0x91, 0x0d, 0x5c, 0x99, 0x4e, 0xcc, 0x29, 0x5d, 0xa3, 0x7e, 0xa5, 0x3f, 0x61, 0x75, 0x24, 0x05, 0x87, 0x79, 0x5b, 0x12, 0xda, 0x75, 0x96, 0x18, 0x3a, 0xcf, 0x1c },
|
||||
{ 0x98, 0x4d, 0x80, 0xb8, 0x1c, 0x7a, 0xe3, 0xe4, 0xe3, 0xf2, 0x24, 0x30, 0x6a, 0xf4, 0x97, 0x82, 0x97, 0x42, 0xe9, 0x0f, 0xff, 0x52, 0xde, 0xba, 0x86, 0x3d, 0x6f, 0x8e, 0xdb, 0xe8, 0x76, 0x26 },
|
||||
};
|
||||
static const unsigned char vec_enc_eq_input[268] = { 0x00, 0x00, 0x00, 0x02, 0x02, 0x4a, 0x73, 0xaa, 0xd2, 0xf5, 0x00, 0xc7, 0xca, 0x28, 0x24, 0x5e, 0xfa, 0xd5, 0x55, 0x93, 0x67, 0xcf, 0xfb, 0xaa, 0x01, 0x19, 0x31, 0xa6, 0x9c, 0xe4, 0x11, 0xb3, 0x8e, 0xa7, 0x3d, 0x3f, 0x52, 0x03, 0x14, 0x72, 0x50, 0xbc, 0x22, 0x95, 0xb2, 0x46, 0x18, 0x25, 0x31, 0x7a, 0x10, 0x01, 0x12, 0x09, 0x32, 0xf4, 0xea, 0x0c, 0x8a, 0xaa, 0xba, 0xc3, 0x24, 0xa4, 0x35, 0x5f, 0x6e, 0xf2, 0x85, 0xb6, 0x03, 0x30, 0x45, 0x46, 0x1f, 0xd4, 0xb4, 0xe8, 0xbc, 0xd2, 0x88, 0x8b, 0xc0, 0x5d, 0x2f, 0x8c, 0x86, 0x10, 0x53, 0x43, 0x10, 0x2e, 0x42, 0x5f, 0x18, 0xae, 0x64, 0xe0, 0x03, 0x2a, 0xba, 0xe1, 0xe3, 0x03, 0x5c, 0x1f, 0xe2, 0x1b, 0xce, 0x62, 0x99, 0x2a, 0xe0, 0x66, 0x67, 0x7e, 0xc0, 0x4f, 0x68, 0xfc, 0x1b, 0x25, 0x79, 0x5f, 0x1a, 0x33, 0x62, 0x9a, 0xfb, 0x00, 0x24, 0x90, 0x60, 0x02, 0x85, 0x37, 0x02, 0x19, 0xd6, 0xb1, 0x40, 0xab, 0x84, 0xa2, 0x5a, 0x49, 0x38, 0xcd, 0x62, 0xb2, 0x63, 0xd1, 0xd9, 0x85, 0x5e, 0xa4, 0x1e, 0x1e, 0xbc, 0x19, 0x56, 0x85, 0x47, 0x7f, 0xed, 0xd6, 0xd6, 0xa1, 0x38, 0x02, 0xb4, 0x37, 0x07, 0x73, 0x50, 0x98, 0x00, 0xf2, 0x22, 0x91, 0x6a, 0x54, 0x79, 0x78, 0x41, 0xd6, 0xcf, 0xc5, 0xb7, 0x00, 0x88, 0x0b, 0xcf, 0xb0, 0x39, 0xfb, 0x00, 0x08, 0x49, 0x41, 0x5f, 0x3f, 0x03, 0x97, 0x21, 0xcb, 0xf9, 0xbe, 0xde, 0xbf, 0x1b, 0xd5, 0x53, 0x0a, 0x04, 0x8d, 0x9d, 0x5b, 0x08, 0xf4, 0x6b, 0xb6, 0x1e, 0x6e, 0x7f, 0xf6, 0xc9, 0x96, 0x12, 0x9b, 0x14, 0x9e, 0xf3, 0xa0, 0x2d, 0x02, 0x12, 0xab, 0xc1, 0x3e, 0x84, 0x05, 0xa3, 0x3f, 0xcb, 0x4c, 0x43, 0x77, 0x43, 0xf8, 0x65, 0x20, 0x37, 0xf1, 0x4b, 0x67, 0x0e, 0x8d, 0x57, 0x42, 0xea, 0x26, 0x33, 0xa6, 0xec, 0x5e, 0x42, 0x37 };
|
||||
static const unsigned char vec_enc_out_secshares[3][32] = {
|
||||
{ 0xbf, 0x52, 0xb6, 0x81, 0xfb, 0xea, 0x1b, 0x4a, 0xde, 0x2d, 0xe5, 0x45, 0xae, 0x80, 0xf8, 0x79, 0x5a, 0x86, 0x65, 0x85, 0xe2, 0x54, 0xaa, 0x25, 0xf6, 0xf0, 0x38, 0x80, 0x71, 0x82, 0x83, 0x11 },
|
||||
{ 0x7d, 0x86, 0xbe, 0x5d, 0x04, 0x99, 0xac, 0x5a, 0x02, 0x18, 0x6c, 0xef, 0xf3, 0x26, 0x2f, 0xef, 0x95, 0x8e, 0x71, 0x43, 0xb6, 0xf0, 0x48, 0xa0, 0xc6, 0x13, 0x77, 0x3b, 0xb1, 0x8d, 0xc8, 0xae },
|
||||
{ 0x3b, 0xba, 0xc6, 0x38, 0x0d, 0x49, 0x3d, 0x69, 0x26, 0x02, 0xf4, 0x9a, 0x37, 0xcb, 0x67, 0x65, 0xd0, 0x96, 0x7d, 0x01, 0x8b, 0x8b, 0xe7, 0x1b, 0x95, 0x36, 0xb5, 0xf6, 0xf1, 0x99, 0x0e, 0x4b },
|
||||
};
|
||||
static const unsigned char vec_enc_thresh_pk[33] = { 0x03, 0xba, 0x4f, 0x2c, 0x1a, 0x9d, 0x2c, 0xf5, 0x36, 0x9d, 0x7b, 0xd4, 0xff, 0x32, 0x8c, 0x76, 0x92, 0xce, 0x87, 0x32, 0x9e, 0x88, 0x00, 0x05, 0x7b, 0x31, 0xf7, 0x09, 0xd0, 0xa8, 0x88, 0x48, 0x22 };
|
||||
static const unsigned char vec_enc_pubshares[3][33] = {
|
||||
{ 0x03, 0xa9, 0x45, 0xce, 0x22, 0xcd, 0x1c, 0x4d, 0x2c, 0x67, 0x24, 0xdb, 0xc1, 0x76, 0x77, 0xe8, 0xd7, 0x38, 0x8b, 0x6f, 0x7c, 0x74, 0x2f, 0xa1, 0x5a, 0x15, 0x76, 0x82, 0xa4, 0x9f, 0xca, 0x56, 0x45 },
|
||||
{ 0x02, 0xf4, 0x8a, 0xc7, 0x32, 0x0e, 0xb3, 0x40, 0x52, 0x79, 0xa8, 0x63, 0xdf, 0x81, 0xb2, 0x6c, 0x44, 0xe9, 0x5b, 0x0c, 0x1f, 0x7d, 0xe2, 0x8c, 0x7a, 0x68, 0xa8, 0xa8, 0x01, 0x7f, 0x6c, 0xee, 0xf3 },
|
||||
{ 0x03, 0x2b, 0xf1, 0xf8, 0xdf, 0x4a, 0x28, 0x18, 0xe5, 0xbf, 0xde, 0x30, 0xbe, 0xb0, 0xa9, 0x2e, 0x2e, 0xa2, 0xb0, 0x79, 0x92, 0xab, 0xeb, 0xd5, 0x14, 0xdd, 0x54, 0x44, 0x2e, 0xb7, 0x12, 0xd8, 0xb9 },
|
||||
};
|
||||
/* encpedpop n = 3, t = 2 */
|
||||
/* all python-side sanity checks passed */
|
||||
|
||||
/* The group order n and (2^256 - 1) mod n, for scalar parsing edge cases. */
|
||||
static const unsigned char vec_scalar_order_n[32] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
@@ -513,6 +601,363 @@ static void chilldkg_vss_test(void) {
|
||||
secp256k1_scalar_clear(&tweak);
|
||||
}
|
||||
|
||||
static void chilldkg_simplpedpop_test(void) {
|
||||
const uint32_t n = 3, t = 2;
|
||||
const size_t pmsg_len = 33 * 2 + 64;
|
||||
const size_t cmsg_len = 97 * 3 + 33 * 1;
|
||||
const size_t eq_len = 4 + 33 * 2;
|
||||
secp256k1_chilldkg_simplpedpop_participant_state states[3];
|
||||
secp256k1_scalar shares[3][3]; /* shares[dealer][recipient] */
|
||||
secp256k1_scalar partials[3];
|
||||
secp256k1_scalar secshare, secshare_tweaked;
|
||||
secp256k1_ge pubshare;
|
||||
unsigned char pmsgs[3][130];
|
||||
const unsigned char *pmsg_ptrs[3];
|
||||
unsigned char cmsg[324];
|
||||
unsigned char cmsg_bad[324];
|
||||
unsigned char eq_input[70];
|
||||
unsigned char buf32[32];
|
||||
secp256k1_chilldkg_simplpedpop_dkg_output dkg_outputs[3];
|
||||
secp256k1_chilldkg_simplpedpop_dkg_output coord_dkg;
|
||||
secp256k1_chilldkg_fault fault;
|
||||
uint32_t fault_index = 0;
|
||||
uint32_t i, j;
|
||||
|
||||
/* participant_step1: messages are byte-exact against the reference. */
|
||||
for (i = 0; i < n; i++) {
|
||||
CHECK(secp256k1_chilldkg_simplpedpop_participant_step1(CTX, &states[i], pmsgs[i], shares[i], vec_simpl_seeds[i], t, n, i, vec_simpl_auxs[i]) == 1);
|
||||
CHECK(secp256k1_memcmp_var(pmsgs[i], vec_simpl_pmsgs[i], pmsg_len) == 0);
|
||||
pmsg_ptrs[i] = pmsgs[i];
|
||||
}
|
||||
/* Invalid inputs are rejected: participant_id >= n, t > n, t == 0, n
|
||||
* exceeding the participant cap. */
|
||||
CHECK(secp256k1_chilldkg_simplpedpop_participant_step1(CTX, &states[0], pmsgs[0], shares[0], vec_simpl_seeds[0], t, n, n, vec_simpl_auxs[0]) == 0);
|
||||
CHECK(secp256k1_chilldkg_simplpedpop_participant_step1(CTX, &states[0], pmsgs[0], shares[0], vec_simpl_seeds[0], n + 1, n, 0, vec_simpl_auxs[0]) == 0);
|
||||
CHECK(secp256k1_chilldkg_simplpedpop_participant_step1(CTX, &states[0], pmsgs[0], shares[0], vec_simpl_seeds[0], 0, n, 0, vec_simpl_auxs[0]) == 0);
|
||||
CHECK(secp256k1_chilldkg_simplpedpop_participant_step1(CTX, &states[0], pmsgs[0], shares[0], vec_simpl_seeds[0], t, SECP256K1_CHILLDKG_MAX_PARTICIPANTS + 1, 0, vec_simpl_auxs[0]) == 0);
|
||||
|
||||
/* coordinator_step: cmsg, eq_input and the DKG output are byte-exact. */
|
||||
fault = secp256k1_chilldkg_simplpedpop_coordinator_step(CTX, cmsg, &coord_dkg, eq_input, &fault_index, pmsg_ptrs, t, n);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_SUCCESS);
|
||||
CHECK(secp256k1_memcmp_var(cmsg, vec_simpl_cmsg, cmsg_len) == 0);
|
||||
CHECK(secp256k1_memcmp_var(eq_input, vec_simpl_eq_input, eq_len) == 0);
|
||||
CHECK(secp256k1_memcmp_var(coord_dkg.thresh_pk33, vec_simpl_thresh_pk, 33) == 0);
|
||||
for (j = 0; j < 32; j++) {
|
||||
CHECK(coord_dkg.secshare32[j] == 0);
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
CHECK(secp256k1_memcmp_var(coord_dkg.pubshares33[i], vec_simpl_pubshares[i], 33) == 0);
|
||||
}
|
||||
|
||||
/* participant_step2 for all participants (happy path). */
|
||||
for (i = 0; i < n; i++) {
|
||||
unsigned char eq_input_p[70];
|
||||
for (j = 0; j < n; j++) {
|
||||
partials[j] = shares[j][i];
|
||||
}
|
||||
secp256k1_chilldkg_simplpedpop_participant_step2_prepare_secshare(&secshare, partials, n);
|
||||
secp256k1_scalar_get_b32(buf32, &secshare);
|
||||
CHECK(secp256k1_memcmp_var(buf32, vec_simpl_untweaked_secshares[i], 32) == 0);
|
||||
fault = secp256k1_chilldkg_simplpedpop_participant_step2(CTX, &dkg_outputs[i], eq_input_p, &fault_index, &states[i], cmsg, cmsg_len, &secshare);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_SUCCESS);
|
||||
CHECK(secp256k1_memcmp_var(eq_input_p, vec_simpl_eq_input, eq_len) == 0);
|
||||
CHECK(secp256k1_memcmp_var(dkg_outputs[i].secshare32, vec_simpl_secshares[i], 32) == 0);
|
||||
CHECK(secp256k1_memcmp_var(dkg_outputs[i].thresh_pk33, vec_simpl_thresh_pk, 33) == 0);
|
||||
for (j = 0; j < n; j++) {
|
||||
CHECK(secp256k1_memcmp_var(dkg_outputs[i].pubshares33[j], vec_simpl_pubshares[j], 33) == 0);
|
||||
}
|
||||
/* The tweaked secshare verifies against the tweaked own pubshare. */
|
||||
secp256k1_scalar_set_b32(&secshare_tweaked, dkg_outputs[i].secshare32, NULL);
|
||||
CHECK(secp256k1_chilldkg_point_load(&pubshare, dkg_outputs[i].pubshares33[i]) == 1);
|
||||
CHECK(secp256k1_chilldkg_vss_verify_secshare(CTX, &secshare_tweaked, &pubshare) == 1);
|
||||
}
|
||||
|
||||
/* Fault cases (participant 0's view; the untweaked secshare of
|
||||
* participant 0 is still in `secshare`). */
|
||||
for (j = 0; j < n; j++) {
|
||||
partials[j] = shares[j][0];
|
||||
}
|
||||
secp256k1_chilldkg_simplpedpop_participant_step2_prepare_secshare(&secshare, partials, n);
|
||||
|
||||
/* The coordinator echoes a wrong commitment to our secret. */
|
||||
memcpy(cmsg_bad, cmsg, cmsg_len);
|
||||
{
|
||||
unsigned char swap[33];
|
||||
memcpy(swap, cmsg_bad, 33);
|
||||
memcpy(cmsg_bad, cmsg_bad + 33, 33);
|
||||
memcpy(cmsg_bad + 33, swap, 33);
|
||||
}
|
||||
fault = secp256k1_chilldkg_simplpedpop_participant_step2(CTX, &dkg_outputs[0], eq_input, &fault_index, &states[0], cmsg_bad, cmsg_len, &secshare);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_FAULTY_COORDINATOR);
|
||||
|
||||
/* A tampered pop blames the corresponding participant (or the
|
||||
* coordinator). */
|
||||
memcpy(cmsg_bad, cmsg, cmsg_len);
|
||||
cmsg_bad[33 * 3 + 33 * 1 + 64 * 1] ^= 1;
|
||||
fault_index = 0;
|
||||
fault = secp256k1_chilldkg_simplpedpop_participant_step2(CTX, &dkg_outputs[0], eq_input, &fault_index, &states[0], cmsg_bad, cmsg_len, &secshare);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_FAULTY_PARTICIPANT_OR_COORDINATOR);
|
||||
CHECK(fault_index == 1);
|
||||
|
||||
/* A pop valid for participant 2 fails at the position of participant 1
|
||||
* (wrong signer for this index). */
|
||||
memcpy(cmsg_bad, cmsg, cmsg_len);
|
||||
{
|
||||
unsigned char swap[64];
|
||||
memcpy(swap, cmsg_bad + 33 * 3 + 33 + 64, 64);
|
||||
memcpy(cmsg_bad + 33 * 3 + 33 + 64, cmsg_bad + 33 * 3 + 33 + 2 * 64, 64);
|
||||
memcpy(cmsg_bad + 33 * 3 + 33 + 2 * 64, swap, 64);
|
||||
}
|
||||
fault_index = 0;
|
||||
fault = secp256k1_chilldkg_simplpedpop_participant_step2(CTX, &dkg_outputs[0], eq_input, &fault_index, &states[0], cmsg_bad, cmsg_len, &secshare);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_FAULTY_PARTICIPANT_OR_COORDINATOR);
|
||||
CHECK(fault_index == 1);
|
||||
|
||||
/* A point at infinity as commitment to the secret of participant 2. */
|
||||
memcpy(cmsg_bad, cmsg, cmsg_len);
|
||||
memset(cmsg_bad + 33 * 2, 0, 33);
|
||||
fault_index = 0;
|
||||
fault = secp256k1_chilldkg_simplpedpop_participant_step2(CTX, &dkg_outputs[0], eq_input, &fault_index, &states[0], cmsg_bad, cmsg_len, &secshare);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_FAULTY_PARTICIPANT_OR_COORDINATOR);
|
||||
CHECK(fault_index == 2);
|
||||
|
||||
/* A tampered sum of the commitments to the non-constant terms (flipping
|
||||
* the prefix byte negates the point, which stays valid) makes the
|
||||
* secshare verification fail: the fault cannot be attributed without the
|
||||
* investigation procedure. */
|
||||
memcpy(cmsg_bad, cmsg, cmsg_len);
|
||||
cmsg_bad[33 * 3] ^= 1;
|
||||
fault_index = 0;
|
||||
fault = secp256k1_chilldkg_simplpedpop_participant_step2(CTX, &dkg_outputs[0], eq_input, &fault_index, &states[0], cmsg_bad, cmsg_len, &secshare);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_UNKNOWN_FAULTY_PARTICIPANT_OR_COORDINATOR);
|
||||
CHECK(fault_index == UINT32_MAX);
|
||||
|
||||
/* A malformed cmsg (wrong length, invalid point) blames the coordinator. */
|
||||
fault = secp256k1_chilldkg_simplpedpop_participant_step2(CTX, &dkg_outputs[0], eq_input, &fault_index, &states[0], cmsg, cmsg_len - 1, &secshare);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_FAULTY_COORDINATOR);
|
||||
memcpy(cmsg_bad, cmsg, cmsg_len);
|
||||
cmsg_bad[0] = 0x04;
|
||||
fault = secp256k1_chilldkg_simplpedpop_participant_step2(CTX, &dkg_outputs[0], eq_input, &fault_index, &states[0], cmsg_bad, cmsg_len, &secshare);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_FAULTY_COORDINATOR);
|
||||
|
||||
/* The coordinator blames the sender of a malformed participant message. */
|
||||
{
|
||||
unsigned char pmsg_bad[130];
|
||||
const unsigned char *pmsg_bad_ptrs[3];
|
||||
pmsg_bad_ptrs[0] = pmsg_ptrs[0];
|
||||
pmsg_bad_ptrs[1] = pmsg_bad;
|
||||
pmsg_bad_ptrs[2] = pmsg_ptrs[2];
|
||||
memcpy(pmsg_bad, pmsgs[1], pmsg_len);
|
||||
pmsg_bad[0] = 0x04; /* invalid point in the commitment */
|
||||
fault_index = 0;
|
||||
fault = secp256k1_chilldkg_simplpedpop_coordinator_step(CTX, cmsg_bad, &coord_dkg, eq_input, &fault_index, pmsg_bad_ptrs, t, n);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_FAULTY_PARTICIPANT);
|
||||
CHECK(fault_index == 1);
|
||||
/* Invalid session parameters are input errors. */
|
||||
fault = secp256k1_chilldkg_simplpedpop_coordinator_step(CTX, cmsg_bad, &coord_dkg, eq_input, &fault_index, pmsg_ptrs, n + 1, n);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_INVALID_INPUT);
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
for (j = 0; j < n; j++) {
|
||||
secp256k1_scalar_clear(&shares[i][j]);
|
||||
}
|
||||
secp256k1_scalar_clear(&partials[i]);
|
||||
}
|
||||
secp256k1_scalar_clear(&secshare);
|
||||
secp256k1_scalar_clear(&secshare_tweaked);
|
||||
}
|
||||
|
||||
static void chilldkg_encpedpop_test(void) {
|
||||
const uint32_t n = 3, t = 2;
|
||||
const size_t pmsg_len = 33 * 2 + 64 + 33 + 32 * 3;
|
||||
const size_t simpl_cmsg_len = 97 * 3 + 33 * 1;
|
||||
const size_t cmsg_len = simpl_cmsg_len + 33 * 3;
|
||||
const size_t eq_len = 4 + 33 * 2 + 33 * 3 + 33 * 3;
|
||||
secp256k1_chilldkg_encpedpop_participant_state states[3];
|
||||
secp256k1_scalar enc_secshares[3];
|
||||
secp256k1_scalar pads_send[3];
|
||||
secp256k1_scalar pads_recv[3];
|
||||
secp256k1_scalar scalar_tmp, scalar_tmp2;
|
||||
secp256k1_ge pubshare;
|
||||
unsigned char pmsgs[3][259];
|
||||
const unsigned char *pmsg_ptrs[3];
|
||||
unsigned char cmsg[423];
|
||||
unsigned char cmsg_bad[423];
|
||||
unsigned char eq_input[268];
|
||||
unsigned char enc_context[4 + 33 * 3];
|
||||
unsigned char buf32[32];
|
||||
secp256k1_chilldkg_simplpedpop_dkg_output dkg_output;
|
||||
secp256k1_chilldkg_simplpedpop_dkg_output coord_dkg;
|
||||
secp256k1_chilldkg_fault fault;
|
||||
uint32_t fault_index = 0;
|
||||
uint32_t i, j;
|
||||
int overflow;
|
||||
|
||||
/* serialize_enc_context: u32be(t) || host public keys. */
|
||||
secp256k1_chilldkg_encpedpop_serialize_enc_context(enc_context, t, &vec_enc_hostpubkeys[0][0], n);
|
||||
CHECK(secp256k1_memcmp_var(enc_context, vec_enc_context, sizeof(enc_context)) == 0);
|
||||
|
||||
/* participant_step1: messages (and thus the derivations of simpl_seed,
|
||||
* secnonce, pubnonce, shares and pads) are byte-exact against the
|
||||
* reference. */
|
||||
for (i = 0; i < n; i++) {
|
||||
CHECK(secp256k1_chilldkg_encpedpop_participant_step1(CTX, &states[i], pmsgs[i], vec_enc_hostseckeys[i], vec_enc_hostseckeys[i], &vec_enc_hostpubkeys[0][0], t, i, vec_enc_randoms[i], n) == 1);
|
||||
CHECK(secp256k1_memcmp_var(pmsgs[i], vec_enc_pmsgs[i], pmsg_len) == 0);
|
||||
CHECK(secp256k1_memcmp_var(states[i].pubnonce33, vec_enc_pubnonces[i], 33) == 0);
|
||||
pmsg_ptrs[i] = pmsgs[i];
|
||||
}
|
||||
/* Invalid inputs are rejected. */
|
||||
CHECK(secp256k1_chilldkg_encpedpop_participant_step1(CTX, &states[0], pmsgs[0], vec_enc_hostseckeys[0], vec_enc_hostseckeys[0], &vec_enc_hostpubkeys[0][0], t, n, vec_enc_randoms[0], n) == 0);
|
||||
CHECK(secp256k1_chilldkg_encpedpop_participant_step1(CTX, &states[0], pmsgs[0], vec_enc_hostseckeys[0], vec_enc_hostseckeys[0], &vec_enc_hostpubkeys[0][0], n + 1, 0, vec_enc_randoms[0], n) == 0);
|
||||
|
||||
/* Pad symmetry: the pad computed by sender 0 for recipient i equals the
|
||||
* pad computed by recipient i for sender 0 (for the own index both sides
|
||||
* use the symmetric self pad). */
|
||||
secp256k1_scalar_set_b32(&scalar_tmp, vec_enc_secnonces[0], &overflow);
|
||||
CHECK(!overflow);
|
||||
CHECK(secp256k1_chilldkg_encpedpop_encaps_multi(CTX, pads_send, &scalar_tmp, vec_enc_pubnonces[0], vec_enc_hostseckeys[0], &vec_enc_hostpubkeys[0][0], enc_context, sizeof(enc_context), 0, n) == 1);
|
||||
for (i = 0; i < n; i++) {
|
||||
fault = secp256k1_chilldkg_encpedpop_decaps_multi(CTX, pads_recv, &fault_index, vec_enc_hostseckeys[i], vec_enc_hostpubkeys[i], &vec_enc_pubnonces[0][0], enc_context, sizeof(enc_context), i, n);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_SUCCESS);
|
||||
CHECK(secp256k1_scalar_eq(&pads_send[i], &pads_recv[0]));
|
||||
}
|
||||
/* decaps_multi rejects an invalid own host secret key. */
|
||||
memset(buf32, 0, 32);
|
||||
fault = secp256k1_chilldkg_encpedpop_decaps_multi(CTX, pads_recv, &fault_index, buf32, vec_enc_hostpubkeys[0], &vec_enc_pubnonces[0][0], enc_context, sizeof(enc_context), 0, n);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_INVALID_INPUT);
|
||||
|
||||
/* encrypt -> coordinator sum -> decrypt_sum roundtrip with deterministic
|
||||
* plaintexts (plaintext from sender i to recipient j is 3*i + j + 1). */
|
||||
for (j = 0; j < n; j++) {
|
||||
secp256k1_scalar_set_int(&enc_secshares[j], 0);
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar plaintexts[3];
|
||||
secp256k1_scalar ciphertexts[3];
|
||||
secp256k1_scalar_set_b32(&scalar_tmp, vec_enc_secnonces[i], &overflow);
|
||||
CHECK(!overflow);
|
||||
for (j = 0; j < n; j++) {
|
||||
secp256k1_scalar_set_int(&plaintexts[j], 3 * i + j + 1);
|
||||
}
|
||||
CHECK(secp256k1_chilldkg_encpedpop_encrypt_multi(CTX, ciphertexts, &scalar_tmp, vec_enc_pubnonces[i], vec_enc_hostseckeys[i], &vec_enc_hostpubkeys[0][0], enc_context, sizeof(enc_context), i, plaintexts, n) == 1);
|
||||
for (j = 0; j < n; j++) {
|
||||
secp256k1_scalar_add(&enc_secshares[j], &enc_secshares[j], &ciphertexts[j]);
|
||||
secp256k1_scalar_clear(&plaintexts[j]);
|
||||
secp256k1_scalar_clear(&ciphertexts[j]);
|
||||
}
|
||||
}
|
||||
for (j = 0; j < n; j++) {
|
||||
fault = secp256k1_chilldkg_encpedpop_decrypt_sum(CTX, &scalar_tmp, &fault_index, vec_enc_hostseckeys[j], vec_enc_hostpubkeys[j], &vec_enc_pubnonces[0][0], enc_context, sizeof(enc_context), j, &enc_secshares[j], n);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_SUCCESS);
|
||||
secp256k1_scalar_set_int(&scalar_tmp2, 0);
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar p;
|
||||
secp256k1_scalar_set_int(&p, 3 * i + j + 1);
|
||||
secp256k1_scalar_add(&scalar_tmp2, &scalar_tmp2, &p);
|
||||
}
|
||||
CHECK(secp256k1_scalar_eq(&scalar_tmp, &scalar_tmp2));
|
||||
}
|
||||
|
||||
/* coordinator_step: cmsg, eq_input, summed encrypted shares and the DKG
|
||||
* output are byte-exact. */
|
||||
fault = secp256k1_chilldkg_encpedpop_coordinator_step(CTX, cmsg, &coord_dkg, eq_input, enc_secshares, &fault_index, pmsg_ptrs, t, &vec_enc_hostpubkeys[0][0], n);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_SUCCESS);
|
||||
CHECK(secp256k1_memcmp_var(cmsg, vec_enc_cmsg, cmsg_len) == 0);
|
||||
CHECK(secp256k1_memcmp_var(eq_input, vec_enc_eq_input, eq_len) == 0);
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar_get_b32(buf32, &enc_secshares[i]);
|
||||
CHECK(secp256k1_memcmp_var(buf32, vec_enc_secshares[i], 32) == 0);
|
||||
CHECK(secp256k1_memcmp_var(coord_dkg.pubshares33[i], vec_enc_pubshares[i], 33) == 0);
|
||||
}
|
||||
CHECK(secp256k1_memcmp_var(coord_dkg.thresh_pk33, vec_enc_thresh_pk, 33) == 0);
|
||||
|
||||
/* participant_step2 for all participants (happy path): the decrypted
|
||||
* (tweaked) secshare matches the pubshare, and all outputs are
|
||||
* byte-exact. */
|
||||
for (i = 0; i < n; i++) {
|
||||
unsigned char eq_input_p[268];
|
||||
fault = secp256k1_chilldkg_encpedpop_participant_step2(CTX, &dkg_output, eq_input_p, &fault_index, &states[i], vec_enc_hostseckeys[i], cmsg, cmsg_len, &enc_secshares[i]);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_SUCCESS);
|
||||
CHECK(secp256k1_memcmp_var(eq_input_p, vec_enc_eq_input, eq_len) == 0);
|
||||
CHECK(secp256k1_memcmp_var(dkg_output.secshare32, vec_enc_out_secshares[i], 32) == 0);
|
||||
CHECK(secp256k1_memcmp_var(dkg_output.thresh_pk33, vec_enc_thresh_pk, 33) == 0);
|
||||
for (j = 0; j < n; j++) {
|
||||
CHECK(secp256k1_memcmp_var(dkg_output.pubshares33[j], vec_enc_pubshares[j], 33) == 0);
|
||||
}
|
||||
secp256k1_scalar_set_b32(&scalar_tmp, dkg_output.secshare32, NULL);
|
||||
CHECK(secp256k1_chilldkg_point_load(&pubshare, dkg_output.pubshares33[i]) == 1);
|
||||
CHECK(secp256k1_chilldkg_vss_verify_secshare(CTX, &scalar_tmp, &pubshare) == 1);
|
||||
}
|
||||
|
||||
/* Fault cases (participant 0's view). */
|
||||
|
||||
/* The coordinator echoes a wrong pubnonce for us. */
|
||||
memcpy(cmsg_bad, cmsg, cmsg_len);
|
||||
cmsg_bad[simpl_cmsg_len] ^= 1;
|
||||
fault = secp256k1_chilldkg_encpedpop_participant_step2(CTX, &dkg_output, eq_input, &fault_index, &states[0], vec_enc_hostseckeys[0], cmsg_bad, cmsg_len, &enc_secshares[0]);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_FAULTY_COORDINATOR);
|
||||
|
||||
/* An invalid pubnonce of sender 1 (bad encoding, or the infinity
|
||||
* encoding) blames the sender or the coordinator. */
|
||||
memcpy(cmsg_bad, cmsg, cmsg_len);
|
||||
memset(cmsg_bad + simpl_cmsg_len + 33, 0xff, 33);
|
||||
fault_index = 0;
|
||||
fault = secp256k1_chilldkg_encpedpop_participant_step2(CTX, &dkg_output, eq_input, &fault_index, &states[0], vec_enc_hostseckeys[0], cmsg_bad, cmsg_len, &enc_secshares[0]);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_FAULTY_PARTICIPANT_OR_COORDINATOR);
|
||||
CHECK(fault_index == 1);
|
||||
memcpy(cmsg_bad, cmsg, cmsg_len);
|
||||
memset(cmsg_bad + simpl_cmsg_len + 33, 0, 33);
|
||||
fault_index = 0;
|
||||
fault = secp256k1_chilldkg_encpedpop_participant_step2(CTX, &dkg_output, eq_input, &fault_index, &states[0], vec_enc_hostseckeys[0], cmsg_bad, cmsg_len, &enc_secshares[0]);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_FAULTY_PARTICIPANT_OR_COORDINATOR);
|
||||
CHECK(fault_index == 1);
|
||||
|
||||
/* A tampered encrypted secshare decrypts to a wrong secshare: the fault
|
||||
* cannot be attributed without the investigation procedure. */
|
||||
secp256k1_scalar_set_int(&scalar_tmp2, 1);
|
||||
secp256k1_scalar_add(&scalar_tmp, &enc_secshares[0], &scalar_tmp2);
|
||||
fault_index = 0;
|
||||
fault = secp256k1_chilldkg_encpedpop_participant_step2(CTX, &dkg_output, eq_input, &fault_index, &states[0], vec_enc_hostseckeys[0], cmsg, cmsg_len, &scalar_tmp);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_UNKNOWN_FAULTY_PARTICIPANT_OR_COORDINATOR);
|
||||
CHECK(fault_index == UINT32_MAX);
|
||||
|
||||
/* A malformed cmsg (wrong length) blames the coordinator. */
|
||||
fault = secp256k1_chilldkg_encpedpop_participant_step2(CTX, &dkg_output, eq_input, &fault_index, &states[0], vec_enc_hostseckeys[0], cmsg, cmsg_len - 1, &enc_secshares[0]);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_FAULTY_COORDINATOR);
|
||||
|
||||
/* The coordinator blames the sender of a malformed participant message:
|
||||
* an encrypted share that overflows the group order, or an invalid
|
||||
* commitment. */
|
||||
{
|
||||
unsigned char pmsg_bad[259];
|
||||
const unsigned char *pmsg_bad_ptrs[3];
|
||||
pmsg_bad_ptrs[0] = pmsg_ptrs[0];
|
||||
pmsg_bad_ptrs[1] = pmsg_bad;
|
||||
pmsg_bad_ptrs[2] = pmsg_ptrs[2];
|
||||
memcpy(pmsg_bad, pmsgs[1], pmsg_len);
|
||||
memset(pmsg_bad + 33 * 2 + 64 + 33, 0xff, 32); /* share for recipient 0 */
|
||||
fault_index = 0;
|
||||
fault = secp256k1_chilldkg_encpedpop_coordinator_step(CTX, cmsg_bad, &coord_dkg, eq_input, enc_secshares, &fault_index, pmsg_bad_ptrs, t, &vec_enc_hostpubkeys[0][0], n);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_FAULTY_PARTICIPANT);
|
||||
CHECK(fault_index == 1);
|
||||
memcpy(pmsg_bad, pmsgs[1], pmsg_len);
|
||||
pmsg_bad[33] = 0x07; /* invalid prefix of the second commitment entry */
|
||||
fault_index = 0;
|
||||
fault = secp256k1_chilldkg_encpedpop_coordinator_step(CTX, cmsg_bad, &coord_dkg, eq_input, enc_secshares, &fault_index, pmsg_bad_ptrs, t, &vec_enc_hostpubkeys[0][0], n);
|
||||
CHECK(fault == SECP256K1_CHILLDKG_FAULTY_PARTICIPANT);
|
||||
CHECK(fault_index == 1);
|
||||
}
|
||||
|
||||
secp256k1_scalar_clear(&scalar_tmp);
|
||||
secp256k1_scalar_clear(&scalar_tmp2);
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar_clear(&enc_secshares[i]);
|
||||
secp256k1_scalar_clear(&pads_send[i]);
|
||||
secp256k1_scalar_clear(&pads_recv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct tf_test_entry tests_chilldkg[] = {
|
||||
CASE1(chilldkg_tagged_hashes_test),
|
||||
CASE1(chilldkg_params_hash_test),
|
||||
@@ -521,6 +966,8 @@ static const struct tf_test_entry tests_chilldkg[] = {
|
||||
CASE1(chilldkg_schnorrsig_test),
|
||||
CASE1(chilldkg_ecdh_pad_test),
|
||||
CASE1(chilldkg_vss_test),
|
||||
CASE1(chilldkg_simplpedpop_test),
|
||||
CASE1(chilldkg_encpedpop_test),
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,6 +12,32 @@
|
||||
#include "../../hash.h"
|
||||
#include "../../scalar.h"
|
||||
|
||||
/* Maximum number of participants (and thus the maximum threshold) supported by
|
||||
* this module. The state objects of the module are fixed-size and do not use
|
||||
* dynamic allocation, so a compile-time cap is required. This matches the
|
||||
* frost module's convention; the public header will expose the same constant
|
||||
* in a later phase. */
|
||||
#define SECP256K1_CHILLDKG_MAX_PARTICIPANTS 128
|
||||
|
||||
/* Return codes of the internal SimplPedPop/EncPedPop functions, mirroring the
|
||||
* exception taxonomy of chilldkg_ref/util.py. The public API will expose its
|
||||
* own enum in a later phase.
|
||||
*
|
||||
* For SECP256K1_CHILLDKG_FAULTY_PARTICIPANT and
|
||||
* SECP256K1_CHILLDKG_FAULTY_PARTICIPANT_OR_COORDINATOR, the fault_index output
|
||||
* of the failing function receives the index of the (suspected) faulty
|
||||
* participant. For SECP256K1_CHILLDKG_UNKNOWN_FAULTY_PARTICIPANT_OR_COORDINATOR
|
||||
* the faulty party cannot be identified without the investigation procedure
|
||||
* (a later phase); fault_index is set to UINT32_MAX. */
|
||||
typedef enum {
|
||||
SECP256K1_CHILLDKG_SUCCESS = 0,
|
||||
SECP256K1_CHILLDKG_FAULTY_COORDINATOR,
|
||||
SECP256K1_CHILLDKG_FAULTY_PARTICIPANT,
|
||||
SECP256K1_CHILLDKG_FAULTY_PARTICIPANT_OR_COORDINATOR,
|
||||
SECP256K1_CHILLDKG_UNKNOWN_FAULTY_PARTICIPANT_OR_COORDINATOR,
|
||||
SECP256K1_CHILLDKG_INVALID_INPUT
|
||||
} secp256k1_chilldkg_fault;
|
||||
|
||||
/* This file contains the internal primitives of the ChillDKG module that
|
||||
* mirror chilldkg_ref/util.py, secp256k1lab/bip340.py and secp256k1lab/ecdh.py
|
||||
* of the bip-frost-dkg reference implementation. Byte-exactness with the
|
||||
|
||||
Reference in New Issue
Block a user