You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: doc-site/docs/implementations/anon_nullifier_qurrency.md
+36-2Lines changed: 36 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,12 +8,12 @@
8
8
9
9
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.
10
10
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.
12
12
13
13
The encryption is performed in the follow step, according to the ML-KEM scheme:
14
14
15
15
- 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.
17
17
- The secrets meant for the auditing authority are encrypted with this key, and sent as part of the transaction payload
18
18
- 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
19
19
- 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:
35
35
- the public signals representing the SHA256 hash of the ciphertext is correctly calculated
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
+
constmlkem=newMlKem512();
60
+
const [ek, dk] =awaitmlkem.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