Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Secret Network uses both symmetric and asymmetric encryption protocols. Specifically, asymmetric cryptography is used for achieving consensus and sharing secrets between nodes and users, whereas symmetric cryptography is used for input/output encryption with users of Secret Contracts, as well as internal contract state encryption.
Secret Network Protocol uses the Elliptic-curve Diffie-Hellman (ECDH) key exchange mechanism between users and validators. This process involves the user, the Secret Blockchain, as well as the trusted component of the Secret Protocol. It is initiated any time a transaction is sent from the user to the Secret Contract.
The encryption and key derivation logic Secret Network uses are as follows:
HKDF-SHA256 function for deterministic key derivation;
ECDH (x25519) function for generating public / private key pairs; and
AES-128-SIV symmetric encryption scheme.
A combination of the above symmetric and asymmetric encryption methods is used to create a safe process for the bootstrapping of the decentralized network, the addition of new SGX nodes, and the encryption of input, output, and state. The management of all the private and public keys may only be shared under specific conditions, and others never leave the SGX instance to ensure private data handling.
The Secret Network uses a random number called the “consensus seed” as a parameter to derive a public and private key set used by the Network for encryption purposes. The consensus seed is unknown to any party in the ecosystem and was created at the genesis of the network by the network itself. For deterministic key generation, the network uses a known “salt” which is chosen to be the hash of the Bitcoin halving block.
As a transaction is initiated by a user of the network they derive Input Key Material (IKM) using their own private key and the network-generated public key, the network derives the same IKM using the user's public key and the network-generated private key. An encryption key for the transaction is then derived inside the TEE from the IKM, the salt, and a random number generated with the consensus seed. The encryption key is used to encrypt the input specific to this transaction. Only the protocol and the user signing the transaction have access to the encryption key, and therefore access to the input, output, and state related to this specific smart contract computation.
When a full node resumes network participation, it reads consensus_seed
from $HOME/.sgx_secrets/consensus_seed.sealed
, does the same key derivation steps as above in steps 2-5.
The new full node verifies the remote attestation proof of the bootstrap node from genesis.json
and creates a remote attestation proof for their own machine to show to the network that the node's Enclave is genuine.
Using HKDF-SHA256, hkdf_salt
and nonce
(a 256 bit true random) a private key is derived. From registration_privkey
calculate registration_pubkey
The node needs to send an secretcli tx register auth
transaction with the following inputs:
The remote attestation proof the node's Enclave is genuine
registration_pubkey
256 bits true random nonce
On the consensus layer, inside the enclave of every full node the auth transaction comes in.
The Network validator nodes:
Receive the secretcli tx register auth
transaction
Verify the remote attestation proof that the new node's Enclave is genuine
seed_exchange_key
seed_exchange_key
: An AES-128-SIV encryption key is used to send consensus_seed
to the new node
This key is derived in several steps:
This IKM is never publicly available and protects the Secret network private entropy
In the second step seed_exchange_key
is derived using HKDF-SHA256 from seed_exchange_ikm
and nonce
. When sending the seed_exchange_key
to new nodes the Nonce is added as plaintext, it just serves the function of making each seed_exchange_key
unique.
consensus_seed
with the new nodeThe seed_exchange_key
generated in step 5 is used to encrypt the consensus_seed
. The AD
for this encryption algorithm is the public key of the new node: new_node_public_key
All this logic is done in side the Authorization transaction. secretcli tx register auth
outputs the encrypted_consensus_seed
The encrypted output is received by the new full node. The new node now has access to the encrypted_consensus_seed
and will have to decrypt to plaintext to receive the consensus_seed
seed_exchange_key
The AES-128-SIV encryption key seed_exchange_key
is used to decrypt consensus_seed
To derive this the reverse logic is followed highlighted in step 5.
First the same seed_exchange_ikm
is derived using ECDH (x25519) with consensus_seed_exchange_pubkey
(public in genesis.json
) and registration_privkey
(available only inside the new node's Enclave) This is the DH-key echange in action as this is the reverse public/private input of the IKM generation in step 5.
seed_exchange_key
is derived using HKDF-SHA256 with seed_exchange_ikm
and nonce
encrypted_consensus_seed
encrypted_consensus_seed
is encrypted with AES-128-SIV, seed_exchange_key
as the encryption key and the public key of the registering node as the ad
as the decryption additional data The new node now has all of these parameters inside its Enclave, so it's able to decrypt consensus_seed
from encrypted_consensus_seed
and then seal consensus_seed
to disk at $HOME/.sgx_secrets/consensus_seed.sealed
An extensive discussion of Secret Network's cryptography
Secret Network recently upgraded to , which rotated the network consensus seed during the upgrade.
A consensus seed is a true random 256 bit seed that is used as entropy for generating shareable keypairs between the nodes of the network.
Previously, the consensus seed remained unchanged ever since the network’s inception–the network state was encrypted using private keys generated during the network bootstrapping from a consensus seed, similar to a universal trusted zero knowledge setup. However, if anyone were to gain access to this seed they would have the master key to decrypt the state of the entire network. Thus, Secret Network has introduced consensus seed rotation in order to increase network security.
In order to protect against potential future breaches, Secret Network developed a two-part protocol for changing the consensus seed:
Rotate the current seed (The "Genesis" seed) and change the encryption scheme
Implement contract state migration and allow seed rotation on upgrade (currently in development)
It is important to note that the upgrade to consensus seed rotation does not change the state (and the consensus seed) of the network prior to the upgrade. This means that the new encryption scheme must be able to distinguish between values that were encrypted with the genesis seed and those that will be encrypted with future seeds. To this end, the following features were implemented:
A way to distinguish between values that were encrypted with the genesis seed and those that will be encrypted with future seeds
The ability to iterate over all of the keys for a specific contract using CosmWasm iterators (currently in development)
The ability to decrypt state keys, rotate the seed, and decrypt and re-encrypt all keys & values in the state
In order to rotate the Genesis seed, a new seed must be created that will be shared with all current nodes as well as new nodes. To this end, Secret Labs updated all of the existing nodes with the new seed and every new node that joins the network will contain 2 consensus seeds (The genesis and the current) and will use them both based on the encrypted value.
The new seed can be received via three methods:
On upgrade: When upgrading to 1.7.1, the node will identify that the current seed is missing and will communicate with Secret Labs’ seed service in order to obtain the seed
On Registration: On registration, both the current and the genesis seed will be passed to the newly registered node
On Bootstrap: Boostrap will access the seed service unless the "use_seed_service_on_bootstrap" feature is off (Which is the default state in localsecret). If so, it will generate one instead.
In the previous encryption scheme, the key and the value were stored as follows:
In the new encryption scheme, the plaintext key is no longer necessary in order to decrypt the value. The encrypted value also looks a bit different in the new scheme:
This new encryption scheme ensures that:
the encrypted_state_key encrypts differently between different keys
The salt will verify that on different instances, the same value is encrypted differently for the same key. The salt is the current block's timestamp and the msg id, which is a counter of the messages and allows for different values between different messages in the same block.
In order to authenticate a node, the node first sends an attestation report to the designated /authenticate endpoint as the request body. The server then responds with a challenge, which is a randomly generated 4-byte value that is linked to the public key of the node. The node then creates a new attestation report that incorporates the challenge into its quote, which proves that the node can generate new attestation reports certified by Intel while also rendering old certificates invalid. Subsequently, the node transmits this new attestation report to the /seed/[id] endpoint, where the ID represents the desired seed. Upon receiving the attestation report, the server verifies it and sends the seed to the node.
The port of the service is 4487 and there are 2 DNS names that are used.
On MainNet - sss.scrtlabs.com
On Pulsar - sssd.scrtlabs.com
Secret Network has implemented consensus seed rotation in the upgrade to version 1.7.1. Previously, the consensus seed remained unchanged since the network's inception, but this posed a security risk as anyone with access to the seed would have the master key to decrypt the entire network's state. The new consensus seed rotation includes a two-part protocol to change the genesis seed and encryption scheme, and implement contract state migration to allow seed rotation on upgrade. The upgrade does not change the network state prior to the upgrade, so the new encryption scheme distinguishes between values encrypted with the genesis seed and those encrypted with future seeds. Secret Labs updated all existing nodes with the new seed and new nodes joining the network will have both the genesis and current seeds, using them based on the encrypted value. These updates increase the security of Secret Network by protecting against potential future breaches.
Secret Network is set up to perform computation while having encrypted state, input and output. The state is encrypted using private keys generated during the network bootstrapping from a consensus_seed
. The bootstrap node was the first full node on the network and generated the shared secrets similar to a universal trusted zero knowledge setup.
The bootstrap node first does a remote attestation to prove they are running a genuine SGX enclave with updated software. After registering the bootstrap node handled the initialization of following variables:
Consensus_seed
a true random 256 bit seed used as entropy for generating shareable keypairs between the nodes of the network.
consensus_seed_exchange_pubkey
- consensus_seed_exchange_pubkey
an HDKF private key and a matching curve25519 public key for encryption of the random seed and sharing this with other full nodes in the network.
consensus_io_exchange_pubkey
- consensus_io_exchange_pubkey
an HDKF private key and a matching curve25519 public key for encrypting transactions IO in the network. Also referenced as the "Secret Network keypair".
consensus_state_ikm
An input keyring material (IKM) for HKDF-SHA256 is used to derive encryption keys for contract state.
consensus_callback_secret
A curve25519 private key is used to create callback signatures when contracts call other contracts
The bootstrap node proves to have a genuine enclave after which it can participate in the network. More information can be found on .
consensus_seed
The bootstrap node is instructed when started to generate a true random 256 bit seed inside the enclave, the consensus_seed
.
The consensus_seed
is sealed with MRSIGNER to a local file : $HOME/.sgx_secrets/consensus_seed.sealed
For the network to start decentralizing the bootstrap node needs to be able to share the consensus_seed
. The network can then use the seed to create shared secrets while in the enclave. To securely share the seed the Network uses a DH-key exchange.
Using HKDF-SHA256, hkdf_salt
and consensus_seed
a private key is derived. From consensus_seed_exchange_privkey
calculate consensus_seed_exchange_pubkey
Using HKDF-SHA256, hkdf_salt
and consensus_seed
a private key is derived. - From consensus_io_exchange_privkey
calculate consensus_io_exchange_pubkey
consensus_state_ikm
Using HKDF-SHA256, hkdf_salt
and consensus_seed
derive consensus_state_ikm
5. consensus_callback_secret
Using HKDF-SHA256, hkdf_salt
and consensus_seed
derive consensus_callback_secret
Publish to genesis.json
:
The remote attestation proof that the Enclave is genuine
consensus_seed_exchange_pubkey
consensus_io_exchange_pubkey
When a contract is executed on chain the state of the contracts needs to be encrypted so that observers can not see the computation that is initialized. The contract should be able to call certain functions inside the enclave and store the contract state on-chain.
A contract can call 3 different functions: write_db(field_name, value)
, read_db(field_name)
, and remove_db(field_name)
. It is important that the field_name
remains constant between contract calls.
We will go over the different steps associated with the encryption of the contract state.
contract_key
The contract_key
is the encryption key for the contract state and is a combination of two values: signer_id || authenticated_contract_key
. Every contract has its own unforgeable encryption key. The concatenation of the values is what makes every unique and this is important for several reasons
Make sure the state of two contracts with the same code is different
Make sure a malicious node runner won't be able to locally encrypt transactions with it's own encryption key, and then decrypt the resulting state with the fake key
so to reiterate, every contract on Secret Network has its own unique and unforgeable encryption key contract_key
This process of creating contract_key
is started when the Secret contract is deployed on-chain. First authentication_key
is generated using HDKF-SHA256 inside the enclave from the following values:
consensus_state_ikm
HDK-salt
signer_id
From the authentication_key
create authenticated_contract_key
by calling the hmac-SHA256 hash function with the contract code_hash
as hashing data.
This step makes sure the key is unique for every contracts with different code.
Lastly concat the signer_id
and authenticated_contract_key
to create contract_key
. This step makes it so the key is unforgeable as the key can only be recreated with the current signer_id
contract_key
with enclaveEvery time a contract execution is called, contract_key
should be sent to the enclave. In the enclave, the following verification needs to happen to proof a genuine contract_key
write_db(field_name, value)
read_db(field_name)
remove_db(field_name)
Very similar to read_db
.
To do deterministic key generation inside the SGX enclave Secret Network leverages HDKF-SHA256 . HDKF-SHA256 is a key derivation function for symmetric (private key) encryption. The function generates a 256-bit encryption key from a common public "salt" and a piece of Input Key Material (IKM). The salt
for the use in the Secret Network encryption schemes is chosen to be the Bitcoin's block halving hash hkdf_salt = 0x000000000000000000024bead8df69990852c202db0e0097c1a12ea637d7e96d
HDKF is commonly used to extract entropy from a larger source and deliver smaller output (eg. an encryption key) as well as expand already existing random output into a larger cryptographic-ally independent output. The deterministic keys coming from HDKF can be shared amongst network participants without revealing the underlying randomness. In the end this symmetric function is used to ensure safety for the pseudo-random consensus_seed
and secure the shared secrets of the network participants.
The output of the HDKF is a curve25519 private key, which can be used to derive a public key as well.
Elliptic-curve Diffie-Hellman () is a key derivation protocol designed to support assymetric encryption by returning a public-private key pair. ECDH allows for sharing secrets over public channels as one needs the private key to decrypt information while using the public key for sending the encrypted message. These Shared secrets can be used by both parties to then set up subsequent symmetric keys with functions like HDKF as mentioned above. ECDH delivers 256 bits Curve25519 encryption keys which have a probabilistic level of security of 2^128.
ECDH also allows for a special way of generating shared secrets which involves using the private and public key of both participants. Participant A and B can create a shared secret by doing: ecdh(Apriv, Bpub) == ecdh(Bpriv, Apub)
, this feature is called "key-exchange" and is the basis of sharing information amongst network participants on Secret Network.
For additional explanation of Diffie-Hellman, check out .
Advanced Encyption Standard (AES) is an encryption algorithm slightly varying from the block cipher "Rijndael" set to a fixed 128 bits size block. The algorithm generates 256 bit encryption keys which offer very high security guarantees.
The AES-SIV encryption scheme is a perfect addition to the ECDH keypairs used in SGX enclaves. The combination allows for sharing encrypted data amongst nodes and protecting the private entropy of the protocol. was chosen to prevent IV misuse by client libraries. The algorithm does not pad ciphertext which leaks information about the plaintext, in particular its size.
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.
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
.
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.
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.
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.
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:
on a Contract
message, the msg
value should be the same msg
as in our tx_input
, so we need to prepend the nonce
and tx_sender_wallet_pubkey
just like we did on the tx sender above
On a Contract
message, we also send a callback_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
from genesis.json
and nonce
from the tx_input
that is attached to the tx_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:
The output of the computation is encrypted using the tx_encryption_key
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