Skip to content

Latest commit

 

History

History
1212 lines (844 loc) · 59.4 KB

nep-0488.md

File metadata and controls

1212 lines (844 loc) · 59.4 KB
NEP Title Authors Status DiscussionsTo Type Version Created LastUpdated
488
Host Functions for BLS12-381 Curve Operations
Olga Kuniavskaia <olga.kunyavskaya@aurora.dev>
Final
Runtime Spec
0.0.1
2023-07-17
2023-11-21

Summary

This NEP introduces host functions to perform operations on the BLS12-381 elliptic curve. It is a minimal set of functions needed to efficiently verify BLS signatures and zkSNARKs.

Motivation

The primary aim of this NEP is to enable fast and efficient verification of BLS signatures and zkSNARKs based on the BLS12-3811,2,3 elliptic curve on NEAR.

To efficiently verify zkSNARKs4, host functions for operations on the BN254 elliptic curve (also known as Alt-BN128)5, 6 have already been implemented on NEAR7. For instance, the Zeropool8 project utilizes these host functions for verifying zkSNARKs on NEAR. However, recent research shows that the BN254 security level is lower than 100-bit9 and it is not recommended for use. BLS12-381, on the other hand, offers over 120 bits of security10 and is widely used11,12,13,14,15,16 as a robust alternative. Supporting operations for BLS12-381 elliptic curve will significantly enhance the security of projects similar to Zeropool.

Another crucial objective is the verification of BLS signatures. Initially, host functions for BN254 on NEAR were designed for zkSNARK verification and are insufficient for BLS signature verification. However, even if these host functions were sufficient for BLS signature verification on the BN254 elliptic curve, this would not be enough for compatibility with other projects. In particular, projects such as ZCash11, Ethereum12, Tezos14, and Filecoin15 incorporate BLS12-381 specifically within their protocols. If we aim for compatibility with these projects, we must also utilize this elliptic curve. For instance, to create a trustless bridge17 between Ethereum and NEAR, we must efficiently verify BLS signatures based on BLS12-381, as these are the signatures employed within Ethereum's protocol.

In this NEP, we propose to add the following host functions:

  • bls12381_p1_sum — computes the sum of signed points from $E(F_p)$ elliptic curve. This function is useful for aggregating public keys or signatures in the BLS signature scheme. It can be employed for simple addition in $E(F_p)$. It is kept separate from the multiexp function due to gas cost considerations.
  • bls12381_p2_sum — computes the sum of signed points from $E'(F_{p^2})$ elliptic curve. This function is useful for aggregating signatures or public keys in the BLS signature scheme.
  • bls12381_g1_multiexp — calculates $\sum p_i s_i$ for points $p_i \in G_1 \subset E(F_p)$ and scalars $s_i$. This operation can be used to multiply a group element by a scalar.
  • bls12381_g2_multiexp — calculates $\sum p_i s_i$ for points $p_i \in G_2 \subset E'(F_{p^2})$ and scalars $s_i$.
  • bls12381_map_fp_to_g1 — maps base field elements into $G_1$ points. It does not perform the mapping of byte strings into field elements.
  • bls12381_map_fp2_to_g2 — maps extension field elements into $G_2$ points. This function does not perform the mapping of byte strings into extension field elements, which would be needed to efficiently map a message into a group element. We are not implementing the hash_to_field18 function because the latter can be executed within a contract and various hashing algorithms can be used within this function.
  • bls12381_p1_decompress — decompresses points from $E(F_p)$ provided in a compressed form. Certain protocols offer points on the curve in a compressed form (e.g., the light client updates in Ethereum 2.0), and decompression is a time-consuming operation. All the other functions in this NEP only accept decompressed points for simplicity and optimized gas consumption.
  • bls12381_p2_decompress — decompresses points from $E'(F_{p^2})$ provided in a compressed form.
  • bls12381_pairing_check — verifies that $\prod e(p_i, q_i) = 1$, where $e$ is a pairing operation and $p_i \in G_1 \land q_i \in G_2$. This function is used to verify BLS signatures or zkSNARKs.

Functions required for verifying BLS signatures19:

  • bls12381_p1_sum
  • bls12381_p2_sum
  • bls12381_map_fp2_to_g2
  • bls12381_p1_decompress
  • bls12381_p2_decompress
  • bls12381_pairing_check

Functions required for verifying zkSNARKs:

  • bls12381_p1_sum
  • bls12381_g1_multiexp
  • bls12381_pairing_check

Both zkSNARKs and BLS signatures can be implemented alternatively by swapping $G_1$ and $G_2$. Therefore, all functions have been implemented for both $G_1$ and $G_2$.

An analogous proposal, EIP-253720, exists in Ethereum. The functions here have been designed with compatibility with that Ethereum's proposal in mind. This design approach aims to ensure future ease in supporting corresponding precompiles for Aurora21.

Specification

BLS12-381 Curve Specification

Elliptic Curve

The field $F_p$ for some prime $p$ is a set of integer elements $\textbraceleft 0, 1, \ldots, p - 1 \textbraceright$ with two operations: multiplication $\cdot$ and addition $+$. These operations involve standard integer multiplication and addition, followed by computing the remainder modulo $p$.

The elliptic curve $E(F_p)$ is the set of all pairs $(x, y)$ with coordinates in $F_p$ satisfying:

$$ y^2 \equiv x^3 + Ax + B \mod p $$

together with an imaginary point at infinity $\mathcal{O}$, where: $A, B \in F_p$, $p$ is a prime $&gt; 3$, and $4A^3 + 27B^2 \not \equiv 0 \mod p$

In the case of BLS12-381 the equation is $y^2 \equiv x^3 + 4 \mod p$20,22,23,2

Parameters for our case:

  • $A = 0$
  • $B = 4$
  • $p = \mathtt{0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab}$

Let $P \in E(F_q)$ have coordinates $(x, y)$, define $-P$ as a point on a curve with coordinates $(x, -y)$.

The addition operation for Elliptic Curve is a function $+\colon E(F_p) \times E(F_p) \rightarrow E(F_p)$ defined with following rules: let $P$ and $Q \in E(F_p)$

  • if $P \ne Q$ and $P \ne -Q$
    • draw a line passing through $P$ and $Q$. This line intersects the curve at a third point $R$.
    • reflect the point $R$ across the $x$-axis by changing the sign of the $y$-coordinate. The resulting point is $P+Q$.
  • if $P=Q$
    • draw a tangent line through $P$ for an elliptic curve. The line will intersect the curve at the second point $R$.
    • reflect the point $R$ across the $x$-axis the same way to get point $2P$
  • $P = -Q$
    • $P + Q = P + (-P) = \mathcal{O}$ — the point on infinity
  • $Q = \mathcal{O}$
    • $P + Q = P + \mathcal{O} = P$

With the addition operation, Elliptic Curve forms a group.

Subgroups

Subgroup H is a subset of the group G with the following properties:

  • $\forall h_1, h_2 \in H\colon h_1 + h_2 \in H$
  • $0 \in H$
  • $\forall h \in H \colon -h \in H$

