Monero
Loading...
Searching...
No Matches
multisig Namespace Reference

Namespaces

namespace  signing

Classes

class  multisig_account
class  multisig_kex_msg
struct  multisig_kex_msg_serializable_round1
 round 1 kex message More...
struct  multisig_kex_msg_serializable_general
 general kex message (if round > 1) More...
class  MultisigTest
class  Guard

Typedefs

using multisig_keyset_map_memsafe_t

Functions

crypto::secret_key get_multisig_blinded_secret_key (const crypto::secret_key &key)
 get_multisig_blinded_secret_key - converts an input private key into a blinded multisig private key Use 1a: converts account private spend key into multisig private key, which is used for key exchange and message signing Use 1b: converts account private view key into ancillary private key share, for the composite multisig private view key Use 2: converts DH shared secrets (curve points) into private keys, which are intermediate private keys in multisig key exchange
bool generate_multisig_key_image (const cryptonote::account_keys &keys, std::size_t multisig_key_index, const crypto::public_key &out_key, crypto::key_image &ki)
void generate_multisig_LR (const crypto::public_key pkey, const crypto::secret_key &k, crypto::public_key &L, crypto::public_key &R)
bool generate_multisig_composite_key_image (const cryptonote::account_keys &keys, const std::unordered_map< crypto::public_key, cryptonote::subaddress_index > &subaddresses, const crypto::public_key &out_key, const crypto::public_key &tx_public_key, const std::vector< crypto::public_key > &additional_tx_public_keys, std::size_t real_output_index, const std::vector< crypto::key_image > &pkis, crypto::key_image &ki)
std::uint32_t multisig_kex_rounds_required (const std::uint32_t num_signers, const std::uint32_t threshold)
std::uint32_t multisig_setup_rounds_required (const std::uint32_t num_signers, const std::uint32_t threshold)
static void check_multisig_config (const std::uint32_t round, const std::uint32_t threshold, const std::uint32_t num_signers)
static crypto::secret_key calculate_multisig_keypair_from_derivation (const crypto::public_key_memsafe &derivation, crypto::public_key &derived_pubkey_out)
static void make_multisig_common_privkey (std::vector< crypto::secret_key > participant_base_common_privkeys, crypto::secret_key &common_privkey_out)
static rct::key compute_multisig_aggregation_coefficient (const std::vector< crypto::public_key > &sorted_keys, const crypto::public_key &aggregation_key)
static crypto::public_key generate_multisig_aggregate_key (std::vector< crypto::public_key > final_keys, std::vector< crypto::secret_key > &privkeys_inout)
static void multisig_kex_make_round_keys (const crypto::secret_key &base_privkey, multisig_keyset_map_memsafe_t pubkey_origins_map, multisig_keyset_map_memsafe_t &derivation_origins_map_out)
static void check_messages_round (const std::vector< multisig_kex_msg > &expanded_msgs, const std::uint32_t expected_round)
static std::uint32_t multisig_kex_msgs_sanitize_pubkeys (const std::vector< multisig_kex_msg > &expanded_msgs, const std::vector< crypto::public_key > &exclude_pubkeys, multisig_keyset_map_memsafe_t &sanitized_pubkeys_out)
static void remove_key_from_mapped_sets (const crypto::public_key &key_to_remove, multisig_keyset_map_memsafe_t &keyset_inout)
static multisig_keyset_map_memsafe_t evaluate_multisig_kex_round_msgs (const crypto::public_key &base_pubkey, const std::uint32_t expected_round, const std::vector< crypto::public_key > &signers, const std::vector< multisig_kex_msg > &expanded_msgs, const std::vector< crypto::public_key > &exclude_pubkeys, const bool incomplete_signer_set)
static multisig_keyset_map_memsafe_t evaluate_multisig_post_kex_round_msgs (const crypto::public_key &base_pubkey, const std::uint32_t expected_round, const std::vector< crypto::public_key > &signers, const std::vector< multisig_kex_msg > &expanded_msgs, const bool incomplete_signer_set)
static void multisig_kex_process_round_msgs (const crypto::secret_key &base_privkey, const crypto::public_key &base_pubkey, const std::uint32_t current_round, const std::uint32_t threshold, const std::vector< crypto::public_key > &signers, const std::vector< multisig_kex_msg > &expanded_msgs, const std::vector< crypto::public_key > &exclude_pubkeys, const bool incomplete_signer_set, multisig_keyset_map_memsafe_t &keys_to_origins_map_out)

