Skip to content

Commit

Permalink
Update EIP-3026: Move to Draft (ethereum#7006)
Browse files Browse the repository at this point in the history
* EIP-3026 gas meter

* Update

* Update

* Update

* Lint

* Lint

* Update

* Update

* Update
  • Loading branch information
hujw77 authored and RaphaelHardFork committed Jan 30, 2024
1 parent 75bd7e2 commit f5a5692
Showing 1 changed file with 64 additions and 33 deletions.
97 changes: 64 additions & 33 deletions EIPS/eip-3026.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
---
eip: 3026
title: BW6-761 curve operations
author: Youssef El Housni (@yelhousni), Michael Connor (@iAmMichaelConnor), Aurore Guillevic <aurore.guillevic@inria.fr>
author: Youssef El Housni (@yelhousni), Michael Connor (@iAmMichaelConnor), Aurore Guillevic <aurore.guillevic@inria.fr>, hujw77 (@hujw77)
discussions-to: https://ethereum-magicians.org/t/eip-3026-bw6-761-curve-operations/4790
status: Stagnant
status: Draft
type: Standards Track
category: Core
requires: 2539
created: 2020-10-05
---

## Simple Summary

This precompile adds operations for the BW6-761 curve (from the EY/Inria [research paper](https://eprint.iacr.org/2020/351.pdf)) as a precompile in a set necessary to *efficiently* perform verification of one-layer composed zkSNARKs proofs.

## Abstract
Expand Down Expand Up @@ -79,92 +80,101 @@ loop_count_1 is negative = false
loop_count_2 is negative = false
```

#### Encoding
### Encoding

##### Field elements encoding:
#### Field elements encoding:

To encode points involved in the operation one has to encode elements of only the base field.

The base field element (Fp) is encoded as `96` bytes by performing BigEndian encoding of the corresponding (unsigned) integer. The corresponding integer **MUST** be less than the base field modulus.

If encodings do not follow this spec anywhere during parsing in the precompile, the precompile **MUST** revert with "endoding error".

##### Encoding of uncompressed points:
#### Encoding of uncompressed points:

Points in both G1 and G2 can be expressed as `(x, y)` affine coordinates, where `x` and `y` are elements of the base field.
Therefore, points in both G1 and G2 are encoded as the byte concatenation of the field element encodings of the `x` and `y` affine coordinates. The total encoding length for a G1/G2 point is thus `192` bytes.

##### Point at infinity encoding:
#### Point at infinity encoding:

Also referred as the "zero point". For BW6-761 (`y^2=x^3-1`) and its M-twisted curves (`y^3=x^3+4`), the point with coordinates `(0, 0)` (formal zeros in Fp) is *not* on the curve, and so the encoding of `(0, 0)` is used as a convention to encode the point at infinity.

##### Encoding of scalars for multiplication and multiexponentiation operations:
#### Encoding of scalars for multiplication and multiexponentiation operations:

For multiplication and multiexponentiation operations, a scalar is encoded as `64` bytes by performing BigEndian encoding of the corresponding (unsigned) integer.

Note that the main subgroup order for BW6-761 is actually only `377` bits (`48` bytes), but an encoding of `64` bytes has been chosen to have a `32`-byte-aligned ABI (representable as e.g. `bytes32[2]` or `uint256[2]`).

The corresponding integer **MAY** be greater than the main subgroup order.

#### ABI for operations
### ABI for operations

##### ABI for G1 addition
#### ABI for G1 addition

G1 addition call expects `384` bytes as an input that is interpreted as the byte concatenation of two G1 points (point-encoded as `192` bytes each). Output is a point-encoding of the addition operation result.

Error cases:

- Either of the points being not on the curve
- Input has invalid length
- Field element encoding rules apply (obviously)

##### ABI for G1 multiplication
#### ABI for G1 multiplication

G1 multiplication call expects `256` bytes as an input that is interpreted as the byte concatenation of the point-encoding of a G1 point (`192` bytes) and the encoding of a scalar value (`64` bytes). Output is a point-encoding of the multiplication operation result.

Error cases:

- Point being not on the curve
- Input has invalid length
- Field element encoding rules apply (obviously)
- Scalar encoding rules apply (obviously)

##### ABI for G1 multiexponentiation
#### ABI for G1 multiexponentiation

G1 multiplication call expects `256*k` bytes as an input that is interpreted as the byte concatenation of `k` slices, each of them being a byte concatenation of the point-encoding of a G1 point (`192` bytes) and the encoding of a scalar value (`64` bytes). Output is an encoding of the multiexponentiation operation result.

Error cases:

- Any of the G1 points being not on the curve
- Input has invalid length
- Field element encoding rules apply (obviously)
- Scalar encoding rules apply (obviously)

##### ABI for G2 addition
#### ABI for G2 addition

G2 addition call expects `384` bytes as an input that is interpreted as the byte concatenation of two G2 points (point-encoded as `192` bytes each). Output is a point-encoding of the addition operation result.

Error cases:

- Either of points being not on the curve
- Input has invalid length
- Field elements encoding rules apply (obviously)

##### ABI for G2 multiplication
#### ABI for G2 multiplication

G2 multiplication call expects `256` bytes as an input that is interpreted as the byte concatenation of the point-encoding of a G2 point (`192` bytes) and the encoding of a scalar value (`64` bytes). Output is an encoding of multiplication operation result.

Error cases:

- Point being not on the curve must result in error
- Field elements encoding rules apply (obviously)
- Input has invalid length

##### ABI for G2 multiexponentiation
#### ABI for G2 multiexponentiation

G2 multiplication call expects `240*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G2 point (`192` bytes) and encoding of a scalar value (`48` bytes). Output is an encoding of multiexponentiation operation result.

Error cases:

- Any of G2 points being not on the curve must result in error
- Field elements encoding rules apply (obviously)
- Input has invalid length

##### ABI for pairing
#### ABI for pairing

Pairing call expects `384*k` bytes as an input, that is interpreted as the byte concatenation of `k` slices. Each slice has the following structure:

- `192` bytes G1 point encoding
- `192` bytes G2 point encoding

Expand All @@ -174,45 +184,54 @@ Output is `32` bytes representing a boolean:
- `0x0000000000000000000000000000000000000000000000000000000000000000` otherwise.

Error cases:

- Any of the G1 or G2 points being not on the curve
- Any of the G1 or G2 points being not in the correct subgroup
- Input has invalid length
- Field elements encoding rules apply (obviously)

#### Prevention of DDoS on error handling
### Prevention of DDoS on error handling

This precompile performs extensive computations and in case of any errors during execution it **MUST** consume all gas from the the gas schedule for the corresponding operation.

#### Gas schedule
### Gas schedule

#### G1 addition

`180` gas

#### G1 multiplication

`64000` gas

##### G1 addition
`<to be estimated>` gas
#### G2 addition

##### G1 multiplication
`<to be estimated>` gas
`180` gas

##### G2 addition
`<to be estimated>` gas
#### G2 multiplication

##### G2 multiplication
`<to be estimated>` gas
`64000` gas

#### G1/G2 Multiexponentiation

##### G1/G2 Multiexponentiation
Discounts table as a vector of pairs `[k, discount]`:

```
<to be estimated>
[[1, 1266], [2, 733], [3, 561], [4, 474], [5, 422], [6, 387], [7, 362], [8, 344], [9, 329], [10, 318], [11, 308], [12, 300], [13, 296], [14, 289], [15, 283], [16, 279], [17, 275], [18, 272], [19, 269], [20, 266], [21, 265], [22, 260], [23, 259], [24, 256], [25, 255], [26, 254], [27, 252], [28, 251], [29, 250], [30, 249], [31, 249], [32, 220], [33, 228], [34, 225], [35, 223], [36, 219], [37, 216], [38, 214], [39, 212], [40, 209], [41, 209], [42, 205], [43, 203], [44, 202], [45, 200], [46, 198], [47, 196], [48, 199], [49, 195], [50, 192], [51, 192], [52, 191], [53, 190], [54, 187], [55, 186], [56, 185], [57, 184], [58, 184], [59, 181], [60, 181], [61, 181], [62, 180], [63, 178], [64, 179], [65, 176], [66, 177], [67, 176], [68, 175], [69, 174], [70, 173], [71, 171], [72, 171], [73, 170], [74, 170], [75, 169], [76, 168], [77, 168], [78, 167], [79, 167], [80, 166], [81, 165], [82, 167], [83, 166], [84, 166], [85, 165], [86, 165], [87, 164], [88, 164], [89, 163], [90, 163], [91, 162], [92, 162], [93, 160], [94, 163], [95, 159], [96, 162], [97, 159], [98, 160], [99, 159], [100, 159], [101, 158], [102, 158], [103, 158], [104, 158], [105, 157], [106, 157], [107, 156], [108, 155], [109, 155], [110, 156], [111, 155], [112, 155], [113, 154], [114, 155], [115, 154], [116, 153], [117, 153], [118, 153], [119, 152], [120, 152], [121, 152], [122, 152], [123, 151], [124, 151], [125, 151], [126, 151], [127, 151], [128, 150]]
```

`max_discount = <to be estimated>`
`max_discount = 150`

#### Pairing operation

##### Pairing operation
Base cost of the pairing operation is `<to be estimated>*k + <to be estimated>` where `k` is a number of pairs.
Base cost of the pairing operation is `120000*k + 320000` where `k` is a number of pairs.

## Rationale

Gas costs are based on EIP1962 estimation strategy (but do not fully include yet parsing of ABI, decoding and encoding of the result as a byte array).

#### Gas estimation strategy
### Gas estimation strategy

Gas cost is derived by taking the average timing of the same operations over different implementations and assuming a constant `30 MGas/second`. Since the execution time is machine-specific, this constant is determined based on execution times of [ECRECOVER](https://github.com/matter-labs/eip1962/blob/master/run_bn_pairing_estimate.sh) and [BNPAIR](https://github.com/matter-labs/eip1962/blob/master/run_bn_pairing_estimate.sh) precompiles on my machine and their proposed gas price (`43.5 MGas/s` for ECRECOVER and `16.5 MGas/s` for BNPAIR). Following are the proposed methods to time the precompile operations:

- G1 addition: Average timing of 1000 random samples.
Expand All @@ -222,13 +241,16 @@ Gas cost is derived by taking the average timing of the same operations over dif
- G1 and G2 multiexponentiations: Expected to be performed by the Peppinger algorithm, with a table prepared for discount in case of `k <= 128` points in the multiexponentiation with a discount cup `max_discount` for `k > 128`. To avoid non-integer arithmetic call cost is calculated as `k * multiplication_cost * discount / multiplier` where `multiplier = 1000`, `k` is a number of (scalar, point) pairs for the call, `multiplication_cost` is a corresponding single multiplication call cost for G1/G2.
- Pairing: Average timing of 1000 random samples (random points in G1 and G2) for different number of pairs with linear lifting.

#### Multiexponentiation as a separate call
### Multiexponentiation as a separate call

Explicit separate multiexponentiation operation that allows one to save execution time (so gas) by both the algorithm used (namely Peppinger algorithm) and (usually forgotten) by the fact that `CALL` operation in Ethereum is expensive (at the time of writing), so one would have to pay non-negigible overhead if e.g. for multiexponentiation of `100` points would have to call the multipication precompile `100` times and addition for `99` times (roughly `138600` would be saved).

#### Explicit subgroup checks
### Explicit subgroup checks

G2 subgroup check has the same cost as G1 subgroup check. Endomorphisms can be leverages to optimize this operation.

## Backwards Compatibility

There are no backward compatibility questions.

## Test Cases
Expand All @@ -246,32 +268,41 @@ Requeired properties for basic ops (add/multiply):
- Multiplication by the unnormalized scalar `(scalar + group_order) * P = scalar * P`

Required properties for pairing operation:

- Degeneracy `e(P, 0*Q) = e(0*P, Q) = 1`
- Bilinearity `e(a*P, b*Q) = e(a*b*P, Q) = e(P, a*b*Q)` (internal test, not visible through ABI)

Test vector for all operations are expanded in this [gist](https://gist.github.com/shamatar/506ab3193a7932fe9302a2f3a31a23e8) until it's final.

## Implementation

There is a various choice of existing implementations:

**Libraries:**

- Rust implementation (EY/Zexe): https://github.com/yelhousni/zexe/tree/youssef/BW6-761-Fq-ABLR-2ML-M
- C++ implementation (EY/libff): https://github.com/EYBlockchain/zk-swap-libff
- Golang implementation (Consensys/gurvy): https://github.com/ConsenSys/gurvy

**Stand-alone implementation:**

- Golang implementation with Intel assembly (Onur Kilic): https://github.com/kilic/bw6

**Precompiles:**

- OpenEthereum (EY/Parity): https://github.com/EYBlockchain/solidity-elliptic-curves
- Frontier (Parity): https://github.com/paritytech/frontier/pull/1049/files

**Scripts:**

- SageMath and Magma scripts: https://gitlab.inria.fr/zk-curves/bw6-761/

## Security Considerations

Strictly following the spec will eliminate security implications or consensus implications in a contrast to the previous BN254 precompile.

Important topic is a "constant time" property for performed operations. We explicitly state that this precompile **IS NOT REQUIRED** to perform all the operations using constant time algorithms.

## Copyright

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

0 comments on commit f5a5692

Please sign in to comment.