/*********************************************************************** * Distributed under the MIT software license, see the accompanying * * file COPYING or https://www.opensource.org/licenses/mit-license.php.* ***********************************************************************/ #ifndef SECP256K1_MODULE_CHILLDKG_UTIL_H #define SECP256K1_MODULE_CHILLDKG_UTIL_H #include "../../../include/secp256k1.h" #include "../../../include/secp256k1_chilldkg.h" #include "../../group.h" #include "../../hash.h" #include "../../scalar.h" /* The public header defines SECP256K1_CHILLDKG_MAX_PARTICIPANTS and the fault * enum secp256k1_chilldkg_fault (SECP256K1_CHILLDKG_OK, ...), which the * internal SimplPedPop/EncPedPop functions use directly as their return * codes. */ /* 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 is the goal; the tagged hash strings below are copied verbatim * from the Python sources. */ /* Tagged hash initializers (BIP 340 tagged hashes). All ChillDKG tags share * the "BIP DKG/" prefix (BIP_TAG in chilldkg_ref/util.py); "TapTweak" is the * BIP 341 tag. */ static void secp256k1_chilldkg_sha256_tagged_params_hash(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *sha); static void secp256k1_chilldkg_sha256_tagged_encpedpop_seed(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *sha); static void secp256k1_chilldkg_sha256_tagged_simplpedpop_aux(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *sha); static void secp256k1_chilldkg_sha256_tagged_encpedpop_secnonce(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *sha); static void secp256k1_chilldkg_sha256_tagged_encpedpop_ecdh(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *sha); static void secp256k1_chilldkg_sha256_tagged_self_pad(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *sha); static void secp256k1_chilldkg_sha256_tagged_vss_coeffs(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *sha); static void secp256k1_chilldkg_sha256_tagged_taptweak(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *sha); /* Serialize a group element to 33 bytes: the point at infinity maps to 33 * zero bytes, otherwise the standard SEC compressed encoding (0x02/0x03 * prefix) is used. Mirrors GE.to_bytes_compressed_with_infinity. */ static void secp256k1_chilldkg_point_save(unsigned char *out33, const secp256k1_ge *p); /* Parse a 33-byte group element encoding: 33 zero bytes map to the point at * infinity, otherwise standard SEC compressed parsing applies. Returns 1 on * success and 0 if the encoding is invalid (wrong prefix, x >= p, or x not on * the curve). On failure, *p is set to the point at infinity. Mirrors * GE.from_bytes_compressed_with_infinity. */ static int secp256k1_chilldkg_point_load(secp256k1_ge *p, const unsigned char *in33); /* Serialize the x coordinate of a non-infinity group element (32 bytes). * Mirrors GE.to_bytes_xonly, which asserts non-infinity. */ static void secp256k1_chilldkg_xonly_save(unsigned char *out32, const secp256k1_ge *p); /* Parse a 32-byte x-only group element encoding (even y). Returns 1 on * success, 0 if x >= p or x is not on the curve. Mirrors * GE.from_bytes_xonly. */ static int secp256k1_chilldkg_xonly_load(secp256k1_ge *p, const unsigned char *in32); /* Write str (at most 33 bytes) zero-padded to 33 bytes. Used to build the * domain separation prefixes of the CertEq and recovery acknowledgment * messages (see certeq_message/recovery_ack_message in chilldkg_ref). */ static void secp256k1_chilldkg_pad33(unsigned char *out33, const char *str); /* BIP 340 Schnorr signing/verification with a parameterized tag prefix and * arbitrary-length messages, mirroring secp256k1lab/bip340.py's schnorr_sign * and schnorr_verify. The tags used for aux, nonce and challenge hashes are * tag_prefix || "/aux", tag_prefix || "/nonce" and tag_prefix || * "/challenge". ChillDKG uses tag_prefix "BIP DKG/pop message" for proofs of * possession (POP_MSG_TAG in simplpedpop.py) and the standard "BIP0340" * prefix for CertEq and recovery acknowledgments. * * sign returns 1 on success and 0 if seckey32 is not in range 1..n-1 or the * derived nonce is zero (negligible probability). On failure, sig64 is set to * zero. verify returns 1 if the signature is valid and 0 otherwise. */ static int secp256k1_chilldkg_schnorrsig_sign(const secp256k1_context *ctx, unsigned char *sig64, const unsigned char *msg, size_t msglen, const unsigned char *seckey32, const unsigned char *aux_rand32, const char *tag_prefix); static int secp256k1_chilldkg_schnorrsig_verify(const secp256k1_context *ctx, const unsigned char *sig64, const unsigned char *msg, size_t msglen, const unsigned char *pubkey32, const char *tag_prefix); /* Compute the EncPedPop ECDH pad (encpedpop.py `ecdh`): * shared = SHA256(compressed(seckey * their_point)) [libsecp256k1 ECDH] * out = Scalar.from_bytes_wrapping(TH("BIP DKG/encpedpop ecdh", * shared || my_pubkey33 || their_pubkey33 || context)) if sending * out = Scalar.from_bytes_wrapping(TH("BIP DKG/encpedpop ecdh", * shared || their_pubkey33 || my_pubkey33 || context)) otherwise * In the protocol, my/their_pubkey33 are the sender's pubnonce and the * receiver's host pubkey (in this order in the hash input, regardless of * sending), and context is u32be(receiver_index) || enc_context. * their_point must be the parsed their_pubkey33 and must not be infinity * (enforced by VERIFY_CHECK). seckey must be nonzero. */ static void secp256k1_chilldkg_encpedpop_ecdh(const secp256k1_context *ctx, secp256k1_scalar *out, const secp256k1_scalar *seckey, const secp256k1_ge *their_point, const unsigned char *my_pubkey33, const unsigned char *their_pubkey33, const unsigned char *context, size_t context_len, int sending); /* Compute the EncPedPop symmetric pad for encrypting to ourselves * (encpedpop.py `self_pad`): * out = Scalar.from_bytes_wrapping(TH("BIP DKG/encaps_multi self_pad", * symkey32 || nonce33 || context)) * where symkey32 is the host seckey, nonce33 is the own pubnonce and context * is u32be(own_index) || enc_context. */ static void secp256k1_chilldkg_encpedpop_self_pad(const secp256k1_hash_ctx *hash_ctx, secp256k1_scalar *out, const unsigned char *symkey32, const unsigned char *nonce33, const unsigned char *context, size_t context_len); /* Compute the session parameters hash (chilldkg.py `params_hash`): * out32 = TH("BIP DKG/params_hash", u32be(t) || hostpubkeys[0] || ... || hostpubkeys[n-1]) * where hostpubkeys33 is an array of n 33-byte compressed host public keys. */ static void secp256k1_chilldkg_params_hash_internal(const secp256k1_hash_ctx *hash_ctx, unsigned char *out32, const unsigned char *hostpubkeys33, size_t n, uint32_t t); #endif