Variables

list TEST_CASES
list PUB_ADDRS = [case[2] for case in TEST_CASES]

Typedef Documentation

◆ multisig_keyset_map_memsafe_t

Initial value:
std::unordered_map<crypto::public_key_memsafe, std::unordered_set<crypto::public_key>>

multisig account:

  • handles account keys for an M-of-N multisig participant (M <= N; M >= 1; N >= 2)
  • encapsulates multisig account construction process (via key exchange [kex])
  • TODO: encapsulates key preparation for aggregation-style signing

:: multisig pubkey: the private key is split, M group participants are required to reassemble (e.g. to sign something)

  • in cryptonote, this is the multisig spend key :: multisig common pubkey: the private key is known to all participants (e.g. for authenticating as a group member)
  • in cryptonote, this is the multisig view key

multisig key exchange:

An 'M-of-N' (M <= N; M >= 1; N >= 2) multisignature key is a public key where at least 'M' out of 'N' possible co-signers must collaborate in order to create a signature.

Constructing a multisig key involves a series of Diffie-Hellman exchanges between participants. At the end of key exchange (kex), each participant will hold a number of private keys. Each private key is shared by a group of (N - M + 1) participants. This way if (N - M) co-signers are missing, every private key will be held by at least one of the remaining M people.

Note on MULTISIG_MAX_SIGNERS: During key exchange, participants will have up to '(N - 1) choose (N - M)' key shares. If N is large, then the max number of key shares (when M = (N-1)/2) can be huge. A limit of N <= 16 was arbitrarily chosen as a power of 2 that can accomodate the vast majority of practical use-cases. To increase the limit, FROST-style key aggregation should be used instead (it is more efficient than DH-based key generation when N - M > 1).

Function Documentation

◆ calculate_multisig_keypair_from_derivation()

crypto::secret_key multisig::calculate_multisig_keypair_from_derivation ( const crypto::public_key_memsafe & derivation,
crypto::public_key & derived_pubkey_out )
static

INTERNAL

brief: calculate_multisig_keypair_from_derivation - wrapper on calculate_multisig_keypair() for an input public key Converts an input public key into a crypto private key (type cast, does not change serialization), then passes it to get_multisig_blinded_secret_key().

Result:

  • privkey = H(derivation)
  • pubkey = privkey * G param: derivation - a curve point outparam: derived_pubkey_out - public key of the resulting privkey return: multisig private key

◆ check_messages_round()

void multisig::check_messages_round ( const std::vector< multisig_kex_msg > & expanded_msgs,
const std::uint32_t expected_round )
static

INTERNAL

brief: check_messages_round - Check that a set of messages have an expected round number. param: expanded_msgs - set of multisig kex messages to process param: expected_round - round number the kex messages should have

◆ check_multisig_config()

void multisig::check_multisig_config ( const std::uint32_t round,
const std::uint32_t threshold,
const std::uint32_t num_signers )
static

INTERNAL

brief: check_multisig_config - validate multisig configuration details param: round - the round of the message that should be produced param: threshold - threshold for multisig (M in M-of-N) param: num_signers - number of participants in multisig (N)

◆ compute_multisig_aggregation_coefficient()

rct::key multisig::compute_multisig_aggregation_coefficient ( const std::vector< crypto::public_key > & sorted_keys,
const crypto::public_key & aggregation_key )
static

INTERNAL

brief: compute_multisig_aggregation_coefficient - creates aggregation coefficient for a specific public key in a set of public keys

WARNING: The coefficient will only be deterministic if... 1) input keys are pre-sorted

  • tested here 2) input keys are in canonical form (compressed points in the prime-order subgroup of Ed25519)
  • untested here for performance param: sorted_keys - set of component public keys that will be merged into a multisig public spend key param: aggregation_key - one of the component public keys return: aggregation coefficient

