Skip to content

Commit 4a63dc3

Browse files
authored
Merge pull request #143 from kaleido-io/setup-qurrency-docs
Documentation for auditor setup in qurrency
2 parents c62ac99 + 4308ea5 commit 4a63dc3

File tree

1 file changed

+36
-2
lines changed

1 file changed

+36
-2
lines changed

doc-site/docs/implementations/anon_nullifier_qurrency.md

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88

99
This implementation builds on top of the `anon_nullifiers` to add post-quantum cryptography inside the circuit to encrypt sensitive information for a designated authority, such as a regulator, for auditing purposes.
1010

11-
The encryption scheme is based on the ML-KEM (Module-Lattice-Based Key-Encapsulation Mechanism) derived from the CRYSTALS-KYBER algorithm. This is a NIST approved algorithm for post-quantum secure encryption, meaning even the quatum computers can not break the encryption.
11+
To implement post-quantum secure encryption, these circuits use the public key encryption scheme internal to ML-KEM (Module-Lattice-Based Key-Encapsulation Mechanism), which is derived from the CRYSTALS-KYBER algorithm. This algorithm has been selected by NIST for standardization of post-quantum secure encryption, meaning even quantum computers cannot break the cryptosystem.
1212

1313
The encryption is performed in the follow step, according to the ML-KEM scheme:
1414

1515
- An AES-256 encryption key is generated for the transaction. This key is used only for this transaction
16-
- AES encryption is quantum secure
16+
- AES-256 is a quantum-secure block cipher.
1717
- The secrets meant for the auditing authority are encrypted with this key, and sent as part of the transaction payload
1818
- The key is passed into the circuit as a private input and encrypted inside the circuit under the ML-KEM scheme, using the auditing authority's public key
1919
- The public key is statically programmed into the circuit. This is to avoid making it a signal which would be very inefficient due to the large size of the public key (1184 bytes)
@@ -35,3 +35,37 @@ The statements in the proof include:
3535
- the public signals representing the SHA256 hash of the ciphertext is correctly calculated
3636

3737
![wiring_anon_nullifier_qurrency](../images/circuit_wiring_anon_nullifier_qurrency.jpg)
38+
39+
# Zero-Knowledge Circuit Setup
40+
41+
In order to initialize a zero-knowledge proof circuit corresponding to a particular auditor, we require information about the auditor's ML-KEM public key to be encoded into the circuit.
42+
43+
## Background
44+
45+
[ML-KEM](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf) is a key-encapsulation mechanism, which internally initializes and uses a public key encryption scheme referred to as K-PKE. The Qurrency protocol uses this internal PKE scheme to provide post-quantum secure public key encryption. K-PKE was chosen because to date it is the only post-quantum secure PKE scheme to appear in a NIST standardization. It has been selected for standardization as a standalone post-quantum secure PKE scheme, and the standardization process is expected to complete by 2027.
46+
47+
For any implementation, calling $\mathsf{ML\mathrm{-}KEM}.\mathsf{KeyGen}()$ will return an encapsulation key `ek` and a decapsulation key `dk`. Since `ek` is identical to the public key of the internal PKE scheme, we can directly use `ek` to build the ZK circuit. `ek` is an array of 800 bytes, of the following form:
48+
49+
- The first 768 bytes encode an array `t` of 512 integers modulo a prime $q$, where $q = 3329$. Each integer is encoded in 12 bits.
50+
- The remaining 32 bytes is used as a random seed `rho`, which generates a matrix `a`. This is a 2x2 matrix, where each element is an array of 256 integers mod $q$.
51+
52+
Our circuits are designed for ML-KEM-512 in particular, so all parameters are chosen relative to this scheme.
53+
54+
## Circuit generation
55+
56+
For this example, we'll demonstrate the circuit generation process using the `mlkem` [npm module](https://www.npmjs.com/package/mlkem), although any secure ML-KEM implementation will suffice. After generating your keys:
57+
58+
```javascript
59+
const mlkem = new MlKem512();
60+
const [ek, dk] = await mlkem.generateKeyPair();
61+
```
62+
63+
Securely store `dk` to use in audits. (In particular, auditing requires the first 768 bytes of `dk`, which corresponds to the private key of the PKE scheme.) Then setup the `kyber.circom` circuit inside `zkp/circuits/lib/kyber` with the following steps.
64+
65+
1. Separate `ek` into `t` (the first 768 bytes) and `rho` (the remaining 32 bytes).
66+
2. For each 384-byte half `ti` of `t`, compute `polyFromBytes(ti)`. This is the `mlkem` implementation of $\mathsf{ByteDecode}_{12}$ from the ML-KEM specification. It decodes the two halves of `t` back into arrays of integers. These two arrays can be inserted as `t[0]` and `t[1]` inside the `kyber_enc` circuit.
67+
3. Compute the matrix `a` as `_sampleMatrix(rho, false)`. In the ML-KEM specification, each entry `a[i,j]` of `a` is computed as $\mathsf{SampleNTT}(\rho \mathbin\Vert j \mathbin\Vert i)$. In `mlkem`, this function computes all four entries of `a` at once. These can then be inserted into the corresponding `a[0][0]`, `a[0][1]`, `a[1][0]`, and `a[1][1]` inside the `kyber_enc` circuit.
68+
69+
After this, circuit generation is complete, and setup can continue the same as all other Zeto tokens.
70+
71+
**Note**: The `_sampleMatrix` function is not exposed by the `mlkem` library for external use, so for circuit initialization, you may have to either re-implement this functionality, or temporarily modify the library to expose this.

0 commit comments

Comments
 (0)