Notation: $H \subseteq G$

Group/subgroup order is the number of elements in group/subgroup.

Notation: |G| or #G, where G represents the group.

For some technical reason (related to the pairing operation which we will define later), we will not operate over the entire $E(F_p)$, but only over the two subgroups $G_1$ and $G_2$ having the same order $r$. $G_1$ is a subset of $E(F_p)$, while $G_2$ is a subgroup of another group that we will define later. The value of $r$ should be a prime number and $G_1 \ne G_2$

For the BLS12-381 Elliptic Curve, the order r of $G_1$ and $G_2$20,22 is given by:

  • $r = \mathtt{0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001}$

Field extension

The field extension $F_{p^k}$ of $F_{p}$ is a set comprising all polynomials of degree < k and coefficients from $F_p$, along with defined operations of multiplication ($\cdot$) and addition ($+$).

$$ a_{k - 1}x^{k - 1} + \ldots + a_1x + a_0 = A(x) \in F_{p^k} \vert a_i \in F_p $$

The addition operation ($+$) is defined as regular polynomial addition:

$$ A(x) + B(x) = C(x) $$

$$ \sum a_i x^i + \sum b_i x^i = \sum c_i x^i $$

$$ c_i = (a_i + b_i) \mod p $$

The multiplication $\cdot$ is defined as regular polynomial multiplication modulo $M(x)$, where $M(x)$ is an irreducible polynomial of degree $k$ with coefficients from $F_p$.

$$ C(x) = A(x) \cdot B(x)\mod M(x) $$

Notation: $F_{p^k} = F_{p}[x] / M(x)$

In BLS12-381, we will require $F_{p^{12}}$. We'll construct this field not directly as an extension from $F_p$, but rather through a stepwise process. First, we'll build $F_{p^2}$ as a quadratic extension of the field $F_p$. Second, we'll establish $F_{p^6}$ as a cubic extension of $F_{p^2}$. Finally, we'll create $F_{p^{12}}$ as a quadratic extension of the field $F_{p^6}$.

To define these fields, we'll need to set up three irreducible polynomials22:

  • $F_{p^2} = F_p[u] / (u^2 + 1)$
  • $F_{p^6} = F_{p^2}[v] / (v^3 - u - 1)$
  • $F_{p^{12}} = F_{p^6}[w] / (w^2 - v)$

The second subgroup we'll utilize has order r and resides within the same elliptic curve but with elements from $F_{p^{12}}$. Specifically, $G_2 \subset E(F_{p^{12}})$, where $E: y^2 = x^3 + 4$

Twist

Storing elements from $E(F_{p^{12}})$ consumes a significant amount of memory. The twist operation transforms the original curve $E(F_{p^{12}})$ into another curve within a different space, denoted as $E'(F_{p^2})$. It is crucial that this new curve also includes a $G'_2$ subgroup with order 'r' so that we can easily transform it back to the original $G_2$.

We want to have $\psi \colon E'(F_{p^2}) \rightarrow E(F_{p^{12}})$, such as

  • $\forall a, b \in E'(F_{p^2}) \colon \psi(a + b) = \psi(a) + \psi(b)$
  • $\forall a, b \in E'(F_{p^2}) \colon \psi(a) = \psi(b) \Rightarrow a = b$

This is referred to as an injective group homomorphism.

For BLS12-381, E’ is defined as22:

$$ E'\colon y^2 = x^3 + 4(u + 1) $$

In most cases, we will be working with points from $G_2' \subset E'(F_{p^2})$ and will simply use the notation $G_2$ for this subgroup.

Generators

If there exists an element $g$ in the group $G$ such that $\textbraceleft g, 2 \cdot g, 3 \cdot g, \ldots, |G|g \textbraceright = G$, the group $G$ is called a cyclic group and $g$ is termed a generator

$G_1$ and $G_2$ are cyclic subgroups with the following generators20,22:

$G_1$:

  • $x = \mathtt{0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb}$
  • $y = \mathtt{0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1}$

For $(x', y') \in G_2 \subset E'(F_{p^2}):$ $$x' = x_0 + x_1u$$

$$y' = y_0 + y_1u$$

$G_2$:

  • $x_0 = \mathtt{0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8}$
  • $x_1 = \mathtt{0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e}$
  • $y_0 = \mathtt{0x0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801}$
  • $y_1 = \mathtt{0x0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be}$

Cofactor is the ratio of the size of the entire group $G$ to the size of the subgroup $H$:

$$ |G|/|H| $$

Cofactor $G_1\colon h = |E(F_p)|/r$22

$$h = \mathtt{0x396c8c005555e1568c00aaab0000aaab}$$

Cofactor $G_2\colon h' = |E'(F_{p^2})|/r$22

$$h' = \mathtt{0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5}$$

Pairing

Pairing is a necessary operation for the verification of BLS signatures and certain zkSNARKs. It performs the operation $e\colon G_1 \times G_2 \rightarrow G_T$, where $G_T \subset F_{p^{12}}$.

The main properties of the pairing operation are:

  • $e(P, Q + R) = e(P, Q) \cdot e(P, R)$
  • $e(P + S, R) = e(P, R)\cdot e(S, R)$

To compute this function, we utilize an algorithm called Miller Loop. For an affective implementation of this algorithm, we require a key parameter for the BLS curve, denoted as $x$:

$$ x = -\mathtt{0xd201000000010000}$$

This parameter can be found in the following sources:

  • 20 section specification, pairing parameters, Miller loop scalar
  • 22 section 4.2.1 Parameter t
  • 23 section BLS12-381, parameter u
  • 2 section Curve equation and parameters, parameter x

Summary

The parameters for the BLS12-381 curve are as follows:

Base field modulus: $p = \mathtt{0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab}$

$$ E\colon y^2 \equiv x^3 + 4 $$

$$ E'\colon y^2 \equiv x^3 + 4(u + 1) $$

Main subgroup order: $r = \mathtt{0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001}$

$$ F_{p^2} = F_p[u] / (u^2 + 1) $$

$$ F_{p^6} = F_{p^2}[v] / (v^3 - u - 1) $$

$$ F_{p^{12}} = F_{p^6}[w] / (w^2 - v) $$

Generator for $G_1$:

  • $x = \mathtt{0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb}$
  • $y = \mathtt{0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1}$

Generator for $G_2$:

  • $x_0 = \mathtt{0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8}$
  • $x_1 = \mathtt{0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e}$
  • $y_0 = \mathtt{0x0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801}$
  • $y_1 = \mathtt{0x0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be}$

Cofactor for $G_1$: $$h = \mathtt{0x396c8c005555e1568c00aaab0000aaab}$$

Cofactor for $G_2$: $$h' = \mathtt{0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5}$$

Key BLS12-381 parameter used in Miller Loop: $$x = -\mathtt{0xd201000000010000}$$

All parameters were sourced from 20, 22, and 23, and they remain consistent across these sources.

Map to curve specification