◆ evaluate_multisig_kex_round_msgs()

multisig_keyset_map_memsafe_t multisig::evaluate_multisig_kex_round_msgs ( const crypto::public_key & base_pubkey,
const std::uint32_t expected_round,
const std::vector< crypto::public_key > & signers,
const std::vector< multisig_kex_msg > & expanded_msgs,
const std::vector< crypto::public_key > & exclude_pubkeys,
const bool incomplete_signer_set )
static

INTERNAL

brief: evaluate_multisig_kex_round_msgs - Evaluate pubkeys from a kex round in order to prepare for the next round.

  • Sanitizes input msgs.
  • Require uniqueness in: 'exclude_pubkeys'.
  • Requires each input pubkey be recommended by 'num_recommendations = expected_round' msg signers.
    • For a final multisig key to be truly 'M-of-N', each of the the private key's components must be shared by (N - M + 1) signers.
  • Requires that msgs are signed by only keys in 'signers'.
  • Requires that each key in 'signers' recommends [num_signers - 2 CHOOSE (expected_round - 1)] pubkeys.
    • These should be derivations each signer recommends for round 'expected_round', excluding derivations shared with the local account.
  • Requires that 'exclude_pubkeys' has [num_signers - 1 CHOOSE (expected_round - 1)] pubkeys.
    • These should be derivations the local account has corresponding to round 'expected_round'. param: base_pubkey - multisig account's base public key param: expected_round - expected kex round of input messages param: signers - expected participants in multisig kex param: expanded_msgs - set of multisig kex messages to process param: exclude_pubkeys - derivations held by the local account corresponding to round 'expected_round' param: incomplete_signer_set - only require the minimum number of signers to complete this round minimum = num_signers - (round num - 1) (including local signer) return: fully sanitized and validated pubkey:origins map for building the account's next kex round message

◆ evaluate_multisig_post_kex_round_msgs()

multisig_keyset_map_memsafe_t multisig::evaluate_multisig_post_kex_round_msgs ( const crypto::public_key & base_pubkey,
const std::uint32_t expected_round,
const std::vector< crypto::public_key > & signers,
const std::vector< multisig_kex_msg > & expanded_msgs,
const bool incomplete_signer_set )
static

INTERNAL

brief: evaluate_multisig_post_kex_round_msgs - Evaluate messages for the post-kex verification round.

  • Sanitizes input msgs.
  • Requires that only one pubkey is recommended.
  • Requires that all signers (other than self) recommend that one pubkey. param: base_pubkey - multisig account's base public key param: expected_round - expected kex round of input messages param: signers - expected participants in multisig kex param: expanded_msgs - set of multisig kex messages to process param: incomplete_signer_set - only require the minimum amount of messages to complete this round (1 message) return: sanitized and validated pubkey:origins map

◆ generate_multisig_aggregate_key()

crypto::public_key multisig::generate_multisig_aggregate_key ( std::vector< crypto::public_key > final_keys,
std::vector< crypto::secret_key > & privkeys_inout )
static

INTERNAL

brief: generate_multisig_aggregate_key - generates a multisig public spend key via key aggregation Key aggregation via aggregation coefficients prevents key cancellation attacks. See: https://www.getmonero.org/resources/research-lab/pubs/MRL-0009.pdf param: final_keys - address components (public keys) obtained from other participants (not shared with local) param: privkeys_inout - private keys of address components known by local; each key will be multiplied by an aggregation coefficient (return by reference) return: final multisig public spend key for the account

◆ generate_multisig_composite_key_image()

bool multisig::generate_multisig_composite_key_image ( const cryptonote::account_keys & keys,
const std::unordered_map< crypto::public_key, cryptonote::subaddress_index > & subaddresses,
const crypto::public_key & out_key,
const crypto::public_key & tx_public_key,
const std::vector< crypto::public_key > & additional_tx_public_keys,
std::size_t real_output_index,
const std::vector< crypto::key_image > & pkis,
crypto::key_image & ki )

◆ generate_multisig_key_image()

bool multisig::generate_multisig_key_image ( const cryptonote::account_keys & keys,
std::size_t multisig_key_index,
const crypto::public_key & out_key,
crypto::key_image & ki )

