Closed PopcornPaws closed 10 months ago
There is a little confusion here. Either we use adaptor signatures to ensure atomicity off-chain, or we use a smart contract-based solution in which the contract's logic ensures atomicity, and then there is no need to have adaptor signatures.
In my view, there are three valuable comments in this issue so far:
Okay, thanks for clearing that up @seresistvanandras ! Yeah, I guess the adaptor signature part can be a separate issue. I already have a baseline implementation for a Schnorr signature on secp256k1
but we should probably implement one for the ECDSA version as well, which is used by Ethereum.
For the sake of posterity, here are some adaptor signature implementations I found:
secp256k1-zkp
- essentially a wrapper around libsecp256k1
which is written in C. I'd avoid this, because I used this in a few projects and building Rust with C bindings can be painful sometimes on different platforms. IMO let's just keep the code as homogeneous as possible.ecdsa_fun
- also uses secp256k1
under the hood, see previous pointfarcaster_core
- very Bitcoin specific with structs like Alice
and Bob
, I'm not sure this is what we would need, but I'll just leave it here.Personally, I'd only use arkworks
crates for this project, we just have to implement the AdaptorSignature
trait for the ECDSA version of signature generation on secp256k1
. I'll make this a separate issue probably.
Nice overview on the available adaptor signature implementations.
+1 for arkworks
. It should be our choice.
p.s.: I have a vague thought that maybe the issue mentioned in the very first post of this issue in the adaptor-signature-based implementation, namely that the client can preemptively spend the money before the server adapts the signature, could be prevented with the usage of the CREATE2
opcode. Maybe I'm wrong, and there is no solution that uses the CREATE2
opcode....anyways, this preemptively spending the money from the client's address feels like an orthogonal problem that I don't know we need to pay much attention to.
@seresistvanandras if you think the contract is finished on a demo-level, we can close this issue right?
Yepp...I've just added the Solidity code of the ElGamal protocol to the paper. There are countless future directions but let's leave it to future work! As a proof of concept, it should be fine! Closing! Thanks for the discussion!
Goal
The goal of this issue is to start a conversation about the smart contract structure and design choices. We want to make payments atomic, i.e. the number of messages between the client and the server should be minimal. Thus, if possible, we want to implement something better than a traditional escrow contract where the buyer locks tokens and the seller can only access these tokens if the conditions programmed into the smart contract are met.
In our case, the buyer is the client who pays the server for the decryption key of some encrypted data. The server is the seller who should only receive payment if they provide valid encrypted data to the client. Furthermore, upon receiving the payment, the server must send the valid decryption key for the encrypted data.
We can see that the above scenario takes multiple steps (transactions) and requires the client to trust the server. Thus, by making the above scenario atomic, we could eliminate the trust factor.
Adaptor signatures
Adaptor signatures, in theory, could be used to make the outlined scenario atomic. The process would look like this:
Note, that all steps above can be executed offline, except for the step where the server submits the transaction on chain, making the whole process atomic from the network's perspective.
Concerns/questions
However, my main concern about this is that nothing enforces the client to sign the transaction with a wallet that indeed holds enough funds for the transaction to succeed. I.e. if the client's signer wallet is empty, the submitted transaction will fail because there's not enough funds to transfer to the server's address.
Another concern of mine---although it might just be that I don't fully understand adaptor signatures yet---is that funds can only be transferred from the client's address if the client is the transaction signer. But in case of an adapted signature, the ultimate signer will be the server, thus they cannot just send a transaction that transfers funds from another address to their address. The client just "pre-signs" the transaction, thus, from the network's perspective, it will be the server who sends the adapted, valid transaction that attempts to transfer funds from the client's address.
Possible solution
Thus, it might not be possible to reduce the whole protocol to a single transaction. I see the following solution
The only problem I currently see with this solution is that the server may malfunction/etc. and never submit a transaction, meaning that the client's funds are locked forever. Thus, we should provide the option for the user to withdraw their locked funds after a week or something. If the client could withdraw their funds at any time, they could withdraw it at a point where the server's transaction has already been submitted, meaning that the client gets back their funds and the server's transaction will fail. However, the adapted signature of the failed transaction will still be visible and the client gets the decryption key without payment to the server.
Thus, there should be at least three callable functions in this contract:
lockFunds(client_address, server_address, amount, pre-signature)
withdrawFundsClient(client_address, server_address)
- here's an example to check expiration usingblock.timestamp
withdrawFundsServer(server_address, client-address, adapted-signature)
- the provided adapted signature should be checked against the storedpre-signature
submitted by the clientNot sure about the state yet, but we should store the locked amounts and pre-signatures in a map that has the concatenated
server_address
andclient_address
as key?Let me know @seresistvanandras what you think.