Private Transactions

Note: This is an extension on work done by the JPMC Quorum working group

A quick overview

While a “permissioned” network does address privacy concerns to some extent, oftentimes there need to be additional layers of obscurity within an already isolated network. The Quorum client, through usage of a special module referred to as “constellation”, accommodates these concerns. The internal flow of private transactions in Quorum is outlined step-by-step below, however a basic grasp of the architecture is necessary before continuing.

The first key area of understanding is the separation of the Quorum node (a forked iteration of Geth containing a public and private Merkle Patricia Trie) and the concept of the constellation. The constellation is a module that accommodates private transaction processing and has two distinct sub-modules: transaction manager & enclave. The transaction manager stores encrypted payloads, encrypted symmetric keys and encrypted transaction hashes. These hashes serve as indexes for encrypted symmetric keys and their corresponding encrypted payloads, and allow clients to discover if they are privy to a private transaction when they attempt to execute upon receipt of a block. The enclave co-exists alongside the transaction manager and provides utility support for crypto-operations such as symmetric key generation and transaction payload encryption/decryption.

The flow

Assume a scenario with three parties – A, B and C – where a private transaction is conducted between A and B, and the third party, C, has no visibility into the transaction inputs and ensuing state.

Step 1: A initiates a private transaction to their Quorum node and specifies B as a recipient through the privateFor parameter. The argument passed to this field is the public key of B‘s transaction manager.

Step 2: Quorum Node A sends the transaction payload to its transaction manager, requesting for it to store the payload.

Step 3: The transaction manager sends a call to its enclave requesting encryption of the payload.

The enclave generates a symmetric key (SK) and random nonce.

Using the previously generated SK, the transaction payload & nonce are encrypted.

The encrypted payload is hashed through a SHA3-512 algorithm.

The enclave now holds the SK, an encrypted payload, and a hash of the encrypted payload.The critical piece here is the SK which can unlock the encrypted payload and make sense of the inputs. But the SK can’t just be transferred out in the open; there needs to be some assurance that only the parties relevant to THIS private transaction will be able to access it. So how is that accomplished? The enclave will use what is called PGP encryption and utilize the transaction manager public keys to encrypt unique symmetric keys for each recipient.

The enclave uses its own transaction manager public key – tm.pubKey – to generate an encrypted symmetric key (ESK) for itself. It also uses the tm.pubKey of B, which it has stored, to generate a separate ESK for B.

The encrypted payload, the hash of the payload and the ESKs are returned to A‘s transaction manager.

A‘s transaction manager stores the encrypted payload, the hash and its own ESK. The hash is important here, because it serves as an index or reference for the ESK and the corresponding payload.

C‘s transaction manager does not receive the three items (encrypted payload, hash and ESK) because its address was not specified in the privateFor field when the transaction was initiated.

The sending party, A, waits for an ACK response from B‘s transaction manager before the transaction moves forward.

Step 5: Upon confirmation, A’s transaction manager sends the hash back to its Quorum node.

Quorum Node A replaces the original transaction payload with the hash. It also changes the transaction’s V value to 37 or 38, indicating to fellow nodes that the hash represents a private transaction with an encrypted payload as opposed to standard public transactions with executable machine code.

The transaction is propagated to the rest of the network using basic p2p protocol.

The hashed private transaction gets bundled into a block and via Raft or IBFT consensus, is disseminated to all nodes in the environment.

Step 6: In processing the block, each node will attempt to execute the transaction. The V value of 37 or 38 informs the nodes that they are dealing with a private transaction and encrypted payload. Upon this realization, they make a call to their transaction manager asking to look up the hash.

Recall that the hash serves as an index for the encrypted payload & ESK.

Quorum Nodes A and B discover that the hash is present in each of their transaction managers.

Step 7: A and B’s transaction managers send a signature, and the encrypted payload + ESK corresponding to the hash to their respective enclaves.

The enclave verifies the signature and then takes the transaction manager’s private key, which it has stored, to decrypt the ESK.

Recall that the tm.pubKey was used to encrypt the SK, so the corresponding private key can decrypt it. With the decrypted SK in hand, the payload can also be decrypted.

Step 8: The decrypted payload is passed back to the Quorum nodes of A and B for EVM contract code execution.

Quorum Nodes A and B make state updates for the transaction in their private state trie.

The transaction manager finds nothing in its database and returns a nonRecipient message to the Quorum node.

Quorum Node C makes no updates to its private state trie.

Conclusion

Every node still appends the same block to its ledger. The key piece here is the presence of a private state trie in the Quorum node and the encryption/decryption flow made possible by the constellation module.