◆ generate_multisig_LR()

void multisig::generate_multisig_LR ( const crypto::public_key pkey,
const crypto::secret_key & k,
crypto::public_key & L,
crypto::public_key & R )

◆ get_multisig_blinded_secret_key()

crypto::secret_key multisig::get_multisig_blinded_secret_key ( const crypto::secret_key & key)

get_multisig_blinded_secret_key - converts an input private key into a blinded multisig private key Use 1a: converts account private spend key into multisig private key, which is used for key exchange and message signing Use 1b: converts account private view key into ancillary private key share, for the composite multisig private view key Use 2: converts DH shared secrets (curve points) into private keys, which are intermediate private keys in multisig key exchange

Parameters
key- private key to transform
Returns
transformed private key

◆ make_multisig_common_privkey()

void multisig::make_multisig_common_privkey ( std::vector< crypto::secret_key > participant_base_common_privkeys,
crypto::secret_key & common_privkey_out )
static

INTERNAL

brief: make_multisig_common_privkey - Create the 'common' multisig privkey, owned by all multisig participants.

  • common privkey = H(sorted base common privkeys) param: participant_base_common_privkeys - Base common privkeys contributed by multisig participants. outparam: common_privkey_out - result

◆ multisig_kex_make_round_keys()

void multisig::multisig_kex_make_round_keys ( const crypto::secret_key & base_privkey,
multisig_keyset_map_memsafe_t pubkey_origins_map,
multisig_keyset_map_memsafe_t & derivation_origins_map_out )
static

INTERNAL

brief: multisig_kex_make_round_keys - Makes a kex round's keys.

  • Involves DH exchanges with pubkeys provided by other participants.
  • Conserves mapping [pubkey -> DH derivation] : [origin keys of participants that share this secret with you]. param: base_privkey - account's base private key, for performing DH exchanges and signing messages param: pubkey_origins_map - map between pubkeys to produce DH derivations with and identity keys of participants who will share each derivation with you outparam: derivation_origins_map_out - map between DH derivations (shared secrets) and identity keys

◆ multisig_kex_msgs_sanitize_pubkeys()

std::uint32_t multisig::multisig_kex_msgs_sanitize_pubkeys ( const std::vector< multisig_kex_msg > & expanded_msgs,
const std::vector< crypto::public_key > & exclude_pubkeys,
multisig_keyset_map_memsafe_t & sanitized_pubkeys_out )
static

INTERNAL

brief: multisig_kex_msgs_sanitize_pubkeys - Sanitize multisig kex messages.

  • Removes duplicates from msg pubkeys, ignores keys found in input 'exclusion set', constructs map of pubkey:origins.
  • Requires that all input msgs have the same round number.

origins = all the signing pubkeys that recommended a given pubkey found in input msgs

  • If the messages' round numbers are all '1', then only the message signing pubkey is considered 'recommended'. Furthermore, the 'exclusion set' is ignored. param: expanded_msgs - set of multisig kex messages to process param: exclude_pubkeys - pubkeys to exclude from output set outparam: sanitized_pubkeys_out - processed pubkeys obtained from msgs, mapped to their origins return: round number shared by all input msgs

◆ multisig_kex_process_round_msgs()

void multisig::multisig_kex_process_round_msgs ( const crypto::secret_key & base_privkey,
const crypto::public_key & base_pubkey,
const std::uint32_t current_round,
const std::uint32_t threshold,
const std::vector< crypto::public_key > & signers,
const std::vector< multisig_kex_msg > & expanded_msgs,
const std::vector< crypto::public_key > & exclude_pubkeys,
const bool incomplete_signer_set,
multisig_keyset_map_memsafe_t & keys_to_origins_map_out )
static

INTERNAL

