Open UkoeHB opened 4 years ago
After a multisig group key image has been created, it is useful to also prove it is a legitimate key so other cosigners can learn it without needing to go through the whole process again. The most straightforward way, which any M cosigners (for M-of-N multisig) can do together, is a multibase Schnorr signature on base keys (G, KI^{inv})
, and public keys (K^(grp), U)
(see zero to monero 2 chapter 8 and section 9.5).
Triptych, a next-generation transaction protocol under consideration for Monero, uses a style of key images different from Monero's current key images (also RingCT3.0 and one version of Omniring). This poses some challenges for multisig-based transactions, where key images must be constructed by collaboration between cosigners. Other details related to multisig are not discussed here.
Note: To transition from current bLSAG-style key images to inversion-style key images, the question of verifying double spends comes up, since double spends are identified when the same key image appears. The simple solution is that post-hardfork all new outputs can only be spent with TriptychType1 transactions (that use Triptych to sign them), while all old (pre-Triptych) outputs can only be spent with RingCT transactions (signing with MLSAG, or CLSAG). This way key images are clearly related to subsets of outputs, with no risk of cross-over. Note that in practice it means ring membership is constrained.
Key images; before and after
Using the hash-to-point function
H_p()
, and one-time addressK^o
(with private keyk^o
), our current key images are made like thisKI = k^o*H_p(K^o)
In Triptych (and others), key images are made like this, where
U
is an elliptic curve generator (not the normal oneG
), e.g.U = H_p("U")
(or something similar)KI^{inv} = (1/k^o)*U
Current multisig, where multiple participants, indexed
e
, own components of the group's private key (e.g.k^{o,grp} = k^o_1 + k^o_2 + ...
) reconstruct the key image as a simple sumKI = \sum k^o_e*H_p(K^{o,grp})
Clearly that won't work with Triptych key images, which contain an inversion of the private key. Thankfully, Paillier encryption, which I won't pretend to understand, provides a route to constructing aggregate inversions without compromising any participant's share of the full private key (see Gennaro and Goldfeder's original paper, especially Section 3).
Inversion-style aggregate key images for multisig
The method explained here was first explored for Monero by @SarangNoether. My objective is to document the process (also documented by sarang here), and also recommend some optimizations regarding message rounds.
An aside: Paillier encryption
First it will be helpful to lay out Paillier encryption, which is very RSA-esque.
N = p*q
, wherep
andq
are prime numbers. The private key isphi = (p-1)*(q-1) mod N^2
.m
using a randomly generated scalarr
withE(m) = [(1+N)^m * r^N] mod N^2
.m = [[E(m)^(phi) mod N^2 - 1]/N * (1/phi mod N)] mod N
. Note thatr
'disappears' during decryption, and so only the encrypter needs to know it.The process
There are many participants, indexed
e
, with componentsk_e
of a group keyk^{grp}
, where the aggregate public key isK^{grp} = (\sum k_e)*G
, who wish to construct the inversion-style key imageKI^{inv} = (1/k^{grp})*U
. In each round participants will perform some computations then send information to other participants, and the next round doesn't begin until the previous round is done.N_e
.e
a) privately generates a random scalargamma_e
, computesgamma_e*U
, and generates a Schnorr signaturesigma_e
proving knowledge ofgamma_e
ingamma_e*U
b) privately generates a commitment maskx_e
, and computes the commitmentC_e = H_p("MPC gamma commit", gamma_e*U, x_e)
c) privately, for each other participanti
, generate a random scalarbeta_e_i
d) privately encrypts their private key with their Paillier public keyN_e
,E_e = E_e(k_e)
e) sendsC_e
andE_e
to the other participantse
a) privately computes, for each other participanti
(using the valuebeta_e_i
generated for them earlier),c_e_i = [E_i(x)^gamma_e mod N_i^2]*E_i(-beta_e_i) mod N_i^2
b) sendsc_e_i
to participanti
e
a. privately computes, using the valuesc_e_i
received from other participants,alpha_e_i = decrypt(c_e_i, N_e)
for each of those participants; this is where the Paillier encryption magic shows its face (although exactly how, I couldn't say) b. privately computeslocal_delta_e = k_e*gamma_e + \sum_i alpha_e_i + \sum_i beta_e_i
c. sendsgamma_e*U
(the value committed to inC_e
) andx_e
,sigma_e
, andlocal_delta_e
to the other participantse
a. privately verifies for each other participanti
, thatC_i ?= H_p("MPC gamma commit", gamma_i*U, x_i)
b. privately computes the full key imageKI^{inv} = (\sum_e local_delta_e)^(-1)*(\sum gamma_e*U)
Seamless escrowed multisig
For a 2-of-3 escrowed marketplace, with buyer, vendor, and moderator, it is important to minimize the number of communication rounds. Escrowed markets with the current Monero transaction protocol can do collaborative transaction signing in the following steps (A is the buyer, B is the vendor). Please see Zero to Monero: Second Edition, chapter 10. There is a controversial optimization, namely single-commitment signing, which I won't get into here, but is a big part of the system I designed (and also part of this key image process).
Thankfully, making inversion-style key images can fit into that framework without disrupting the existing pattern.
N_B
, andE_B
, which were pre-computed/prepared by B. B's private key component is the shared secret between buyer-moderator, while A's private key component will be the sum of buyer-vendor and buyer-moderator key components and the part related to the sender-receiver shared secret based on the view key for a given one-time address owned by the multisig group (for efficiency, even though the buyer will also know the buyer-vendor key component and view key component).gamma_A
, computesgamma_A*U
, generatesx_A
, generatesbeta_A_B
; [stuff to send] computesE_A
,c_B_A
,C_A
, and prepares Paillier keyN_A
alpha_B_A
, generatesbeta_B_A
; [stuff to send] computesc_A_B
,local_delta_B
,gamma_B*U
,sigma_B
. He does not create a commitment forgamma_B*U
(I don't know if this is a legitimate simplification).alpha_A_B
,KI^{inv}
; [stuff to send]gamma_A*U
,x_A
, createssigma_A
, computeslocal_delta_A
C_A
, and computesKI^{inv}
Crucially, A learns
K^{inv}
in step 3 when she needs to make her partial signature, and likewise B learns it in step 4 when he finishes the signature.