This section delineates the functionality of the bls12381_map_fp_to_g1 and bls12381_map_fp2_to_g2 functions, operating in accordance with the RFC9380 specification "Hashing to Elliptic Curves"24.

These functions map field elements in $F_p$ or $F_{p^2}$ to their corresponding subgroups: $G_1 \subset E(F_p)$ or $G_2 \subset E'(F_{p^2})$. bls12381_map_fp_to_g1/bls12381_map_fp2_to_g2 combine the functionalities of map_to_curve and clear_cofactor from RFC938025.

fn bls12381_map_fp_to_g1(u):
    let Q = map_to_curve(u);
    return clear_cofactor(Q);

We choose not to implement the hash_to_field function as a host function due to potential changes in hashing methods. Additionally, executing this function within the contract consumes approximately 2 TGas, which is acceptable for our goals.

Specific implementation parameters for bls12381_map_fp_to_g1 and bls12381_map_fp2_to_g2 can be found in RFC9380 under sections 8.8.126 and 8.8.227, respectively.

Curve points encoding

General comments

The encoding rules for curve points and field elements align with the standards established in zkcrypto28 and the implementation in the milagro lib29.

For elements from $F_p$ the first three bits will always be $0$, because the first byte of $p$ equals $1$. As a result, we can use these bits to encode extra information: the encoding format, the point at infinity, and the points' sign. Read more in sections: Uncompressed/compressed points on curve $E(F_p)$ / $E'(F_{p^2})$.

Sign

The sign of a point on the elliptic curve is represented as a u8 type in Rust, with two possible values: 0 for a positive sign and 1 for a negative sign. Any other u8 value is considered invalid and should be treated as incorrect.

Scalar

A scalar value is encoded as little-endian [u8; 32]. All possible byte combinations are allowed.

Fields elements $F_p$

Values from $F_p$ are encoded as big-endian [u8; 48]. Only values less than p are permitted. If the value is equal to or greater than p, an error should be returned.

Extension fields elements $F_{p^2}$

An element $q \in F_{p^{2}}$ can be expressed as $q = c_0 + c_1 v$, where $c_0, c_1 \in F_p$. An element from $F_{p^2}$ is encoded in [u8; 96] as the byte concatenation of $c_1$ and $c_0$. The encoding for $c_1$ and $c_0$ follows the rule described in the previous section.

Uncompressed points on curve $E(F_p)$

Points on the curve are represented by affine coordinates: $(x: F_p, y: F_p)$. Elements from $E(F_p)$ are encoded in [u8; 96] as the byte concatenation of the x and y point coordinates, where $x, y \in F_p$. The encoding follows the rules outlined in the section “Fields elements $F_p$”.

The second-highest bit within the encoding serves to signify a point at infinity. When this bit is set to 1, it designates an infinity point. In this case, all other bits should be set to 0.

Encoding the point at infinity:

let x: [u8; 96] = [0; 96];
x[0] = x[0] | 0x40;

Compressed points on curve $E(F_p)$

The points on the curve are represented by affine coordinates: $(x: F_p, y: F_p)$. Elements from $E(F_p)$ in compressed form are encoded as [u8; 48], with big-endian encoded $x \in F_p$. The $y$ coordinate is determined by the formula: $y = \pm \sqrt{x^3 + 4}$.

  • The highest bit indicates that the point is encoded in compressed form and thus must always be set to 1.
  • The second-highest bit marks the point at infinity (if set to 1).
    • For the point at infinity, all bits except the first two should be set to 0; other encodings should be considered as incorrect.
  • To represent the sign of $y$, the third-highest bit in the x encoding is utilized.
    • If the bit is 0, $y$ is positive; if 1, $y$ is negative. We'll consider the number positive by taking the smallest value between $y$ and $-y$, after reducing them to $[0, p)$.

The encoding for $x \in F_p$ as [u8; 48] bytes follows the rules described in the section "Extension fields elements $F_{p}$".

Encoding a point on $E(F_p)$ with a negative $y$ coordinate:

let x: [u8; 48] = encodeFp(x)
x[0] = x[0] | 0x80;
x[0] = x[0] | 0x20;

Encoding the point at infinity:

let x: [u8; 48] = [0; 48];
x[0] = x[0] | 0x80;
x[0] = x[0] | 0x40;

Uncompressed points on the twisted curve $E'(F_{p^2})$

The points on the curve are represented by affine coordinates: $(x: F_{p^2}, y: F_{p^2})$. Elements from $E'(F_{p^2})$ are encoded in [u8; 192] as a concatenation of bytes representing x and y coordinates, where $x, y \in F_{p^2}$. The encoding for $x$ and $y$ follows the rules detailed in the "Extension Fields Elements $F_{p^2}$" section.

The second-highest bit within the encoding serves to signify a point at infinity. When this bit is set to 1, it designates an infinity point. In this case, all other bits should be set to 0.

Encoding the point at infinity:

let x: [u8; 192] = [0; 192];
x[0] = x[0] | 0x40;

Compressed points on twisted curve $E'(F_{p^2})$

The points on the curve are represented by affine coordinates: $(x: F_{p^2}, y: F_{p^2})$. Elements from $E'(F_{p^2})$ in compressed form are encoded as [u8; 96], with big-endian encoded $x \in F_{p^2}$. The $y$ coordinate is determined using the formula: $y = \pm \sqrt{x^3 + 4(u + 1)}$.

  • The highest bit indicates if the point is encoded in compressed form and should be set to 1.
  • The second-highest bit marks the point at infinity (if set to 1).
    • For the point at infinity, all bits except the first two should be set to 0; other encodings should be considered as incorrect.
  • To represent the sign of $y$, the third-highest bit in the x encoding is utilized.
    • If the bit is 0, $y$ is positive; if 1, $y$ is negative. We'll consider the number positive by taking the smallest value between $y$ and $-y$: first compare $c_1$, then $c_0$, after reduction to $[0, p)$.

The encoding of $x \in F_{p^2}$ as [u8; 96] bytes follows the rules from the section “Extension Fields Elements $F_{p^2}$”.

Encoding a point on $E'(F_{p^2})$ with a negative $y$ coordinate:

let x: [u8; 96] = encodeFp2(x);
x[0] = x[0] | 0x80;
x[0] = x[0] | 0x20;

Encoding the point at infinity:

let x: [u8; 96] = [0; 96];
x[0] = x[0] | 0x80;
x[0] = x[0] | 0x40;

ERROR_CODE

Validating the input for the host functions within the contract can consume significant gas. For instance, verifying if a point belongs to the subgroup is gas-consuming. If an error is returned by the near host function, the entire execution is reverted. To mitigate this, when the input verification is complex, the host function will successfully complete its work but return an ERROR_CODE. This enables users to handle error cases independently. It's important to note that host functions might terminate with an error if it's straightforward to avoid it (e.g., incorrect input size).

