Skip to content

Commit 1e5adc6

Browse files
authored
Merge pull request #4 from nconsigny/eip-falcon-contrib
Nconsigny/eip falcon contrib
2 parents 666ce3f + 726994c commit 1e5adc6

File tree

1 file changed

+82
-77
lines changed

1 file changed

+82
-77
lines changed

EIPS/eip-8052.md

Lines changed: 82 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
---
2-
eip: 9999
2+
eip: 8052
33
title: Precompile for Falcon support
44
description: Proposal to add a precompiled contract that performs signature verifications using the Falcon signature scheme.
5-
author: Renaud Dubois, Simon Masson, Antonio Sanso (@asanso), Marius Van Der Wijden, Kevaundray Wedderburn, Zhenfei Zhang
6-
discussions-to: https://ethereum-magicians.org/t/eip-for-a-modular-fndsa/25860
5+
author: Renaud Dubois, Simon Masson, Antonio Sanso (@asanso), Marius van der Wijden, Kevaundray Wedderburn, Zhenfei Zhang, Nicolas Consigny
6+
discussions-to: https://ethereum-magicians.org/t/eip-8052-precompile-for-falcon-support/25860
77
status: Draft
88
type: Standards Track
99
category: Core
1010
created: 2025-10-17
11+
1112
---
1213

1314
# Falcon EIP
@@ -18,10 +19,12 @@ The signature scheme can be instantiated in two version:
1819
* Falcon, the standard signature scheme, fully compliant with the algorithm recommended by the NIST,
1920
* An EVM-friendly version where the hash function is efficiently computed in the Ethereum Virtual Machine.
2021

