This commit adds signature generation and aggregation, as well as partial signature serialization and parsing.
692 lines
31 KiB
C
692 lines
31 KiB
C
#ifndef SECP256K1_FROST_H
|
|
#define SECP256K1_FROST_H
|
|
|
|
#include "secp256k1_extrakeys.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include <stdint.h>
|
|
|
|
/** This code is currently a work in progress. It's not secure nor stable.
|
|
* IT IS EXTREMELY DANGEROUS AND RECKLESS TO USE THIS MODULE IN PRODUCTION!
|
|
*
|
|
* This module implements a variant of Flexible Round-Optimized Schnorr
|
|
* Threshold Signatures (FROST) by Chelsea Komlo and Ian Goldberg
|
|
* (https://crysp.uwaterloo.ca/software/frost/). Signatures are compatible with
|
|
* BIP-340 ("Schnorr").
|
|
*
|
|
* The module also supports BIP-341 ("Taproot") and BIP-32 ("ordinary") public
|
|
* key tweaking, and adaptor signatures.
|
|
*
|
|
* Following the convention used in the MuSig module, the API uses the singular
|
|
* term "nonce" to refer to the two "nonces" used by the FROST scheme.
|
|
*/
|
|
|
|
/** Opaque data structures
|
|
*
|
|
* The exact representation of data inside is implementation defined and not
|
|
* guaranteed to be portable between different platforms or versions. If you
|
|
* need to convert to a format suitable for storage, transmission, or
|
|
* comparison, use the corresponding serialization and parsing functions.
|
|
*/
|
|
|
|
/** Opaque data structure that caches information about key tweaking.
|
|
*
|
|
* Guaranteed to be 101 bytes in size. It can be safely copied/moved. No
|
|
* serialization and parsing functions.
|
|
*/
|
|
typedef struct {
|
|
unsigned char data[101];
|
|
} secp256k1_frost_tweak_cache;
|
|
|
|
/** Opaque data structure that holds a signer's _secret_ share.
|
|
*
|
|
* Guaranteed to be 36 bytes in size. Serialized and parsed with
|
|
* `frost_share_serialize` and `frost_share_parse`.
|
|
*/
|
|
typedef struct {
|
|
unsigned char data[36];
|
|
} secp256k1_frost_share;
|
|
|
|
/** Opaque data structure that holds a signer's _secret_ nonce.
|
|
*
|
|
* Guaranteed to be 68 bytes in size.
|
|
*
|
|
* WARNING: This structure MUST NOT be copied or read or written to directly.
|
|
* A signer who is online throughout the whole process and can keep this
|
|
* structure in memory can use the provided API functions for a safe standard
|
|
* workflow. See
|
|
* https://blockstream.com/2019/02/18/musig-a-new-multisignature-standard/ for
|
|
* more details about the risks associated with serializing or deserializing
|
|
* this structure.
|
|
*
|
|
* We repeat, copying this data structure can result in nonce reuse which will
|
|
* leak the secret signing key.
|
|
*/
|
|
typedef struct {
|
|
unsigned char data[68];
|
|
} secp256k1_frost_secnonce;
|
|
|
|
/** Opaque data structure that holds a signer's public nonce.
|
|
*
|
|
* Guaranteed to be 132 bytes in size. It can be safely copied/moved.
|
|
* Serialized and parsed with `frost_pubnonce_serialize` and
|
|
* `frost_pubnonce_parse`.
|
|
*/
|
|
typedef struct {
|
|
unsigned char data[132];
|
|
} secp256k1_frost_pubnonce;
|
|
|
|
/** Opaque data structure that holds a FROST session.
|
|
*
|
|
* This structure is not required to be kept secret for the signing protocol
|
|
* to be secure. Guaranteed to be 133 bytes in size. It can be safely
|
|
* copied/moved. No serialization and parsing functions.
|
|
*/
|
|
typedef struct {
|
|
unsigned char data[133];
|
|
} secp256k1_frost_session;
|
|
|
|
/** Opaque data structure that holds a partial FROST signature.
|
|
*
|
|
* Guaranteed to be 36 bytes in size. Serialized and parsed with
|
|
* `frost_partial_sig_serialize` and `frost_partial_sig_parse`.
|
|
*/
|
|
typedef struct {
|
|
unsigned char data[36];
|
|
} secp256k1_frost_partial_sig;
|
|
|
|
/** Parse a signer's public nonce.
|
|
*
|
|
* Returns: 1 when the nonce could be parsed, 0 otherwise.
|
|
* Args: ctx: pointer to a context object
|
|
* Out: nonce: pointer to a nonce object
|
|
* In: in66: pointer to the 66-byte nonce to be parsed
|
|
*/
|
|
SECP256K1_API int secp256k1_frost_pubnonce_parse(
|
|
const secp256k1_context *ctx,
|
|
secp256k1_frost_pubnonce *nonce,
|
|
const unsigned char *in66
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
|
|
|
/** Serialize a signer's public nonce
|
|
*
|
|
* Returns: 1 when the nonce could be serialized, 0 otherwise
|
|
* Args: ctx: pointer to a context object
|
|
* Out: out66: pointer to a 66-byte array to store the serialized nonce
|
|
* In: nonce: pointer to the nonce
|
|
*/
|
|
SECP256K1_API int secp256k1_frost_pubnonce_serialize(
|
|
const secp256k1_context *ctx,
|
|
unsigned char *out66,
|
|
const secp256k1_frost_pubnonce *nonce
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
|
|
|
/** Serialize a FROST partial signature
|
|
*
|
|
* Returns: 1 when the signature could be serialized, 0 otherwise
|
|
* Args: ctx: pointer to a context object
|
|
* Out: out32: pointer to a 32-byte array to store the serialized signature
|
|
* In: sig: pointer to the signature
|
|
*/
|
|
SECP256K1_API int secp256k1_frost_partial_sig_serialize(
|
|
const secp256k1_context *ctx,
|
|
unsigned char *out32,
|
|
const secp256k1_frost_partial_sig *sig
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
|
|
|
/** Parse a FROST partial signature.
|
|
*
|
|
* Returns: 1 when the signature could be parsed, 0 otherwise.
|
|
* Args: ctx: pointer to a context object
|
|
* Out: sig: pointer to a signature object
|
|
* In: in32: pointer to the 32-byte signature to be parsed
|
|
*
|
|
* After the call, sig will always be initialized. If parsing failed or the
|
|
* encoded numbers are out of range, signature verification with it is
|
|
* guaranteed to fail for every message and public key.
|
|
*/
|
|
SECP256K1_API int secp256k1_frost_partial_sig_parse(
|
|
const secp256k1_context *ctx,
|
|
secp256k1_frost_partial_sig *sig,
|
|
const unsigned char *in32
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
|
|
|
/** Serialize a FROST share
|
|
*
|
|
* Returns: 1 when the share could be serialized, 0 otherwise
|
|
* Args: ctx: pointer to a context object
|
|
* Out: out32: pointer to a 32-byte array to store the serialized share
|
|
* In: share: pointer to the share
|
|
*/
|
|
SECP256K1_API int secp256k1_frost_share_serialize(
|
|
const secp256k1_context *ctx,
|
|
unsigned char *out32,
|
|
const secp256k1_frost_share *share
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
|
|
|
/** Parse a FROST share.
|
|
*
|
|
* Returns: 1 when the share could be parsed, 0 otherwise.
|
|
* Args: ctx: pointer to a context object
|
|
* Out: share: pointer to a share object
|
|
* In: in32: pointer to the 32-byte share to be parsed
|
|
*/
|
|
SECP256K1_API int secp256k1_frost_share_parse(
|
|
const secp256k1_context *ctx,
|
|
secp256k1_frost_share *share,
|
|
const unsigned char *in32
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
|
|
|
/** Creates key shares
|
|
*
|
|
* To generate a key, each participant generates a share for each other
|
|
* participant. For example, in the case of 2 particpants, Alice and Bob, they
|
|
* each generate 2 shares, distribute 1 share to each other using a secure
|
|
* channel, and keep 1 for themselves.
|
|
*
|
|
* Each participant must transmit shares over secure channels to each other
|
|
* participant.
|
|
*
|
|
* Each call to this function must have a UNIQUE and uniformly RANDOM seed32
|
|
* that must that must NOT BE REUSED in subsequent calls to this function and
|
|
* must be KEPT SECRET (even from other participants).
|
|
*
|
|
* Returns: 0 if the arguments are invalid, 1 otherwise
|
|
* Args: ctx: pointer to a context object
|
|
* Out: shares: pointer to the key shares
|
|
* vss_commitment: pointer to the VSS commitment
|
|
* pok64: pointer to the proof of knowledge
|
|
* In: seed32: 32-byte random seed as explained above. Must be
|
|
* unique to this call to secp256k1_frost_shares_gen
|
|
* and must be uniformly random.
|
|
* threshold: the minimum number of signers required to produce a
|
|
* signature
|
|
* n_participants: the total number of participants
|
|
* ids33: array of 33-byte participant IDs
|
|
*/
|
|
SECP256K1_API int secp256k1_frost_shares_gen(
|
|
const secp256k1_context *ctx,
|
|
secp256k1_frost_share *shares,
|
|
secp256k1_pubkey *vss_commitment,
|
|
unsigned char *pok64,
|
|
const unsigned char *seed32,
|
|
size_t threshold,
|
|
size_t n_participants,
|
|
const unsigned char * const* ids33
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(8);
|
|
|
|
/** Aggregates shares
|
|
*
|
|
* As part of the key generation protocol, each participant receives a share
|
|
* from each participant, including a share they "receive" from themselves.
|
|
* This function verifies those shares against their VSS commitments,
|
|
* aggregates the shares, and then aggregates the commitments to each
|
|
* participant's first polynomial coefficient to derive the aggregate public
|
|
* key.
|
|
*
|
|
* If this function returns an error, `secp256k1_frost_share_verify` can be
|
|
* called on each share to determine which participants submitted faulty
|
|
* shares.
|
|
*
|
|
* Returns: 0 if the arguments are invalid, 1 otherwise (which does NOT mean
|
|
* the resulting signature verifies).
|
|
* Args: ctx: pointer to a context object
|
|
* Out: agg_share: the aggregated share
|
|
* agg_pk: the aggregated x-only public key
|
|
* In: shares: all key generation shares for the partcipant's index
|
|
* vss_commitments: coefficient commitments of all participants ordered by
|
|
* the x-only pubkeys of the participants
|
|
* n_shares: the total number of shares
|
|
* threshold: the minimum number of shares required to produce a
|
|
* signature
|
|
* id33: the 33-byte ID of the participant whose shares are being
|
|
* aggregated
|
|
*/
|
|
SECP256K1_API int secp256k1_frost_share_agg(
|
|
const secp256k1_context *ctx,
|
|
secp256k1_frost_share *agg_share,
|
|
secp256k1_xonly_pubkey *agg_pk,
|
|
const secp256k1_frost_share * const *shares,
|
|
const secp256k1_pubkey * const *vss_commitments,
|
|
size_t n_shares,
|
|
size_t threshold,
|
|
const unsigned char *id33
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(8);
|
|
|
|
/** Verifies a share received during a key generation session
|
|
*
|
|
* The signature is verified against the VSS commitment received with the
|
|
* share. This is only useful for purposes of determining which share(s) are
|
|
* invalid if share_agg returns an error.
|
|
*
|
|
* Returns: 0 if the arguments are invalid or the share does not verify, 1
|
|
* otherwise
|
|
* Args ctx: pointer to a context object
|
|
* In: threshold: the minimum number of signers required to produce a
|
|
* signature
|
|
* id33: the 33-byte participant ID of the share recipient
|
|
* share: pointer to a key generation share
|
|
* vss_commitment: the VSS commitment associated with the share
|
|
*/
|
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_share_verify(
|
|
const secp256k1_context *ctx,
|
|
size_t threshold,
|
|
const unsigned char *id33,
|
|
const secp256k1_frost_share *share,
|
|
const secp256k1_pubkey * const *vss_commitment
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
|
|
|
/** Computes a public verification share used for verifying partial signatures
|
|
*
|
|
* Returns: 0 if the arguments are invalid, 1 otherwise
|
|
* Args: ctx: pointer to a context object
|
|
* In: pubshare: pointer to a struct to store the public verification
|
|
* share
|
|
* threshold: the minimum number of signers required to produce a
|
|
* signature
|
|
* id33: the 33-byte participant ID of the participant whose
|
|
* partial signature will be verified with the pubshare
|
|
* vss_commitments: coefficient commitments of all participants
|
|
* n_participants: the total number of participants
|
|
*/
|
|
SECP256K1_API int secp256k1_frost_compute_pubshare(
|
|
const secp256k1_context *ctx,
|
|
secp256k1_pubkey *pubshare,
|
|
size_t threshold,
|
|
const unsigned char *id33,
|
|
const secp256k1_pubkey * const *vss_commitments,
|
|
size_t n_participants
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
|
|
|
/** Obtain the aggregate public key from a FROST x-only aggregate public key.
|
|
*
|
|
* This is only useful if you need the non-xonly public key, in particular for
|
|
* ordinary (non-xonly) tweaking or batch-verifying multiple key aggregations
|
|
* (not implemented).
|
|
*
|
|
* Returns: 0 if the arguments are invalid, 1 otherwise
|
|
* Args: ctx: pointer to a context object
|
|
* Out: ec_agg_pk: the FROST-aggregated public key.
|
|
* In: xonly_agg_pk: the aggregated x-only public key that is the output of
|
|
* `secp256k1_frost_share_agg`
|
|
*/
|
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_pubkey_get(
|
|
const secp256k1_context *ctx,
|
|
secp256k1_pubkey *ec_agg_pk,
|
|
const secp256k1_xonly_pubkey *xonly_agg_pk
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
|
|
|
/** Initializes a tweak cache used for applying tweaks to a FROST key
|
|
*
|
|
* Returns: 0 if the arguments are invalid, 1 otherwise
|
|
* Args: ctx: pointer to a context object
|
|
* Out: tweak_cache: pointer to a frost_tweak_cache struct that is required
|
|
* for key tweaking
|
|
* In: agg_pk: the aggregated x-only public key that is the output of
|
|
* `secp256k1_frost_share_agg`
|
|
*/
|
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_pubkey_tweak(
|
|
const secp256k1_context *ctx,
|
|
secp256k1_frost_tweak_cache *tweak_cache,
|
|
const secp256k1_xonly_pubkey *agg_pk
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
|
|
|
/** Apply ordinary "EC" tweaking to a public key in a given tweak_cache by
|
|
* adding the generator multiplied with `tweak32` to it. This is useful for
|
|
* deriving child keys from an aggregate public key via BIP32.
|
|
*
|
|
* The tweaking method is the same as `secp256k1_ec_pubkey_tweak_add`. So after
|
|
* the following pseudocode buf and buf2 have identical contents (absent
|
|
* earlier failures).
|
|
*
|
|
* secp256k1_frost_share_agg(..., xonly_agg_pk, ...)
|
|
* secp256k1_frost_pubkey_tweak(..., tweak_cache, xonly_agg_pk)
|
|
* secp256k1_frost_pubkey_ec_tweak_add(..., output_pk, tweak_cache, tweak32)
|
|
* secp256k1_ec_pubkey_serialize(..., buf, output_pk)
|
|
* secp256k1_frost_pubkey_get(..., ec_agg_pk, xonly_agg_pk)
|
|
* secp256k1_ec_pubkey_tweak_add(..., ec_agg_pk, tweak32)
|
|
* secp256k1_ec_pubkey_serialize(..., buf2, ec_agg_pk)
|
|
*
|
|
* This function is required if you want to _sign_ for a tweaked aggregate key.
|
|
* On the other hand, if you are only computing a public key, but not intending
|
|
* to create a signature for it, you can just use
|
|
* `secp256k1_ec_pubkey_tweak_add`.
|
|
*
|
|
* Returns: 0 if the arguments are invalid or the resulting public key would be
|
|
* invalid (only when the tweak is the negation of the corresponding
|
|
* secret key). 1 otherwise.
|
|
* Args: ctx: pointer to a context object
|
|
* Out: output_pubkey: pointer to a public key to store the result. Will be set
|
|
* to an invalid value if this function returns 0. If you
|
|
* do not need it, this arg can be NULL.
|
|
* In/Out: tweak_cache: pointer to a `frost_tweak_cache` struct initialized by
|
|
* `frost_pubkey_tweak`
|
|
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid
|
|
* according to `secp256k1_ec_seckey_verify`, this function
|
|
* returns 0. For uniformly random 32-byte arrays the
|
|
* chance of being invalid is negligible (around 1 in
|
|
* 2^128).
|
|
*/
|
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_pubkey_ec_tweak_add(
|
|
const secp256k1_context *ctx,
|
|
secp256k1_pubkey *output_pubkey,
|
|
secp256k1_frost_tweak_cache *tweak_cache,
|
|
const unsigned char *tweak32
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
|
|
|
/** Apply x-only tweaking to a public key in a given tweak_cache by adding the
|
|
* generator multiplied with `tweak32` to it. This is useful for creating
|
|
* Taproot outputs.
|
|
*
|
|
* The tweaking method is the same as `secp256k1_xonly_pubkey_tweak_add`. So in
|
|
* the following pseudocode xonly_pubkey_tweak_add_check (absent earlier
|
|
* failures) returns 1.
|
|
*
|
|
* secp256k1_frost_share_agg(..., agg_pk, ...)
|
|
* secp256k1_frost_pubkey_tweak(..., tweak_cache, agg_pk)
|
|
* secp256k1_frost_pubkey_xonly_tweak_add(..., output_pk, tweak_cache, tweak32)
|
|
* secp256k1_xonly_pubkey_serialize(..., buf, output_pk)
|
|
* secp256k1_xonly_pubkey_tweak_add_check(..., buf, ..., agg_pk, tweak32)
|
|
*
|
|
* This function is required if you want to _sign_ for a tweaked aggregate key.
|
|
* On the other hand, if you are only computing a public key, but not intending
|
|
* to create a signature for it, you can just use
|
|
* `secp256k1_xonly_pubkey_tweak_add`.
|
|
*
|
|
* Returns: 0 if the arguments are invalid or the resulting public key would be
|
|
* invalid (only when the tweak is the negation of the corresponding
|
|
* secret key). 1 otherwise.
|
|
* Args: ctx: pointer to a context object
|
|
* Out: output_pubkey: pointer to a public key to store the result. Will be set
|
|
* to an invalid value if this function returns 0. If you
|
|
* do not need it, this arg can be NULL.
|
|
* In/Out: tweak_cache: pointer to a `frost_tweak_cache` struct initialized by
|
|
* `frost_pubkey_tweak`
|
|
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid
|
|
* according to secp256k1_ec_seckey_verify, this function
|
|
* returns 0. For uniformly random 32-byte arrays the
|
|
* chance of being invalid is negligible (around 1 in
|
|
* 2^128).
|
|
*/
|
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_pubkey_xonly_tweak_add(
|
|
const secp256k1_context *ctx,
|
|
secp256k1_pubkey *output_pubkey,
|
|
secp256k1_frost_tweak_cache *tweak_cache,
|
|
const unsigned char *tweak32
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
|
|
|
/** Starts a signing session by generating a nonce
|
|
*
|
|
* This function outputs a secret nonce that will be required for signing and a
|
|
* corresponding public nonce that is intended to be sent to other signers.
|
|
*
|
|
* FROST, like MuSig, differs from regular Schnorr signing in that
|
|
* implementers _must_ take special care to not reuse a nonce. This can be
|
|
* ensured by following these rules:
|
|
*
|
|
* 1. Each call to this function must have a UNIQUE session_id32 that must NOT BE
|
|
* REUSED in subsequent calls to this function.
|
|
* If you do not provide a seckey, session_id32 _must_ be UNIFORMLY RANDOM
|
|
* AND KEPT SECRET (even from other signers). If you do provide a seckey,
|
|
* session_id32 can instead be a counter (that must never repeat!). However,
|
|
* it is recommended to always choose session_id32 uniformly at random.
|
|
* 2. If you already know the seckey, message or aggregate public key, they
|
|
* can be optionally provided to derive the nonce and increase
|
|
* misuse-resistance. The extra_input32 argument can be used to provide
|
|
* additional data that does not repeat in normal scenarios, such as the
|
|
* current time.
|
|
* 3. Avoid copying (or serializing) the secnonce. This reduces the possibility
|
|
* that it is used more than once for signing.
|
|
*
|
|
* Remember that nonce reuse will leak the secret key!
|
|
* Note that using the same agg_share for multiple FROST sessions is fine.
|
|
*
|
|
* Returns: 0 if the arguments are invalid and 1 otherwise
|
|
* Args: ctx: pointer to a context object (not secp256k1_context_static)
|
|
* Out: secnonce: pointer to a structure to store the secret nonce
|
|
* pubnonce: pointer to a structure to store the public nonce
|
|
* In: session_id32: a 32-byte session_id32 as explained above. Must be
|
|
* unique to this call to secp256k1_frost_nonce_gen and
|
|
* must be uniformly random unless you really know what you
|
|
* are doing.
|
|
* agg_share: the aggregated share that will later be used for
|
|
* signing, if already known (can be NULL)
|
|
* msg32: the 32-byte message that will later be signed, if
|
|
* already known (can be NULL)
|
|
* agg_pk: the FROST-aggregated public key (can be NULL)
|
|
* extra_input32: an optional 32-byte array that is input to the nonce
|
|
* derivation function (can be NULL)
|
|
*/
|
|
SECP256K1_API int secp256k1_frost_nonce_gen(
|
|
const secp256k1_context *ctx,
|
|
secp256k1_frost_secnonce *secnonce,
|
|
secp256k1_frost_pubnonce *pubnonce,
|
|
const unsigned char *session_id32,
|
|
const secp256k1_frost_share *agg_share,
|
|
const unsigned char *msg32,
|
|
const secp256k1_xonly_pubkey *agg_pk,
|
|
const unsigned char *extra_input32
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
|
|
|
/** Takes the public nonces of all signers and computes a session that is
|
|
* required for signing and verification of partial signatures. The participant
|
|
* IDs can be sorted before combining, but the corresponding pubnonces must be
|
|
* resorted as well. All signers must use the same sorting of pubnonces,
|
|
* otherwise signing will fail.
|
|
*
|
|
* Returns: 0 if the arguments are invalid or if some signer sent invalid
|
|
* pubnonces, 1 otherwise
|
|
* Args: ctx: pointer to a context object
|
|
* Out: session: pointer to a struct to store the session
|
|
* In: pubnonces: array of pointers to public nonces sent by the signers
|
|
* n_pubnonces: number of elements in the pubnonces array. Must be
|
|
* greater than 0.
|
|
* msg32: the 32-byte message to sign
|
|
* agg_pk: the FROST-aggregated public key
|
|
* myd_id33: the 33-byte ID of the participant who will use the
|
|
* session for signing
|
|
* ids33: array of the 33-byte participant IDs of the signers
|
|
* tweak_cache: pointer to frost_tweak_cache struct (can be NULL)
|
|
* adaptor: optional pointer to an adaptor point encoded as a
|
|
* public key if this signing session is part of an
|
|
* adaptor signature protocol (can be NULL)
|
|
*/
|
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_nonce_process(
|
|
const secp256k1_context *ctx,
|
|
secp256k1_frost_session *session,
|
|
const secp256k1_frost_pubnonce * const *pubnonces,
|
|
size_t n_pubnonces,
|
|
const unsigned char *msg32,
|
|
const secp256k1_xonly_pubkey *agg_pk,
|
|
const unsigned char *my_id33,
|
|
const unsigned char * const* ids33,
|
|
const secp256k1_frost_tweak_cache *tweak_cache,
|
|
const secp256k1_pubkey *adaptor
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8);
|
|
|
|
/** Produces a partial signature
|
|
*
|
|
* This function overwrites the given secnonce with zeros and will abort if given a
|
|
* secnonce that is all zeros. This is a best effort attempt to protect against nonce
|
|
* reuse. However, this is of course easily defeated if the secnonce has been
|
|
* copied (or serialized). Remember that nonce reuse will leak the secret key!
|
|
*
|
|
* Returns: 0 if the arguments are invalid or the provided secnonce has already
|
|
* been used for signing, 1 otherwise
|
|
* Args: ctx: pointer to a context object
|
|
* Out: partial_sig: pointer to struct to store the partial signature
|
|
* In/Out: secnonce: pointer to the secnonce struct created in
|
|
* frost_nonce_gen that has been never used in a
|
|
* partial_sign call before
|
|
* In: agg_share: the aggregated share
|
|
* session: pointer to the session that was created with
|
|
* frost_nonce_process
|
|
* tweak_cache: pointer to frost_tweak_cache struct (can be NULL)
|
|
*/
|
|
SECP256K1_API int secp256k1_frost_partial_sign(
|
|
const secp256k1_context *ctx,
|
|
secp256k1_frost_partial_sig *partial_sig,
|
|
secp256k1_frost_secnonce *secnonce,
|
|
const secp256k1_frost_share *agg_share,
|
|
const secp256k1_frost_session *session,
|
|
const secp256k1_frost_tweak_cache *tweak_cache
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
|
|
|
/** Verifies an individual signer's partial signature
|
|
*
|
|
* The signature is verified for a specific signing session. In order to avoid
|
|
* accidentally verifying a signature from a different or non-existing signing
|
|
* session, you must ensure the following:
|
|
* 1. The `tweak_cache` argument is identical to the one used to create the
|
|
* `session` with `frost_nonce_process`.
|
|
* 2. The `pubshare` argument must be the output of
|
|
* `secp256k1_frost_shares_trusted_gen` for the signer's 'pk'.
|
|
* 3. The `pubnonce` argument must be identical to the one sent by the
|
|
* signer and used to create the `session` with `frost_nonce_process`.
|
|
*
|
|
* This function can be used to assign blame for a failed signature.
|
|
*
|
|
* Returns: 0 if the arguments are invalid or the partial signature does not
|
|
* verify, 1 otherwise
|
|
* Args ctx: pointer to a context object
|
|
* In: partial_sig: pointer to partial signature to verify, sent by
|
|
* the signer associated with `pubnonce` and `pubkey`
|
|
* pubnonce: public nonce of the signer in the signing session
|
|
* pubshare: public verification share of the signer in the signing
|
|
* session that is the output of
|
|
* `secp256k1_frost_shares_trusted_gen`
|
|
* session: pointer to the session that was created with
|
|
* `frost_nonce_process`
|
|
* tweak_cache: pointer to frost_tweak_cache struct (can be NULL)
|
|
*/
|
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_partial_sig_verify(
|
|
const secp256k1_context *ctx,
|
|
const secp256k1_frost_partial_sig *partial_sig,
|
|
const secp256k1_frost_pubnonce *pubnonce,
|
|
const secp256k1_pubkey *pubshare,
|
|
const secp256k1_frost_session *session,
|
|
const secp256k1_frost_tweak_cache *tweak_cache
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
|
|
|
/** Aggregates partial signatures
|
|
*
|
|
* Returns: 0 if the arguments are invalid, 1 otherwise (which does NOT mean
|
|
* the resulting signature verifies).
|
|
* Args: ctx: pointer to a context object
|
|
* Out: sig64: complete (but possibly invalid) Schnorr signature
|
|
* In: session: pointer to the session that was created with
|
|
* frost_nonce_process
|
|
* partial_sigs: array of pointers to partial signatures to aggregate
|
|
* n_sigs: number of elements in the partial_sigs array. Must be
|
|
* greater than 0.
|
|
*/
|
|
SECP256K1_API int secp256k1_frost_partial_sig_agg(
|
|
const secp256k1_context *ctx,
|
|
unsigned char *sig64,
|
|
const secp256k1_frost_session *session,
|
|
const secp256k1_frost_partial_sig * const *partial_sigs,
|
|
size_t n_sigs
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
|
|
|
/** Extracts the nonce_parity bit from a session
|
|
*
|
|
* This is used for adaptor signatures.
|
|
*
|
|
* Returns: 0 if the arguments are invalid, 1 otherwise
|
|
* Args: ctx: pointer to a context object
|
|
* Out: nonce_parity: pointer to an integer that indicates the parity
|
|
* of the aggregate public nonce. Used for adaptor
|
|
* signatures.
|
|
* In: session: pointer to the session that was created with
|
|
* frost_nonce_process
|
|
*/
|
|
SECP256K1_API int secp256k1_frost_nonce_parity(
|
|
const secp256k1_context *ctx,
|
|
int *nonce_parity,
|
|
const secp256k1_frost_session *session
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
|
|
|
/** Verifies that the adaptor can be extracted by combining the adaptor
|
|
* pre-signature and the completed signature.
|
|
*
|
|
* Returns: 0 if the arguments are invalid or the adaptor signature does not
|
|
* verify, 1 otherwise
|
|
* Args: ctx: pointer to a context object
|
|
* In: pre_sig64: 64-byte pre-signature
|
|
* msg32: the 32-byte message being verified
|
|
* pubkey: pointer to an x-only public key to verify with
|
|
* adaptor: pointer to the adaptor point being verified
|
|
* nonce_parity: the output of `frost_nonce_parity` called with the
|
|
* session used for producing the pre-signature
|
|
*/
|
|
SECP256K1_API int secp256k1_frost_verify_adaptor(
|
|
const secp256k1_context *ctx,
|
|
const unsigned char *pre_sig64,
|
|
const unsigned char *msg32,
|
|
const secp256k1_xonly_pubkey *pubkey,
|
|
const secp256k1_pubkey *adaptor,
|
|
int nonce_parity
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
|
|
|
/** Creates a signature from a pre-signature and an adaptor.
|
|
*
|
|
* If the sec_adaptor32 argument is incorrect, the output signature will be
|
|
* invalid. This function does not verify the signature.
|
|
*
|
|
* Returns: 0 if the arguments are invalid, or pre_sig64 or sec_adaptor32 contain
|
|
* invalid (overflowing) values. 1 otherwise (which does NOT mean the
|
|
* signature or the adaptor are valid!)
|
|
* Args: ctx: pointer to a context object
|
|
* Out: sig64: 64-byte signature. This pointer may point to the same
|
|
* memory area as `pre_sig`.
|
|
* In: pre_sig64: 64-byte pre-signature
|
|
* sec_adaptor32: 32-byte secret adaptor to add to the pre-signature
|
|
* nonce_parity: the output of `frost_nonce_parity` called with the
|
|
* session used for producing the pre-signature
|
|
*/
|
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_adapt(
|
|
const secp256k1_context *ctx,
|
|
unsigned char *sig64,
|
|
const unsigned char *pre_sig64,
|
|
const unsigned char *sec_adaptor32,
|
|
int nonce_parity
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
|
|
|
/** Extracts a secret adaptor from a FROST pre-signature and corresponding
|
|
* signature
|
|
*
|
|
* This function will not fail unless given grossly invalid data; if it is
|
|
* merely given signatures that do not verify, the returned value will be
|
|
* nonsense. It is therefore important that all data be verified at earlier
|
|
* steps of any protocol that uses this function. In particular, this includes
|
|
* verifying all partial signatures that were aggregated into pre_sig64.
|
|
*
|
|
* Returns: 0 if the arguments are NULL, or sig64 or pre_sig64 contain
|
|
* grossly invalid (overflowing) values. 1 otherwise (which does NOT
|
|
* mean the signatures or the adaptor are valid!)
|
|
* Args: ctx: pointer to a context object
|
|
* Out:sec_adaptor32: 32-byte secret adaptor
|
|
* In: sig64: complete, valid 64-byte signature
|
|
* pre_sig64: the pre-signature corresponding to sig64, i.e., the
|
|
* aggregate of partial signatures without the secret
|
|
* adaptor
|
|
* nonce_parity: the output of `frost_nonce_parity` called with the
|
|
* session used for producing sig64
|
|
*/
|
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_extract_adaptor(
|
|
const secp256k1_context *ctx,
|
|
unsigned char *sec_adaptor32,
|
|
const unsigned char *sig64,
|
|
const unsigned char *pre_sig64,
|
|
int nonce_parity
|
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|