ethereum.crypto.alt_bn128

The alt_bn128 curve ^^^^^^^^^^^^^^^^^^^

  1"""
  2The alt_bn128 curve
  3^^^^^^^^^^^^^^^^^^^
  4"""
  5
  6from . import elliptic_curve, finite_field
  7
  8ALT_BN128_PRIME = 21888242871839275222246405745257275088696311157297823662689037894645226208583  # noqa: E501
  9ALT_BN128_CURVE_ORDER = 21888242871839275222246405745257275088548364400416034343698204186575808495617  # noqa: E501
 10ATE_PAIRING_COUNT = 29793968203157093289
 11ATE_PAIRING_COUNT_BITS = 63
 12
 13
 14class BNF(finite_field.PrimeField):
 15    """
 16    The prime field over which the alt_bn128 curve is defined.
 17    """
 18
 19    PRIME = ALT_BN128_PRIME
 20
 21
 22class BNP(elliptic_curve.EllipticCurve):
 23    """
 24    The alt_bn128 curve.
 25    """
 26
 27    FIELD = BNF
 28    A = BNF(0)
 29    B = BNF(3)
 30
 31
 32class BNF2(finite_field.GaloisField):
 33    """
 34    `BNF` extended with a square root of 1 (`i`).
 35    """
 36
 37    PRIME = ALT_BN128_PRIME
 38    MODULUS = (1, 0)
 39
 40    i: "BNF2"
 41    i_plus_9: "BNF2"
 42
 43
 44BNF2.FROBENIUS_COEFFICIENTS = BNF2.calculate_frobenius_coefficients()
 45"""autoapi_noindex"""
 46
 47BNF2.i = BNF2((0, 1))
 48"""autoapi_noindex"""
 49
 50BNF2.i_plus_9 = BNF2((9, 1))
 51"""autoapi_noindex"""
 52
 53
 54class BNP2(elliptic_curve.EllipticCurve):
 55    """
 56    A twist of `BNP`. This is actually the same curve as `BNP` under a change
 57    of variable, but that change of variable is only possible over the larger
 58    field `BNP12`.
 59    """
 60
 61    FIELD = BNF2
 62    A = BNF2.zero()
 63    B = BNF2.from_int(3) / (BNF2.i + BNF2.from_int(9))
 64
 65
 66class BNF12(finite_field.GaloisField):
 67    """
 68    `BNF2` extended by adding a 6th root of `9 + i` called `w` (omega).
 69    """
 70
 71    PRIME = ALT_BN128_PRIME
 72    MODULUS = (82, 0, 0, 0, 0, 0, -18, 0, 0, 0, 0, 0)
 73
 74    w: "BNF12"
 75    i_plus_9: "BNF12"
 76
 77    def __mul__(self: "BNF12", right: "BNF12") -> "BNF12":  # type: ignore[override] # noqa: E501
 78        """
 79        Multiplication special cased for BNF12.
 80        """
 81        mul = [0] * 23
 82
 83        for i in range(12):
 84            for j in range(12):
 85                mul[i + j] += self[i] * right[j]
 86
 87        for i in range(22, 11, -1):
 88            mul[i - 6] -= mul[i] * (-18)
 89            mul[i - 12] -= mul[i] * 82
 90
 91        return BNF12.__new__(
 92            BNF12,
 93            mul[:12],
 94        )
 95
 96
 97BNF12.FROBENIUS_COEFFICIENTS = BNF12.calculate_frobenius_coefficients()
 98"""autoapi_noindex"""
 99