The ERROR_CODE is an u64 and can hold the following values:

  • 0: No error, execution was successful. For bls12381_pairing_check function, the pairing result equals the multiplicative identity.
  • 1: Execution finished with error due to:
    • Incorrect encoding (e.g., incorrectly set compression/decompression bit, coordinate >= p, etc.).
    • A point not on the curve (where applicable).
    • A point not in the expected subgroup (where applicable).
  • 2: Can be returned only in bls12381_pairing_check. No error, execution was successful, but the pairing result doesn't equal the multiplicative identity.

Host functions

General comments for all functions

In all functions, the input is fetched from memory, beginning at value_ptr and extending to value_ptr + value_len. If value_len is u64::MAX, input will come from the register with id value_ptr.

Execution ends only if there's an incorrect input length, input extends beyond memory bounds, or gas limits are reached. Otherwise, execution completes successfully, providing the ERROR_CODE.

If the ERROR_CODE equals 0, the output data will be written to the register with the register_id identifier. Otherwise, nothing will be written to the register.

Gas Estimation:

The algorithms described above exhibit linear complexity concerning the number of elements. Gas estimation can be calculated using the following formula:

let k = input_bytes/item_size
let gas_consumed = A + B * k

Here, A and B denote empirically calculated constants unique to each algorithm.

For gas estimation, the benchmark vectors outlined in EIP-253730 can be used where applicable.

Error cases (execution is terminated):

For all functions, execution will terminate in the following cases:

  • The input length is not divisible by item_size.
  • The input is beyond memory bounds.

bls12381_p1_sum

Description:

The function calculates the sum of signed elements on the BLS12-381 curve. It accepts an arbitrary number of pairs $(s_i, p_i)$, where $p_i \in E(F_p)$ represents a point on the elliptic curve, and $s_i \in {0, 1}$ signifies the point's sign. The output is a single point from $E(F_p)$ equivalent to $\sum (-1)^{s_i}p_i$.

The operations, including the $E(F_p)$ curve, points on the curve, multiplication by -1, and the addition operation, are detailed in the BLS12-381 Curve Specification section.

Note: This function accepts points from the entire curve and is not restricted to points in $G_1$.

Input:

The sequence of pairs $(s_i, p_i)$, where $p_i \in E(F_p)$ represents a point and $s_i \in {0, 1}$ denotes the sign. Each point is encoded in decompressed form as $(x\colon F_p, y\colon F_p)$, and the sign is encoded in one byte, taking only two allowed values: 0 or 1. Expect 97*k bytes as input, which are interpreted as byte concatenation of k slices, with each slice representing the point sign and the uncompressed point from $E(F_p)$. Further details are available in the Curve Points Encoding section.

Output:

The ERROR_CODE is returned.

  • ERROR_CODE = 0: the input is correct
    • Output: 96 bytes represent one point $\in E(F_p)$ in its decompressed form. In case of an empty input, it outputs a point on infinity (refer to the Curve Points Encoding section for more details).
  • ERROR_CODE = 1:
    • Points or signs are incorrectly encoded (refer to Curve points encoded section).
    • Point is not on the curve.

Test cases:

Tests for the sum of two points

This section aims to verify the correctness of summing up two valid elements on the curve:

  • Utilize points on the curve with known addition results for comparison, such as tests from EIP-253731,32.
  • Generate random points on the curve and verify the commutative property: P + Q = Q + P.
  • Validate that the sum of random points from $G_1$ remains in $G_1$.
  • Generate random points on the curve and use another library to cross-check the results.

Edge cases:

  • Points not from $G_1$.
  • $\mathcal{O} + \mathcal{O} = \mathcal{O}$.
  • $P + \mathcal{O} = \mathcal{O} + P = P$.
  • $P + (-P) = (-P) + P = \mathcal{O}$.
  • P + P (tangent to the curve).
  • The sum of two points P and (-(P + P)) (tangent to the curve at point P).

Tests for inversion

This section aims to validate the correctness of point inversion:

  • Generate random points on the curve and verify $P - P = -P + P = \mathcal{O}$.
  • Generate random points on the curve and verify -(-P) = P.
  • Generate random points from $G_1$ and ensure that -P also belong to $G_1$.
  • Utilize an external implementation, generate random points on the curve, and compare results.

Edge cases:

  • Points not from $G_1$.
  • $-\mathcal{O}$

Tests for incorrect data

This section aims to validate the handling of incorrect input data:

  • Incorrect input length.
  • Incorrect sign value (not 0 or 1).
  • Erroneous coding of field elements: one of the first three bits set up incorrectly.
  • Erroneous coding of field elements resulting in a correct element on the curve modulo p.
  • Erroneous coding of field elements with an incorrect extra bit in the decompressed encoding.
  • Point not on the curve.
  • Incorrect encoding of the point at infinity.
  • Input is beyond memory bounds.

Tests for the sum of an arbitrary amount of points

This section focuses on validating the summation functionality with an arbitrary number of points:

  • Generate random points on the curve and verify that the sum of a random permutation matches.
  • Generate random points on the curve and utilize another library to validate results.
  • Create points and cross-check the outcome with the multiexp function.
  • Generate random points from $G_1$ and confirm that the sum is also from $G_1$.

Edge cases:

  • Empty input
  • Sum with the maximum number of elements
  • A single point

Annotation:

pub fn bls12381_p1_sum(&mut self,
                       value_len: u64,
                       value_ptr: u64,
                       register_id: u64) -> Result<u64>;

bls12381_p2_sum

Description:

The function computes the sum of the signed elements on the BLS12-381 curve. It accepts an arbitrary number of pairs $(s_i, p_i)$, where $p_i \in E'(F_{p^2})$ represents a point on the elliptic curve and $s_i \in {0, 1}$ is the point's sign. The output is a single point from $E'(F_{p^2})$ equal to $\sum (-1)^{s_i}p_i$.

The $E'(F_{p^2})$ curve, the points on the curve, the multiplication by -1, and the addition operation are all defined in the BLS12-381 Curve Specification section.

Note: The function accepts any points on the curve and is not limited to points in $G_2$.

Input:

The sequence of pairs $(s_i, p_i)$, where $p_i \in E'(F_{p^2})$ is point and $s_i \in \textbraceleft 0, 1 \textbraceright$ represents a sign. Each point is encoded in decompressed form as $(x: F_{p^2}, y: F_{p^2})$, and the sign is encoded in one byte. The expected input size is 193*k bytes, interpreted as a byte concatenation of k slices, each slice representing the point sign alongside the uncompressed point from $E'(F_{p^2})$. More details are available in the Curve Points Encoding section.

Output:

The ERROR_CODE is returned.

  • ERROR_CODE = 0: the input is correct
    • Output: 192 bytes represent one point $\in E'(F_{p^2})$ in its decompressed form. In case of an empty input, it outputs the point at infinity (refer to the Curve Points Encoding section for more details).
  • ERROR_CODE = 1:
    • Points or signs are incorrectly encoded (refer to Curve points encoded section).
    • Point is not on the curve.

Test cases:

The test cases are identical to those of bls12381_p1_sum, with the only alteration being the substitution of points from $G_1$ and $E(F_p)$ with points from $G_2$ and $E'(F_{p^2})$.

