Skip to content

Commit

Permalink
EIP-7213: Falcon Signature verification
Browse files Browse the repository at this point in the history
  • Loading branch information
eum602 committed Jul 5, 2023
1 parent 3907772 commit 3819d15
Showing 1 changed file with 213 additions and 0 deletions.
213 changes: 213 additions & 0 deletions EIPS/eip-7213.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
---
eip: xxxx
title: Add Precompile for Falcon512 post-quantum signature verification function
author: Erick Pacheco Pedraza (@eum602), Marcos Allende, Diego Lopez León
discussions-to: https://ethereum-magicians.org/t/eip-xxxx-falcon512-signatures-verification
status: Draft
type: Standards Track
category: Core
created: 2023-07-03
---

## Abstract

This standard proposes the inclusion of a precompiled signature verification function. The algorithm used is Falcon-512, standarized by NIST and quantum resistant with a security level I.

A successful signature verification returns a Shake256 digest with 32 bytes output of the Falcon public key, which makes it suitable to be used by smart contracts without implying high transaction fees.

## Motivation

The advancement in Quantum Computers is moving faster, what was thought to be ready in 20 years seems to be coming soon due to the effort taken by different entities around the globe. One Step forward on this area is the work that NIST has done in order to analyze and standarize post quantum algorithms.

## Specification

The precompiled signature verification function runs at address `0x13`. The required inputs are:

- `message digest` - a 32 bytes
- `public key` - Falcon Public key of 897 bytes
- `signature` - 666 bytes

Output is:

- `result digest` - Shake256 digest with 32 bytes output of the falcon public key.

### Example Usage in Solidity

The precompile can be wrapped in Solidity to provide a more development-friendly interface to `Falcon-512` signature verification.

```solidity
function _falconRecover(
bytes calldata signature,
bytes calldata publicKey,
bytes32 data
) private view returns (bytes32 signer) {
(bool success, bytes memory verifies) = address(
0x0000000000000000000000000000000000000013
).staticcall(
abi.encodeWithSignature(
"verify(bytes,bytes,bytes32)",
signature,
publicKey,
data
)
);
assembly {
signer := mload(add(verifies, 0x20))
}
require(
success && verifies.length == 32 && signer != bytes32(0),
"Invalid signature"
);
}
```

### Gas costs and benchmarks

Each operation to execute the precompiled call will require 2350 units of gas (approximate average value taken from 3 benchmark ourputs at 5,10 and 30 seconds). Values for each measurement is presented at the benchmark section.

## Rationale

Falcon-512 is a good candidate to be a new signature implementation. First of all, key sizes are relatively small compared to ther signature algorithms that are also quantum resistant.