100BNF12.w = BNF12((0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
101"""autoapi_noindex"""
102
103BNF12.i_plus_9 = BNF12.w**6
104"""autoapi_noindex"""
105
106
107class BNP12(elliptic_curve.EllipticCurve):
108    """
109    The same curve as `BNP`, but defined over the larger field. This curve has
110    both subgroups of order `ALT_BN128_CURVE_ORDER` and allows pairings to be
111    computed.
112    """
113
114    FIELD = BNF12
115    A = BNF12.zero()
116    B = BNF12.from_int(3)
117
118
119def bnf2_to_bnf12(x: BNF2) -> BNF12:
120    """
121    Lift a field element in `BNF2` to `BNF12`.
122    """
123    return BNF12.from_int(x[0]) + BNF12.from_int(x[1]) * (
124        BNF12.i_plus_9 - BNF12.from_int(9)
125    )
126
127
128def bnp_to_bnp12(p: BNP) -> BNP12:
129    """
130    Lift a point from `BNP` to `BNP12`.
131    """
132    return BNP12(BNF12.from_int(int(p.x)), BNF12.from_int(int(p.y)))
133
134
135def twist(p: BNP2) -> BNP12:
136    """
137    Apply to twist to change variables from the curve `BNP2` to `BNP12`.
138    """
139    return BNP12(
140        bnf2_to_bnf12(p.x) * (BNF12.w**2),
141        bnf2_to_bnf12(p.y) * (BNF12.w**3),
142    )
143
144
145def linefunc(p1: BNP12, p2: BNP12, t: BNP12) -> BNF12:
146    """
147    Evaluate the function defining the line between points `p1` and `p2` at the
148    point `t`. The mathematical significance of this function is that is has
149    divisor `(p1) + (p2) + (p1 + p2) - 3(O)`.
150
151    Note: Abstract mathematical presentations of Miller's algorithm often
152    specify the divisor `(p1) + (p2) - (p1 + p2) - (O)`. This turns out not to
153    matter.
154    """
155    if p1.x != p2.x:
156        lam = (p2.y - p1.y) / (p2.x - p1.x)
157        return lam * (t.x - p1.x) - (t.y - p1.y)
158    elif p1.y == p2.y:
159        lam = BNF12.from_int(3) * p1.x**2 / (BNF12.from_int(2) * p1.y)
160        return lam * (t.x - p1.x) - (t.y - p1.y)
161    else:
162        return t.x - p1.x
163
164
165def miller_loop(q: BNP12, p: BNP12) -> BNF12:
166    """
167    The core of the pairing algorithm.
168    """
169    if p == BNP12.point_at_infinity() or q == BNP12.point_at_infinity():
170        return BNF12.from_int(1)
171    r = q
172    f = BNF12.from_int(1)
173    for i in range(ATE_PAIRING_COUNT_BITS, -1, -1):
174        f = f * f * linefunc(r, r, p)
175        r = r.double()
176        if (ATE_PAIRING_COUNT - 1) & (2**i):
177            f = f * linefunc(r, q, p)
178            r = r + q
179    assert r == q.mul_by(ATE_PAIRING_COUNT - 1)
180
181    q1 = BNP12(q.x.frobenius(), q.y.frobenius())
182    nq2 = BNP12(q1.x.frobenius(), -q1.y.frobenius())
183
184    f = f * linefunc(r, q1, p)
185    r = r + q1
186    f = f * linefunc(r, nq2, p)
187
188    return f ** ((ALT_BN128_PRIME**12 - 1) // ALT_BN128_CURVE_ORDER)
189
190
191def pairing(q: BNP2, p: BNP) -> BNF12:
192    """
193    Compute the pairing of `q` and `p`.
194    """
195    return miller_loop(twist(q), bnp_to_bnp12(p))
class BNF(ethereum.crypto.finite_field.PrimeField):
15class BNF(finite_field.PrimeField):
16    """
17    The prime field over which the alt_bn128 curve is defined.
18    """
19
20    PRIME = ALT_BN128_PRIME

The prime field over which the alt_bn128 curve is defined.

Inherited Members
ethereum.crypto.finite_field.PrimeField
from_be_bytes
to_be_bytes32
builtins.int
conjugate
bit_length
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class BNP(typing.Generic[~F]):
23class BNP(elliptic_curve.EllipticCurve):
24    """
25    The alt_bn128 curve.
26    """
27
28    FIELD = BNF
29    A = BNF(0)
30    B = BNF(3)

The alt_bn128 curve.

class BNF2(ethereum.crypto.finite_field.GaloisField):
33class BNF2(finite_field.GaloisField):
34    """
35    `BNF` extended with a square root of 1 (`i`).
36    """
37
38    PRIME = ALT_BN128_PRIME
39    MODULUS = (1, 0)
40
41    i: "BNF2"
42    i_plus_9: "BNF2"

BNF extended with a square root of 1 (i).

class BNP2(typing.Generic[~F]):
55class BNP2(elliptic_curve.EllipticCurve):
56    """
57    A twist of `BNP`. This is actually the same curve as `BNP` under a change
58    of variable, but that change of variable is only possible over the larger
59    field `BNP12`.
60    """
61
62    FIELD = BNF2
63    A = BNF2.zero()
64    B = BNF2.from_int(3) / (BNF2.i + BNF2.from_int(9))

A twist of BNP. This is actually the same curve as BNP under a change of variable, but that change of variable is only possible over the larger field BNP12.

class BNF12(ethereum.crypto.finite_field.GaloisField):
67class BNF12(finite_field.GaloisField):
68    """
69    `BNF2` extended by adding a 6th root of `9 + i` called `w` (omega).
70    """
71
72    PRIME = ALT_BN128_PRIME
73    MODULUS = (82, 0, 0, 0, 0, 0, -18, 0, 0, 0, 0, 0)
74
75    w: "BNF12"
76    i_plus_9: "BNF12"
77
78    def __mul__(self: "BNF12", right: "BNF12") -> "BNF12":  # type: ignore[override] # noqa: E501
79        """
80        Multiplication special cased for BNF12.
81        """
82        mul = [0] * 23
83
84        for i in range(12):
85            for j in range(12):
86                mul[i + j] += self[i] * right[j]
87
88        for i in range(22, 11, -1):
89            mul[i - 6] -= mul[i] * (-18)
90            mul[i - 12] -= mul[i] * 82
91
92        return BNF12.__new__(
93            BNF12,
94            mul[:12],
95        )

BNF2 extended by adding a 6th root of 9 + i called w (omega).

class BNP12(typing.Generic[~F]):
108class BNP12(elliptic_curve.EllipticCurve):
109    """
110    The same curve as `BNP`, but defined over the larger field. This curve has
111    both subgroups of order `ALT_BN128_CURVE_ORDER` and allows pairings to be
112    computed.
113    """
114
115    FIELD = BNF12
116    A = BNF12.zero()
117    B = BNF12.from_int(3)

The same curve as BNP, but defined over the larger field. This curve has both subgroups of order ALT_BN128_CURVE_ORDER and allows pairings to be computed.

def bnf2_to_bnf12(x: BNF2) -> BNF12:
120def bnf2_to_bnf12(x: BNF2) -> BNF12:
121    """
122    Lift a field element in `BNF2` to `BNF12`.
123    """
124    return BNF12.from_int(x[0]) + BNF12.from_int(x[1]) * (
125        BNF12.i_plus_9 - BNF12.from_int(9)
126    )

Lift a field element in BNF2 to BNF12.

def bnp_to_bnp12(p: BNP) -> BNP12:
129def bnp_to_bnp12(p: BNP) -> BNP12:
130    """
131    Lift a point from `BNP` to `BNP12`.
132    """
133    return BNP12(BNF12.from_int(int(p.x)), BNF12.from_int(int(p.y)))

Lift a point from BNP to BNP12.

def twist(p: BNP2) -> BNP12:
136def twist(p: BNP2) -> BNP12:
137    """
138    Apply to twist to change variables from the curve `BNP2` to `BNP12`.
139    """
140    return BNP12(
141        bnf2_to_bnf12(p.x) * (BNF12.w**2),
142        bnf2_to_bnf12(p.y) * (BNF12.w**3),
143    )

Apply to twist to change variables from the curve BNP2 to BNP12.

def linefunc( p1: BNP12, p2: BNP12, t: BNP12) -> BNF12:
146def linefunc(p1: BNP12, p2: BNP12, t: BNP12) -> BNF12:
147    """
148    Evaluate the function defining the line between points `p1` and `p2` at the
149    point `t`. The mathematical significance of this function is that is has
150    divisor `(p1) + (p2) + (p1 + p2) - 3(O)`.
151
152    Note: Abstract mathematical presentations of Miller's algorithm often
153    specify the divisor `(p1) + (p2) - (p1 + p2) - (O)`. This turns out not to
154    matter.
155    """
156    if p1.x != p2.x:
157        lam = (p2.y - p1.y) / (p2.x - p1.x)
158        return lam * (t.x - p1.x) - (t.y - p1.y)
159    elif p1.y == p2.y:
160        lam = BNF12.from_int(3) * p1.x**2 / (BNF12.from_int(2) * p1.y)
161        return lam * (t.x - p1.x) - (t.y - p1.y)
162    else:
163        return t.x - p1.x

Evaluate the function defining the line between points p1 and p2 at the point t. The mathematical significance of this function is that is has divisor (p1) + (p2) + (p1 + p2) - 3(O).

Note: Abstract mathematical presentations of Miller's algorithm often specify the divisor (p1) + (p2) - (p1 + p2) - (O). This turns out not to matter.

def miller_loop( q: BNP12, p: BNP12) -> BNF12:
166def miller_loop(q: BNP12, p: BNP12) -> BNF12:
167    """
168    The core of the pairing algorithm.
169    """
170    if p == BNP12.point_at_infinity() or q == BNP12.point_at_infinity():
171        return BNF12.from_int(1)
172    r = q
173    f = BNF12.from_int(1)
174    for i in range(ATE_PAIRING_COUNT_BITS, -1, -1):
175        f = f * f * linefunc(r, r, p)
176        r = r.double()
177        if (ATE_PAIRING_COUNT - 1) & (2**i):
178            f = f * linefunc(r, q, p)
179            r = r + q
180    assert r == q.mul_by(ATE_PAIRING_COUNT - 1)
181
182    q1 = BNP12(q.x.frobenius(), q.y.frobenius())
183    nq2 = BNP12(q1.x.frobenius(), -q1.y.frobenius())
184
185    f = f * linefunc(r, q1, p)
186    r = r + q1
187    f = f * linefunc(r, nq2, p)
188
189    return f ** ((ALT_BN128_PRIME**12 - 1) // ALT_BN128_CURVE_ORDER)

The core of the pairing algorithm.

def pairing( q: BNP2, p: BNP) -> BNF12:
192def pairing(q: BNP2, p: BNP) -> BNF12:
193    """
194    Compute the pairing of `q` and `p`.
195    """
196    return miller_loop(twist(q), bnp_to_bnp12(p))

Compute the pairing of q and p.