I propose an update to the existing swap protocol that will dramatically reduce the gas costs to deploy the contract and call Claim/Refund.
the current protocol verifies that the secret passed to the contract (either s_a
or s_b
) corresponds to the public key of either Alice or Bob (that was set when the contract was deployed) by performing an ed25519 scalar base multiplication and checking that the resulting point == the public key. this is expensive (around 1mil gas currently)
however, this can be replaced by only verifying a keccak256 hash (30 gas!!)
for background, a monero private view key is derived from the private spend key as follows:
func (k *PrivateSpendKey) View() (*PrivateViewKey, error) {
h := Keccak256(k.key.Bytes())
vk, err := ed25519.NewScalar().SetBytesWithClamping(h[:])
if err != nil {
return nil, err
}
return &PrivateViewKey{
key: vk,
}, nil
}
first, the spend key is hashed using keccak256 and then set to a point on the ed25519 curve using clamping. the resulting scalar is the view key.
the updated protocol is as follows:
- in the key exchange step, Alice and Bob exchange public spend keys (
P_a
and P_b
) and private view keys (v_a
and v_b
), and additionally the keccak256-hashes of their private spend keys (h_a
and h_b
) that are used to derive their private view keys. when each party receives the other party's keys, they verify that the hash they receive corresponds to the view key.
- Alice deploys a Swap contract storing the keccak256 hashes
h_a
and h_b
in the contract. Claim can be called by revealing the pre-image to h_b
(ie. s_b
) and Refund can be called by revealing the pre-image to h_a
(ie. s_a
)
- the rest of the protocol proceeds as usual - Bob locks his XMR in the account
P_a + P_b
, which is viewable with v_a + v_b
and spendable with s_a + s_b
. either Claim or Refund will be called on the contract, and thus one party will end up with the spend key to the account at completion of the protocol.
note: we don't verify in step 1 that the view key corresponds to the public spend key, as it's impossible to do so. however, if the public spend key does not correspond to the view key, then the funds cannot be viewed. before Bob locks his XMR, he can check that he can generate a view-only wallet using the summation of the two view keys. if he cannot, he should abort the protocol as the view keys and public keys do not correspond. or, on Alice's side, if she cannot view the funds after they are locked (as the view keys are wrong), she should abort.
implications:
- the only drawback I see to this method is that both Alice and Bob now have the secret view key to the account with the locked XMR, so at the end of the protocol, now both Alice and Bob can view when the funds are transferred out. I don't see this being an issue, as Alice can just transfer the funds to another account once the swap is done if she wishes. either way, both parties know of the amount being swapped to begin with, so it doesn't really reduce privacy imo.
- actually, as the libp2p messages aren't encrypted, there's a chance anyone can get the secret view keys and create a view-only wallet for the account. however if someone intercepts the messages between Alice and Bob, they also already know of the amounts transferred and where. so, as long as Alice transfers her funds out after the swap (if she cares about someone viewing the account), I think this is ok.
I'll work on updating the contract/code for this and reply with the benchmark updates. and of course, let me know if there are security issuse with this proposed update.