diff --git a/neps/nep-0488.md b/neps/nep-0488.md new file mode 100644 index 000000000..71c079923 --- /dev/null +++ b/neps/nep-0488.md @@ -0,0 +1,1212 @@ +--- +NEP: 488 +Title: Host Functions for BLS12-381 Curve Operations +Authors: Olga Kuniavskaia +Status: Draft +DiscussionsTo: https://github.com/nearprotocol/neps/pull/488 +Type: Runtime Spec +Version: 0.0.1 +Created: 2023-07-17 +LastUpdated: 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-381[^1],[^11],[^52] elliptic curve on NEAR. + +To efficiently verify zkSNARKs[^19], host functions for operations on the BN254 +elliptic curve (also known as Alt-BN128)[^9], [^12] have already been implemented on NEAR[^10]. +For instance, the Zeropool[^20] project utilizes these host functions for verifying zkSNARKs on NEAR. +However, recent research shows that the BN254 security level is lower than 100-bit[^13] and it is not recommended for use. +BLS12-381, on the other hand, offers over 120 bits of security[^8] and is widely used[^2],[^3],[^4],[^5],[^6],[^7] 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 ZCash[^2], Ethereum[^3], Tezos[^5], and Filecoin[^6] 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 bridge[^17] 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_field`[^60] 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 signatures[^59]: + +- 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-2537[^15], 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 Aurora[^24]. + +## 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 $> 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$[^15],[^51],[^14],[^11] + +**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$[^15],[^51] 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 polynomials[^51]: + +- $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 as[^51]: + +$$ +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 generators[^15],[^51]: + +$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$[^51] + +$$h = \mathtt{0x396c8c005555e1568c00aaab0000aaab}$$ + +Cofactor $G_2\colon h' = |E'(F_{p^2})|/r$[^51] + +$$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: + +- [^15] section specification, pairing parameters, Miller loop scalar +- [^51] section 4.2.1 Parameter t +- [^14] section BLS12-381, parameter u +- [^11] 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 [^15], [^51], and [^14], 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"[^62]. + +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 RFC9380[^63]. + +```text +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.1[^64] and 8.8.2[^65], respectively. + +### Curve points encoding + +#### General comments + +The encoding rules for curve points and field elements align with the standards established in zkcrypto[^53] and +the implementation in the milagro lib[^29]. + +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: + +```bash +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: + +```rust +let x: [u8; 48] = encodeFp(x) +x[0] = x[0] | 0x80; +x[0] = x[0] | 0x20; +``` + +Encoding the point at infinity: + +```rust +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: + +```bash +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: + +```rust +let x: [u8; 96] = encodeFp2(x); +x[0] = x[0] | 0x80; +x[0] = x[0] | 0x20; +``` + +Encoding the point at infinity: + +```rust +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: + +```rust +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-2537[^46] 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-2537[^47],[^48]. +- 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:*** + +```rust +pub fn bls12381_p1_sum(&mut self, + value_len: u64, + value_ptr: u64, + register_id: u64) -> Result; +``` + +#### 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:*** + +```rust +pub fn bls12381_p2_sum(&mut self, + value_len: u64, + value_ptr: u64, + register_id: u64) -> Result; +``` + +#### ***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 algorithm[^25] 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-2537[^47],[^48]. +- 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 algorithm[^61]. + +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-2537[^47],[^48] +- 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:*** + +```rust +pub fn bls12381_g1_multiexp( + &mut self, + value_len: u64, + value_ptr: u64, + register_id: u64, +) -> Result; +``` + +#### ***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 algorithm[^25] 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:*** + +```rust +pub fn bls12381_g2_multiexp( + &mut self, + value_len: u64, + value_ptr: u64, + register_id: u64, +) -> Result; +``` + +#### 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 $< 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-2537[^47],[^48]. +- 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:*** + +```rust +pub fn bls12381_map_fp_to_g1( + &mut self, + value_len: u64, + value_ptr: u64, + register_id: u64, +) -> Result; +``` + +#### 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 $< 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-2537[^47],[^48] +- 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:*** + +```rust +pub fn bls12381_map_fp2_to_g2( + &mut self, + value_len: u64, + value_ptr: u64, + register_id: u64, +) -> Result; +``` + +#### 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-2537[^47],[^48] +- 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:*** + +```rust +pub fn bls12381_pairing_check(&mut self, + value_len: u64, + value_ptr: u64) -> Result; +``` + +#### 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:*** + +```rust +pub fn bls12381_p1_decompress(&mut self, + value_len: u64, + value_ptr: u64, + register_id: u64) -> Result; +``` + +#### 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:*** + +```rust +pub fn bls12381_p2_decompress(&mut self, + value_len: u64, + value_ptr: u64, + register_id: u64) -> Result; +``` + +## 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*** [^30][^31]. +3. ***Matter labs EIP-1962 implementation*** [^32] +4. ***zCash origin implementation*** [^33] +5. ***MCL Library*** [^34] +6. ***FileCoin implementation*** [^35] +7. ***zkCrypto*** [^36] + +To compile the list, we used links from EIP-2537[^43], the pairing-curves specification[^44], and an article containing benchmarks[^45]. 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 library***[^37] +2. Haskell, ***Adjoint Lib***[^38] +3. Go, ***Go-Ethereum***[^39] +4. JavaScript, ***Noble JS***[^40] +5. Go, ***Matter Labs Go EIP-1962 implementation***[^41] +6. C++, ***Matter Labs C++ EIP-1962 implementation***[^42] + +One of the possible libraries to use is the blst library[^30]. +This library exhibits good performance[^45] and has undergone several audits[^55]. +You can find a draft implementation in nearcore, which is based on this library, through this link[^54]. + +## 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 implemented[^10]. Some projects[^20] 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 use[^13]. 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-381[^3]. 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 solution[^26]. However, this solution lacks flexibility[^28] 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-2537[^15], there was a proposal, EIP-1962[^27], 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` operations[^58]. 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-381[^26] + +[^1]: BLS 2002 [https://www.researchgate.net/publication/2894224_Constructing_Elliptic_Curves_with_Prescribed_Embedding_Degrees](https://www.researchgate.net/publication/2894224_Constructing_Elliptic_Curves_with_Prescribed_Embedding_Degrees) +[^2]: ZCash protocol: [https://zips.z.cash/protocol/protocol.pdf](https://zips.z.cash/protocol/protocol.pdf) +[^3]: Ethereum 2 specification: [https://github.com/ethereum/consensus-specs/blob/master/specs/phase0/beacon-chain.md](https://github.com/ethereum/consensus-specs/blob/master/specs/phase0/beacon-chain.md) +[^4]: Dfinity: [https://internetcomputer.org/docs/current/references/ic-interface-spec#certificate](https://internetcomputer.org/docs/current/references/ic-interface-spec#certificate) +[^5]: Tezos: [https://wiki.tezosagora.org/learn/futuredevelopments/layer2#zkchannels](https://wiki.tezosagora.org/learn/futuredevelopments/layer2#zkchannels) +[^6]: Filecoin: [https://spec.filecoin.io/](https://spec.filecoin.io/) +[^7]: 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-](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-09#name-adoption-status-of-pairing-) +[^8]: 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](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-09#section-4.2.1) +[^9]: BN2005: [https://eprint.iacr.org/2005/133](https://eprint.iacr.org/2005/133) +[^10]: NEP-98 for BN254 host functions on NEAR: [https://github.com/near/NEPs/issues/98](https://github.com/near/NEPs/issues/98) +[^11]: BLS12-381 for the Rest of Us: [https://hackmd.io/@benjaminion/bls12-381](https://hackmd.io/@benjaminion/bls12-381) +[^12]: BN254 for the Rest of Us: [https://hackmd.io/@jpw/bn254](https://hackmd.io/@jpw/bn254) +[^13]: 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](https://www.ietf.org/archive/id/draft-irtf-cfrg-pairing-friendly-curves-02.html#name-for-100-bits-of-security) +[^14]: ZCash Transfer from bn254 to bls12-381: [https://electriccoin.co/blog/new-snark-curve/](https://electriccoin.co/blog/new-snark-curve/) +[^15]: EIP-2537 Precompiles for Ethereum for BLS12-381: [https://eips.ethereum.org/EIPS/eip-2537](https://eips.ethereum.org/EIPS/eip-2537) +[^17]: Article about Rainbow Bridge [https://near.org/blog/eth-near-rainbow-bridge](https://near.org/blog/eth-near-rainbow-bridge) +[^19]: Intro into zkSNARKs: [https://media.consensys.net/introduction-to-zksnarks-with-examples-3283b554fc3b](https://media.consensys.net/introduction-to-zksnarks-with-examples-3283b554fc3b) +[^20]: Zeropool project: [https://zeropool.network/](https://zeropool.network/) +[^24]: Precompiles on Aurora: [https://doc.aurora.dev/dev-reference/precompiles/](https://doc.aurora.dev/dev-reference/precompiles/) +[^25]: Pippenger Algorithm: [https://github.com/wborgeaud/python-pippenger/blob/master/pippenger.pdf](https://github.com/wborgeaud/python-pippenger/blob/master/pippenger.pdf) +[^26]: NEP-446 proposal for BLS-signature verification: [https://github.com/nearprotocol/neps/pull/446](https://github.com/nearprotocol/neps/pull/446) +[^27]: EIP-1962 EC arithmetic and pairings with runtime definitions: [https://eips.ethereum.org/EIPS/eip-1962](https://eips.ethereum.org/EIPS/eip-1962) +[^28]: Drawbacks of NEP-446: [https://github.com/near/NEPs/pull/446#pullrequestreview-1314601508](https://github.com/near/NEPs/pull/446#pullrequestreview-1314601508) +[^29]: BLS12-381 Milagro: [https://github.com/sigp/incubator-milagro-crypto-rust/tree/057d238936c0cbbe3a59dfae6f2405db1090f474](https://github.com/sigp/incubator-milagro-crypto-rust/tree/057d238936c0cbbe3a59dfae6f2405db1090f474) +[^30]: BLST: [https://github.com/supranational/blst](https://github.com/supranational/blst), +[^31]: BLST EIP-2537 adaptation: [https://github.com/sean-sn/blst_eip2537](https://github.com/sean-sn/blst_eip2537) +[^32]: EIP-1962 implementation matter labs Rust: https://github.com/matter-labs/eip1962 +[^33]: zCash origin rust implementation: [https://github.com/zcash/zcash/tree/master/src/rust/src](https://github.com/zcash/zcash/tree/master/src/rust/src) +[^34]: MCL library: [https://github.com/herumi/bls](https://github.com/herumi/bls) +[^35]: filecoin/bls-signature: [https://github.com/filecoin-project/bls-signatures](https://github.com/filecoin-project/bls-signatures) +[^36]: zkCrypto: [https://github.com/zkcrypto/bls12_381](https://github.com/zkcrypto/bls12_381), [https://github.com/zkcrypto/pairing](https://github.com/zkcrypto/pairing) +[^37]: BLS12-381 code bases for ETH2.0 client Chia library C++: [https://github.com/Chia-Network/bls-signatures](https://github.com/Chia-Network/bls-signatures) +[^38]: Adjoint Lib: [https://github.com/sdiehl/pairing](https://github.com/sdiehl/pairing) +[^39]: Ethereum Go implementation for EIP-2537: [https://github.com/ethereum/go-ethereum/tree/master/core/vm/testdata/precompiles](https://github.com/ethereum/go-ethereum/tree/master/core/vm/testdata/precompiles) +[^40]: Noble JS implementation: [https://github.com/paulmillr/noble-bls12-381](https://github.com/paulmillr/noble-bls12-381) +[^41]: EIP-1962 implementation matter labs Go: https://github.com/kilic/eip2537, +[^42]: EIP-1962 implementation matter labs C++: https://github.com/matter-labs-archive/eip1962_cpp +[^43]: EIP-2537 with links: [https://github.com/matter-labs-forks/EIPs/blob/bls12_381/EIPS/eip-2537.md](https://github.com/matter-labs-forks/EIPs/blob/bls12_381/EIPS/eip-2537.md) +[^44]: Pairing-friendly curves specification, crypto libs: [https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-09#name-cryptographic-libraries](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-09#name-cryptographic-libraries) +[^45]: Comparing different libs for pairing-friendly curves: [https://hackmd.io/@gnark/eccbench](https://hackmd.io/@gnark/eccbench) +[^46]: Bench vectors from EIP2537: [https://eips.ethereum.org/assets/eip-2537/bench_vectors](https://eips.ethereum.org/assets/eip-2537/bench_vectors) +[^47]: Metter Labs tests for EIP2537: [https://github.com/matter-labs/eip1962/tree/master/src/test/test_vectors/eip2537](https://github.com/matter-labs/eip1962/tree/master/src/test/test_vectors/eip2537) +[^48]: Tests from Go Ethereum implementation: [https://github.com/ethereum/go-ethereum/tree/master/core/vm/testdata/precompiles](https://github.com/ethereum/go-ethereum/tree/master/core/vm/testdata/precompiles) +[^51]: 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-](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-11#name-bls-curves-for-the-128-bit-) +[^52]: Paper with BLS12-381: [https://eprint.iacr.org/2019/403.pdf](https://eprint.iacr.org/2019/403.pdf) +[^53]: Zkcrypto points encoding: [https://github.com/zkcrypto/pairing/blob/0.14.0/src/bls12_381/README.md](https://github.com/zkcrypto/pairing/blob/0.14.0/src/bls12_381/README.md) +[^54]: Draft PR for BLS12-381 operations in nearcore: [https://github.com/near/nearcore/pull/9317](https://github.com/near/nearcore/pull/9317) +[^55]: Audit for BLST library: [https://research.nccgroup.com/wp-content/uploads/2021/01/NCC_Group_EthereumFoundation_ETHF002_Report_2021-01-20_v1.0.pdf](https://research.nccgroup.com/wp-content/uploads/2021/01/NCC_Group_EthereumFoundation_ETHF002_Report_2021-01-20_v1.0.pdf) +[^58]: hash_to_curve and hash_to_field function: [https://datatracker.ietf.org/doc/html/rfc9380#name-hash_to_field-implementatio](https://datatracker.ietf.org/doc/html/rfc9380#name-hash_to_field-implementatio) +[^59]: Implementation of BLS-signature based on these host functions: [https://github.com/olga24912/bls-signature-verificaion-poc/blob/main/src/lib.rs](https://github.com/olga24912/bls-signature-verificaion-poc/blob/main/src/lib.rs) +[^60]: hash_to_field specification: [https://datatracker.ietf.org/doc/html/rfc9380#name-hash_to_field-implementatio](https://datatracker.ietf.org/doc/html/rfc9380#name-hash_to_field-implementatio) +[^61]: double-and-add algorithm: [https://en.wikipedia.org/wiki/Exponentiation_by_squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) +[^62]: RFC 9380 Hashing to Elliptic Curves specification: [https://www.rfc-editor.org/rfc/rfc9380](https://www.rfc-editor.org/rfc/rfc9380) +[^63]: map_to_curve and clear_cofactor functions: [https://datatracker.ietf.org/doc/html/rfc9380#name-encoding-byte-strings-to-el](https://datatracker.ietf.org/doc/html/rfc9380#name-encoding-byte-strings-to-el) +[^64]: Specification of parameters for BLS12-381 G1: [https://datatracker.ietf.org/doc/html/rfc9380#name-bls12-381-g1](https://datatracker.ietf.org/doc/html/rfc9380#name-bls12-381-g1) +[^65]: Specification of parameters for BLS12-381 G2: [https://datatracker.ietf.org/doc/html/rfc9380#name-bls12-381-g2](https://datatracker.ietf.org/doc/html/rfc9380#name-bls12-381-g2)