brief: multisig_kex_process_round_msgs - Process kex messages for the active kex round.

  • A wrapper around evaluate_multisig_kex_round_msgs() -> multisig_kex_make_next_msg().
    • In other words, evaluate the input messages and try to make a message for the next round.
  • Note: Must be called on the final round's msgs to evaluate the final key components recommended by other participants. param: base_privkey - multisig account's base private key param: current_round - round of kex the input messages should be designed for param: threshold - threshold for multisig (M in M-of-N) param: signers - expected participants in multisig kex param: expanded_msgs - set of multisig kex messages to process param: exclude_pubkeys - keys held by the local account corresponding to round 'current_round'
  • If 'current_round' is the final round, these are the local account's shares of the final aggregate key. param: incomplete_signer_set - allow messages from an incomplete signer set outparam: keys_to_origins_map_out - map between round keys and identity keys
  • If in the final round, these are key shares recommended by other signers for the final aggregate key.
  • Otherwise, these are the local account's DH derivations for the next round.
    • See multisig_kex_make_next_msg() for an explanation. return: multisig kex message for next round, or empty message if 'current_round' is the final round

◆ multisig_kex_rounds_required()

std::uint32_t multisig::multisig_kex_rounds_required ( const std::uint32_t num_signers,
const std::uint32_t threshold )

brief: multisig_kex_rounds_required - The number of key exchange rounds required to produce an M-of-N shared key.

  • Key exchange (kex) is a synchronous series of 'rounds'. In an 'active round', participants send messages to each other.
  • A participant considers a round 'complete' when they have collected sufficient messages from other participants, processed those messages, and updated their multisig account state.
  • Typically (as implemented in this module), completing a round coincides with making a message for the next round. param: num_signers - number of participants in multisig (N) param: threshold - threshold of multisig (M) return: number of kex rounds required

◆ multisig_setup_rounds_required()

std::uint32_t multisig::multisig_setup_rounds_required ( const std::uint32_t num_signers,
const std::uint32_t threshold )

brief: multisig_setup_rounds_required - The number of setup rounds required to produce an M-of-N shared key.

  • A participant must complete all kex rounds and 1 initialization round. param: num_signers - number of participants in multisig (N) param: threshold - threshold of multisig (M) return: number of setup rounds required

◆ remove_key_from_mapped_sets()

void multisig::remove_key_from_mapped_sets ( const crypto::public_key & key_to_remove,
multisig_keyset_map_memsafe_t & keyset_inout )
static

INTERNAL

brief: remove_key_from_mapped_sets - Remove a specified key from the mapped sets in a multisig keyset map. param: key_to_remove - specified key to remove inoutparam: keyset_inout - keyset to update

Variable Documentation

◆ PUB_ADDRS

list multisig.PUB_ADDRS = [case[2] for case in TEST_CASES]

◆ TEST_CASES

list multisig.TEST_CASES
Initial value:
1= \
2[
3# M N Primary Address
4 [2, 2, '45J58b7PmKJFSiNPFFrTdtfMcFGnruP7V4CMuRpX7NsH4j3jGHKAjo3YJP2RePX6HMaSkbvTbrWUFhDNcNcHgtNmQ3gr7sG'],
5 [2, 3, '44G2TQNfsiURKkvxp7gbgaJY8WynZvANnhmyMAwv6WeEbAvyAWMfKXRhh3uBXT2UAKhAsUJ7Fg5zjjF2U1iGciFk5duN94i'],
6 [3, 3, '41mro238grj56GnrWkakAKTkBy2yDcXYsUZ2iXCM9pe5Ueajd2RRc6Fhh3uBXT2UAKhAsUJ7Fg5zjjF2U1iGciFk5ief4ZP'],
7 [3, 4, '44vZSprQKJQRFe6t1VHgU4ESvq2dv7TjBLVGE7QscKxMdFSiyyPCEV64NnKUQssFPyWxc2meyt7j63F2S2qtCTRL6dakeff'],
8 [2, 4, '47puypSwsV1gvUDratmX4y58fSwikXVehEiBhVLxJA1gRCxHyrRgTDr4NnKUQssFPyWxc2meyt7j63F2S2qtCTRL6aRPj5U'],
9 [1, 2, '4A8RnBQixry4VXkqeWhmg8L7vWJVDJj4FN9PV4E7Mgad5ZZ6LKQdn8dYJP2RePX6HMaSkbvTbrWUFhDNcNcHgtNmQ4S8RSB']
10]