Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
fa35512
Push EIP NTT proposal with assets
rdubois-crypto Feb 18, 2025
3dfc3be
update mail, link and PR number
rdubois-crypto Feb 18, 2025
859fbef
update mail
rdubois-crypto Feb 18, 2025
7da67d6
update eip assets folder name + simon modifications of EIP
rdubois-crypto Feb 18, 2025
3e3e021
update mail
rdubois-crypto Feb 18, 2025
7d14aca
update header according to linter errors
rdubois-crypto Feb 18, 2025
e5dbf1f
add missing image
rdubois-crypto Feb 18, 2025
5503ad6
removal of TODOs useless sections
rdubois-crypto Feb 18, 2025
096f81a
update with magician thread
rdubois-crypto Feb 18, 2025
59dc1ae
remove blank lines
rdubois-crypto Feb 18, 2025
3af803a
remove blank line
rdubois-crypto Feb 18, 2025
09b3f35
update EIP number according to provided number
rdubois-crypto Feb 19, 2025
40b3595
Update EIPS/eip-7885.md
rdubois-crypto Feb 25, 2025
3ebc1fc
Update EIPS/eip-7885.md
rdubois-crypto Feb 25, 2025
4127991
Update EIPS/eip-7885.md
rdubois-crypto Feb 25, 2025
c42f071
Update EIPS/eip-7885.md
rdubois-crypto Feb 25, 2025
da332ca
Update EIPS/eip-7885.md
rdubois-crypto Feb 25, 2025
7da5b78
Update EIPS/eip-7885.md
rdubois-crypto Feb 25, 2025
517431d
Update EIPS/eip-7885.md
rdubois-crypto Feb 25, 2025
7636b47
Update EIPS/eip-7885.md
rdubois-crypto Feb 25, 2025
e3abf62
Update assets/eip-9374/README.md
rdubois-crypto Feb 25, 2025
9dbb147
Merge branch 'ethereum:master' into eip/NTT-proposal
rdubois-crypto Feb 26, 2025
c4ebe76
update assets to assigned number
rdubois-crypto Feb 26, 2025
56c84e2
Update EIP-7885: add Go implementation and update eip-7885.md
yhl125 Sep 8, 2025
2077392
Update EIP-7885: assets integration-test
yhl125 Sep 10, 2025
29fb431
Merge pull request #1 from yhl125/eip/NTT-proposal
rdubois-crypto Sep 30, 2025
211a810
Fix EIP-7885 formatting and linking errors, add co-author
yhl125 Sep 30, 2025
592704e
Update EIP-7885: add VECMULMOD and VECADDMOD implementation and bench…
yhl125 Oct 1, 2025
a2a57fc
Update EIP-7885: Migrate to liboqs implementation
yhl125 Nov 6, 2025
c50b0e1
Merge pull request #2 from yhl125/eip/NTT-proposal
simonmasson Nov 14, 2025
c4a0934
Update EIP-7885: Add nocgo/cgo implementation variants
yhl125 Nov 20, 2025
5d571d9
Merge pull request #5 from yhl125/eip/NTT-proposal
simonmasson Dec 3, 2025
52be8e0
Update EIP-7885: Add end-to-end signature verification benchmarks for…
yhl125 Dec 30, 2025
77792a7
Merge pull request #6 from yhl125/eip/NTT-proposal
simonmasson Jan 21, 2026
7d5c5ba
Update EIP-7885: Address reviewer feedback
yhl125 Feb 20, 2026
32bb296
Merge pull request #7 from yhl125/eip/NTT-proposal
simonmasson Feb 27, 2026
d1e2e80
Update EIP-7885: Fix MD049 linter error for mathbb notation
yhl125 Feb 27, 2026
b47c985
Merge pull request #8 from yhl125/eip/NTT-proposal
simonmasson Feb 27, 2026
a194c4d
Merge branch 'ethereum:master' into eip/NTT-proposal
simonmasson Feb 27, 2026
d0c9a13
Update EIP-7885: update discussion link
yhl125 Mar 2, 2026
d50256b
Merge pull request #9 from yhl125/eip/NTT-proposal
simonmasson Mar 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
374 changes: 374 additions & 0 deletions EIPS/eip-7885.md

Large diffs are not rendered by default.

97 changes: 97 additions & 0 deletions assets/eip-7885/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# NTT-EIP as a building block for FALCON, DILITHIUM and STARK verifiers

This repository contains the EIP for NTT transform, along with a python reference code, and a solidity implementation.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you link this asset dir or this readme in the main EIP? if not recommend to do so for a user to navigate here


## Context

