The documentation says that in order to encrypt input data, the user need to “Request the application key pair from the dApp config” and “Request an encryption public key from the dApp config”, but what is dApp config? If it refers to some server the dApp developers own, wouldn’t it be too dangerous to just give the dApp’s key pair to any user?
The current public release (MVT) is a developer release. There is only one encryption key. You can simply hard code it in your application. See this example: https://github.com/enigmampc/enigma-contract/blob/develop/integration/coin-mixer-2.js (like 238 in particular). In our next release, encryption keys will be assigned to each workers and distributed by the network.
It would be dangerous to give the encryption key material to any user, but we are only giving the encryption public key. Users encrypt data with a key derived from their own private key + encryption public key.
Hi, I’m still confused about whether the private key mentioned is a private key for an end user using a DApp, or part of a keypair that the DApp itself holds. If it’s the former, how does Enigma know which derived key to use to decrypt arguments when a compute task is submitted, if only the contract address is passed through in
compute()? And if it’s the latter, how would this private key be stored securely, and wouldn’t this allow users to decrypt data from other users?
- The dApp itself does not hold keys, only facilitates encryption and decryption with the specified keys.
- The dApp user has a private/public key pair (somewhat akin to a crypto wallet, where the public address is (a hash of) your public key that is publicly known, and your private key is only known to you.
- The node in the network that will compute a secret contract also has a private/public key pair, where the private key is only known inside the enclave (the owner of that computer that runs the node does not have access, nor anyone else has access either), and public key is publicly known.
Now, when a dApp user want to trigger a secret computation, gets the public key of the given node, and encrypts her inputs with the node public’s key, so that these parameters can only be decrypted inside the enclave with the node’s private key, and nowhere else.
Analogously, when the node has computed that task, and if there are outputs that need to be encrypted back to the user, the node will encrypt the output with the user’s public key, so that only the user can decrypt them with its private key (only known to her).
Does this clarify your question? Feel free to reply back with more questions.
@victor, Thanks for the thorough reply! Just to confirm-- the node doesn’t need to know which user encrypted the data in order to decrypt it, because it just needs to use its private key? I’m wondering why the examples in the guide use a derived key instead of the enclave’s public key. I thought that a derived key would be different for each user, and it doesn’t seem to match encryption using the recipient’s public key like you mentioned.
The guide is based on the initial developers’ release that we put out on June 30th of this year. It’s a sandboxed release for users to get started in the development of secret contracts, but doesn’t implement all of its features. In my explanations above, I was focused on the upcoming release where the Enigma network becomes live, and we release live on the Ethereum testnet, to later release it on mainnet.
Just to clarify, in the upcoming release I confirm that the node does not need to know which user encrypted the data in order to decrypt it because the data comes encrypted with the node’s public key, and only the node will be able to decrypt it with the node private key. Additionally, in that request the user includes his/her public key, in case the node needs to encrypt the results of the secret contract back to the user.
In the code examples that are linked above, as you point out the scheme is different from what’s explained above in the following:
- All the nodes have the same hardcoded private key (not to be used in production! )
- The node and the user establish a shared secret computing a derived key as you point out by computing each of their private key and the other’s public key, which is a symmetrical operation (Diffie Hellman)
Hope this clarifies the differences between both releases, and clarifies the answers in this post. Sorry for the confusion!
Thanks for clarifying, Victor! I understand now that the functionality in the guide for the developer’s release is different from the planned functionality of the live Enigma network.
Hi @victor, I have a couple followup questions about this quote from you:
“Analogously, when the node has computed that task, and if there are outputs that need to be encrypted back to the user, the node will encrypt the output with the user’s public key, so that only the user can decrypt them with its private key (only known to her).”
Are you using a standard ECIES implementation for this? Would it be possible for this process to have Trezor/ Ledger support? I wasn’t aware that these hardware wallets support decrypting an arbitrary message. For Trezor, the main contributor hasn’t found a standard that’s widely supported, and so this hasn’t been implemented on their side: https://github.com/trezor/trezor-crypto/issues/153. For Ledger, I can’t find any documentation on support for that sort of decryption.
If this isn’t possible, is there a workaround that the Enigma team has come up with to enable hardware wallets for encryption between the user and the enclave?
That’s a very good point. For now, we are focusing on software encryption and decryption.The cryptography primitives for the upcoming Discovery release remain the same as those included and documented in our first testnet release as a dockerized network from June 30, 2018 documented here:
From the link above, you will see that it is our understanding that there is no such a thing as a “standard” ECIES implementation, which you also refer to in your comment about Trezor, and thus it is not implemented in the most common crypto libraries. Thus we opted instead for ECDH.
In summary, we are currently implementing software encryption in the Enigma.JS library that dApps can leverage to interface between user and the enclave. Specifically, this is the implementation of the ECDH routine in our code, which will remain the same in the Discovery release:
(in the above release the keys were hardcoded elsewhere in the code, but this function is the generic implementation that takes any two private and public keys). Currently, we are not focusing on supporting hardware wallets for encryption between user and enclave, but we may consider as a future feature if there is interest (and we would most certainly accept contributions from the community to implement this feature! )
Thanks for the link and code snippet, Victor. I overlooked that section in the docs. I’m confused because earlier in this thread you said “in the upcoming release I confirm that the node does not need to know which user encrypted the data in order to decrypt it because the data comes encrypted with the node’s public key, and only the node will be able to decrypt it with the node private key.”. Does this mean you’re planning on using a symmetric ECDH key initially for the Discovery release, and then switching to another method later on?
With the symmetric key, the user will always need to send their public key to the enclave, correct?
The doc you linked me to said that “Any user that wants to encrypt a message for the enclave can generate a one-time asymmetric key-pair”. Are you expecting users to always generate a new keypair every time they send a message, and never use a persistent private key? If they generate a new keypair every time, how would they retrieve something that was stored on Enigma with a different keypair? How would the dApp logic be able to identify that user if the
msg.sender is different every time?
I looked into Trezor’s ECDH implementation, and it seems different than the one used by Enigma, since it doesn’t replace the Y and hash X and Y together, but instead seems to concatenate the X and Y after replacing the first byte. The doc mentions that Enigma “uses an adaptation of” ECDH. Would you happen to know if this adaptation is different from the Trezor implementation, and if so, why the specific adaptation for Enigma was chosen?
I followed up with some Trezor contributors about this, and it seems that it would be possible to retrieve the X and Y from a
get_ecdh_session_key API call, and then apply Enigma’s adaptation to the result.
One thing they pointed out was that once the ECDH symmetric key is derived, it could be exposed on the browser. Since the derived key is non-ephemeral, an attacker that obtains that key could use it to decrypt all past and future messages. I thought that Enigma was also using a similar non-ephemeral symmetric key. But I think my understanding was incorrect. Now I have a bunch of questions, for which I apologize in advance. All of this is concerning the Discovery release encryption implementation with the symmetric key.
Referring to the Enigma docs, this says that “The one-time symmetric key is generated with a key derivation function (KDF) that is yet to be specified”. Is it supposed to say “The one-time asymmetric key-pair key is generated with a key derivation function (KDF) that is yet to be specified”? Or is the KDF function related to ECDH somehow, and used in order to generate the symmetric key?
Is the use of a KDF the reason why it’s not an issue for the user to decrypt data that has been encrypted and stored with other one-time symmetric keys (generated from the use of one-time asymmetric pairs, which are generated with the KDF from the master key)?
If there is a KDF being applied to a master key, is this master key provided by the user? Does this mean the Dapp user has to call Enigma’s JS code with their private key? This is my primary concern, and is the reason why I want to enable the use of hardware wallets for this interaction.
I’m still not sure how a hardware wallet would be used for this. Would the firmware need to implement the same KDF function that Enigma chooses? If this is the case, would it possible to take hardware wallet implementations into consideration when determining that step? I think that it’s important that hardware wallets are used if Enigma is meant to be usable by the average person, and not just those who know how to set up a secure environment when using their private key.
I also realized I still don’t understand what the Dapp config is in the doc here. Is it part of the JS Enigma library on the frontend side?
Edit: I’m thinking now that the Dapp config is the application code on top of the Enigma library, since there’s already a client library in that diagram. If this is correct, how does it generate the
appKey mentioned in the diagram? Is this derived from the user’s key pair somehow?
I confused myself, please ignore the wall of text above. I think the Enigma protocol doesn’t require a hardware wallet at all to establish a symmetric key. Using a hardware wallet would only make sense if the key generation and message encryption were both done on that, as Victor suggested already. Aside from encrypting messages for Enigma, the user could use a hardware wallet to interact with the Dapp as usual, which I didn’t realize initially.
Here’s my current understanding of how the encryption process works:
- The Dapp config generates a random one-time asymmetric key pair. This does not require an existing private key.
- The private key of this generated key pair, and the public key of an enclave node, are used with ECDH to derive a shared secret.
- This shared secret is not suitable to be used directly as a shared key, so it’s passed through a KDF. The resulting shared key is used to encrypt transactions for Enigma.
- If the user wants to store data, they encrypt the data with this shared key and send it to the Dapp, along with the public key of the one time key pair. The Dapp somehow stores the encrypted data along with this public key.
- If a user wants to retrieve data from storage, this transaction is brokered through the Dapp, which will identify the user based on the public key they use to sign that transaction. It would then retrieve the stored data by somehow looking up the one-time public key that was associated with it.
@victor are the steps above correct? I’m still unclear on how encrypted data is stored and retrieved, if each message needs a one time public key to be stored with it.