Annotation:

pub fn bls12381_p2_sum(&mut self,
                       value_len: u64,
                       value_ptr: u64,
                       register_id: u64) -> Result<u64>;

bls12381_g1_multiexp

Description:

The function accepts a list of pairs $(p_i, s_i)$, where $p_i \in G_1 \subset E(F_p)$ represents a point on the curve, and $s_i \in \mathbb{N}_0$ denotes a scalar. It calculates $\sum s_i \cdot p_i$.

The scalar multiplication operation signifies the addition of that point a scalar number of times:

$$ s \cdot p = \underbrace{p + p + \ldots + p}_{s} $$

The $E(F_p)$ curve, $G_1$ subgroup, points on the curve, and the addition operation are defined in the BLS12-381 Curve Specification section.

Please note:

  • The function accepts only points from $G_1$.
  • The scalar is an arbitrary unsigned integer and can exceed the group order.
  • To enhance gas efficiency, the Pippenger’s algorithm33 can be utilized.

Input: The sequence of pairs $(p_i, s_i)$, where $p_i \in G_1 \subset E(F_p)$ represents a point on the curve, and $s_i \in \mathbb{N}_0$ is a scalar. The expected input size is 128*k bytes, interpreted as byte concatenation of k slices. Each slice comprises the concatenation of an uncompressed point from $G_1 \subset E(F_p)$— 96 bytes, along with a scalar— 32 bytes. Further details are available in the Curve Points Encoding section.

Output:

The ERROR_CODE is returned.

  • ERROR_CODE = 0: the input is correct
    • Output: 96 bytes represent one point $\in G_1 \subset E(F_p)$ in its decompressed form. In case of an empty input, it outputs the point at infinity (refer to the Curve Points Encoding section for more details).
  • ERROR_CODE = 1:
    • Points are incorrectly encoded (refer to Curve points encoded section).
    • Point is not on the curve.
    • Point is not from $G_1$

Test cases:

Tests for multiplication

  • Tests with known answers for multiplication from EIP-253731,32.
  • Random small scalar n and point P:
    • Check results with the sum function: P + P + P + .. + P = n*P.
    • Compare with results from another library.
  • Random scalar n and point P:
    • Verify against results from another library.
    • Implement multiplication by using the sum function and the double-and-add algorithm34.

Edge cases:

  • group_order * P = 0
  • (scalar + groupt_order) * P = scalar * P
  • P + P + P .. + P = N*P
  • 0 * P = 0
  • 1 * P = P
  • Scalar is a MAX_INT

Tests for sum of two points

These are identical test cases to those in the bls12381_p1_sum section, but only with points from $G_1$ subgroup.

  • Generate random points P and Q, then compare the results with the sum function.

Tests for the sum of an arbitrary amount of points

  • Random number of points, random point values; compare results with the sum function.
  • Empty input.
  • Input of maximum size.

Tests for the multiexp of an arbitrary amount of points

  • Tests with known answers from EIP-253731,32
  • Random number of points, scalars, and points:
    • Check with results from another library.
    • Check with raw implementation based on the sum function and the double-and-add algorithm.
  • Empty input
  • Maximum number of scalars and points.

Tests for error cases

  • The same test cases as those in the bls12381_p1_sum section.
  • Points not from $G_1$.

Annotation:

pub fn bls12381_g1_multiexp(
        &mut self,
        value_len: u64,
        value_ptr: u64,
        register_id: u64,
) -> Result<u64>;

bls12381_g2_multiexp

Description:

The function takes a list of pairs $(p_i, s_i)$ as input, where $p_i \in G_2 \subset E'(F_{p^2})$ represents a point on the curve, and $s_i \in \mathbb{N}_0$ denotes a scalar. The function computes $\sum s_i \cdot p_i$.

This scalar multiplication operation involves adding the point $p$ to itself a specified number of times:

$$ s \cdot p = \underbrace{p + p + \ldots + p}_{s} $$

The $E'(F_{p^2})$ curve, $G_2$ subgroup, points on the curve, and the addition operation are defined in the BLS12-381 Curve Specification section.

Please note:

  • The function accepts only points from $G_2$.
  • The scalar is an arbitrary unsigned integer and can exceed the group order.
  • To enhance gas efficiency, the Pippenger’s algorithm33 can be utilized.

Input: the sequence of pairs $(p_i, s_i)$, where $p_i \in G_2 \subset E'(F_{p^2})$ is a point on the curve and $s_i \in \mathbb{N}_0$ is a scalar.

The expected input size is 224*k bytes, interpreted as the byte concatenation of k slices. Each slice is the concatenation of an uncompressed point from $G_2 \subset E'(F_{p^2})$192 bytes and a scalar — 32 bytes. More details are in the Curve Points Encoding section.

Output:

The ERROR_CODE is returned.

  • ERROR_CODE = 0: the input is correct
    • Output: 192 bytes represent one point $\in G_2 \subset E'(F_{p^2})$ in its decompressed form. In case of an empty input, it outputs the point at infinity (refer to the Curve Points Encoding section for more details).
  • ERROR_CODE = 1:
    • Points are incorrectly encoded (refer to Curve points encoded section).
    • Point is not on the curve.
    • Point is not in $G_2$ subgroup.

Test cases:

The test cases are identical to those for bls12381_g1_multiexp, except that the points from $G_1$ and $E(F_p)$ are replaced with points from $G_2$ and $E'(F_{p^2})$

Annotation:

pub fn bls12381_g2_multiexp(
        &mut self,
        value_len: u64,
        value_ptr: u64,
        register_id: u64,
) -> Result<u64>;

bls12381_map_fp_to_g1

Description:

This function takes as input a list of field elements $a_i \in F_p$ and maps them to $G_1 \subset E(F_p)$. You can find the specification of this mapping function in the section titled 'Map to curve specification.' Importantly, this function does NOT perform the mapping of the byte string into $F_p$. The implementation of the mapping to $F_p$ may vary and can be effectively executed within the contract.

Input:

The function expects 48*k bytes as input, representing a list of element from $F_p$ (unsigned integer $&lt; p$). Additional information is available in the Curve Points Encoding section.

Output:

The ERROR_CODE is returned.

  • ERROR_CODE = 0: the input is correct
    • Output: 96*k bytes - represents a list of points $\in G_1 \subset E(F_p)$ in decompressed format. Further information is available in the Curve Points Encoding section.
  • ERROR_CODE = 1: $a_i \ge p$.

Test cases:

Tests for general cases

  • Validate the results for known answers from EIP-253731,32.
  • Generate a random point $a$ from $F_p$:
    • Verify the result using another library.
    • Check that the resulting point lies on the curve in $G_1$.
    • Compare the results for $a$ and $-a$; they should share the same x-coordinates and have opposite y-coordinates.

Edge cases:

  • $a = 0$
  • $a = p - 1$

Tests for an arbitrary number of elements

  • Empty input
  • Maximum number of points.
  • Generate a random number of field elements and compare the result with another library.

