NOTE: This would have to be checked by a cryptographer. It merely serves as a collection of thoughts on what the issues are and what might be a solution to these.
This document suggests that a slate could commit to a certain outcome of the participants for instance, the outcome could be the following:
Alice: -5
Bob: +2
Charlie: +3
Consider that Charlie is the last to do the key setup (partial excess and nonce) and the first to sign. This means that when he gets the slate, he sees all the previous contributed pairs of (excess, nonce) from both Alice and Bob:
Alice:
excess: AE,
nonce: AR,
Bob:
excess: BE,
nonce: BR,
Charlie:
excess: null,
nonce: null,
Since Charlie received the slatepack from Bob, it's impossible for him to know that AE really came from Alice. It could have just as easily been planted by Bob. This can be solved by providing a signature from Alice signing her contribution e.g.
Alice:
excess: AE,
nonce: AR,
sig: sig with Alice's grinaddress for challenge e=H(AE || AR),
Bob:
excess: BE,
nonce: BR,
sig: sig with Bob's grinaddress for challenge e=H(BE || BR),
Charlie:
excess: null,
nonce: null,
sig: null,
This might look secure at first, but it turns out it's not. This is because if Bob did a transaction with Alice before, they could have observed a triplet (AE, AR, valid_sig) which they could reuse the next time while choosing excess to be BE2 - AE
to subtract the need for Alice's partial signature. This might convince Charlie (or someone else) that Alice is a part of the total excess we are signing when in fact she is not.
The idea is very simple. We have to come up with a way to prevent any possibility of key cancellation by another party. To achieve this, we do the following. When party is ready to sign, they compute a new randomly scaled total excess for the transaction. Given a sequence of contributions
[
(AE, AR, sig(M=H(AE || AR)),
(BE, BR, sig(M=H(BE || BR)),
(CE, CR, sig(M=H(CE || CR))
]
every party computes what we will call slate challenges:
e00 = H(AE || AR || BE || BR || CE || CR || 00) # challenge for AE
e01 = H(AE || AR || BE || BR || CE || CR || 01) # challenge for AR
e10 = H(AE || AR || BE || BR || CE || CR || 10) # challenge for BE
e11 = H(AE || AR || BE || BR || CE || CR || 11) # challenge for BR
e20 = H(AE || AR || BE || BR || CE || CR || 20) # challenge for CE
e21 = H(AE || AR || BE || BR || CE || CR || 21) # challenge for CR
and the final total excess is computed as
E = e00*AE + e01*AR + e10*BE + e11*BR + e20*CE + e21*CR
We have scaled every contributed key randomly to prevent any kind of key cancelling. The party contributes the "scaled by challenges" partial signature e.g. Charlie contributes a partial sig for partial excess e20*CE
and nonce e21*CR
.
This gives us the following properties:
- Every party computes the same new excess deterministically from the given partial excess and nonce values
- If a party contributes their own random partial excess and nonce (meaning it doesn't reuse an old one), it is impossible for any other party to cancel another key because every slate challenge includes this new key in the hash and hence to cancel a key, you'd need to predict the challenge values
I think computing the excess this way guarantees the contributed partial signature is a commitment to these exact excess and nonce values and every party involved will have to contribute a unique signature for the new excess.
Is this secure?
It seems that if I'm a party in the transaction, all other parties will have to produce a partial sig that is unique for the slate's partial excess and nonce values.
Do we have to commit to amounts as well in slate challenges?
I think not. Even if we did commit to the amounts, it's impossible to tell the outputs reflect the commitment because we don't know how to open them.
@tromp these are valid question.
I myself am not sure how problematic this is. There's definitely an uncertainty in the slate because publicly contributed data could be planted or changed over time, but I'm not yet sure how this could be used apart from the "Charlie thought Alice was also a part of the transaction when she wasn't". Perhaps this cancellation could also be used in a m/n multisig by somehow convincing Alice is a part of the multisig they're making when she isn't, but I can't tell if that's the case since I don't know how a multisig on MW would look like. I agree that caring only about your net change seems enough and I've given up on this "immutable slate parts" idea since it adds too much complexity for some unknown gains. There's also a downside to committing to this state which is that you must know who the parties are which also removes plausible deniability. I decided to document this for when we encounter these ideas in the future.
I hope I'm not missing something obvious here. If you want to guarantee that every party must use the partial excess and nonce that you saw in the slate as part of total excess signing, then I'm not sure how you'd guarantee this with a MAC since a party can only see all of these values once they are ready to sign the total excess. Before that, the partial excess and nonce are not yet populated by all the parties. It seems the safest (and most obvious) way to guarantee this is to capture the party contributed data and do the same trick as used in Schnorr signatures. For a sequence of (pubkey, nonce) pairs, generate a challenge for every pub key present (I think we could skip challenging the nonces, I don't think it adds any more security). It's really just the same trick for challenging pubkeys as done in Schnorr except that it's for many (pubkey, nonce) pairs and not just for 1.
But it's of course possible that I made mistakes.