### The threat
With the release of Willow cheap, the concern for quantum threat against Ethereum seems to accelerate. Post by [Asanso](https://ethresear.ch/t/so-you-wanna-post-quantum-ethereum-transaction-signature/21291) and [PMiller](https://ethresear.ch/t/tidbits-of-post-quantum-eth/21296) summarize those stakes and possible solutions. Those solutions include use of lattice based signatures such as Dillithium or FALCON (the latter being more optimized for onchain constraints), STARKs and FHE. There is a consensus in the cryptographic research community around lattices as the future of asymetric protocols, and STARKs won the race for ZKEVMs implementation (as used by Scroll, Starknet and ZKsync).

Those protocols have in common to require fast polynomial multiplication over prime fields, and use NTT (a special [FFT](https://vitalik.eth.limo/general/2019/05/12/fft.html) adapted to prime fields). While in the past Montgomery multipliers over elliptic curve fields were the critical target of optimizations (both hardware and software), NTT optimization is the key to a performant PQ implementation.

### Discussion

In the past Ethereum chose specificity by picking secp256k1 as its sole candidate for signature. Later, after dedicated hardware and proving systems working on other hardwares were realeased, a zoo of EIP flourished to propose alternative curves. There where attempt to have higher level EIPs to enable all of those at once, such as EWASM, SIMD, EVMMAX, or RIP7696 (by decreasing order of genericity and complexity).

Picking NTT as EIP instead of a given scheme would provide massive gas cost reduction for all schemes relying on it.
- **pros** : massive reduction to all cited protocols, more agility for evolutions.
- **cons**: requires to be wrapped into implementations, not optimal for a given target compared to dedicated EIP, not stateless.

## Overview

The NTT operates on sequences of numbers (often coefficients of polynomials) in a modular arithmetic system. It maps these sequences into a different domain where convolution operations (e.g., polynomial multiplication) become simpler and faster, akin to how FFT simplifies signal convolution. Compared to FFT which uses root of unity in complex plane, NTT uses roots of unity in a finite field or ring.

The NTT is based on the Discrete Fourier Transform (DFT), defined as:
$$
X[k] = \sum_{j=0}^{N-1} x[j] \cdot \omega^{j \cdot k} \mod q$$

Where:
- $x[j]$: Input sequence of length N.
- $X[k]$: Transformed sequence,
- $q$: A prime modulus,
- $\omega$: A primitive N-th root of unity modulo $q$, with
$\omega^N \equiv 1 \mod q \quad \text{and} \quad \omega^k \not\equiv 1 \mod q \; \forall \; 0 < k < N$

NTT computation uses the a similar approach as Cooley-Tukey algorithm to provide a O(N log N) complexity. The NTT algorithm transforms a sequence $(x[j])$ to $(X[k])$ using modular arithmetic. It is invertible, allowing reconstruction of the original sequence via the Inverse NTT (INTT). The inverse process is similar but requires dividing by \(N\) (mod \(q\)) and using $(\omega^{-1}$) (the modular inverse of $\omega$). The following algorithm is extracted from
[[LN16]](https://eprint.iacr.org/2016/504.pdf), and describe how to compute the NTT when $R_q= \mathbb{Z}_q[X]/X^n+1$ (Negative Wrap Convolution).

![alt text](image.png)

The Inverse NTT is computed through the following algorithm:

![alt text](image-1.png)

## Benchmarks

### Python

| Field | $n$ | Recursive NTT (Tetration) | Iterative NTT (ZKNox) | Iterative InvNTT (ZKNox)|
|-|-|-|-|-|
|Falcon | 512 | 761 μs | 528 μs | 561 μs |
|Falcon | 1024 | 1642 μs | 1076 μs | 1199 μs |
|Dilithium| 128 | 165 μs | 114 μs | 113 μs |
|Dilithium| 256 | 371 μs | 258 μs | 260 μs |
|BabyBear | 256 | 531 μs | 389 μs | 404 μs |

The recursive inverse NTT is very costly because of the required inversions. For Falcon, the field is small enough so that field inversions can be precomputed, but the cost is still higher than the iterative inverse NTT.
The field arithmetic has not been optimized. In the case of BabyBear, this becomes significant and so the comparison is not really significant.

### Solidity


| Function | Description | gas cost | Tests Status |
|------------------------|---------------------|---------------------|---------------------|
| NTT recursive | original gas cost from [falcon-solidity](https://github.com/Tetration-Lab/falcon-solidity/blob/main/src/Falcon.sol) | 6.9M | OK|
| InvNTT recursive | original gas cost from [falcon-solidity](https://github.com/Tetration-Lab/falcon-solidity/blob/main/src/Falcon.sol) | 7.8M | OK|
| Full Falcon verification | original gas cost from [falcon-solidity](https://github.com/Tetration-Lab/falcon-solidity/blob/main/src/Falcon.sol) | 24 M| OK|
| NTT iterative | ZKNOX | 4M | OK|
| InvNTT iterative | ZKNOX | 4.2M | OK|
| Full Falcon verification | ZKNOX | 8.5 M| OK|


### Yul


Further optimizations are reached by using Yul for critical sections and using the CODECOPY and EXTCODECOPY trick detailed in of [[RD23]](https://eprint.iacr.org/2023/939.pdf) (section 3.3, "Hacking EVM memory access cost").


| Function | Description | gas cost | Tests Status |
|------------------------|---------------------|---------------------|---------------------|
| ntt.NTTFW | ZKNOX_NTTFW, iterative yuled | 1.9M | OK|
| falcon.verify_opt | Full falcon verification with precomputated pubkey | 3.6M | OK|

### Go Ethereum (WIP)

ZKNOX is planning a client implementation for node of the considered EIP.

## Conclusion

We provided an optimized version of FALCON, using an optimized version of NTT. This code can be used to speed up Stark verification as well as other lattices primitives (Dilithium, Kyber, etc.). While it seems achievable to use FALCON as a progressive precompile, the cost remains very high. Using a client implementation with NTT-EIP (in a Geth fork for example), ETHEREUM could become from a PQ-Friendly and ZK-Friendly chain. This work is supported by the Ethereum Foundation.


## References

- [[LN16]](https://eprint.iacr.org/2016/504.pdf) Speeding up the Number Theoretic Transform for Faster Ideal Lattice-Based Cryptography. Patrick Longa, Michael Naehrig.
- [[EIP616]](https://eips.ethereum.org/EIPS/eip-616) EIP-616: SIMD Operations for the EVM. Greg Colvin.
- [[RD23]](https://eprint.iacr.org/2023/939.pdf) Speeding up elliptic computations for Ethereum Account Abstraction. Renaud Dubois.
- [[DILITHIUM]](https://eprint.iacr.org/2017/633.pdf) CRYSTALS-Dilithium: A Lattice-Based Digital Signature Scheme. Léo Ducas, Eike Kiltz, Tancrède Lepoint, Vadim Lyubashevsky, Peter Schwabe, Gregor Seiler and Damien Stehlé.
Binary file added assets/eip-7885/image-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/eip-7885/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
151 changes: 151 additions & 0 deletions assets/eip-7885/op-geth/cgo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Optimism-geth with NTT Precompiles (liboqs Implementation)

Fork of `op-geth` with precompiled contracts for Number Theoretic Transform (NTT) operations using open-quantum-safe liboqs via CGO bindings, enabling efficient on-chain post-quantum cryptographic operations.

## Precompiled Contracts

| Address | Name | Description |
| ------- | --------- | ---------------------------------------------------------------------- |
| `0x12` | NTT_FW | Forward NTT using liboqs (Falcon-512/1024, ML-DSA) |
| `0x13` | NTT_INV | Inverse NTT using liboqs (same schemes as NTT_FW) |
| `0x14` | VECMULMOD | Element-wise modular multiplication: `result[i] = (a[i] * b[i]) mod q` |
| `0x15` | VECADDMOD | Element-wise modular addition: `result[i] = (a[i] + b[i]) mod q` |

### Supported Schemes

| Scheme | Ring Degree | Modulus | Element Size |
| ----------- | ----------- | ------- | ---------------- |
| Falcon-512 | 512 | 12289 | uint16 (2 bytes) |
| Falcon-1024 | 1024 | 12289 | uint16 (2 bytes) |
| ML-DSA | 256 | 8380417 | int32 (4 bytes) |

## Installation

### 1. Install liboqs with NTT CGO Bindings

```bash
# Clone and install dependencies
git clone -b feature/ntt-cgo-bindings https://github.com/yhl125/liboqs.git
sudo apt install astyle cmake gcc ninja-build libssl-dev python3-pytest python3-pytest-xdist unzip xsltproc doxygen graphviz python3-yaml valgrind pkg-config

# Build liboqs and Go bindings
cd liboqs/bindings/go
make all
```

### 2. Configure Environment

```bash
# Set paths (adjust to your installation directory)
export PKG_CONFIG_PATH=/path/to/liboqs/bindings/go/.config:$PKG_CONFIG_PATH
export DYLD_LIBRARY_PATH=/path/to/liboqs/build/lib:$DYLD_LIBRARY_PATH # macOS
export LD_LIBRARY_PATH=/path/to/liboqs/build/lib:$LD_LIBRARY_PATH # Linux
```

### 3. Build op-geth

```bash
make geth
```

## API Reference

### NTT_FW (0x12) - Forward Transform

Transforms coefficients into NTT domain using liboqs.

**Input:**

```
[0:4] ring_degree (uint32, big-endian)
[4:12] modulus (uint64, big-endian)
[12:*] coefficients (Falcon: uint16×N, ML-DSA: int32×N, big-endian)
```

**Output:** NTT-transformed coefficients (same format as input)

**Gas Cost:**

- Falcon-512: 500 gas (~9.4μs, 53 mgas/s)
- Falcon-1024: 1,080 gas (~20.4μs, 53 mgas/s)
- ML-DSA: 256 gas (~4.8μs, 53 mgas/s)

### NTT_INV (0x13) - Inverse Transform

Transforms NTT domain coefficients back to standard representation.

**Input:** Same as NTT_FW (coefficients in NTT domain)

**Output:** Coefficients in standard representation

**Gas Cost:**

- Falcon-512: 500 gas (~9.4μs, 53 mgas/s)
- Falcon-1024: 1,080 gas (~20.3μs, 53 mgas/s)
- ML-DSA: 340 gas (~6.4μs, 53 mgas/s)

### VECMULMOD (0x14) - Vector Multiplication

Element-wise modular multiplication in NTT domain.

**Input:**

```
[0:4] ring_degree (uint32, big-endian)
[4:12] modulus (uint64, big-endian)
[12:12+n*size] vector_a
[12+n*size:*] vector_b
```

**Output:** Element-wise product `(a[i] * b[i]) mod q`

**Gas Cost:** `ceil(0.32 × n)`

- Falcon-512: 164 gas (~2.9μs, 56 mgas/s)
- Falcon-1024: 328 gas (~6.0μs, 55 mgas/s)
- ML-DSA: 82 gas (~2.0μs, 42 mgas/s)

### VECADDMOD (0x15) - Vector Addition

Element-wise modular addition.

**Input:** Same as VECMULMOD

**Output:** Element-wise sum `(a[i] + b[i]) mod q`

**Gas Cost:** `ceil(0.3 × n)`

- Falcon-512: 154 gas (~2.8μs, 55 mgas/s)
- Falcon-1024: 308 gas (~5.8μs, 53 mgas/s)
- ML-DSA: 77 gas (~1.6μs, 47 mgas/s)

## Testing

```bash
cd core/vm

# All NTT tests
go test -v -run TestPrecompiled.*NTT

# Specific tests
go test -v -run TestPrecompiledNTT_FW
go test -v -run TestPrecompiledNTT_VECMULMOD

# Benchmarks
go test -bench=BenchmarkPrecompiledNTT -benchtime=5s
```

**Test Coverage:**

- Scheme detection (Falcon-512/1024, ML-DSA)
- Input validation (malformed inputs, invalid parameters)
- Round-trip verification (`INTT(NTT(x)) = x`)
- Cross-scheme isolation
- Performance benchmarks with crypto standards

### Benchmark Results

Benchmarks were run on an Intel(R) Xeon(R) CPU @ 2.20GHz. For detailed results, please see the files below:

- [Ecrecover Benchmark Test Results](./benchmark_results/BenchmarkPrecompiledEcrecover)
- [NTT & NTT Vector Operations Benchmark Test Results](./benchmark_results/BenchmarkPrecompiledNTT)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
goos: linux
goarch: amd64
pkg: github.com/ethereum/go-ethereum/core/vm
cpu: Intel(R) Xeon(R) CPU @ 2.20GHz
BenchmarkPrecompiledEcrecover/-Gas=3000-4 65388 57182 ns/op 3000 gas/op 52.46 mgas/s 352 B/op 6 allocs/op
BenchmarkPrecompiledEcrecover/-Gas=3000-4 64994 55950 ns/op 3000 gas/op 53.61 mgas/s 352 B/op 6 allocs/op
BenchmarkPrecompiledEcrecover/-Gas=3000-4 61538 56411 ns/op 3000 gas/op 53.18 mgas/s 352 B/op 6 allocs/op
BenchmarkPrecompiledEcrecover/-Gas=3000-4 66052 55283 ns/op 3000 gas/op 54.26 mgas/s 352 B/op 6 allocs/op
BenchmarkPrecompiledEcrecover/-Gas=3000-4 65418 56104 ns/op 3000 gas/op 53.47 mgas/s 352 B/op 6 allocs/op
PASS
ok github.com/ethereum/go-ethereum/core/vm 21.021s
Loading
Loading