The following table shows a summary of the typicall values for keys and the approximate amount of time taken per second to execute signature verifications. [source](https://falcon-sign.info/)

```
variant verify/s pub size(bytes) sig size(bytes)
----------------------------------------- --------- ---------------- ---------------
Falcon512 27933.0 897 666
```

Falcon uses shake256 under the hood, an implementation made in solidity showed it is not viable to implement this algorithm at that layer, on the other hand the implementation of falcon-512 by using precompiles turned to be the best approach since the gas cost (as show in the previous section) is relatively low.

Since Falcon public keys are 897 bytes, the signature verification returns a digest shake256 of 32 bytes output of the falcon public key, otherwise returns bytes32(0). It was made that way to allow smart contracts that call that method to have a digest of the public key which can be used further in the custom contract logic to associate it to some other value or to perform some assertion, in that way contracts can avoid storing the public keys but just the public key digest.

Implementing just the signature verification is sufficiently enough to open a wide range of use cases at smart contract level. To give an example, this method can perfectly work with the Account Abstraction concept, where the authentication process would rely on Falcon and the account is a smart contract.

## Backwards Compatibility

There is very little risk of breaking backwards-compatibility with this EIP, the sole issue being if someone were to build a contract relying on the address at `0x13` being empty. The likelihood of this is low, and should specific instances arise, the address could be chosen to be any arbitrary value with negligible risk of collision.

## Test Cases

#### Test vector 0

- description: empty input
- input: (empty)
- output: error "invalid input"

#### Test vector 1

- descrption: signature lenght not present in input
- input:
`000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000003103d474d06cef2d8da1c97afd7d4993ba792297ca4e161967578494141cab04202`
- output: error "invalid input"

#### Test vector 2

- description: Signature indicated length is zero
- input:
`000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c03d474d06cef2d8da1c97afd7d4993ba792297ca4e161967578494141cab04202000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000`
- output: error "invalid input"

#### Test vector 3

- description: Public Key indicated length is zero
- input:
`000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c03d474d06cef2d8da1c97afd7d4993ba792297ca4e161967578494141cab04202000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000`
- output: error "invalid input"

#### Test vector 4

- description: Signature indicated length is too long
- input:
`000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c03d474d06cef2d8da1c97afd7d4993ba792297ca4e161967578494141cab04202000000000000000000000000000000000000000000000000000000000007774000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000`
- output: error "invalid input"

#### Test vector 5

- description: Public Key indicated length is too long
- input:
`000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c03d474d06cef2d8da1c97afd7d4993ba792297ca4e161967578494141cab04202000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004444000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000`
- output: error "invalid input"

#### Test vector 6

- description: Well formatted input but invalid signature
- input:
`000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000003103d474d06cef2d8da1c97afd7d4993ba792297ca4e161967578494141cab0420200000000000000000000000000000000000000000000000000000000000002901113b3c07507e4201748494d832b6ee2a6c93bff9b0ee343b550d1f85a3d0de0d704c6d1784295130960fbe956c6851e141ab3c09a5475bdda2d81ee113f1e16e2ddd8e408bbb3f5b06a555d8f1ac072e5be2f9a365b33ace3d8254709c185b6f3d3db4b50baf14536779f24b5e843fb36b5a00ca475d1801a964d09961c1959dad0f80f0615476c75f58e4ae9a9f8eb93e65f1a4753ca75a62269d74a49ddc75f539bfecd60fe3c8966e77b01d9c69a965a39907862b2de754ad319644d21134fccee194278b326aa4e94359f1d4a08814cad9b27d62687cc31cfcf057490cea0512e02b3b3834e6803c30679f2f2ae2bf4d4e670b283f5105dad272da0f8b95168ea1080b184d98787ba335c22a0a40fd5ba4a70d905c373304c2759e695214f741b98629184789ffdaf63731b43188bda77ed49924da34968ee347b973b525ce0b40af92889b479e5e8717c05c923d76f0bf4689747de1821c1c42968eb164a5fe7c25ef75629511ce220c9d71c4fdb4d60b927b1e473dcda691062b6977338e8666b8c82b8f0f118eefeb5e66e408e63aa9cf876a0a4249688aae132955f5ea98fff2bb4f565b4ec4db39d414dd9c9d3edd089ac74af2f9f3feffa72332982d5e470a74bb2b3b7462639ed89319a327e8a11aef2e3cc391789b4c616b1aef335e9b47a294a47d2c42e7daca30c119e8098b6895aa32bb989a675aa72e84dc1ccc8b9f1a6cd274adbb86fc5ca9c2744cd73f064eba715e06dce542ef0646c94f41d3f47bb7c1a6c4e91ee55996dec4cbbc931f0047e3ba251f71b0bbc7e8633cc7479b1361697a131436d5958ee6fd1ccc1a5d31a9a8391bde2d075cce140de8f1dc58a093310821ae1d26917bc2a17dec09225374ee078d977f901825955ec8623304459a51e5cf7fe60c68b16800000000000000000000000000000000000000000000000000000000000000381096ba86cb658a8f445c9a5e4c28374bec879c8655f68526923240918074d0147c03162e4a49200648c652803c6fd7509ae9aa799d6310d0bd42724e0635920186207000767ca5a8546b1755308c304b84fc93b069e265985b398d6b834698287ff829aa820f17a7f4226ab21f601ebd7175226bab256d8888f009032566d6383d68457ea155a94301870d589c678ed304259e9d37b193bc2a7ccbcbec51d69158c44073aec9792630253318bc954dbf50d15028290dc2d309c7b7b02a6823744d463da17749595cb77e6d16d20d1b4c3aad89d320ebe5a672bb96d6cd5c1efec8b811200cbb062e473352540eddef8af9499f8cdd1dc7c6873f0c7a6bcb7097560271f946849b7f373640bb69ca9b518aa380a6eb0a7275ee84e9c221aed88f5bfbaf43a3ede8e6aa42558104faf800e018441930376c6f6e751569971f47adbca5ca00c801988f317a18722a29298925ea154dbc9024e120524a2d41dc0f18fd8d909f6c50977404e201767078ba9a1f9e40a8b2ba9c01b7da3a0b73a4c2a6b4f518bbee3455d0af2204ddc031c805c72ccb647940b1e6794d859aaebcea0deb581d61b9248bd9697b5cb974a8176e8f910469cae0ab4ed92d2aee9f7eb50296daf8057476305c1189d1d9840a0944f0447fb81e511420e67891b98fa6c257034d5a063437d379177ce8d3fa6eaf12e2dbb7eb8e498481612b1929617da5fb45e4cdf893927d8ba842aa861d9c50471c6d0c6df7e2bb26465a0eb6a3a709de792aafaaf922aa95dd5920b72b4b8856c6e632860b10f5cc08450003671af388961872b466400adb815ba81ea794945d19a100622a6ca0d41c4ea620c21dc125119e372418f04402d9fa7180f7bc89afa54f8082244a42f46e5b5abce87b50a7d6febe8d7bbbac92657cbda1db7c25572a4c1d0baea30447a865a2b1036b880037e2f4d26d453e9e913259779e9169b28a62eb809a5c744e04e260e1f2bbda874f1ac674839ddb47b3148c5946de0180148b7973d63c58193b17cd05d16e80cd7928c2a338363a23a81c0608c87505589b9da1c617e7b70786b6754fbb30a5816810b9e126cfcc5aa49326e9d842973874b6359b5db75610ba68a98c7b5e83f125a82522e13b83fb8f864e2a97b73b5d544a7415b6504a13939eab1595d64faf41fab25a864a574de524405e878339877886d2fc07fa0311508252413edfa1158466667aff78386daf7cb4c9b850992f96e20525330599ab601d454688e294c8c3e`
- output:
`0000000000000000000000000000000000000000000000000000000000000000`

#### Test vector 7

- description: Well formatted input and valid signature
- input:
`000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000003103d474d06cef2d8da1c97afd7d4993ba792297ca4e161967578494141cab0420200000000000000000000000000000000000000000000000000000000000002903933b3c07507e4201748494d832b6ee2a6c93bff9b0ee343b550d1f85a3d0de0d704c6d1784295130960fbe956c6851e141ab3c09a5475bdda2d81ee113f1e16e2ddd8e408bbb3f5b06a555d8f1ac072e5be2f9a365b33ace3d8254709c185b6f3d3db4b50baf14536779f24b5e843fb36b5a00ca475d1801a964d09961c1959dad0f80f0615476c75f58e4ae9a9f8eb93e65f1a4753ca75a62269d74a49ddc75f539bfecd60fe3c8966e77b01d9c69a965a39907862b2de754ad319644d21134fccee194278b326aa4e94359f1d4a08814cad9b27d62687cc31cfcf057490cea0512e02b3b3834e6803c30679f2f2ae2bf4d4e670b283f5105dad272da0f8b95168ea1080b184d98787ba335c22a0a40fd5ba4a70d905c373304c2759e695214f741b98629184789ffdaf63731b43188bda77ed49924da34968ee347b973b525ce0b40af92889b479e5e8717c05c923d76f0bf4689747de1821c1c42968eb164a5fe7c25ef75629511ce220c9d71c4fdb4d60b927b1e473dcda691062b6977338e8666b8c82b8f0f118eefeb5e66e408e63aa9cf876a0a4249688aae132955f5ea98fff2bb4f565b4ec4db39d414dd9c9d3edd089ac74af2f9f3feffa72332982d5e470a74bb2b3b7462639ed89319a327e8a11aef2e3cc391789b4c616b1aef335e9b47a294a47d2c42e7daca30c119e8098b6895aa32bb989a675aa72e84dc1ccc8b9f1a6cd274adbb86fc5ca9c2744cd73f064eba715e06dce542ef0646c94f41d3f47bb7c1a6c4e91ee55996dec4cbbc931f0047e3ba251f71b0bbc7e8633cc7479b1361697a131436d5958ee6fd1ccc1a5d31a9a8391bde2d075cce140de8f1dc58a093310821ae1d26917bc2a17dec09225374ee078d977f901825955ec8623304459a51e5cf7fe60c68b16800000000000000000000000000000000000000000000000000000000000000381096ba86cb658a8f445c9a5e4c28374bec879c8655f68526923240918074d0147c03162e4a49200648c652803c6fd7509ae9aa799d6310d0bd42724e0635920186207000767ca5a8546b1755308c304b84fc93b069e265985b398d6b834698287ff829aa820f17a7f4226ab21f601ebd7175226bab256d8888f009032566d6383d68457ea155a94301870d589c678ed304259e9d37b193bc2a7ccbcbec51d69158c44073aec9792630253318bc954dbf50d15028290dc2d309c7b7b02a6823744d463da17749595cb77e6d16d20d1b4c3aad89d320ebe5a672bb96d6cd5c1efec8b811200cbb062e473352540eddef8af9499f8cdd1dc7c6873f0c7a6bcb7097560271f946849b7f373640bb69ca9b518aa380a6eb0a7275ee84e9c221aed88f5bfbaf43a3ede8e6aa42558104faf800e018441930376c6f6e751569971f47adbca5ca00c801988f317a18722a29298925ea154dbc9024e120524a2d41dc0f18fd8d909f6c50977404e201767078ba9a1f9e40a8b2ba9c01b7da3a0b73a4c2a6b4f518bbee3455d0af2204ddc031c805c72ccb647940b1e6794d859aaebcea0deb581d61b9248bd9697b5cb974a8176e8f910469cae0ab4ed92d2aee9f7eb50296daf8057476305c1189d1d9840a0944f0447fb81e511420e67891b98fa6c257034d5a063437d379177ce8d3fa6eaf12e2dbb7eb8e498481612b1929617da5fb45e4cdf893927d8ba842aa861d9c50471c6d0c6df7e2bb26465a0eb6a3a709de792aafaaf922aa95dd5920b72b4b8856c6e632860b10f5cc08450003671af388961872b466400adb815ba81ea794945d19a100622a6ca0d41c4ea620c21dc125119e372418f04402d9fa7180f7bc89afa54f8082244a42f46e5b5abce87b50a7d6febe8d7bbbac92657cbda1db7c25572a4c1d0baea30447a865a2b1036b880037e2f4d26d453e9e913259779e9169b28a62eb809a5c744e04e260e1f2bbda874f1ac674839ddb47b3148c5946de0180148b7973d63c58193b17cd05d16e80cd7928c2a338363a23a81c0608c87505589b9da1c617e7b70786b6754fbb30a5816810b9e126cfcc5aa49326e9d842973874b6359b5db75610ba68a98c7b5e83f125a82522e13b83fb8f864e2a97b73b5d544a7415b6504a13939eab1595d64faf41fab25a864a574de524405e878339877886d2fc07fa0311508252413edfa1158466667aff78386daf7cb4c9b850992f96e20525330599ab601d454688e294c8c3e`
- output:
`73aa7ae4db8706ba89cbc14fa6ad475de55d65cb51c2c492ea4b1a1c4f1853e2`

## Implementation

- The implementation for Falcon-512 signature verification can be found in [Golang Liboqs-go](https://github.com/open-quantum-safe/liboqs-go).
- The reference implementation for the precompiled signature using Falcon can be found at [Go-Ethereum](https://github.com/lacchain/go-ethereum/pull/1)
- The reference iplementation for Hyperledger Besu Client can be found at [Besu Client](https://github.com/lacchain/besu/pull/1)

## References

For reference, further discussion on this EIP also occurred in the following PRs and issues

- [Original Issue](https://github.com/ethereum/EIPs/issues/xxxx)
- [Ethereum Magicians](https://ethereum-magicians.org/t/falcon-512-precompile/xxxx)
- [PR xxxx](https://github.com/ethereum/EIPs/pull/xxxx)

## Appendix - benchmarks

Assuming ecRecover precompile is perfectly priced, a set of benchmarks were executed comparing Falcon-512 signature verification function precompile with ecRecover precompile. For benchmarks, it was used 2.6 GHz Intel Core i7 64-bit machine.

```sh
$ cat /proc/cpuinfo | grep "model name"
Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz
```

### 5 seconds benchmark

An average gas price for Falcon-512 precompile call compared to ecRecover precompiled results in 2259 units of gas.

```
Name Gascost Time (ns) MGas/S Gasprice for 10MGas/S Gasprice for ECDSA eq
----------------------------------------- --------- ---------------- --------- ----------------------- -----------------------
PrecompiledEcrecover/ 3000 69396 43.2301 693.96 3000
PrecompiledFalcon512/ 1 52265 0.0191 522.65 2259.4241
```

### 10 seconds benchmark

An average gas price for Falcon-512 precompile call compared to ecRecover precompiled results in 2433 units of gas.

```
Name Gascost Time (ns) MGas/S Gasprice for 10MGas/S Gasprice for ECDSA eq
----------------------------------------- --------- ---------------- --------- ----------------------- -----------------------
PrecompiledEcrecover/ 3000 63478 47.2604 634.78 3000
PrecompiledFalcon512/ 1 51485 0.0194 514.85 2433.2052
```

### 30 seconds benchmark

An average gas price for Falcon-512 precompile call compared to ecRecover precompiled results in 2370 units of gas.

```
Name Gascost Time (ns) MGas/S Gasprice for 10MGas/S Gasprice for ECDSA eq
----------------------------------------- --------- ---------------- --------- ----------------------- -----------------------
PrecompiledEcrecover/ 3000 65715 45.6516 657.15 3000
PrecompiledFalcon512/ 1 51928 0.0192 519.28 2370.6003
```

Columns

- `MGas/S` - Shows what MGas per second was measured on that machine at that time
- `Gasprice for 10MGas/S` shows what the gasprice should have been, in order to reach 10 MGas/second
- `Gasprice for ECDSA eq` shows what the gasprice should have been, in order to have the same cost/cycle as ecRecover

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).

0 comments on commit 3819d15

Please sign in to comment.