Tests for error cases

  • Input length is not divisible by 48:
  • Input is beyond memory bounds.
  • $a = p$
  • Random number $\ge p$

Annotation:

pub fn bls12381_map_fp_to_g1(
        &mut self,
        value_len: u64,
        value_ptr: u64,
        register_id: u64,
) -> Result<u64>;

bls12381_map_fp2_to_g2

Description:

This function takes as input a list of elements $a_i \in F_{p^2}$ and maps them to $G_2 \subset E'(F_{p^2})$. You can find the mapping function specification in the "Map to Curve Specification" section. It's important to note that this function does NOT map byte strings into $F_{p^2}$. The implementation of the mapping to $F_{p^2}$ may vary and can be effectively executed within the contract.

Input: the function takes as input 96*k bytes — the elements from $F_{p^2}$ (two unsigned integers $&lt; p$). Additional details can be found in the Curve Points Encoding section.

Output:

The ERROR_CODE is returned.

  • ERROR_CODE = 0: the input is correct
    • Output: 192*k bytes - represents a list of points $\in G_2 \subset E'(F_{p^2})$ in decompressed format. More details are in the Curve Points Encoding section.
  • ERROR_CODE = 1: one of the values is not a valid extension field $F_{p^2}$ element

Test cases:

Tests for general cases

  • Validate the results for known answers from EIP-253731,32
  • Generate a random point $a$ from $F_{p^2}$:
    • Verify the result with another library.
    • Check that the resulting point lies in $G_2$.
    • Compare results for $a$ and $-a$; they should have the same x-coordinates and opposite y-coordinates.

Edge cases:

  • $a = (0, 0)$
  • $a = (p - 1, p - 1)$

Tests for an arbitrary number of elements

  • Empty input
  • Maximum number of points.
  • Generate a random number of field elements and compare the result with another library.

Tests for error cases

  • Input length is not divisible by 96.
  • Input is beyond memory bounds.
  • $a = (0, p)$
  • $a = (p, 0)$
  • (random number $\ge p$, 0)
  • (0, random number $\ge p$)

Annotation:

pub fn bls12381_map_fp2_to_g2(
        &mut self,
        value_len: u64,
        value_ptr: u64,
        register_id: u64,
) -> Result<u64>;

bls12381_pairing_check

Description:

The pairing function is a bilinear function $e\colon G_1 \times G_2 \rightarrow G_T$, where $G_T \subset F_{q^{12}}$, which is used to verify BLS signatures/zkSNARKs.

This function takes as input the sequence of pairs $(p_i, q_i)$, where $p_i \in G_1 \subset E(F_{p})$ and $q_i \in G_2 \subset E'(F_{p^2})$ and validates:

$$ \prod e(p_i, q_i) = 1 $$

We don’t need to calculate the pairing function itself as the result would lie on a huge field, and in all known applications only this validation check is necessary.

Input: A sequence of pairs $(p_i, q_i)$, where $p_i \in G_1 \subset E(F_{p})$ and $q_i \in G_2 \subset E'(F_{p^2})$. Each point is encoded in decompressed form. An expected input size of 288*k bytes is anticipated, interpreted as byte concatenation of k slices. Each slice comprises the concatenation of an uncompressed point from $G_1 \subset E(F_p)$ (occupying 96 bytes) and a point from $G_2 \subset E'(F_{p^2})$ (occupying 192 bytes). Additional details can be found in the Curve Points Encoding section.

Output:

The ERROR_CODE is returned.

  • ERROR_CODE = 0: the input is correct, the pairing result equals the multiplicative identity.
  • ERROR_CODE = 1:
    • Points encoded incorrectly (refer to the Curve Points Encoded section).
    • Point not on the curve.
    • Point not in $G_1/G_2$.
  • ERROR_CODE = 2: the input is correct, the pairing result doesn't equal the multiplicative identity.

Test cases:

Tests for one pair

  • Generate a random point $P \in G_1$: verify $e(P, \mathcal{O}) = 1$
  • Generate a random point $Q \in G_2$: verify $e(\mathcal{O}, Q) = 1$
  • Generate random points $P \ne \mathcal{O} \in G_1$ and $Q \ne \mathcal{O} \in G_2$: verify $e(P, Q) \ne 1$

Tests for two pairs

  • Generate random points $P \in G_1$, $Q \in G_2$ and random scalars $s_1, s_2$:

    • $e(P, Q) \cdot e(P, -Q) = 1$
    • $e(P, Q) \cdot e(-P, Q) = 1$
    • $e(s_1P, s_2Q) \cdot e(-s_2P, s_1Q) = 1$
    • $e(s_1P, s_2Q) \cdot e(s_2P, -s_1Q) = 1$
  • $g_1 \in G_1$, $g_2 \in G_2$ are generators defined in section 'BLS12-381 Curve Specification', r is the order of $G_1$ and $G_2$, and $p_1, p_2, q_1, q_2$ are randomly generated scalars:

    • if $p_1 \cdot q_1 + p_2 \cdot q_2 \not \equiv 0 (\mod r)$, verify $e(p_1 g_1, q_1 g_2) \cdot e(p_2 g_1, q_2 g_2) \ne 1$
    • if $p_1 \cdot q_1 + p_2 \cdot q_2 \equiv 0 (\mod r)$, verify $e(p_1 g_1, q_1 g_2) \cdot e(p_2 g_1, q_2 g_2) = 1$

Tests for an arbitrary number of pairs

  • Empty input
  • Test with the maximum number of pairs
  • Tests using known answers from EIP-253731,32
  • For all possible values of 'n', generate random scalars $p_1 \cdots p_n$ and $q_1 \cdots q_n$ such that $\sum p_i \cdot q_i \not \equiv 0 (\mod r)$:
    • Verify $\prod e(p_i g_1, q_i g_2) \ne 1$
  • For all possible values of 'n', generate random scalars $p_1 \cdots p_{n - 1}$ and $q_1 \cdots q_{n - 1}$:
    • Verify $(\prod e(p_i g_1, q_i g_2)) \cdot e(-(\sum p_i q_i) g_1, g_2) = 1$
    • Verify $(\prod e(p_i g_1, q_i g_2)) \cdot e(g_1, -(\sum p_i q_i) g_2) = 1$

Tests for error cases

  • The first point is on the curve but not in $G_1$.
  • The second point is on the curve but not in $G_2$.
  • The input length is not divisible by 288.
  • The first point is not on the curve.
  • The second point is not on the curve.
  • Input length exceeds the memory limit.
  • Incorrect encoding of the point at infinity.
  • Incorrect encoding of a curve point:
    • Incorrect decompression bit.
    • Coordinates greater than or equal to 'p'.

Annotation:

pub fn bls12381_pairing_check(&mut self,
                              value_len: u64,
                              value_ptr: u64) -> Result<u64>;

bls12381_p1_decompress

Description: The function decompresses compressed points from $E(F_p)$. It takes an arbitrary number of points $p_i \in E(F_p)$ in compressed format as input and outputs the same number of points from $E(F_p)$ in decompressed format. Further details about the decompressed and compressed formats are available in the Curve Points Encoding section.

