Transaction Encryption
Transaction encryption unlike contract state encryption has two parties who need data access. The scheme therefore makes use of the DH-key exchange as described in the previous section to generate a shared encryption key. This symmetric tx_encryption_key
is unique for every transaction and can be used by both the network and the user to verify the completed transactions.
1. Generation of shared secret - user side
Using the Eliptic-Curve Diffie Hellman key exchange (ECDH) the user generates a shared secret from consensus_io_exchange_pubkey
and tx_sender_wallet_privkey
.
2. Generate tx_encryption_key
- user side
tx_encryption_key
- user sideThe user then generates a shared tx_encryption_key
using HKDF-SHA256 and the tx_encryption_ikm
generated in step 1. The pseudo-random HDKF is used to ensure deterministic consensus across all nodes.
The random component comes from a 256-bit nonce so that each transaction has its own encryption key, An AES-256-GCM encryption key is never used twice.
3. Encrypt transaction - user side
After initiating a transaction the user encrypts the input data with the shared transaction encryption key, using an AES-256-GCM authenticated encryption scheme.
The input (
msg
) to the contract is always prepended with the sha256 hash of the contract's code. This is meant to prevent replaying an encrypted input of a legitimate contract to a malicious contract, and asking the malicious contract to decrypt the input.
In this attack example the output will still be encrypted with a tx_encryption_key
that only the original sender knows, but the malicious contract can be written to save the decrypted input to its state, and then via a getter with no access control retrieve the encrypted input.
4. Generation tx_ecryption_key
- network side
tx_ecryption_key
- network sideThe enclave uses ECDH to derive the same tx_encryption_ikm
from the tx_sender_wallet_pubkey
and the consensus_io_exchange_privkey
. The network then derives the tx_encryption_key
from the publicly signed nonce
and this shared secret using HDKF.
Within the trusted component the transaction input is decrypted to plaintext.
BREAK - Data output formatting
The output must be a valid JSON object, as it is passed to multiple mechanisms for final processing:
Logs are treated as Tendermint events
Messages can be callbacks to another contract call or contract init
Messages can also instruct sending funds from the contract's wallet
A data section which is free-form bytes to be interpreted by the client (or dApp)
An error section
Here is an example output for an execution:
Please Note!
on a
Contract
message, themsg
value should be the samemsg
as in ourtx_input
, so we need to prepend thenonce
andtx_sender_wallet_pubkey
just like we did on the tx sender aboveOn a
Contract
message, we also send acallback_signature
, so we can verify the parameters sent to the enclave (read more here: ......)
For the rest of the encrypted outputs we only need to send the ciphertext, as the tx sender can get
consensus_io_exchange_pubkey
fromgenesis.json
andnonce
from thetx_input
that is attached to thetx_output
with this info only they can decrypt the transaction details.Here is an example output with an error:
An example output for a query:
5. Writing output - network side
The output of the computation is encrypted using the tx_encryption_key
6. Receiving output - user side
The transaction output is written to the chain and only the wallet with the right tx_sender_wallet_privkey
can derive tx_encryption_key
. To everyone else but the tx signer the transaction data will be private.
Every encrypted value can be decrypted by the user following:
For
output["ok"]["messages"][i]["type"] == "Contract"
,output["ok"]["messages"][i]["msg"]
will be decrypted in by the consensus layer when it handles the contract callback
Last updated