PayneJoe
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

Your note will be visible on your profile and discoverable by anyone.
Your note is now live.
This note is visible on your profile and discoverable online.
Everyone on the web can find and read all notes of this public team.
See published notes
Unpublish note
Please check the box to agree to the Community Guidelines.
View profile
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
1
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
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]()

Import from clipboard

Paste your markdown or webpage here...

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template has been removed or transferred.
Upgrade
All
  • All
  • Team
No template.

Create a template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

Slide Example

API Docs

Edit in VSCode

Install browser extension

Contacts

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

Note content is identical to the latest version.
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully