If you are a **Snarker** you must have already heard of **KZG** commitment, if you heard of **KZG** you must know **Pairings**. This is what we will talk about. <br /> # What we do not have - group theory, field theory and homomorphism basic concepts will not be covered here, you can refer any books on **abstract algebraic** - divisors basic concepts will not be covered here, [Pairing for Beginners](https://static1.squarespace.com/static/5fdbb09f31d71c1227082339/t/5ff394720493bd28278889c6/1609798774687/PairingsForBeginners.pdf) is enough for pairings, if you want to know more about that you might need to dive into any books on **algebraic geometry** - structure of elliptic curve over finite field and its arithmetics (scalar multiplication) theories and algorithms will not be covered here, you can refer [Guide to Elliptic Curve Cryptography](http://tomlr.free.fr/Math%E9matiques/Math%20Complete/Cryptography/Guide%20to%20Elliptic%20Curve%20Cryptography%20-%20D.%20Hankerson,%20A.%20Menezes,%20S.%20Vanstone.pdf) - hash to curve will be filled in later on - non-affine coordinate will be filled in later on - advanced scalar multiplication algorithms GLV/GLS will be filled in later on <br /> --- # What we have This artical mainly focus on variant pairings: - [Weil Pairing](#Weil-Pairing) - [Tate Pairing](#Tate-Pairing) - [Ate Pairing](#Ate-Pairing) - [Optimal Pairing](#Optimal-Pairing) and their practical implementations. Besides, we include some neccesary tricks in implementation, especially: - [Tower Fields](#Tower-Fields) - [Frobenius Map](#Magic-Power-of-Frobenius-Map) - [Twist](#Magic-Power-of-Twist) - [Cyclotomic Group](#Arithmetics-over-Cyclotomic-Group) --- # About Code - [python implementation](https://github.com/PayneJoe/crypto_research/tree/main/ecc/src/pairings) Mainly focus on pairing computations, including **Miller Loop** and **Final Exponentiation**. It has already been done. Arithmetics of finite field and elliptic curve not been cracked yet, just use **Galois Field** and **Elliptic Curve** of sagemath instead. - [rust implementation](https://github.com/PayneJoe/crypto_research/tree/main/ecc/src/pairings) All written with dirty hands, from **Bigint** Arithmetics to **Finite Field** arithmetics to **Elliptic Curve** arithmetics, to **Pairings**. Much testation work to be done ... <br /> --- # Public Information <br /> - Modulus of base prime field (characteristic) $F_p$ with 381-bits: $$ p = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 $$ <br /> - Embedding degree, or the degree of full extension field $F_{p^k}$: $$ k = 12 $$ <br /> - Elliptic Curve (additive group) over **base prime field** $F_p$: $$ \mathbb{G}_1/E(F_p): y^2 = x^3 + 4 $$ <br /> - Elliptic Curve (additive group) over extension field $F_{p^k}$: $$ \mathbb{G}_2/E(F_{p^k}): y^2 = x^3 + 4 $$ <br /> - Largest prime factor of $|E(F_p)|$ with 255-bits: $$ r = 52435875175126190479447740508185965837690552500527637822603658699938581184513 $$ <br /> - Trace of Frobenius: $$ t = p + 1 - |E(F_p)| = -15132376222941642751 $$ <br /> - Parameter for BLS12 Pairing-family: $$ x = -15132376222941642752 $$ while: $$ \begin{aligned} r(x) &= x^4 - x^2 + 1 \\ p(x) &= (x - 1)^2 \cdot r(x) \cdot \frac{1}{3} + x\\ t(x) &= x + 1 \\ \end{aligned} $$ <br /> - Target (multiplicative) group with order $r$ defined over $F_{p^k}$: $$ \mathbb{G}_T: F_{p^k}^{\times}[r] $$ <br /> ---- # Field Arithmetics Underneath <br /> BLS12-381 curve is defined as below: $$ E(F_{p^{12}}): y^2 = x^3 + 4 $$ where $F_{p^{12}} = F_p[v] / X^{12} - 2 X^6 + 2$. Where does the field come from? <br /> ## Tower Fields ### Definition <br /> As we know $G_T$ within BLS12-381 pairing is a $r$-torsion subgroup of multiplicative group defined over $F_{p^{12}}$, usually denoted as $F_{p^{12}}^{\times}[r]$. <br /> How is $F_{p^{12}}$ constructed? **tower fields** comes: $$ F_p[u] \xrightarrow{X^2 - \alpha} F_{p^2}[v] \xrightarrow{X^3 - \beta} F_{p^6}[w] \xrightarrow{X^2 - \gamma} F_{p^{12}} $$ <br /> where these constant parameters of extension field modulus are (specially for BLS12-381): $$ \begin{aligned} \alpha &= -1 \in F_{p} \\ \beta &= u + 1 = \sqrt{\alpha} + 1 = \sqrt{-1} + 1 \in F_{p^2} \\ \gamma &= v = \sqrt[3]{\beta} = \sqrt[3]{u + 1} = \sqrt[3]{\sqrt{\alpha} + 1} = \sqrt[3]{\sqrt{-1} + 1} \in F_{p^6} \end{aligned} $$ <br /> :::info $\bigstar \bigstar \bigstar$ - $X^2 - \gamma = X^2 - v$ is irreducible in $F_{p^6}$ - since $v$ is one root of $X^3 - \beta$, then we have $X^6 - \beta$ is irreducible in $F_{p^2}$ - since $\beta - 1$ is one root of $X^2 - \alpha$, then we have $(X^6 - 1)^2 - \alpha = X^{12} - 2 X^6 + 2$ is irreducible in $F_p$ - therefore we have $F_{p^{12}} = F_p[v] / X^{12} - 2 X^6 + 2$ ::: <br /> That's to say, arithmetics over $F_{p^{12}}$ can be accomplished through $F_{p^6}$, while arithmetics over $F_{p^6}$ can be accomplished through $F_{p^2}$, and $F_{p^2}$ can be accomplished through $F_p$. This what we called **tower fields**. <br /> You may have already noticed that $F_{p} \longrightarrow F_{p^2}$ and $F_{p^6} \longrightarrow F_{p^{12}}$ are both **quadratic extension**, $F_{p^2} \longrightarrow F_{p^6}$ is a **cubic extension**. So **quadratic extension** and **cubic extension** plays an important role within arithmetics over extension fields. <br /> ### Arithmetics for Quadratic Extension This part you can directly refer 5.2.1 of [Guide to Pairing-based Cryptography](https://www.math.u-bordeaux.fr/~damienrobert/csi/book/pairings.pdf). <br /> ### Arithmetics for Cubic Extension This part you can directly refer 5.2.2 of [Guide to Pairing-based Cryptography](https://www.math.u-bordeaux.fr/~damienrobert/csi/book/pairings.pdf). <br /> ### Arithmetics over Cyclotomic Group Cyclotomic group plays an important role in **Final Expoentiation** especially for **Tate/Ate Pairings**. It has special arithmetics, especially **squaring** and **exponentiation**. <br /> Assume $\alpha \in F_{p^3}, p = q^2$, $F_q$ denotes **base prime field**, how to compute square of $\alpha$? <br /> First of all, we need a way to represent $\alpha$, for example: $$ \begin{aligned} F_{p^3} &= F_{(q^2)^3} = F_{q^2}[v] / v^3 - u \\ F_{q^2} &= F_q[u] / u^2 - \xi \\ \end{aligned} $$ <br /> Assume : $$ \alpha = a + b \cdot v + c \cdot v^2 $$ how about $\alpha^2$ ?: $$ \begin{aligned} \alpha^2 &= (a + bv + cv^2)^2 \\ &= a^2 + b^2 v^2 + c^2 v^4 + 2(a \cdot bv + a \cdot cv^2 + bv \cdot cv^2) \\ \end{aligned} $$ since $v^3 - u = 0$, we can proceed forward: $$ \begin{aligned} \alpha^2 &= (a^2 + 2 bc \cdot u) + (c^2 \cdot u + 2 ab) \cdot v + (b^2 + 2 ac) \cdot v^2 \\ &= A + B \cdot v + C \cdot v^2 \end{aligned} $$ <br /> So there are at least 3 squares in $F_{q^2}$ (they are $a^2, b^2, c^2$ respectively), and 5 multiplications in $F_{q^2}$ (they are $a \cdot b, b \cdot c, a \cdot c, bc \cdot u, c^2 \cdot u$ respectively). <br /> Multiplications over $F_{q^2}$ might be a little more expensive. Is there any improvements on this? YES <br /> #### Squaring Friendly Field <br /> If $6 | n$, and $p$ is a large prime characteristic, the order of multiplicative group $F_{p^n}^{\times}$ can be represented multiplication of multiple cyclotomic polymomials: $$ p^n - 1 = \prod_{i = 1}^{i | n} \varPhi_i(p) $$ then we call $F_{p^n}$ is a **Squaring Friendly Field**. <br /> For example: $$ p^{12} - 1 = \varPhi_1(p) \cdot \varPhi_2(p) \cdot \varPhi_3(p) \cdot \varPhi_4(p) \cdot \varPhi_6(p) \cdot \varPhi_{12}(p) $$ where: $$ \begin{aligned} \varPhi_1(p) &= p - 1 \\ \varPhi_2(p) &= p + 1 \\ \varPhi_3(p) &= (p - \zeta_3^1) \cdot (p - \zeta_3^2) = p^2 + p + 1, \zeta_3^3 = 1 \\ \varPhi_4(p) &= (p - \zeta_4^1) \cdot (p - \zeta_4^3) = p^2 + 1, \zeta_4^4 = 1 \\ \varPhi_6(p) &= (p - \zeta_6^1) \cdot (p - \zeta_6^5) = p^2 - p + 1, \zeta_6^6 = 1 \\ \varPhi_{12}(p) &= (p - \zeta_{12}^1) \cdot (p - \zeta_{12}^5) \cdot (p - \zeta_{12}^7) \cdot (p - \zeta_{12}^{11}) = p^4 - p^2 + 1, \zeta_{12}^{12} = 1 \\ \end{aligned} $$ <br /> another words, the order of group $F_{p^{12}}^{\times}$ can be factored into: $$ |F_{p^{12}}^{\times}| = p^{12} - 1 = (p - 1) \cdot (p + 1) \cdot (p^2 + p + 1) \cdot (p^2 + 1) \cdot (p^2 - p + 1) \cdot (p^4 - p^2 + 1) $$ <br /> So there must be a (r-torsion) subgroup $\mathbb{G}_{\varPhi_{12}(p)}$ of order $r = p^4 - p^2 + 1$ within multiplicative group $F_{p^{12}}^{\times}$. <br /> In pairing cryptography (if embedding degree is 12), computations are focus on arithmetics over $\mathbb{G}_{\varPhi_{12}(p)}$. There is a great property upon this: $$ \begin{aligned} &\alpha \in \mathbb{G}_{\varPhi_{12}(p)} \subset F_{p^{12}}^{\times} \\ &\Downarrow \\ &\alpha^{\varPhi_{12}(p)} = \alpha^{p^4 - p^2 + 1} = 1 \end{aligned} $$ <br /> #### Fast Squaring <br /> Back to squaring arithmetic of $\alpha \in F_{(q^2)^3} = F_{q^2}[v] / v^3 - u$: $$ \begin{aligned} \alpha = a + b \cdot v + c \cdot v^2, \{a, b, c\} \in F_{q^2} \\ \end{aligned} $$ according to above formula, the squaring is: $$ \begin{aligned} \alpha^2 &= (a^2 + 2 bc \cdot u) + (c^2 \cdot u + 2 ab) \cdot v + (b^2 + 2 ac) \cdot v^2 \\ &= A + B \cdot v + C \cdot v^2 \end{aligned} $$ The problem is how to compute $\{a \cdot b, b \cdot c, a \cdot c\}$ efficiently? <br /> Since $\alpha \in \mathbb{G}_{\varPhi_6(q)}$, then we have: $$ \begin{aligned} \alpha^{\varPhi_6(q)} = \alpha^{q^2 - q + 1} = 1 \\ \Longrightarrow \alpha^{q^2} \cdot \alpha = \alpha^q \\ \end{aligned} $$ where: $$ \begin{aligned} \alpha^q &= (a + b \cdot v + c \cdot v^2)^q \\ &= a^q + b^q \cdot v^q + c^q \cdot (v^q)^2 \\ \end{aligned} $$ How to compute individual items such as $a^q, b^q, c^q, v^q, v^{2q}$ effectively? Let's get it done piece by piece: - <span style='color:red'>$a^q, b^q, c^q = ?$</span> Put the conclusion first: $a^q = \bar{a}, b^q = \bar{b}, c^q = \bar{c}$. The above formula can be simplified into: $$ \begin{aligned} \alpha^q = \bar{a} + \bar{b} \cdot v^q + \bar{c} \cdot (v^q)^2 \end{aligned} $$ <br /> <br /> - <span style="color:red">$v^q = ?$</span> since $v^3 = u, u^2 = \xi, u \in F_{q^2}, \xi \in F_q$, then we have $$ v^q = v^{3 \cdot (q - 1)/3} \cdot v= u^{\frac{q - 1}{3}} \cdot v = \xi^{\frac{q - 1}{6}} \cdot v= \zeta_6 \cdot v $$ where $\zeta_6$ is a **primitive 6-th root of unity** in $F_q$. <br /> *More properties of primitive 6-th root of unity in $F_q$ can see this* :-1: :::info - $1 + \zeta_6^2 = \zeta_6$ - $\zeta_6^2 + \zeta_6^4 = -1$ - $\zeta_6^4 + \zeta_6 = 0$ ::: <br /> All together we have: $$ \alpha^q = \bar{a} + (\bar{b} \cdot \zeta_6) \cdot v + (\bar{c} \cdot \zeta_6^2) \cdot v^2 $$ <br /> Appling Frobenius map we have: $$ \begin{aligned} \alpha^{q^2} &= \bar{a}^q + (\bar{b}^q \cdot \zeta_6^q) \cdot v^q + (\bar{c}^q \cdot \zeta_6^{2q}) \cdot v^{2q} \\ &= a + (b \cdot \zeta_6^{q + 1}) \cdot v + (c \cdot \zeta_6^{2q + 2}) \cdot v^2 \\ &= a + (b \cdot \zeta_6^2) \cdot v + (c \cdot \zeta_6^4) \cdot v^2 \end{aligned} $$ <br /> Apply the property of Squaring Friendly Field we have: $$ \begin{aligned} &\alpha^{q^2} \cdot \alpha = \alpha^q \\ &\Updownarrow \\ &(a + (b \cdot \zeta_6^2) \cdot v + (c \cdot \zeta_6^4) \cdot v^2) \cdot (a + b \cdot v + c \cdot v^2) = \bar{a} + (\bar{b} \cdot \zeta_6) \cdot v + (\bar{c} \cdot \zeta_6^2) \cdot v^2 \\ \end{aligned} $$ expand the equation: $$ \begin{aligned} \bar{a} &= (a^2 + bc \zeta_6^2 \cdot u + bc \zeta_6^4 \cdot u) \\ \bar{b} \cdot \zeta_6 &= (ab + ab \zeta_6^2 + c^2 \zeta_6^4 \cdot u) \\ \bar{c} \cdot \zeta_6^2 &= (ac + ac \zeta_6^4 + b^2 \zeta_6^2) \\ \end{aligned} $$ So the THREE muliplications will be transformed into: $$ \begin{aligned} b \cdot c &= \frac{\bar{a} - a^2}{(\zeta_6^2 + \zeta_6^4) \cdot u} = \frac{\bar{a} - a^2}{-u} \\ a \cdot b &= \frac{(\bar{b} + c^2 \cdot u) \cdot \zeta_6}{1 + \zeta_6^2} = \frac{(\bar{b} + c^2 \cdot u) \cdot \zeta_6}{\zeta_6} = c^2 \cdot u + \bar{b} \\ a \cdot c &= \frac{(\bar{c} - b^2) \cdot \zeta_6^2}{1 + \zeta_6^4} = \frac{(\bar{c} - b^2) \cdot \zeta_6^2}{-\zeta_6^2} = b^2 - \bar{c} \\ \end{aligned} $$ Finally: $$ \begin{aligned} A &= a^2 + 2 bc \cdot u = 3a^2 - 2 \bar{a} \\ B &= c^2 \cdot u + 2ab = 3c^2 \cdot u + 2 \bar{b} \\ C &= b^2 + 2 ac = 3 b^2 - 2 \bar{c} \\ \\ \Longrightarrow \alpha^2 &= (3a^2 - \bar{a}) + (3c^2 \cdot u - 2 \bar{b}) \cdot v + (3 b^2 - 2 \bar{c}) \cdot v^2 \end{aligned} $$ <br /> ### Intuition of Field Transition In order to have intuitive sense, let's briefly introduce the <span style="color:red">field transitions</span> through **Tate/Ate pairings**. Assume that $P \in \mathbb{G}_1$ defined over $F_p$, while $Q \in \mathbb{G}_2$ defined over $F_{p^{12}}$, actually coordinates of $Q$ must be defined over some subfield of $F_{p^{12}}$ (we will prove for this in later following sections), such as we say $x_Q \in F_{p^6}, x_P \in F_p$: - Miller Loop - Double-Add the line function $f_{r, P}$ still lies where they originally stayed, such as $F_p$: ![double_add.drawio (1)](https://hackmd.io/_uploads/SkIujg2-A.png) - Evaluation Line Function for instance, the single line function: $$ l_{r, P}(Q) = y_Q - y_T - \alpha \cdot (x_Q - x_T) $$ the final evaluation result $f_{r, P}(Q)$ will not in $[r]F_{p^{12}}^{\times}$ anymore. ![double_add](https://hackmd.io/_uploads/B1qMignWC.png) - Final Exponentiation - Easy Part push the **Mill Loop** result $f_{r, P}(Q)$ into a special field, what we called **Cyclotomic Group**, $F_{\varPhi_{12}}$: ![easy_part.drawio](https://hackmd.io/_uploads/r1b71-2WC.png) - Hard Part push into target field $F_{p^{12}}^{\times}[r]$: ![hard_part.drawio](https://hackmd.io/_uploads/Sy5oy-nWC.png) <br /> ## Magic Power of Twist ### Why Twist <br /> Though we have tower fields to represent $F_{p^{12}}$, unfortunately computation over $F_{p^{12}}$ is still expensive. Twist is an advanced trick to solve this problem. <br /> We can map elements of $F_{p^{12}}$ into a much lower extension degree $F_{p^2}$ with a **sextic-twist**(twist degree is 6), then operations over $F_{p^{12}}$ will be replaced to operations over $F_{p^2}$: $$ \varphi: F_{p^{12}} \longmapsto F_{p^2} $$ But how to achieve this? <br /> ### Sextic Twist <br /> One elliptic curve, denoted as $E_{12}$, defined over high extension degree field $F_{p^{12}}$: $$ E_{12}: y^2 = x^3 + b $$ <br /> Another elliptic curve, denoted as $E_2'$, defined over low extension degree field $F_{p^2}$, and has a twist or **isomorphism** relationship with $E_{12}$: $$ E_2': y'^2 = x'^3 + b \cdot \xi $$ where $\xi \in F_{p^2}$, $\xi$ is both **non-quadratic** and **non-cubic** residual, namely to say: $$ \sqrt{\xi} \in F_{p^4}, \sqrt[3]{\xi} \in F_{p^6} $$ therefore we must have: $$ \sqrt[6]{\xi} = w \in F_{p^{12}} $$ <br /> But how to choose a proper $\xi$? It seems like $\xi$ just extends from $F_{p^2}$ to $F_{p^{12}}$. Fortunately, $\beta$ is the very just one! <br /> :::info $\bigstar \bigstar \bigstar \bigstar$ According to above tower fields, we can easily have: $$ F_{p^{2}}[x] \xrightarrow{X^6 - \beta} F_{p^{12}} $$ ::: <br /> So the twisted curve will be :-1: : $$ E_2': y'^2 = x'^3 + b \cdot \beta $$ Is this what we want? After doing some testation you may find that the order of twisted curve maybe is not what we want, it's possible that: $$ |E_2'| \mod r \ne 0 $$ $r$ is not a prime factor of $|E_2'|$. But what we want is map elements (points) of $E_{12} = E(F_{p^{12}})$ into $E_2' = E'(F_{p^2})$, and this is a one-to-one isomorphism: $$ \varphi: E(F_{p^{12}}) \longmapsto E(F_{p^2})' $$ so if $r \nmid |E_2'|$, there's not a cooresponding subgroup with order $r$ in $E_2'$ as $E_{12}$. So must be careful when you are finding a twisted curve (group)! <br /> *If $\beta$ is not proper, the $\beta^5$ must be the very proper ONE*([other papers](http://indigo.ie/%7Emscott/twists.pdf) also mentioned this), you can try it! So the twisted curve is: $$ \begin{aligned} &E_2': y'^2 = x'^3 + b \cdot \xi \\ &\Updownarrow \\ &E_{12}: (\frac{y'}{\sqrt[2]{\xi}})^2 = (\frac{x'}{\sqrt[3]{\xi}})^3 + b \end{aligned} $$ where <span style="color:red">$\xi = \beta^5 \in F_{p^2}$ or $\xi = \beta \in F_{p^2}$</span> and $\sqrt[2]{\xi} \in F_{p^4}, \sqrt[3]{\xi} \in F_{p^6}$. <br /> ### Sextic Twist Map <br /> Last thing on this section is element mapping between these two groups $E_{12}$ and $E_2'$: - **Twist Operation** map element of $E_{12}$ to $E_2'$: $$ \varphi: (x, y) \longmapsto (x \cdot \sqrt[3]{\xi}, y \cdot \sqrt[2]{\xi}) $$ - **Untwist Operation** map element of $E_2'$ to $E_{12}$: $$ \varphi^{-1}: (x', y') \longmapsto (\frac{x'}{\sqrt[3]{\xi}}, \frac{y'}{\sqrt[2]{\xi}}) $$ <br /> The cost of conversion is quite cheap, especially after we have the constant ones $\sqrt[2]{\xi}, \sqrt[3]{\xi}$ **precomputed in advance**. Last but not least , we just need to do a few times of untwist operation when neccessary. <br /> ## Magic Power of Frobenius Map Frobenius Map plays an essential role in arithemtics of high extension fields, especially during **Final Expoentiation** of **Tate/Ate Pairings**. <br /> ### Frobenius Map over $F_{p^2}$ Assume: $$ \begin{aligned} F_{p^2} &= F_p[u] / X^2 - \alpha \\ a &= (a_0 + a_1 u) \in F_{p^2} \\ \end{aligned} $$ where $u^2 = \alpha = -1$ and $a_0, a_1 \in F_p$, we have $a_0^p = a_0, a_1^p = a_1$. <br /> Then: $$ \begin{aligned} a^p &= a_0^p + a_1^p \cdot u^p \\ &= a_0 + a_1 \cdot \alpha^{(p - 1)/2} \cdot u \end{aligned} $$ since $(p - 1) / 2$ must be an odd number, so we have: $$ \begin{aligned} a^p &= a_0 - a_1 \cdot u \\ a^{p^2} &= a_0 + a_1 \cdot u \\ ... \\ a^{p^d} &= a_0 + (-1)^d a_1 \cdot u \end{aligned} $$ <br /> **For conclusion, Frobenius Map $\Phi_d(a) = a^{p^d} = a \in F_{p^2}$ if and only if $2 | d$.** <br /> ### Frobenius Map over $F_{p^6}$ Assume: $$ \begin{aligned} F_{p^6} &= F_{p^2}[v] / X^3 - \beta \\ a &= (a_0 + a_1 v + a_2 v^2) \in F_{p^6} \\ \end{aligned} $$ where $v^3 = \beta = u + 1$ and $\beta, a_0, a_1, a_2 \in F_{p^2}$, we have $a_0^p = \bar{a}_0, a_1^p = \bar{a}_1, a_2^p = \bar{a}_2$, and $$ \begin{aligned} v^p &= \beta^{(p - 1)/3} \cdot v \\ (v^p)^2 &= \beta^{2 \cdot \frac{p - 1}{3}} \cdot v^2 \\ \beta \cdot \bar{\beta} &= 1 - u^2 = N_2(\beta) \in F_p \\ \\ \end{aligned} $$ <br /> Then: $$ \begin{aligned} a^p &= a_0^p + a_1^p \cdot v^p + a_2^p \cdot (v^p)^2 \\ &= \bar{a}_0 + \bar{a}_1 \cdot \beta^{(p - 1)/3} \cdot v + \bar{a}_2 \cdot \beta^{2 \cdot \frac{p - 1}{3}} \cdot v^2 \\ \\ a^{p^2} &= a_0 + a_1 \cdot \bar{\beta}^{(p - 1)/3} \cdot \beta^{(p - 1)/3} \cdot v + a_2 \cdot \bar{\beta}^{2 \cdot \frac{p - 1}{3}} \cdot \beta^{2 \cdot \frac{p - 1}{3}} \cdot v^2 \\ \\ ...\\ \\ a^{p^d} &= C_d(a_0) + C_d(a_1) \cdot N_d(\beta)^{\frac{p - 1}{3}} \cdot v + C_d(a_2) \cdot N_d(\beta)^{2 \cdot \frac{p - 1}{3}} \cdot v^2 \\ \end{aligned} $$ where $C_d(a_i)$ denotes conjugate $d$ times on $a_i$, and $N_d(\beta)$ denotes norm $d$ times on $\beta$. <br /> Two aspects need to be considered: - for $C_d(a_i)$ We can easily have $C_2(a_i) = a_i, C_4(a_i) = a_i, C_6(a_i) = a_i$. - for $N_d(\beta)$ Since $N_2(\beta) = (1 - u^2) \in F_p$, then $N_4(\beta) = (1 - u^2)^2, N_6(\beta) = (1 - u^2)^3 \in F_p$, so we have: $$ \begin{aligned} a^{p^6} &= C_d(a_0) + C_d(a_1) \cdot (1 - u^2)^{p - 1} \cdot v + C_d(a_2) \cdot ((1 - u^2)^{p - 1})^2 \cdot v^2 \\ &= a_0 + a_1 \cdot v + a_2 \cdot v^2 \\ &= a \end{aligned} $$ <br /> **For conclusion, $\Phi_d(a) = a^{p^d} = a \in F_{p^6}$ if and only if $6 | d$.** <br /> ### Frobenius Map over $F_{p^{12}}$ Assume: $$ \begin{aligned} F_{p^{12}} &= F_{p^6}[w] / X^2 - v \\ a &= (a_0 + a_1 w) \in F_{p^{12}} \\ \end{aligned} $$ where $w^2 = v, v^3 = u + 1, u^2 = -1$ and $w, a_0, a_1 \in F_{p^6}$. <br /> Similarily, $$ \begin{aligned} a^p &= a_0^p + a_1^p \cdot w^p \\ &= \Phi_1(a_0) + \Phi_1(a_1) \cdot v^{(p - 1)/2} \cdot w \\ \\ a^{p^2} &= \Phi_2(a_0) + \Phi_2(a_1) \cdot (v^{p + 1})^{(p - 1)/2} \cdot w \\ \\ ...\\ a^{p^d} &= \Phi_d(a_0) + \Phi_d(a_1) \cdot (v^{p^d + p^{d - 1} + ... + 1})^{(p - 1)/2} \cdot w \\ &= \Phi_d(a_0) + \Phi_d(a_1) \cdot (v^{\frac{p^{d} - 1}{p - 1}})^{(p - 1)/2} \cdot w \\ &= \Phi_d(a_0) + \Phi_d(a_1) \cdot v^{(p^d - 1)/2} \cdot w \\ \end{aligned} $$ when $d = 12$, since $6 | d$, then we have $\Phi_d(a_i) = a_i$. since $\frac{p^{12} - 1}{2} = (p^6 - 1) \cdot \frac{p^6 + 1}{2}$, and $v \in F_{p^6}$, then we have: $$ (v^{p^6 - 1})^{\frac{p^6 + 1}{2}} = 1 $$ therefore: $$ \begin{aligned} a^{p^{12}}&= a_0 + a_1 \cdot w \\ &= a \\ \end{aligned} $$ **For conclusion, $\Phi_d(a) = a^{p^d} = a \in F_{p^{12}}$ if and only if $12 | d$.** <br /> ### Frobenius Map and Conjunction There is a quadratic extension: $$ F_{q^2} = F_{q}[u] / X^2 - \alpha $$ where $q = p^m$, assume $a = a_0 + a_1 \cdot u \in F_{q^2} = F_{p^{2m}}$, where $a_0, a_1 \in F_{q} = F_{p^m}$. If we want to do m-times **Frobenius Map** on $a$, then: $$ \begin{aligned} a^{p^m} &= a_0^{p^m} + a_1^{p^m} \cdot u^{p^m} \\ &= a_0 + a_1 \cdot \alpha^{(p^m - 1)/2} \cdot u\\ \end{aligned} $$ since $\alpha$ is non-quadratic residual, namely $\alpha^{(p^m - 1)/2} = -1$, therefore we have: $$ a^q = a^{p^m} = \bar{a} $$ It's free cost! <br /> For instance $(F_{p^{12}})^{p^6} = \bar{F}_{p^{12}}, (F_{p^{6}})^{p^3} = \bar{F}_{p^{6}}, (F_{p^{2}})^{p} = \bar{F}_{p^2}, ...$. ---- # Curve Arithmetics Underneath This is where **Scalar Multiplication** mainly works. There are two curves (groups) we need to instantiate, $\mathbb{G}_1$ and $\mathbb{G}_2$, in curve BLS12-381: $$ \begin{aligned} \mathbb{G}_1 &= E(F_p)[r] \\ \mathbb{G}_2 &= E'(F_{p^2})[r]\\ \end{aligned} $$ where $\mathbb{G}_1$ is the $r$-torsion curve (subgroup) defined over **Base Prime Field** $F_p$, $\mathbb{G}_2$ is the $r$-torsion **twisted curve** (subgroup) defined over **sextic-twisted field** (relative to $F_{p^{12}}$) $F_{p^{12 / 6}} = F_{p^2}$. <br /> ## Arithmetics of Curve $\mathbb{G}_1$ $$ E(F_p): y^2 = x^3 + 4 $$ where $x, y \in F_p$. <br /> While curve $\mathbb{G}_1$ also defined over prime field, it's just a $r$-torsion subgroup of $E(F_p)$. Arithmetics (Scalar Multiplication) is the same, nothing special. <br /> ## Arithmetics of Curve $\mathbb{G}_2$ $$ E'(F_{p^2}): y^2 = x^3 + 4 \cdot \beta $$ where $x, y, \beta \in F_{p^2}, w = \sqrt[6]{\beta} \in F_{p^{12}}$. <br /> Similarly $\mathbb{G}_2$ is just $r$-torsion subgroup of $E'(F_{p^2})$, Arithmetics (Scalar Multiplication) is over $F_{p^2}$, not $F_p$ anymore. Arithmetics over $F_{p^2}$ has already illustrated above. <br /> ## Arithmetics of Target Group $\mathbb{G}_T$ The target group $\mathbb{G}_T$ is actually not a curve (additional group), but a $r$-torsion subgroup of multiplicative group, represented as $F_{p^k}^{\times}[r]$. So its arithmetics is same as $F_{p^k}^{\times}$. <br /> ---- # Evolution of Pairings ## Weil Reciprocity $g$ and $f$ are two zero (divisor) functions defined over elliptic curve over finite field, $f, g \in K(E)$, whose divisors are **disjoints each other**, $supp((f)) \land supp((g)) = \emptyset$. Then we have: $$ g((f)) \equiv f((g)) $$ where $(f)$ denotes divisors of functions $f$, $g((f))$ denotes evaluation of function $g$ on divisor $(f)$, similarly as $f((g))$. <br /> If we relax the constraints, if $supp((f)) \land supp((g)) \ne \emptyset$, then a more general **Weil Reciprocity** comes: $$ g((f)) \equiv \epsilon((f), (g)) \cdot f((g)) $$ where $\epsilon((f), (g)) = 1$ if $(f)$ and $(g)$ are disjoint, otherwise $\epsilon((f), (g)) = -1$. <br /> :::success Details of general definition of Weil Reciprocity, you can refer THEOREM 3.9 of [Guide to Pairing-based Cryptography](https://www.math.u-bordeaux.fr/~damienrobert/csi/book/book.pdf). ::: <br /> What's the significance of Weil Reciprocity? It directly gives birth to **Weil Pairing**. <br /> ## Weil Pairing Assume there are two **linearly disjoint points** of $r$-torsion subgroup defined on curve, $P, Q \in E[r], P \ne \lambda Q$. Upon that, assume $(f) = r \cdot D_P$, and $D_P \equiv (P) - (\mathcal{O})$, similarly $(g) = r \cdot D_Q, D_Q \equiv (Q) - (\mathcal{O})$. Satisfing $Supp(D_P) \land Supp(D_Q) = \emptyset$. <br /> Then we have: $$ \begin{aligned} g_{rD_Q}(r \cdot D_P) &\equiv f_{rD_P}(r \cdot D_Q) \\ &\Downarrow \\ g_{rD_Q}(D_P)^r &\equiv f_{rD_P}(D_Q)^r \\ &\Downarrow \\ (\frac{g_{rD_Q}(D_P)}{f_{rD_P}(D_Q)})^r &\equiv 1 \\ \end{aligned} $$ <br /> So does **Weil Pairing** come: $$ \frac{f_{rD_Q}(D_P)}{f_{rD_P}(D_Q)} = \mu_r \in F_{p^k}^{\times}[r] $$ where $(f_{rD_Q}) = rD_Q, (f_{rD_P}) = rD_P$, and $\mu_r$ is $r$th unity root of multiplicative group $F_{p^k}^{\times}$, namely $\mu_r^r \equiv 1 \mod p^k - 1$. <br /> #### How to choose proper $D_P$ and $D_Q$ Theoretically we have to choose proper divisors $D_P$ and $D_Q$, you may wonder whether the result $\mu_r$ would be different or not if we choose different $D_P$ and $D_Q$? Actually the result value of **Weil Pairing** $\mu_r$ is independent of $D_P$ and $D_Q$. Let's prove it! <br /> Assume $D_{P1}$ and $D_{P2}$ are both equivalent with $(P) - (\mathcal{O})$, then there must exists a divisor $(t)$ satisfing $D_{P1} = D_{P2} + (t)$, then: $$ \frac{f_{rD_Q}(D_{P1})}{f_{rD_{P1}}(D_Q)} = \frac{f_{rD_Q}(D_{P2}) \cdot f_{rD_Q}((t))}{f_{rD_{P2}}(D_Q) \cdot f_{(t)}(D_Q)^r} $$ According to **Weil Reciprocity**, since $supp((t)) \land supp(rD_Q) = \emptyset$, we have $f_{rD_Q}((t)) \equiv f_{(t)}(rD_Q) = f_{(t)}(D_Q)^r$. Therefore: $$ \frac{f_{rD_Q}(D_{P1})}{f_{rD_{P1}}(D_Q)} = \frac{f_{rD_Q}(D_{P2})}{f_{rD_{P2}}(D_Q)} $$ <br /> Since then we choose the simplest divisors, $D_P = (P) - (\mathcal{O}), D_Q = (Q) - (\mathcal{O})$. According to the general **Weil Reciprocity**, we have: $$ (-1)^r \cdot \frac{f_{r((Q) - (\mathcal{O}))}((P) - (\mathcal{O}))}{f_{r((P) - (\mathcal{O}))}((Q) - (\mathcal{O}))} = \mu_r \in F_{p^k}^{\times}[r] $$ <br /> #### How to evaluate divisors $D_P$ and $D_Q$ Evaluation on $D_P = (P) - (\mathcal{O})$ can be simplified further: $$ f_{rD_Q}(D_P) \equiv f_{rD_Q}(P) $$ if and only if $P$ and $Q$ are **linearly disjoint** (independent) with each other, $P \ne \lambda Q, \lambda \le r$. Notice that they are equivalent $\equiv$ not $=$, another words the value maybe different, but it does not have effects on the result of **Weil Pairing** $\mu_r$. <br /> Therefore **Weil Pairing** becomes: $$ (-1)^r \cdot \frac{f_{r((Q) - (\mathcal{O}))}(P)}{f_{r((P) - (\mathcal{O}))}(Q)} = \mu_r \in F_{p^k}^{\times}[r] $$ <br /> **Miller Loop** makes evaluation of function $f_{r((Q) - (\mathcal{O}))}(P)$ practical, obviousely **Weil Pairing** is symmetric, it actually runs two times of **Miller Loop**. Seems like not economic? Actually single one is enough, this is what **Tate Pairing** does. <br /> #### Algorithm Directly come from Algorithm 3.2 of [Guide to Pairing-based Cryptography](https://www.math.u-bordeaux.fr/~damienrobert/csi/book/book.pdf): ![Screen Shot 2024-04-26 at 13.59.01](https://hackmd.io/_uploads/HkjAMTu-A.png) <br /> ## Tate Pairing You may wonder what does $f_{r((P) - (\mathcal{O}))}(Q)$ look like? Since $P, Q \in E_{F_{p^k}}[r]$, then $P_x, P_y, Q_x, Q_y \in F_{p^k}$, so $f_{r((P) - (\mathcal{O}))}(Q) \in F_{p^k}$. Appling property of coset, **Tate Pairing** comes: $$ f_{r((P) - (\mathcal{O}))}(Q)^{\frac{p^k - 1}{r}} \equiv \mu_r \in F_{p^k}^{\times}[r] $$ It has two steps, **Miller Loop** and **Final Exponentiation**. This is also where **Final Exponentiation** comes from. <br /> #### Formal Definition Actually **Tate Pairing** has a more formal definition: $$ e_{T, r}(P, Q): E[r](F_{p^k}) \times E(F_{p^k}) / rE(F_{p^k}) \rightarrow \mu_r $$ specially $P \in E[r](F_{p^k}), Q \in E(F_{p^k}) / rE(F_{p^k})$, **$Q$ is not element of $r$-torsion subgroup**, it does not lie on $E[r](F_{p^k})$ as $P$ anymore. It is actually an element of quotient group, any element in $E(F_{p^k})$ which is **linearly disjoint** with $P$. Since then, how about the evaluation of function $f_{r, P}(Q)$ (result of **Miller Loop**)? It must be also an element of quotient group: $$ f_{r, P}(Q) \in F_{p^k}^{\times} / r F_{p^k}^{\times} $$ <br /> Seems like **Tate Pairing** is more general (more relaxed constraints) than **Weil Pairing**, right? <br /> :::success Since $P \ne \lambda Q, \lambda \le r$, usually for the convenience of computation(utilization of Frobenius Automorphism) we let $P \in \mathbb{G}_1 = \pi[1]$, namely $\pi(P) = 1 \cdot P$, $\mathbb{G}_1$ is so-called **Base Group**. While $Q \in \mathbb{G}_2 = \pi[p]$, namely $\pi(Q) = [p] Q$, $\mathbb{G}_2$ is so-called **Trace-zero Group**. ::: <br /> #### Algorithm Directly come from Algorithm 3.3 of [Guide to Pairing-based Cryptography](https://www.math.u-bordeaux.fr/~damienrobert/csi/book/book.pdf): ![Screen Shot 2024-04-26 at 14.03.27](https://hackmd.io/_uploads/Bky14p_b0.png) <br /> #### Miller Loop You may notice that, lengths of **Miller Loop** of **Weil Pairing** and **Tate Pairing** are both $\log(r)$ (bit length of $r$). *Theoretically **Tate Pairing** is practically good enough, more research are focus on practical implementation of pairings later on.* Specially on shorten **Miller Loop** and more efficient **Final Expoentiation**. Is there any shorter **Miller Loop** algorithms? Yes, but we have to dive into multiplicative group $F_{p^k}^{\times}$ and explore its structure a bit more. <br /> ## Ate Pairing In **Ate Pairing**, point $Q$ is limited within $\mathbb{G}_2 = \pi[p]$, and point $P$ is limited within $\mathbb{G}_1 = \pi[1]$. This constraints can greatly accelerate pairing computation. #### Great Property of Miller Algorithm $$ \begin{aligned} f_{a + b}, Q(P) &= f_{a, Q}(P) \cdot f_{b, Q}(P) \cdot \frac{l_{[a]Q,[b]Q}}{v_{[a + b]Q}} \\ f_{a \cdot b, Q}(P) &= f_{b, Q}^{a}(P) \cdot f_{a, [b]Q}(P) \\ \end{aligned} $$ <br /> #### Shorter Miller Loop $r | p^k - 1$, assume $u = (p^k - 1) // r$, then we have: $$ f_{p^k, Q}(P) = f_{p^k - 1, Q}(P) \cdot f_{1, Q}(P) \cdot \frac{l_{[p^k - 1]Q,[1]Q}(P)}{v_{[p^k - 1 + 1]Q}(P)} $$ <br /> Since $Q \in \mathbb{G}_2$, then $[r] Q = \mathcal{O}, [p^k - 1]Q = \mathcal{O}$, we have $l_{[p^k - 1]Q,[1]Q} = v_{[p^k - 1 + 1]Q} = (Q) + (-Q) - 2(\mathcal{O})$, therefore: $$ f_{p^k, Q}(P) = f_{p^k - 1, Q}(P) = f_{r, Q}(P)^u $$ It seems like we can replace $r$ into $p$, so it is uncessary since $p > r$. <br /> If $\lambda \equiv p \mod r$ and $r | p^k - 1$, then $r | \lambda^k - 1$, assume $m = (\lambda^k - 1) // r$, similarly we have: $$ f_{\lambda^k, Q}(P) = f_{\lambda^k - 1, Q}(P) = f_{r, Q}(P)^m $$ <br /> According to above great property of **Miller Loop** we have: $$ \begin{aligned} f_{\lambda^k, Q} &= f_{\lambda, Q}^{\lambda^{k - 1}} \cdot f_{\lambda^{k - 1}, [\lambda]Q} \\ &= f_{\lambda, Q}^{\lambda^{k - 1}} \cdot f_{\lambda, [\lambda]Q}^{\lambda^{k - 2}} \cdot f_{\lambda^{k - 2}, [\lambda^2]Q} \\ &= f_{\lambda, Q}^{\lambda^{k - 1}} \cdot f_{\lambda, [\lambda]Q}^{\lambda^{k - 2}} \cdot f_{\lambda, [\lambda^2]Q}^{\lambda^{k - 3}} \cdot f_{\lambda^{k - 3}, [\lambda^3]Q} \\ &= ... \\ &= f_{\lambda, Q}^{\lambda^{k - 1}} \cdot f_{\lambda, Q}^{\lambda^{k - 2} \cdot p} \cdot f_{\lambda, Q}^{\lambda^{k - 3} \cdot p^2} \cdot ... \cdot f_{\lambda, Q}^{1 \cdot p^{k - 1}} \\ &= f_{\lambda, Q}^{\sum_{i = 0}^{k - 1} (k - 1 - i) \cdot p^i} \end{aligned} $$ let $c = \sum_{i = 0}^{k - 1} (k - 1 - i) \cdot p^i$, we have: $$ f_{\lambda^k, Q}(P) = f_{\lambda, Q}(P)^c = f_{r, Q}(P)^m $$ since $\lambda < r$, we can absolutely replace $r$ into $\lambda$, but how to get $\lambda$? <br /> #### Trace of Frobenius According to **Hessen Bound**, we have: $$ |p + 1 - t| = \#E(F_p) $$ let $T = t - 1$ where $t$ is the Trace of Frobenius, since $r | \#E(F_p)$, then $\lambda = T \equiv p \mod r$. Finally we have: $$ \begin{aligned} a_{T}(P, Q) &= f_{T, Q}(P)^{\frac{p^k - 1}{r}} \\ (f_{T, Q}(P)^c)^{\frac{p^k - 1}{r}} &= (f_{r, Q}(P)^m)^{\frac{p^k - 1}{r}} \\ \Downarrow \\ a_{T}(P, Q)^c &= e_{T, r}(P, Q)^m \\ \end{aligned} $$ Obviousely we can see the strong relationship between **Tate Pairing** $e_{T, r}(P, Q)$ and **Ate Pairing** $a_{T}(P, Q)$. You may notice that the values of pairings are different, but uniqueness remained. <br /> What we actually do in **Ate Pairing** is finding a multiple of $r$, $T$ is what we just found, $r | T^k - 1$. But, is $\log{T}$ the shortest length of **Miller Loop**? Maybe (or not) <br /> ## Optimal Ate Pairing ![optimal ate.drawio](https://hackmd.io/_uploads/HyiBWfYZ0.png) <br /> Appling **Ate Pairing** above, trivally replacing $T$ into $p$, we have: $$ f_{p, Q}^{x2} = f_{r, Q}^u $$ where $u = (p^k - 1) // r$, and $x2 = k \cdot p^{k - 1}$. <br /> According to **Ate Pairing** above, we have: $$ f_{\lambda, Q}^{x1} = f_{r, Q}^m $$ where $m = (\lambda^k - 1) // r$, and $x1 = \sum_{i = 0}^{k - 1} (k - 1 - i) \cdot p^i$. <br /> Upon this, we have: $$ \begin{aligned} f_{p, Q}^{x2 \cdot m} &= f_{T, Q}^{x1 \cdot u} \\ \Longrightarrow f_{\lambda, Q}^{x1} &= f_{p, Q}^{\frac{x2 \cdot m}{u}} \\ &= f_{p, Q}^{\frac{k \cdot p^{k - 1} \cdot m}{(p^k - 1) // r}} \end{aligned} $$ <br /> Therefore, $x1$ powers of **Ate Pairing**: $$ a_{\lambda}(P, Q)^{x1} = (f_{\lambda, Q}(P)^{x1})^{\frac{p^k - 1}{r}} = (f_{p, Q}(P)^{\frac{k \cdot p^{k - 1} \cdot m}{(p^k - 1) // r}})^{\frac{p^k - 1}{r}}$$ Let's leave it alone for a while. <br /> We generalize the $\lambda = \sum_{i = 0}^l c_i \cdot p^i, l < k$, and $\lambda = m \cdot r$. Same as **Ate Pairing**, finding a multiple of $r$. According to properties of **Miller Loop**, we have: $$ \begin{aligned} f_{\lambda, Q} &= f_{\sum_{i = 0}^l c_i \cdot p^i, Q} \\ &= \prod_{i = 0}^l f_{c_i \cdot p^i, Q} \cdot \prod_{j = 0}^{l - 1} \frac{l_{[s_{j + 1}]Q,[c_j \cdot q^j]Q}}{v_{[s_j]Q}} \\ &= \prod_{i = 0}^l f_{p^i, Q}^{c_i} \cdot (\prod_{i = 0}^l f_{c_i, Q}^{p^i} \cdot \prod_{j = 0}^{l - 1} \frac{l_{[s_{j + 1}]Q,[c_j \cdot q^j]Q}}{v_{[s_j]Q}}) \\ \end{aligned} $$ where applying properties of **Miller Loop**, we have: $$ \prod_{i = 0}^l f_{p^i, Q}^{c_i} = \prod_{i = 0}^l f_{p, Q}^{i \cdot c_i \cdot p^{i - 1}} = f_{p, Q}^{\sum_{i = 0}^l i \cdot c_i \cdot p^{i - 1}} $$ <br /> Then **Ate Pairing** is transformed into: $$ \begin{aligned} a_{\lambda}(P, Q) &= f_{\lambda, Q}(P)^{\frac{p^k - 1}{r}} \\ &= (f_{p, Q}(P)^{\sum_{i = 0}^l i \cdot c_i \cdot p^{i - 1}})^{\frac{p^k - 1}{r}} \cdot (\prod_{i = 0}^l f_{c_i, Q}(P)^{p^i} \cdot \prod_{j = 0}^{l - 1} \frac{l_{[s_{j + 1}]Q,[c_j \cdot q^j]Q}(P)}{v_{[s_j]Q}(P)})^{\frac{p^k - 1}{r}} \\ &= (f_{p, Q}(P)^{\frac{k \cdot p^{k - 1} \cdot m}{(p^k - 1) // r}})^{\frac{p^k - 1}{r}} \\ \end{aligned} $$ Obviousely **Ate Pairing** $a_{\lambda}(P, Q)$ is divided into two parts, since the left part $(f_{p, Q}^{\sum_{i = 0}^l i \cdot c_i \cdot p^{i - 1}})^{\frac{p^k - 1}{r}}$ is a trival **Ate Pairing** (length of **Miller Loop** is $\log{p}$), so **the right part $(\prod_{i = 0}^l f_{c_i, Q}^{p^i} \cdot \prod_{j = 0}^{l - 1} \frac{l_{[s_{j + 1}]Q,[c_j \cdot q^j]Q}}{v_{[s_j]Q}})^{\frac{p^k - 1}{r}}$ must be an Ate Pairing too if and only if $\frac{k \cdot p^{k - 1} \cdot m}{(p^k - 1) // r} \ne \sum_{i = 0}^l i \cdot c_i \cdot p^{i - 1}$**. <br /> So the **Optimal Ate Pairing** comes: $$ a_{[c_0, c_1,...,c_l]}(P, Q) = (\prod_{i = 0}^l f_{c_i, Q}(P)^{p^i} \cdot \prod_{j = 0}^{l - 1} \frac{l_{[s_{j + 1}]Q,[c_j \cdot q^j]Q}(P)}{v_{[s_j]Q}(P)})^{\frac{p^k - 1}{r}} $$ where the coefficients $c_i$ are as small as possible. <br /> No need to worry about powers $p^i$, it's almost free cost after appling few times **Frobenius Map**. What **Optimal Ate Pairing** need to do is concurrently calculuating $f_{c_i, Q}(P)$ and $l_{[s_{j + 1}]Q,[c_j \cdot q^j]Q}(P)$, the length of **Miller Loop** is $max(\log{c_i})$. <br /> The only problem is how to find these coefficients $c_i$? It is actually a **Lattice Problem**, more details you can refer [Optimal Pairings](https://eprint.iacr.org/2008/096.pdf). <br /> --- # Python Implementation ## Instantiation of Curve BLS12-381 ### Trace/Unti-trace Map Trace Map: $$ Tr(Q) = \sum_{i = 0}^k (Q_x^{p^i}, Q_y^{p^i}) $$ where $k$ is the full extension degree. It maps any $r$-torsion points of $E(F_{p^k})[r]$ into $\mathbb{G}_1 = E(F_p)[r]$. <br /> Untri-trace Map: $$ UnTr(Q) = [k] Q - Tr(Q) $$ It maps any $r$-torsion points of $E(F_{p^k})[r]$ into $\mathbb{G}_2$, whose **Trace Map** result is $\mathcal{O}$. <br /> Since $\mathbb{G}_1$ is defined over $F_p$, so $Q \in \mathbb{G}_1, Tr(Q) = [d] Q$. While $Q \in \mathbb{G}_2, Tr(Q) = \mathcal{O}$, this is where **Trace-zero subgroup** come from. <br /> ```python= def anti_trace_map(point, d, p, E): return d * point - trace_map(point, d, p, E) def trace_map(point, d, p, E): result = point point_t = point for i in range(1, d): point_x, point_y = list(point_t)[0], list(point_t)[1] point_t = E(point_x ** p, point_y ** p) result = result + point_t return result ``` <br /> ### Finite Field Conversion ```python= ## map element of Fp2 into Fp12 def into_Fp12(e_fp2, beta, F, gen): a = beta.polynomial().list() if len(a) == 1 : a = a + [0] e = e_fp2.polynomial().list() if len(e) == 1: e = e + [0] return F(e[0]) + F(e[1]) * (gen ** 6 - F(a[0])) / F(a[1]) ## map elements of Fp12 into Fp2 with critical conditions def into_Fp2(e_fp12, F, gen): coef = e_fp12.polynomial().list() zero_coeff = [1 for i in range(12) if ((len(coef) > i) and (i != 0) and (i != 6) and (F(coef[i]) == F(0)))] assert(reduce(mul, zero_coeff) == 1) return (F(coef[0]) + F(coef[6])) + gen * F(coef[6]) ## map elements of Fp12_t into Fp12 def Fp12_t_into_Fp12(e_fp12_t, F, gen): coef = list(e_fp12_t) result = [] for i in range(len(coef)): result.append([(F(c) * (((gen ** 6) - F(1)) ** j) * (gen ** i)) for j, c in enumerate(coef[i].polynomial().list())]) return reduce(add, sum(result, [])) ``` <br /> ### Twist and Untwist ```python= def untwist(x, y, t_x, t_y): return x / t_x, y / t_y def twist(x, y, t_x, t_y): return x * t_x, y * t_y ``` <br /> ### Definition of $\mathbb{G}_1$ $\mathbb{G}_1$ denotes curve defined **base prime field**, namely $E(F_p)[r]$ ```python= p = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 q = 52435875175126190479447740508185965837690552500527637822603658699938581184513 A = 0 B = 4 ## base prime field Fp = GF(p) ## E1 over base prime field, map any point on Efp into the q-torsion subgroup Efp = EllipticCurve(Fp, [A, B]) r_E = Efp.order() cofactor_E1 = r_E // q # g_E1 = Efp(0) # while g_E1 == Efp(0): # a = Efp.random_element() # g_E1 = cofactor * a g_E1 = Efp( 2262513090815062280530798313005799329941626325687549893214867945091568948276660786250917700289878433394123885724147, 3165530325623507257754644679249908411459467330345960501615736676710739703656949057125324800107717061311272030899084 ) assert(q * g_E1 == Efp(0)) ## trace map on E1 is trival, stays on E1 assert(trace_map(g_E1, 12, p, Efp) == 12 * g_E1) print('\n ##################################### Curve G1: \n cofactor = {}, \n generator = {}, \n order = {} \n'.format(cofactor_E1, g_E1, r_E)) ``` <br /> ### Definition of $\mathbb{G}_2'$ $\mathbb{G}_2'$ denotes curve defined over field $F_{p^{k/d}}$, namely $E'(F_{p^{k/d}})[r]$, who is $d$-twisted with $E(F_{p^k})[r]$. In BLS12-381 (sextic-twist), $\mathbb{G}_2' = E'(F_{p^{2}})[r]$. ```python= ########## Fp2 = Fp[X] / X^2 - alpha ## alpha = -1 d = 2 alpha = Fp(-1) X = Fp['X'].gen() pol2 = X ** d - alpha assert(pol2.is_irreducible() == True) Fp2 = GF(p ** d, 'u', modulus = pol2) u = Fp2.gen() ## Fp12 = Fp2[X] / X^6 - beta d = 6 beta = u + 1 XX = Fp2['XX'].gen() pol12 = XX ** d - beta assert(pol2.is_irreducible() == True) beta_t = beta Efp2_t = EllipticCurve(Fp2, [A, B * beta_t]) ## find the proper twisted curve, who has a q-torsion subgroup which is isomorphism with Efpk's one if Efp2_t.order() % q != 0: beta_t = beta ** 5 Efp2_t = EllipticCurve(Fp2, [A, B * beta_t]) ``` <br /> ### Definition of $\mathbb{G}_{12}'$ $\mathbb{G}_{12}'$ denotes twisted curve defined over $F_{p^k}$, namely $E'(F_{p^k})[r]$. ```python= ## twist curve E' over Fp12 Fp12_t = Fp2.extension(pol12, 'x') Efp12_t = Efp2_t.change_ring(Fp12_t) print('\n Twist curve E defined over Fp12: {}\n'.format(Efp12_t)) ``` <br /> ### Definition of $\mathbb{G}_{12}$ $\mathbb{G}_{12}$ denotes curve defined over $F_{p^k}$, namely $E(F_{p^k})[r]$. ```python= ## Fp12 = Fp[X] / X^12 - 2X^6 + 2 Fp12 = GF(p ** 12, 'w', modulus = X ** 12 - 2 * (X ** 6) + 2) w = Fp12.gen() ## constant parameters of twist/untwist beta_t_x = w ** 2 beta_t_y = w ** 3 ## make sure g_E2 is in the q-torsion subgroup on Efp2_t r_E2_t = Efp2_t.order() cofactor_E2_t = r_E2_t // q # g_E2 = Efp2_t(0) # while g_E2 == Efp2_t(0): # b = Efp2_t.random_element() # g_E2 = cofactor_E2_t * b g_E2 = Efp2_t([ [ 1265792444950586559339325656560420460408530841056393412024045461464508512562612331578200132635472221512040207420018, 12405554917932443612178266677500354121343140278261928092817953758979290953103361135966895680930226449483176258412 ], [ 3186142311182140170664472972219788815967440631281796388401764195993124196896119214281909067240924132200570679195848, 1062539859838502367600126754068373748370820338894390252225574631210227991825937548921368149527995055326277175720251 ], ]) assert(q * g_E2 == Efp2_t(0)) print('\n #################################### Curve G2: \n cofactor = {}, \n generator = {}, \n order = {} \n'.format(cofactor_E2_t, g_E2, r_E2_t)) ## make sure g_E2 is in Fp12 first, uniform the field before untwist Efp12 = Efp.change_ring(Fp12) g_E12 = into_E12(g_E2, beta, Fp, w, beta_t_x, beta_t_y, Efp12) ## For the convenience of do Frobenius Map within Fp2, namely (x^p, y^p) ## traditionaly need 3 steps: ## 1. untwist (x, y) to (x', y'), (x', y') = (x / beta_t_x, y / beta_t_y) ## 2. do Frobenius Map within Fp12, (x'^p, y'^p) = (x^p / beta_t_x^p, y^p / beta_t_y^p) ## 3. twist back to (x, y), (x, y) = (x'^p * beta_t_x, y'^p * beta_t_y) = (x^p / beta_t_x^{p - 1}, y^p / beta_t_y^{p - 1}) ## ## Someone may wonder why wouldn't we do Frobenius Map within Fp2 directly? ## Since one time of Frobenius Map within Fp2, phi(P), may skip out of G2, though P belongs to G2, ## so we must do it within the FULL EXTENSION Fp12. ## ## Caching beta_t_x^{-(p - 1)} or beta_t_y^{-(p - 1)} would be much preferable ## twist_frob_x = into_Fp2(1 / (beta_t_x ** (p - 1)), Fp, u) twist_frob_y = into_Fp2(1 / (beta_t_y ** (p - 1)), Fp, u) print('\n Twist parameters: cubic_root(beta_t)^-1 = {}, sqrt(beta_t)^-1 = {} \n'.format(beta_t_x, beta_t_y)) print('\n Twist parameters for Frobenius Map within Fp2: \n cubic_root(beta_t)^-(p - 1) = {}, \n sqrt(beta_t)^-(p - 1) = {} \n'.format( twist_frob_x, twist_frob_y )) print('\n ==================================== DEBUG ====================================\n ') ## make sure g_E12 is in the zero-trace subgroup of q-torsion assert(q * g_E12 == Efp12(0)) assert(trace_map(g_E12, 12, p, Efp12) == Efp12(0)) print('\n #### UNTWIST: Point of E2 \n {} \n is mapped into E12 \n {} \n successfully! \n'.format(g_E2, g_E12)) ## make sure it can be twisted back x, y = twist(list(g_E12)[0], list(g_E12)[1], beta_t_x, beta_t_y) x, y = (into_Fp2(x, Fp, u), into_Fp2(y, Fp, u)) assert(Efp2_t(x, y) == g_E2) print('\n #### TWIST: Point of E12 \n {} \n is mapped into E2 \n {} \n successfully! \n'.format(g_E12, Efp2_t(x, y))) ``` <br /> ## Weil Pairing ### Evaluation of Double-line Function ```python= ## evaluation of double line divisor function ## arithmetics on fields, not on multiplicative group def double_line(line_point, eval_point, E, phi, reverse = False): ######################## arithemtic on finite field of line_point ## lambda = 3x^2 / 2y (x_L, y_L) = (list(line_point)[0], list(line_point)[1]) (x_E, y_E) = (list(eval_point)[0], list(eval_point)[1]) alpha = (3 * x_L^2) / (2 * y_L) x_2L = alpha * alpha - 2 * x_L y_2L = -y_L - alpha * (x_2L - x_L) ######################## arithmetic on mixed finite field ## x_E, y_E \in F2 ## y_L, x_L, alpha, x_2L \in F1 if reverse: ## evaluation of slop line l_2T e_1 = phi(y_E) - y_L - alpha * (phi(x_E) - x_L) ## evaluation of vertical line v_2T e_2 = phi(x_E) - x_2L else: ## evaluation of slop line l_2T e_1 = y_E - phi(y_L) - phi(alpha) * (x_E - phi(x_L)) ## evaluation of vertical line v_2T e_2 = x_E - phi(x_2L) return E(x_2L, y_2L), e_1, e_2 ``` <br /> ### Evaluation of Add-line Function ```python= ## evaluation of add line divisor function ## arithmetics on fields, not on multiplicative group def add_line(line_left_point, line_right_point, eval_point, E, phi, reverse = False): ######################## arithemtic on finite field of line_point ## lambda = (y2 - y1) / (x2 - x1) (x_L, y_L) = (list(line_left_point)[0], list(line_left_point)[1]) (x_R, y_R) = (list(line_right_point)[0], list(line_right_point)[1]) (x_E, y_E) = (list(eval_point)[0], list(eval_point)[1]) alpha = (y_L - y_R) / (x_L - x_R) x_LR = alpha * alpha - x_L - x_R y_LR = -y_L - alpha * (x_LR - x_L) ######################## arithmetic on mixed finite field ## x_E, y_E \in F2 ## y_L, x_L, alpha, x_LR \in F1 if reverse: ## evaluation of slop line l_{T + P} e_1 = phi(y_E) - y_L - alpha * (phi(x_E) - x_L) ## evaluation of vertical line v_{T + P} e_2 = phi(x_E) - x_LR else: ## evaluation of slop line l_{T + P} e_1 = y_E - phi(y_L) - phi(alpha) * (x_E - phi(x_L)) ## evaluation of vertical line v_{T + P} e_2 = x_E - phi(x_LR) return E(x_LR, y_LR), e_1, e_2 ``` <br /> ### Miller Loop ```python= ## Miller Loop of Weil Pairing def MillerLoop(P, Q, G, q, phi, reverse = False): T = P f1 = 1 f2 = 1 e_bits = [int(i) for i in bin(q)[2:]] ## last bit cannot be evaluated, since the slope would be a vertical line for i in range(1, len(e_bits)): if (i == len(e_bits) - 1) and (e_bits[i] == 0): f1 = f1 * (list(Q)[0] - list(T)[0]) T = 2 * T break T, e_1, e_2 = double_line(T, Q, G, phi, reverse) f1, f2 = (f1 * f1 * e_1, f2 * f2 * e_2) if (i == len(e_bits) - 1) and (e_bits[i] == 1): f1 = f1 * (list(Q)[0] - list(T)[0]) T = T + P break if e_bits[i] == 1: T, e_1, e_2 = add_line(T, P, Q, G, phi, reverse) f1, f2 = (f1 * e_1, f2 * e_2) assert(T == G(0)) return f1 / f2 ``` <br /> ### Testation of Weil Pairing ```python= ## Weil Pairing Entry def WeilPairing(P, Qx, G1, G12, q, phi): t0 = time.perf_counter() f_rP_Q = MillerLoop(P, Qx, G1, q, phi, False) t1 = time.perf_counter() f_rQ_P = MillerLoop(Qx, P, G12, q, phi, True) t2 = time.perf_counter() mu_r = ((-1) ** q) * (f_rP_Q / f_rQ_P) print('\n ##[Weil Pairing] Time consuming: t[f(P, Qx)] = {:.3f}, t[f(Qx, P)] = {:.3f}'.format(t1 - t0, t2 - t1)) return mu_r G1, G2_t, G12, G12_t = (Efp, Efp2_t, Efp12, Efp12_t) C1, C2 = (cofactor_E1, cofactor_E2_t) ## make sure they are in G1 and G2_t repectively P, Q = (C1 * G1.random_element(), C2 * G2_t.random_element()) assert(q * P == G1(0)) assert(q * Q == G2_t(0)) ## untwist from E2_t to E12: Q -> Qx Qx = into_E12(Q, beta, Fp, w, beta_t_x, beta_t_y, G12) assert(q * Qx == G12(0)) assert(trace_map(Qx, 12, p, G12) == G12(0)) ####################################### Weil Pairing Testation ## P is defined over E(Fp), Qx is defined over E(Fpk) ## phi maps Fp to Fp12 phi = Hom(Fp, Fp12)(Fp.gen().minpoly().roots(Fp12)[0][0]) assert(P.curve() is not Qx.curve()) mu_r_weil = WeilPairing(P, Qx, G1, G12, q, phi) ## make sure pairing result is in q-torsion subgroup assert(mu_r_weil ** q == Fp12(1)) ####################################### ``` <br /> Output: ```python= ## Time consuming: t[f(P, Qx)] = 0.060, t[f(Qx, P)] = 0.095 ``` <br /> Obviousely time cost of $f_{r, Q}(P)$ is much more than that of $f_{r, P}(Q)$, since $P$ is defined over **Base Prime Field**, $P \in E(F_p)$, while $Q$ is defined over **Full Extension Field**, $Q \in E(F_{p^k})$. - Double-add on $F_{p^k}$ is more expensive than on $F_p$ - Function evaluation is absolutely defined over $F_{p^k}$, so this part would be almost equal <br /> ## Tate Pairing Actually in **Tate Pairing** the vertical line evaluation can be ommited due to the **Final Exponentiation**. Let's prove that! <br /> Recall twist/ untwist operation: $$ \begin{aligned} \varphi: (x', y') \mapsto (x, y) \\ \\ \Longrightarrow \begin{cases} x = x' \cdot w^2 \\ y = y' \cdot w^3 \\ \end{cases} \end{aligned} $$ where $x', y' \in F_{p^2}$, $x, y \in F_{p^{12}}, w \in F_{p^{12}}, w^2 \in F_{p^6}, w^3 \in F_{p^4}$. <br /> According to definition of embedding degree, $k = 12$ is the **minimal value** satisfying $r | p^k - 1$, namely $q \nmid p^2 - 1, q \nmid p^4 - 1, q \nmid p^6 - 1$, so we must have $p^2 - 1 | (p^{12} - 1) / q, p^4 - 1 | (p^{12} - 1) / q, p^6 - 1 | (p^{12} - 1) / q$. <br /> Also since $x'^{p^2 - 1} = 1, (w^2)^{p^6 - 1} = 1, (w^3)^{p^4 - 1} = 1$, assuming $(p^{12} - 1) / q = c_1 \cdot (p^2 - 1) = c_2 \cdot (p^6 - 1)$, then we must have $x^{(p^{12} - 1) / q} = (x'^{p^2 - 1})^{c_1} \cdot ((w^2)^{p^6 - 1})^{c_2} = 1$. <br /> Before untwisting $Q \in \mathbb{G}_2' = E'(F_{p^2})[r]$, after untwisting $Q \in \mathbb{G}_{12} = E(F_{p^{12}})[r]$. The vertical line funcion $x - x_T$, the evaluation would be $x_Q - x_T$, where $x_Q$ is untwisted value and $x_T \in F_p$. Finaly we have $(x_Q - x_T)^{(p^{12} - 1) / q} \equiv 1$. <br /> ### Optimized Evaluation of Double-line Function ```python= ## evaluation of double line divisor function ## arithmetics on fields, not on multiplicative group def double_line(line_point, eval_point, E, phi, reverse = False): ######################## arithemtic on finite field of line_point ## lambda = 3x^2 / 2y (x_L, y_L) = (list(line_point)[0], list(line_point)[1]) (x_E, y_E) = (list(eval_point)[0], list(eval_point)[1]) alpha = (3 * x_L^2) / (2 * y_L) x_2L = alpha * alpha - 2 * x_L y_2L = -y_L - alpha * (x_2L - x_L) ######################## arithmetic on mixed finite field ## x_E, y_E \in F2 ## y_L, x_L, alpha, x_2L \in F1 if reverse: ## evaluation of slop line l_2T e_1 = phi(y_E) - y_L - alpha * (phi(x_E) - x_L) # ## evaluation of vertical line v_2T # e_2 = phi(x_E) - x_2L else: ## evaluation of slop line l_2T e_1 = y_E - phi(y_L) - phi(alpha) * (x_E - phi(x_L)) # ## evaluation of vertical line v_2T # e_2 = x_E - phi(x_2L) return E(x_2L, y_2L), e_1 ``` <br /> ### Optimized Evaluation of Add-line Function ```python= ## evaluation of add line divisor function ## arithmetics on fields, not on multiplicative group def add_line(line_left_point, line_right_point, eval_point, E, phi, reverse = False): ######################## arithemtic on finite field of line_point ## lambda = (y2 - y1) / (x2 - x1) (x_L, y_L) = (list(line_left_point)[0], list(line_left_point)[1]) (x_R, y_R) = (list(line_right_point)[0], list(line_right_point)[1]) (x_E, y_E) = (list(eval_point)[0], list(eval_point)[1]) alpha = (y_L - y_R) / (x_L - x_R) x_LR = alpha * alpha - x_L - x_R y_LR = -y_L - alpha * (x_LR - x_L) ######################## arithmetic on mixed finite field ## x_E, y_E \in F2 ## y_L, x_L, alpha, x_LR \in F1 if reverse: ## evaluation of slop line l_{T + P} e_1 = phi(y_E) - y_L - alpha * (phi(x_E) - x_L) # ## evaluation of vertical line v_{T + P} # e_2 = phi(x_E) - x_LR else: ## evaluation of slop line l_{T + P} e_1 = y_E - phi(y_L) - phi(alpha) * (x_E - phi(x_L)) # ## evaluation of vertical line v_{T + P} # e_2 = x_E - phi(x_LR) return E(x_LR, y_LR), e_1 ``` ### Optimized Miller Loop ```python= ## General Miller Loop Entry def MillerLoop(P, Q, G, q, phi, reverse = False): T = P f1 = 1 f2 = 1 e_bits = [int(i) for i in bin(q)[2:]] print('Miller Loop Length: {}'.format(len(e_bits))) ## last bit cannot be evaluated, since the slope would be a vertical line for i in range(1, len(e_bits)): if (i == len(e_bits) - 1) and (e_bits[i] == 0): f1 = f1 * (list(Q)[0] - list(T)[0]) T = 2 * T break T, e_1 = double_line(T, Q, G, phi, reverse) f1 = f1 * f1 * e_1 if (i == len(e_bits) - 1) and (e_bits[i] == 1): f1 = f1 * (list(Q)[0] - list(T)[0]) T = T + P break if e_bits[i] == 1: T, e_1 = add_line(T, P, Q, G, phi, reverse) f1 = f1 * e_1 assert(T == G(0)) return f1 ``` <br /> ### Easy-part of Final Exponentiation For illustration convenience, we does not use **Frobenius Map** trick here, just directly use time-consuming trivial power. Actually it's almost free cost after using **Frobenius Map**. <br /> ```python= ## trival implementation of easy part, Frobenius not used here actually ## exp = (p^6 - 1) * (p^2 + 1) ## 2 * Frobenius + 2 * Mul + 1 * Inv def easy_part(f): ff = f ## 1 * Frobenius t0 = f ** (p ** 6) ## 1 * Inv t1 = 1 / f ## 1 * Mul f = t0 * t1 ## 1 * Frobenius t0 = f ** (p ** 2) ## 1 * Mul f = t0 * f actual = ff ** (((p ** 6) - 1) * ((p ** 2) + 1)) assert(actual == f) return f ``` <br /> ### Hard-part of Final Exponentiation Same as above, we does not use **Frobenius Map** here. <br /> As we know, the hard part is arithmetics on **Cyclotomic Subgroup**, namely $F_{\varPhi_{12}}^{\times}$. According to [On the Computation of the Optimal Ate Pairing at the 192-bit Security Level](https://eprint.iacr.org/2016/130.pdf), the power of hard part is not $\frac{p^4 - p^2 + 1}{r}$, but **three times of that**: $$ f^{3 \cdot \frac{p^4 - p^2 + 1}{r}} = f^{\lambda_0 + \lambda_1 \cdot p + \lambda_2 \cdot p^2 + \lambda_3 \cdot p^3} $$ where: $$ \begin{aligned} \lambda_3 &= x^2 - 2 x + 1 \\ \lambda_2 &= \lambda_3 \cdot x \\ \lambda_1 &= \lambda_2 \cdot x - \lambda_3 \\ \lambda_0 &= \lambda_1 \cdot x + 3 \\ \end{aligned} $$ In conclusion : $$ e_{T, r}(P, Q) = (f_{r, P}(Q)^{\frac{p^k - 1}{r}})^3 \ne f_{r, P}(Q)^{\frac{p^k - 1}{r}} $$ <br /> ```python= ## reference from Algorithm 1 of "On the Computation of the Optimal Ate Pairing at the 192-bit Security Level" ## trival implementation of hard part, Frobenius not used here actually ## exp = (p^4 - p^2 + 1) / r def hard_part(f, u, p, q): ## 1 * Sqr + 1 * Inv t0 = 1 / (f * f) ## 1 * Pow t5 = f ** u ## 1 * Sqr t1 = t5 * t5 ## 1 * Mul t3 = t0 * t5 ## 1 * Pow t0 = t3 ** u ## 1 * Pow t2 = t0 ** u ## 1 * Pow t4 = t2 ** u ## 1 * Mul t4 = t1 * t4 ## 1 * Pow t1 = t4 ** u ## 1 * Inv t3 = 1 / t3 ## 1 * Mul t1 = t3 * t1 ## 1 * Mul t1 = t1 * f # f^\lambda_0 # 1 * Inv t3 = 1 / f ## 1 * Mul t0 = t0 * f ## 1 * Frobenius t0 = t0 ** (p ** 3) # f^\lambda_3 ## 1 * Mul t4 = t3 * t4 ## 1 * Frobenius t4 = t4 ** p # f^\lambda_1 ## 1 * Mul t5 = t2 * t5 ## 1 * Frobenius t5 = t5 ** (p ** 2) # f^\lambda_2 ## 3 * Mul t5 = t5 * t0 t5 = t5 * t4 t5 = t5 * t1 ## third power of actual pairing result actual = f ** (((p ** 4) - (p ** 2) + 1) // q) assert(t5 == actual ** 3) assert(t5 ** q == 1) return t5 ``` <br /> ### Final Exponentiation ```python= ## Final Exponentiation Entry def FinalExponentiation(f, p, k, q, u, trivial = True): if trivial: mu_r = f ** (((p ** k) - 1) // q) else: t0 = time.perf_counter() f = easy_part(f) t1 = time.perf_counter() mu_r = hard_part(f, u, p, q) t2 = time.perf_counter() print('\n ##[Hard Part of Tate Pairing] Time consuming: t[easy] = {:.3f}, t[hard] = {:.3f}'.format(t1 - t0, t2 - t1)) return mu_r ``` <br /> ### Testation of Tate Pairing ```python= ## Tate Pairing Entry def TatePairing(P, Qx, G1, q, phi, p, k, u, trivial = True): t0 = time.perf_counter() f = MillerLoop(P, Qx, G1, q, phi, False) t1 = time.perf_counter() mu_r = FinalExponentiation(f, p, k, q, u, trivial) t2 = time.perf_counter() print('\n ##[Tate Pairing] Time consuming: t[f(P, Qx)] = {:.3f}, t[exp] = {:.3f}'.format(t1 - t0, t2 - t1)) return mu_r G1, G2_t, G12, G12_t = (Efp, Efp2_t, Efp12, Efp12_t) C1, C2 = (cofactor_E1, cofactor_E2_t) ## make sure they are in G1 and G2_t repectively P, Q = (C1 * G1.random_element(), C2 * G2_t.random_element()) assert(q * P == G1(0)) assert(q * Q == G2_t(0)) ## untwist from E2_t to E12: Q -> Qx Qx = into_E12(Q, beta, Fp, w, beta_t_x, beta_t_y, G12) assert(q * Qx == G12(0)) assert(trace_map(Qx, 12, p, G12) == G12(0)) ####################################### Trivial Tate Pairing Testation mu_r_tate_1 = TatePairing(P, Qx, G1, q, phi, p, k, True) assert(mu_r_tate ** q == Fp12(1)) ####################################### ####################################### parameter for p(x), q(x), and t(x) x = -15132376222941642752 t = x + 1 ## p = ((x - 1)^2 * (x^4 - x^2 + 1)) / 3 + x assert((pow((x - 1), 2) * (pow(x, 4) - pow(x, 2) + 1)) // 3 + x == p) ## q = x^4 - x^2 + 1 assert(pow(x, 4) - pow(x, 2) + 1 == q) ## t = x + 1 assert(abs(p + 1 - t) == Efp.order()) ####################################### Nontrivial Tate Pairing Testation mu_r_tate_2 = TatePairing(P, Qx, G1, q, phi, p, k, x, False) assert(mu_r_tate ** q == Fp12(1)) ## The hard part is 3rd power of pairing assert(mu_r_tate_1 ** 3 == mu_r_tate_2) ``` <br /> The running output: ```python= Miller Loop Length: 255 ##[Tate Pairing] Time consuming: t[f(P, Qx)] = 0.039, t[exp] = 0.079 Miller Loop Length: 255 ##[Hard Part of Tate Pairing] Time consuming: t[easy] = 0.114, t[hard] = 0.082 ##[Tate Pairing] Time consuming: t[f(P, Qx)] = 0.051, t[exp] = 0.195 ``` After applying **Frobenius Map**, the time cost of final exponentiation would greately reduced. <br /> ## Ate Pairing ### Miller Loop In **Ate Pairing**, since $[r] P = \mathcal{O}$, $l_{[r - 1]P, P}$ actually is a vertical line, the last step of **Miller Loop** cannot evaluated directly, so we used a specific manner to deal with it. But in **Ate Pairing**, $[T] P \ne \mathcal{O}$ which is far away from $\mathcal{O}$, no need to worry $l_{[r - 1]P, P}$, so we will strip that specific manner used in **Tate Pairing**. <br /> ```python= ## General Miller Loop Entry def MillerLoop(P, Qx, Qy, G, q, phi, reverse = False): ## if power q is negative or not P = P if q > 0 else -P q = q if q > 0 else -q T = P f1 = 1 e_bits = [int(i) for i in bin(q)[2:]] print('Miller Loop Length: {}'.format(len(e_bits))) for i in range(1, len(e_bits)): ##### strip this specific manner used in Tate Pairing # if (i == len(e_bits) - 1) and (e_bits[i] == 0): # f1 = f1 * (list(Q)[0] - list(T)[0]) # T = 2 * T # break T, e_1 = double_line(T, Qx, Qy, G, phi, reverse) f1 = f1 * f1 * e_1 ##### strip this specific manner used in Tate Pairing # if (i == len(e_bits) - 1) and (e_bits[i] == 1): # f1 = f1 * (list(Q)[0] - list(T)[0]) # T = T + P # break if e_bits[i] == 1: T, e_1 = add_line(T, P, Qx, Qy, G, phi, reverse) f1 = f1 * e_1 return f1 ``` <br /> ### Testation of Ate Pairing Notice that in curve BLS12-381, the parameter $x$ for polynomials $p(x), q(x), t(x)$ is a **negative one**: $$ \begin{aligned} q(x) &= x^4 - x^2 + 1 \\ p(x) &= (x - 1)^2 \cdot q(x) \cdot \frac{1}{3} + x \\ t(x) &= x + 1 \end{aligned} $$ where $x = -15132376222941642752$. <br /> Therefore we must deal with it properly in **Miller Loop** before looping. <br /> ```python= ## Ate Pairing Entry def AtePairing(P, Qx, Qy, G1, q, phi, p, k, u, T): t0 = time.perf_counter() f = MillerLoop(P, Qx, Qy, G1, T, phi, False) t1 = time.perf_counter() mu_r = FinalExponentiation(f, p, k, q, u) t2 = time.perf_counter() print('\n ##[Ate Pairing] Time consuming: t[f(P, Qx)] = {:.3f}, t[exp] = {:.3f}'.format(t1 - t0, t2 - t1)) return mu_r G1, G2_t, G12, G12_t = (Efp, Efp2_t, Efp12, Efp12_t) C1, C2 = (cofactor_E1, cofactor_E2_t) ## make sure they are in G1 and G2_t repectively P, Q = (C1 * G1.random_element(), C2 * G2_t.random_element()) assert(q * P == G1(0)) assert(q * Q == G2_t(0)) ## untwist from E2_t to E12: Q -> Qx # Qx = into_E12(Q, beta, Fp, w, beta_t_x, beta_t_y, G12) # assert(q * Qx == G12(0)) # assert(trace_map(Qx, 12, p, G12) == G12(0)) # Px = into_E2_t(P, Fp, u, beta_t_x, beta_t_y, G2_t) Px_t, Py_t = twist(P.xy()[0], P.xy()[1], beta_t_x, beta_t_y) ## parameter for p(x), q(x), and t(x) x = -15132376222941642752 t = x + 1 ## p = ((x - 1)^2 * (x^4 - x^2 + 1)) / 3 + x assert((pow((x - 1), 2) * (pow(x, 4) - pow(x, 2) + 1)) // 3 + x == p) ## q = x^4 - x^2 + 1 assert(pow(x, 4) - pow(x, 2) + 1 == q) ## t = x + 1 assert(abs(p + 1 - t) == Efp.order()) ## p \equiv T \mod q T = t - 1 ####################################### Ate Pairing Testation phi = Hom(Fp2, Fp12)(Fp2.gen().minpoly().roots(Fp12)[0][0]) mu_r_ate = AtePairing(Q, Px_t, Py_t, G2_t, q, phi, p, k, x, T) assert(mu_r_ate ** q == Fp12(1)) ``` <br /> The running output: ```python= Miller Loop Length: 64 ##[Hard Part of Ate Pairing] Time consuming: t[easy] = 0.106, t[hard] = 0.073 ##[Ate Pairing] Time consuming: t[f(P, Qx)] = 0.025, t[exp] = 0.179 ``` Obviousely time cost of **Miller Loop** is greatly reduced, since $\log{T}$ is far more less than $\log{q}$ (64 vs 255). <br /> --- # Rust Implementation Much testation work need to be done, [code](https://github.com/PayneJoe/crypto_research/tree/main/ecc/src) to be updated... <br /> --- # References [1] [A note on twists for pairing friendly curves](http://indigo.ie/%7Emscott/twists.pdf) [2] [Pairing-Friendly Elliptic Curves of Prime Order](https://eprint.iacr.org/2005/133.pdf) [3] [Pairing for Beginners](https://static1.squarespace.com/static/5fdbb09f31d71c1227082339/t/5ff394720493bd28278889c6/1609798774687/PairingsForBeginners.pdf) [4] [Guide to Pairing-based Cryptography](https://www.math.u-bordeaux.fr/~damienrobert/csi/book/book.pdf) [5] [Faster pairing computations on curves with high-degree twists](https://www.iacr.org/archive/pkc2010/60560227/60560227.pdf) [6] [Optimal Pairings](https://eprint.iacr.org/2008/096.pdf) [7] [On the Computation of the Optimal Ate Pairing at the 192-bit Security Level](https://eprint.iacr.org/2016/130.pdf) [8] [Efficient Final Exponentiation via Cyclotomic Structure for Pairings over Families of Elliptic Curves](https://eprint.iacr.org/2020/875.pdf) [9] [Faster Squaring in the Cyclotomic Subgroup of Sixth Degree Extensions](https://eprint.iacr.org/2009/565.pdf) [10] [A Guide to Plane Algebraic Curves]()