Input: A sequence of points $p_i \in E(F_p)$, with each point encoded in compressed form. An expected input size of 48*k bytes is anticipated, interpreted as the byte concatenation of k slices. Each slice represents the compressed point from $E(F_p)$. Additional details can be found in the Curve Points Encoding section.

Output:

The ERROR_CODE is returned.

  • ERROR_CODE = 0: the input is correct
    • Output: The sequence of points $p_i \in E(F_p)$, with each point encoded in decompressed form. An expected output of 96*k bytes, interpreted as the byte concatenation of k slices. Each slice represents the decompressed point from $E(F_p)$. k is the same as in the input. More details are available in the Curve Points Encoding section.
  • ERROR_CODE = 1:
    • Points are incorrectly encoded (refer to the Curve points encoded section).
    • Point is not on the curve.

Test cases:

Tests for decompressing a single point

  • Generate random points on the curve from $G_1$ and not from $G_1$:
    • Check that the uncompressed point lies on the curve.
    • Compare the result with another library.
  • Generate random points with a negative y:
    • Take the inverse and compare the y-coordinate.
    • Compare the result with another library.
  • Decompress a point on infinity.

Tests for decompression of an arbitrary number of points

  • Empty input.
  • Maximum number of points.
  • Generate a random number of points on the curve and compare the result with another library.

Tests for error cases

  • The input length is not divisible by 48.
  • The input is beyond memory bounds.
  • Point is not on the curve.
  • Incorrect decompression bit.
  • Incorrectly encoded point at infinity.
  • Point with a coordinate larger than 'p'.

Annotation:

pub fn bls12381_p1_decompress(&mut self,
                              value_len: u64,
                              value_ptr: u64,
                              register_id: u64) -> Result<u64>;

bls12381_p2_decompress

Description: The function decompresses compressed points from $E'(F_{p^2})$. It takes an arbitrary number of points $p_i \in E'(F_{p^2})$ in compressed format as input and outputs the same number of points from $E'(F_{p^2})$ in decompressed format. For more information about the decompressed and compressed formats, refer to the Curve Points Encoding section.

Input: A sequence of points $p_i \in E'(F_{p^2})$, with each point encoded in compressed form. The expected input size is 96*k bytes, interpreted as the byte concatenation of k slices. Each slice represents the compressed point from $E'(F_{p^2})$. Additional details are available in the Curve Points Encoding section.

Output:

The ERROR_CODE is returned.

  • ERROR_CODE = 0: the input is correct
    • Output: the sequence of point $p_i \in E'(F_{p^2})$, with each point encoded in decompressed form. The expected output is 192*k bytes, interpreted as the byte concatenation of k slices. k corresponds to the value specified in the input section. Each slice represents the decompressed point from $E'(F_{p^2})$. For more details, refer to the Curve Points Encoding section.
  • ERROR_CODE = 1:
    • Points are incorrectly encoded (refer to Curve points encoded section).
    • Point is not on the curve.

Test cases:

The same test cases as bls12381_p1_decompress, but with points from $G_2$, and the input length should be divisible by 96.

Annotation:

pub fn bls12381_p2_decompress(&mut self,
                              value_len: u64,
                              value_ptr: u64,
                              register_id: u64) -> Result<u64>;

Reference Implementation

Primarily, concerning integration with nearcore, our interest lies in Rust language libraries. The current implementations of BLS12-381 in Rust are:

  1. Milagro Library 29.
  2. BLST 3536.
  3. Matter labs EIP-1962 implementation 37
  4. zCash origin implementation 38
  5. MCL Library 39
  6. FileCoin implementation 40
  7. zkCrypto 41

To compile the list, we used links from EIP-253742, the pairing-curves specification43, and an article containing benchmarks44. This list might be incomplete, but it should encompass the primary BLS12-381 implementations.

In addition, there are implementations in other languages that are less relevant to us in this context but can serve as references.

  1. C++, ETH2.0 Client, Chia library45
  2. Haskell, Adjoint Lib46
  3. Go, Go-Ethereum47
  4. JavaScript, Noble JS48
  5. Go, Matter Labs Go EIP-1962 implementation49
  6. C++, Matter Labs C++ EIP-1962 implementation50

One of the possible libraries to use is the blst library35. This library exhibits good performance44 and has undergone several audits51. You can find a draft implementation in nearcore, which is based on this library, through this link52.

Security Implications

The implementation's security depends on the chosen library's security, supporting operations with BLS curves.

Within this NEP, a constant execution time for all operations isn't mandated. All the computations executed by smart contract are entirely public anyway, so there would be no advantage to a constant-time algorithm.

BLS12-381 offers more security bits compared to the already existing pairing-friendly curve BN254. Consequently, the security of projects requiring a pairing-friendly curve will be enhanced.

Alternatives

In nearcore, host functions for another pairing-friendly curve, BN254, have already been implemented7. Some projects8 might consider utilizing the supported curve as an alternative. However, recent research indicates that this curve provides less than 100 bits of security and is not recommended for use9. Furthermore, projects involved in cross-chain interactions, like Rainbow Bridge, are mandated to employ the same curve as the target protocol, which, in the case of Ethereum, is currently BLS12-38112. Consequently, there is no viable alternative to employing a different pairing-friendly curve.