21-
Three OPCODES are specified:
22-
- `HASH_TO_POINT`, that implements the NIST-compliant HashToPoint as described in [Algorithm 3](https://falcon-sign.info/falcon.pdf) of Falcon.
23-
- `ETH_HASH_TO_POINT`, a EVM-friendly version of HashToPoint.
24-
- `FALCON_CORE`: the core algorithm of Falcon, that verifies the signature from the obtained (HashToPoint) challenge.
22+
Three precompiled contracts are specified (formerly called `ETH_HASH_TO_POINT` / `HASH_TO_POINT_ETH` in drafts):
23+
24+
* `FALCON_HASH_TO_POINT_SHAKE256` — that implements the NIST-compliant HashToPoint as described in [Algorithm 3](https://falcon-sign.info/falcon.pdf) of Falcon.
25+
* `FALCON_HASH_TO_POINT_KECCAKPRNG` — EVM-friendly Hash-to-Point using a Keccak-based XOF/PRNG.
26+
* `FALCON_CORE` — the core algorithm of Falcon, that verifies the signature from the obtained (HashToPoint) challenge.
27+
2528

2629
## 2. Motivation
2730

@@ -43,11 +46,11 @@ For FalconRec,
4346
TOTAL=1324
4447
-->
4548

46-
In the context of the Ethereum Virtual Machine, a precompile for Keccak256 hash function is already available, making Falcon verification much faster when instantiated with an extendable output function derived from Keccak than with SHAKE256, as specified in NIST submission. This EIP specifies a split of the signature verification into two sub procedures:
47-
- `HASH_TO_POINT` or `ETH_HASH_TO_POINT`, instantiated with a different eXtendable Output Function: the first with SHAKE256 (as recommended by NIST), the second with Keccak-PRNG (a version that is more efficient when computed in the EVM). In the future, it is possible to define it for SNARK/STARK circuits. An appropriated hash function choice reduces drastically the circuit size and the proving time in the context of ZK applications.
49+
In the context of the Ethereum Virtual Machine, a precompile for Keccak256 hash function is already available, making Falcon verification much faster when instantiated with an extendable output function derived from Keccak than with SHAKE256, as specified in NIST submission. This EIP specifies a split of the signature verification into two sub procedures:
50+
- `FALCON_HASH_TO_POINT_SHAKE256` or `FALCON_HASH_TO_POINT_KECCAKPRNG`, instantiated with a different eXtendable Output Function: the first with SHAKE256 (as recommended by NIST), the second with Keccak-PRNG (a version that is more efficient when computed in the EVM). In the future, it is possible to define it for SNARK/STARK circuits. An appropriated hash function choice reduces drastically the circuit size and the proving time in the context of ZK applications.
4851
- `FALCON_CORE`, that does not require any hash computation. This sub-algorithm follows the NIST recommendation so that:
49-
- using the SHAKE256 `HASH_TO_POINT`, the signature is fully compliant with the NIST standard,
50-
- using the KeccakPRNG `ETH_HASH_TO_POINT`, the verification can be efficient even in the EVM.
52+
- using the SHAKE256 `FALCON_HASH_TO_POINT_SHAKE256`, the signature is fully compliant with the NIST standard,
53+
- using the KeccakPRNG `FALCON_HASH_TO_POINT_KECCAKPRNG`, the verification can be efficient even in the EVM.
5154

5255
Using this separation, two important features are provided: one version being fully compliant with the NIST specification, the other deviating from the standard in order to reduce the gas cost, and opening up to possible computations of Falcon signature ZK proofs.
5356

@@ -114,13 +117,13 @@ def ethfalcon512_verify(message: bytes, signature: Tuple[bytes, bytes], pubkey:
114117
return FALCON_CORE(signature, pubkey, challenge)
115118
```
116119

117-
The functions `falcon512_verify` and `ethfalcon512_verify` call the opcodes specified in the next sections: `HASH_TO_POINT`, `ETH_HASH_TO_POINT` and `FALCON_CORE`.
120+
The functions `falcon512_verify` and `ethfalcon512_verify` call the precompiles specified in the next sections: `FALCON_HASH_TO_POINT_SHAKE256`, `FALCON_HASH_TO_POINT_KECCAKPRNG` and `FALCON_CORE`.
118121

119122

120-
### 3.1. Hash To Point Challenge
123+
### 3.1. Hash-to-Point challenge (normative)
121124

122125
1. **Parse Input Data:** Check the byte sizes and then extract the message and the signature. The parsed signature is a tuple of values $(r, s_2)$. $r$ is denoted as the salt and contains bytes, and $s_2$ is denoted as the signature vector, a vector of elements mod $q$.
123-
2. **Verify Well-formedness:** Verify that the signature contains 40 bytes of salt for $r$.
126+
2. **Verify Well-formedness:** Verify that the signature contains a 40-byte salt $r$.
124127
<!-- See the `Required Checks in Verification` section for more details. -->
125128
3. **Compute the challenge $c$:** the challenge is obtained from hash-to-point on the salt $r$ of the signature and the message. The output $c$ is a polynomial of degree 512, stored in 896 bytes.
126129
The hash-to-point function computes eXtendable Output from a hash Function (XOF). This EIP provides two instantiations of a XOF:
@@ -167,9 +170,9 @@ The hash-to-point function computes eXtendable Output from a hash Function (XOF)
167170
```
168171
Precompile of `Keccak256` are available in the Ethereum Virtual Machine, making this XOF very efficient in the EVM.
169172

170-
Using one of the XOFs above (SHAKE256 or Keccak-PRNG), it is possible to instantiate two (opcode) algorithms for hashing into points:
173+
Using one of the XOFs above (SHAKE256 or Keccak-PRNG), it is possible to instantiate two (precompiles) algorithms for hashing into points:
171174
```python
172-
def HASH_TO_POINT(message: bytes32, signature: Tuple[bytes, bytes]) -> bool:
175+
def FALCON_HASH_TO_POINT_SHAKE256(message: bytes32, signature: Tuple[bytes, bytes]) -> bool:
173176
"""
174177
Compute the Hash To Point Falcon Challenge.
175178
Args:
@@ -205,7 +208,7 @@ def HASH_TO_POINT(message: bytes32, signature: Tuple[bytes, bytes]) -> bool:
205208
```
206209

207210
```python
208-
def ETH_HASH_TO_POINT(message: bytes32, signature: Tuple[bytes, bytes]) -> bool:
211+
def FALCON_HASH_TO_POINT_KECCAKPRNG(message: bytes32, signature: Tuple[bytes, bytes]) -> bool:
209212
"""
210213
Compute the Hash To Point Falcon Challenge using Keccak-PRNG.
211214
Args:
@@ -240,6 +243,11 @@ def ETH_HASH_TO_POINT(message: bytes32, signature: Tuple[bytes, bytes]) -> bool:
240243
return c
241244
```
242245

246+
#### Encoding of the challenge polynomial `c` (897 bytes, normative)
247+
* Domain: degree-512 polynomial with coefficients in `[0, q)`, `q = 12289`.
248+
* Order: coefficients are serialized in index order `c[0], c[1], …, c[511]`.
249+
* Bit-packing: each coefficient is a 14-bit **big-endian** unsigned integer. Concatenate all 512 encodings into a bitstring, then left-pad the final byte with zero bits to reach exactly **897 bytes**. Consumers MUST reject encodings that are not exactly 897 bytes.
250+
243251
### 3.2 Core algorithm
244252

245253
1. **Parse Input Data:** Check the byte sizes and then extract the public key, the Hash To Point Challenge and the signature.
@@ -329,66 +337,20 @@ if one of the above condition is not met then all the gas supplied along with a
329337
it shall also be burned if an error happens during decompression (incorrect encodings).
330338

331339

332-
### 3.4. Compliance with EIP-7932
333-
334-
In compliance with EIP-7932, the necessary parameters and structure for its integration are provided. `ALG_TYPE = 0xFA` uniquely identifies Falcon-512 transactions, set MAX_SIZE = 699 bytes to accommodate the fixed-length signature_info container (comprising a 1-byte version tag, a 666-byte Falcon signature, and a 32-byte public key hash), and recommend a `GAS_PENALTY` of approximately `3000` gas subject to benchmarking. The verification function follows the EIP-7932 model, parsing the signature_info, recovering the corresponding Falcon public key, verifying the signature against the transaction payload hash, and deriving the signer’s Ethereum address as the last 20 bytes of keccak256(pubkey). This definition ensures that Falcon-512 can be cleanly adopted within the `AlgorithmicTransaction` container specified by EIP-7932.
335-
336-
```python
337-
signature_info = Container[
338-
# 0xFA for Falcon-512 NIST-compliant,
339-
# 0xFB for Falcon-512 for the EVM-friendly version,
340-
version: uint8
341-
# Falcon-512 signature, padded if shorter
342-
signature: ByteVector[666]
343-
# keccak256(pubkey)[12:]
344-
pubkey_hash: ByteVector[20]
345-
]
346-
```
347-
348-
In the format of EIP-7932:
349-
- For the NIST-compliant version:
350-
```python
351-
verify(signature_info: bytes, payload_hash: Hash32) -> Bytes:
352-
assert len(signature_info) == 699
353-
version = signature_info[0]
354-
signature = signature_info[1:667]
355-
pubkey_hash = signature_info[667:687]
356-
assert version == 0xFA
357-
pubkey = lookup_pubkey(pubkey_hash)
358-
assert falcon512_verify(pubkey, signature, payload_hash)
359-
return pubkey
360-
```
361-
- For the EVM-friendly version:
362-
```python
363-
verify(signature_info: bytes, payload_hash: Hash32) -> Bytes:
364-
assert len(signature_info) == 699
365-
version = signature_info[0]
366-
signature = signature_info[1:667]
367-
pubkey_hash = signature_info[667:687]
368-
assert version == 0xFB
369-
pubkey = lookup_pubkey(pubkey_hash)
370-
assert ethfalcon512_verify(pubkey, signature, payload_hash)
371-
return pubkey
372-
```
373-
374-
375340
## 4. Precompiled Contract Specification
341+
The precompiled contracts are proposed with the following input and outputs, which are big-endian values:
376342

377-
### 4.1. Hash To Point precompiled contract
378-
The precompiled contract HASH_TO_POINT is proposed with the following input and outputs, which are big-endian values:
379-
380-
- **Input data**
381-
- 32 bytes for the message
382-
- 666 bytes for Falcon-512 compressed signature
383-
<!-- - 897 bytes for Falcon-512 public key -->
384-
- **Output data**:
385-
- the polynomial Hash To Point challenge as (14*512 = ) 897 bytes.
343+
### 4.1. `FALCON_HASH_TO_POINT_SHAKE256`
344+
**Input**
345+
* 32 bytes: message hash `m`
346+
* 666 bytes: Falcon-512 compressed signature `(r || s2_compressed)`
347+
**Output**
348+
* 897 bytes: packed challenge polynomial `c` (see §3.1 encoding)
386349

387-
#### Error Cases
388-
- Invalid input length (not compliant to described input)
350+
### 4.2. `FALCON_HASH_TO_POINT_KECCAKPRNG`
351+
Same I/O as §4.1, but the XOF is Keccak-PRNG. The construction is normative and MUST define: state initialization, domain-separation (if any), counter width and endianness, and block concatenation order.
389352

390-
### 4.2. Falcon Core precompiled contract
391-
The precompiled contract FALCON_CORE is proposed with the following input and outputs, which are big-endian values:
353+
### 4.3. `FALCON_CORE`
392354

393355
- **Input data**
394356
- 666 bytes for Falcon-512 compressed signature
@@ -404,9 +366,9 @@ The precompiled contract FALCON_CORE is proposed with the following input and ou
404366
- Invalid norm bound
405367
- Signature verification failure
406368

407-
### 4.3. Precompiled Contract Gas Usage
369+
### 4.4. Precompiled Contract Gas Usage
408370

409-
The cost of the **HASH_TO_POINT** and **HASH_TO_POINT_ETH** is set to 1000 gas.
371+
The cost of the **FALCON_HASH_TO_POINT_SHAKE256** and **FALCON_HASH_TO_POINT_KECCAKPRNG** is set to 1000 gas.
410372

411373
The cost of **FALCON_CORE** is set to 2000 gas.
412374

@@ -438,7 +400,50 @@ The cost is interpolated using rule of thumb from SUPERCOPS signatures benchmark
438400

439401
## 6. Backwards Compatibility
440402

441-
No backward compatibility issues found.
403+
In compliance with EIP-7932, the necessary parameters and structure for its integration are provided. `ALG_TYPE = 0xFA` uniquely identifies Falcon-512 transactions, set MAX_SIZE = 667 bytes to accommodate the fixed-length signature_info container (comprising a 1-byte version tag and a 666-byte Falcon signature), and recommend a `GAS_PENALTY` of approximately `3000` gas subject to benchmarking. The verification function follows the EIP-7932 model, parsing the signature_info, recovering the corresponding Falcon public key, verifying the signature against the transaction payload hash, and deriving the signer's Ethereum address as the last 20 bytes of keccak256(pubkey). This definition ensures that Falcon-512 can be cleanly adopted within the `AlgorithmicTransaction` container specified by EIP-7932.
404+
405+
As per EIP-7932, this EIP defines two Falcon algorithm types:
406+
* `ALG_TYPE = 0xFA` — Falcon-512 with SHAKE256 H2P
407+
* `ALG_TYPE = 0xFB` — Falcon-512 with Keccak-PRNG H2P
408+
409+
**Container and sizes.** The `signature_info` container omits any pubkey hash; the public key is recovered by `verify(...)` and the 7932 sig-recover precompile derives the address as `keccak(ALG_TYPE || pubkey)[12:]`. Therefore:
410+
* `MAX_SIZE = 667` bytes (1-byte `ALG_TYPE` + 666-byte Falcon compressed signature).
411+
412+
```python
413+
signature_info = Container[
414+
# 0xFA Falcon-512 (SHAKE H2P), 0xFB Falcon-512 (Keccak H2P)
415+
version: uint8,
416+
# Falcon-512 signature (compressed). If an implementation produces a shorter form, it MUST be left-padded to 666 bytes.
417+
signature: ByteVector[666]
418+
]
419+
```
420+
421+
In the format of EIP-7932:
422+
- For the NIST-compliant version:
423+
```python
424+
verify(signature_info: bytes, payload_hash: Hash32) -> ExecutionAddress:
425+
assert len(signature_info) == 699
426+
version = signature_info[0]
427+
signature = signature_info[1:667]
428+
assert version == 0xFA
429+
pubkey = lookup_pubkey(pubkey_hash)
430+
assert falcon512_verify(pubkey, signature, payload_hash)
431+
return ExecutionAddress(keccak256(pubkey)[12:])
432+
```
433+
- For the EVM-friendly version:
434+
```python
435+
verify(signature_info: bytes, payload_hash: Hash32) -> ExecutionAddress:
436+
assert len(signature_info) == 699
437+
version = signature_info[0]
438+
signature = signature_info[1:667]
439+
assert version == 0xFB
440+
pubkey = lookup_pubkey(pubkey_hash)
441+
assert ethfalcon512_verify(pubkey, signature, payload_hash)
442+
return ExecutionAddress(keccak256(pubkey)[12:])
443+
```
444+
445+
### Addresses
446+
**TBD by ACD.** Final precompile addresses will be selected within the EIP-managed range of EIP-1352, explicitly **avoiding `0x01000x01FF` reserved for RIPs** by EIP-7587.
442447

443448
## 7. Test Cases
444449

@@ -453,7 +458,7 @@ An implementation is provided in `assets` (TODO). For the NIST-compliant version
453458

454459
## 9. Security Considerations
455460

456-
The derivation path to obtain the private key from the seed is (tbd).
461+
The derivation path to obtain the private key from the seed is (tbd). Hash-to-Point functions MUST follow the specified XOFs byte-for-byte; domain separation and padding are normative.
457462

458463
## 10. Copyright
459464
Copyright and related rights waived via [CC0](../LICENSE.md).

0 commit comments

Comments
 (0)