Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update EIP-3026: Move to Draft #7006

Merged
merged 17 commits into from
Aug 22, 2023
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).