An alternative approach involves creating a single straightforward host function in nearcore for BLS signature verification. This was the initially proposed solution53. However, this solution lacks flexibility54 for several reasons: (1) projects may utilize different hash functions; (2) some projects might employ the $G_1$ subgroup for public keys, while others use $G_2$; (3) the specifications for Ethereum 2.0 remain in draft, subject to potential changes; (4) instead of a more varied and adaptable set of functions (inspired by EIP-2537's precompiles), we are left with a single large function; (5) there will be no support for zkSNARKs verification.

Another alternative is to perform BLS12-381 operations off-chain. In this scenario, applications utilizing the BLS curve will no longer maintain trustlessness.

Future possibilities

In the future, there might be support for working with various curves beyond just BLS12-381. In Ethereum, prior to EIP-253720, there was a proposal, EIP-196255, to introduce pairing-friendly elliptic curves in a versatile format, accommodating not only BLS curves but numerous others as well. However, this proposal wasn't adopted due to its extensive scope and complexity. Implementing every conceivable curve might not be practical, but it remains a potential extension worth considering.

Another potential extension could involve supporting hash_to_field or hash_to_curve operations56. Enabling their support would optimize gas usage for encoding messages into elements on the curve, which could be beneficial to BLS signatures. However, implementing the hash_to_field operation requires supporting multiple hashing algorithms simultaneously and doesn't demand a significant amount of gas for implementation within the contract. Therefore, these functions exceed the scope of this proposal.

Additionally, a potential expansion might encompass supporting not only affine coordinates but also other coordinate systems, such as homogeneous or Jacobian projective coordinates.

Consequences

Positive

  • Projects currently utilizing BN254 will have the capability to transition to the BLS12-381 curve, thereby enhancing their security.
  • Trustless cross-chain interactions with blockchains employing BLS12-381 in protocols (like Ethereum 2.0) will become feasible.

Neutral

Negative

  • There emerges a dependency on a library that supports operations with BLS12-381 curves.
  • We'll have to continually maintain operations with BLS12-381 curves, even if vulnerabilities are discovered, and it becomes unsafe to use these curves.

Backward Compatibility

There are no backward compatibility questions.

Changelog

The previous NEP for supporting BLS signature based on BLS12-38153

Footnotes

  1. BLS 2002 https://www.researchgate.net/publication/2894224_Constructing_Elliptic_Curves_with_Prescribed_Embedding_Degrees

  2. BLS12-381 for the Rest of Us: https://hackmd.io/@benjaminion/bls12-381 2 3

  3. Paper with BLS12-381: https://eprint.iacr.org/2019/403.pdf

  4. Intro into zkSNARKs: https://media.consensys.net/introduction-to-zksnarks-with-examples-3283b554fc3b

  5. BN2005: https://eprint.iacr.org/2005/133

  6. BN254 for the Rest of Us: https://hackmd.io/@jpw/bn254

  7. NEP-98 for BN254 host functions on NEAR: https://github.com/near/NEPs/issues/98 2

  8. Zeropool project: https://zeropool.network/ 2

  9. Some analytics of different curve security: https://www.ietf.org/archive/id/draft-irtf-cfrg-pairing-friendly-curves-02.html#name-for-100-bits-of-security 2

  10. Specification of pairing friendly curves, the security level for BLS12-381: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-09#section-4.2.1

  11. ZCash protocol: https://zips.z.cash/protocol/protocol.pdf 2

  12. Ethereum 2 specification: https://github.com/ethereum/consensus-specs/blob/master/specs/phase0/beacon-chain.md 2 3

  13. Dfinity: https://internetcomputer.org/docs/current/references/ic-interface-spec#certificate

  14. Tezos: https://wiki.tezosagora.org/learn/futuredevelopments/layer2#zkchannels 2

  15. Filecoin: https://spec.filecoin.io/ 2

  16. Specification of pairing friendly curves with a list of applications in the table: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-09#name-adoption-status-of-pairing-

  17. Article about Rainbow Bridge https://near.org/blog/eth-near-rainbow-bridge

  18. hash_to_field specification: https://datatracker.ietf.org/doc/html/rfc9380#name-hash_to_field-implementatio

  19. Implementation of BLS-signature based on these host functions: https://github.com/olga24912/bls-signature-verificaion-poc/blob/main/src/lib.rs

  20. EIP-2537 Precompiles for Ethereum for BLS12-381: https://eips.ethereum.org/EIPS/eip-2537 2 3 4 5 6 7

  21. Precompiles on Aurora: https://doc.aurora.dev/dev-reference/precompiles/

  22. draft-irtf-cfrg-pairing-friendly-curves-11 https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-11#name-bls-curves-for-the-128-bit- 2 3 4 5 6 7 8 9

  23. ZCash Transfer from bn254 to bls12-381: https://electriccoin.co/blog/new-snark-curve/ 2 3

  24. RFC 9380 Hashing to Elliptic Curves specification: https://www.rfc-editor.org/rfc/rfc9380

  25. map_to_curve and clear_cofactor functions: https://datatracker.ietf.org/doc/html/rfc9380#name-encoding-byte-strings-to-el

  26. Specification of parameters for BLS12-381 G1: https://datatracker.ietf.org/doc/html/rfc9380#name-bls12-381-g1

  27. Specification of parameters for BLS12-381 G2: https://datatracker.ietf.org/doc/html/rfc9380#name-bls12-381-g2

  28. Zkcrypto points encoding: https://github.com/zkcrypto/pairing/blob/0.14.0/src/bls12_381/README.md

  29. BLS12-381 Milagro: https://github.com/sigp/incubator-milagro-crypto-rust/tree/057d238936c0cbbe3a59dfae6f2405db1090f474 2

  30. Bench vectors from EIP2537: https://eips.ethereum.org/assets/eip-2537/bench_vectors

  31. Metter Labs tests for EIP2537: https://github.com/matter-labs/eip1962/tree/master/src/test/test_vectors/eip2537 2 3 4 5 6

  32. Tests from Go Ethereum implementation: https://github.com/ethereum/go-ethereum/tree/master/core/vm/testdata/precompiles 2 3 4 5 6

  33. Pippenger Algorithm: https://github.com/wborgeaud/python-pippenger/blob/master/pippenger.pdf 2

  34. double-and-add algorithm: https://en.wikipedia.org/wiki/Exponentiation_by_squaring

  35. BLST: https://github.com/supranational/blst, 2

  36. BLST EIP-2537 adaptation: https://github.com/sean-sn/blst_eip2537

  37. EIP-1962 implementation matter labs Rust: https://github.com/matter-labs/eip1962

  38. zCash origin rust implementation: https://github.com/zcash/zcash/tree/master/src/rust/src

  39. MCL library: https://github.com/herumi/bls

  40. filecoin/bls-signature: https://github.com/filecoin-project/bls-signatures

  41. zkCrypto: https://github.com/zkcrypto/bls12_381, https://github.com/zkcrypto/pairing

  42. EIP-2537 with links: https://github.com/matter-labs-forks/EIPs/blob/bls12_381/EIPS/eip-2537.md

  43. Pairing-friendly curves specification, crypto libs: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-09#name-cryptographic-libraries

  44. Comparing different libs for pairing-friendly curves: https://hackmd.io/@gnark/eccbench 2

  45. BLS12-381 code bases for ETH2.0 client Chia library C++: https://github.com/Chia-Network/bls-signatures

  46. Adjoint Lib: https://github.com/sdiehl/pairing

  47. Ethereum Go implementation for EIP-2537: https://github.com/ethereum/go-ethereum/tree/master/core/vm/testdata/precompiles

  48. Noble JS implementation: https://github.com/paulmillr/noble-bls12-381

  49. EIP-1962 implementation matter labs Go: https://github.com/kilic/eip2537,

  50. EIP-1962 implementation matter labs C++: https://github.com/matter-labs-archive/eip1962_cpp

  51. Audit for BLST library: https://research.nccgroup.com/wp-content/uploads/2021/01/NCC_Group_EthereumFoundation_ETHF002_Report_2021-01-20_v1.0.pdf

  52. Draft PR for BLS12-381 operations in nearcore: https://github.com/near/nearcore/pull/9317

  53. NEP-446 proposal for BLS-signature verification: https://github.com/nearprotocol/neps/pull/446 2

  54. Drawbacks of NEP-446: https://github.com/near/NEPs/pull/446#pullrequestreview-1314601508

  55. EIP-1962 EC arithmetic and pairings with runtime definitions: https://eips.ethereum.org/EIPS/eip-1962

  56. hash_to_curve and hash_to_field function: https://datatracker.ietf.org/doc/html/rfc9380#name-hash_to_field-implementatio