Ethereum Privacy: Proof of transaction
This third publication on Ethereum Privacy explains how to extract a proof of a private transaction done over a public blockchain.
Read the introduction and how to get started articles to get familiar with the concepts.
When a transaction is done between two or several parties through
“Ethereum Privacy”, in case of conflict, a party will certainly need to prove to the other that he has received and processed what he was supposed to, or that he has sent what he needed to via the public chain.
This is naturally possible, thanks to the fact that the transaction content is stored, encrypted, in the smart contract in the public blockchain (and therefore not alterable over time).
Say that Alice submits an offer to Bob in the context of a tender implemented via Ethereum Privacy and that Bob accepts Alice’s offer. Bob should be able to prove Alice offer price and content and Alice should be able to prove that Bob has accepted her offer. Let’s see what happen.
Understanding the sending of a private transaction
Each of Alice and Bob actions (making and accepting the offer) are private transactions. A private transaction is a standard Ethereum transaction created and signed by the sender’s wallet (Alice and respectively Bob’s wallet), that gets stored in the PrivateTxStorage smart contract in the public blockchain by a privacy node (Alice and respectively Bob’s node).
First, at the level of the private transaction created by Alice (or Bob) the action is encoded as an interaction with a smart contract that has been created before. This transaction is signed with Alice’s wallet, ie Alice must have access to the private key of that wallet.
Alice’s privacy node generates a json web token that gets signed with the private key of Alice’s node. Alice (or someone she trusts) must control that private key. The JW Token contains a gzip of the transaction and the public key of the privacy node.
Alice’s privacy node generates a symmetric 32 bytes key and a 16 bytes random init vector for AES-256-CBC encryption algorithm, and a unique id for the transaction.
Alice’s privacy node then sends to the public blockchain the symmetrically encrypted JWT via transactions signed by a local wallet that it must have the private key for. The transactions contains 320 bytes parts of the encrypted JWT to reduce the size of each transaction and facilitate its inclusion into the public chain of blocks. Then for each receivers (itself and Bob’s node) Alice’s node encrypts with the public key of the recipient the entry id of the transaction and the aes elements to decrypt the JWT and generates events in the public smart contract
Receiving the private transaction
When Bob’s privacy node sees an event in the public smart contract, it can (try) decrypt(ing) the aes elements with its private key to get the id of the transaction and the symmetric key.
It can then extract from the smart contract the encrypted JWT parts and get the public key of the sender from it. It then checks that Alice node’s public key exists in its PKI and that it is trusted and still valid.
Alice raw transaction can then be extracted and sent to the local private Ethereum VM to be executed by Bob’s copy of the smart contract. Smart contract logic can check that Alice’s wallet is authorised to place the offer.
Alice’s privacy node performs the same process, except that since she always trusts her own public key (derived from her private key) checking it against the PKI is not necessary.
The process for Bob’s transaction accepting Alice’s offer is identical and does not need to be described here.
Getting the transaction proof
Bob can query his privacy node to extract a transaction proof corresponding to the hash of Alice’s transaction by calling the admin_getTransactionProof rpc method with the private tx hash as single parameter. Doing so Bob will get a json object with the following information
ofTxHash: the private tx hash this proof relates to
input: address of the smart contract in the public blockchain and the id of the entry. The aes key and init vector are not retrieved as they are not needed for the proof
decryptedPayload: the decrypted JWT that can be verified with the sender’s public key
sender: the public key in PEM format, the PKI response for this public key at the time of transaction received and as of the generation of the proof
request: the json rpc request that was submitted by the sender that contains a raw transaction from the JWT
storedAt: the public blockchain transaction and block where the event notifying the local privacy node has been made, including the wallet used by the sending privacy node
transactionFromRequest: the decoded raw transaction from the JWT, showing in particular the “hash”, that must be the same as the “ofTxHash” field and the “from” field that refers to the sending wallet (Alice’s wallet)
transactionReceipt: a standard web3 transaction receipt of this private transaction processed by the local private ethereum virtual machine.
How to answer contestations with the proof ?
- Let’s say, Alice contests the details of the offer Bob has received: Bob can get the transaction where Alice has made her offer and extract the related proof from the public blockchain. In that proof, Bob will be able to show that the transaction he has received was signed by Alice’s privacy node (decryptedPayload is a JWT that can be verified with Alice’s public key).
The content of the JWT can be decoded into the raw transaction that in turn can show what values have been passed to the tender smart contract.
It is not possible for anyone, without Alice’s private key, to fake a JWT signed by Alice, so it must Alice who made that submission. - If Alice says she had her private key stolen: It is still her responsibility what has been done with that private key. She would be responsible to declare the corresponding public key as invalid to all participants and communicate a new public key to be used. This would be the function of the PKI (public key infrastructure) to handle declaration and removal of public key. This is the reason why Ethereum Privacy relies on third party PKI solutions.
If Alice can prove that she has declared the private key stolen and communicated her new public key, but that Bob accepted the old public key, then it becomes Bob’s responsibility to have accepted the forged transaction. This implies that the PKI solution must also check the certificate revocation list before accepting the transaction. - Now, let’s say Alice claims that she never received Bob acceptation of her offer and therefore has no reason to honour her offer. Bob can then extract the transaction where he responded to Alice and extract the proof from the blockchain. The storedAt field is an autonomous proof that Bob’s transaction exists in the public blockchain. With that element, the event notifying Alice can be located in the blockchain (event with aes elements encrypted with Alice’s public key). That event is the proof that Alice was able to read Bob’s transaction and it becomes Alice’s responsibility to monitor the public blockchain for events that can be decoded with her private key. Note that this requires that the public key used for Alice is kept even if Alice changes her private key after the facts.
- There may be other cases to discuss and that can be handled with elements in the proof.