ethereum.forks.amsterdam.vm.precompiled_contracts.alt_bn128

Ethereum Virtual Machine (EVM) ALT_BN128 CONTRACTS.

.. contents:: Table of Contents :backlinks: none :local:

Introduction

Implementation of the ALT_BN128 precompiled contracts.

bytes_to_g1

Decode 64 bytes to a point on the curve.

Parameters

data : The bytes data to decode.

Returns

point : Point3D A point on the curve.

Raises

InvalidParameter Either a field element is invalid or the point is not on the curve.

def bytes_to_g1(data: Bytes) -> Point3D[FQ]:
41
    <snip>
60
    if len(data) != 64:
61
        raise InvalidParameter("Input should be 64 bytes long")
62
63
    x_bytes = buffer_read(data, U256(0), U256(32))
64
    x = int(U256.from_be_bytes(x_bytes))
65
    y_bytes = buffer_read(data, U256(32), U256(32))
66
    y = int(U256.from_be_bytes(y_bytes))
67
68
    if x >= field_modulus:
69
        raise InvalidParameter("Invalid field element")
70
    if y >= field_modulus:
71
        raise InvalidParameter("Invalid field element")
72
73
    z = 1
74
    if x == 0 and y == 0:
75
        z = 0
76
77
    point = (FQ(x), FQ(y), FQ(z))
78
79
    # Check if the point is on the curve
80
    if not is_on_curve(point, b):
81
        raise InvalidParameter("Point is not on curve")
82
83
    return point

bytes_to_g2

Decode 128 bytes to a G2 point.

Parameters

data : The bytes data to decode.

Returns

point : Point2D A point on the curve.

Raises

InvalidParameter Either a field element is invalid or the point is not on the curve.

def bytes_to_g2(data: Bytes) -> Point3D[FQ2]:
87
    <snip>
106
    if len(data) != 128:
107
        raise InvalidParameter("G2 should be 128 bytes long")
108
109
    x0_bytes = buffer_read(data, U256(0), U256(32))
110
    x0 = int(U256.from_be_bytes(x0_bytes))
111
    x1_bytes = buffer_read(data, U256(32), U256(32))
112
    x1 = int(U256.from_be_bytes(x1_bytes))
113
114
    y0_bytes = buffer_read(data, U256(64), U256(32))
115
    y0 = int(U256.from_be_bytes(y0_bytes))
116
    y1_bytes = buffer_read(data, U256(96), U256(32))
117
    y1 = int(U256.from_be_bytes(y1_bytes))
118
119
    if x0 >= field_modulus or x1 >= field_modulus:
120
        raise InvalidParameter("Invalid field element")
121
    if y0 >= field_modulus or y1 >= field_modulus:
122
        raise InvalidParameter("Invalid field element")
123
124
    x = FQ2((x1, x0))
125
    y = FQ2((y1, y0))
126
127
    z = (1, 0)
128
    if x == FQ2((0, 0)) and y == FQ2((0, 0)):
129
        z = (0, 0)
130
131
    point = (x, y, FQ2(z))
132
133
    # Check if the point is on the curve
134
    if not is_on_curve(point, b2):
135
        raise InvalidParameter("Point is not on curve")
136
137
    return point

alt_bn128_add

The ALT_BN128 addition precompiled contract.

Parameters

evm : The current EVM frame.

def alt_bn128_add(evm: Evm) -> None:
141
    <snip>
150
    data = evm.call_data
151
152
    # GAS
153
    charge_gas(evm, GasCosts.PRECOMPILE_ECADD)
154
155
    # OPERATION
156
    try:
157
        p0 = bytes_to_g1(buffer_read(data, U256(0), U256(64)))
158
        p1 = bytes_to_g1(buffer_read(data, U256(64), U256(64)))
159
    except InvalidParameter as e:
160
        raise OutOfGasError from e
161
162
    p = add(p0, p1)
163
    x, y = normalize(p)
164
165
    evm.output = Uint(x).to_be_bytes32() + Uint(y).to_be_bytes32()

alt_bn128_mul

The ALT_BN128 multiplication precompiled contract.

Parameters

evm : The current EVM frame.

def alt_bn128_mul(evm: Evm) -> None:
169
    <snip>
178
    data = evm.call_data
179
180
    # GAS
181
    charge_gas(evm, GasCosts.PRECOMPILE_ECMUL)
182
183
    # OPERATION
184
    try:
185
        p0 = bytes_to_g1(buffer_read(data, U256(0), U256(64)))
186
    except InvalidParameter as e:
187
        raise OutOfGasError from e
188
    n = int(U256.from_be_bytes(buffer_read(data, U256(64), U256(32))))
189
190
    p = multiply(p0, n)
191
    x, y = normalize(p)
192
193
    evm.output = Uint(x).to_be_bytes32() + Uint(y).to_be_bytes32()

alt_bn128_pairing_check

The ALT_BN128 pairing check precompiled contract.

Parameters

evm : The current EVM frame.

def alt_bn128_pairing_check(evm: Evm) -> None:
197
    <snip>
206
    data = evm.call_data
207
208
    # GAS
209
    charge_gas(
210
        evm,
211
        ExecutionGas(
212
            GasCosts.PRECOMPILE_ECPAIRING_PER_POINT * (ulen(data) // Uint(192))
213
            + GasCosts.PRECOMPILE_ECPAIRING_BASE
214
        ),
215
    )
216
217
    # OPERATION
218
    if len(data) % 192 != 0:
219
        raise OutOfGasError
220
    result = FQ12.one()
221
    for i in range(len(data) // 192):
222
        try:
223
            p = bytes_to_g1(buffer_read(data, U256(192 * i), U256(64)))
224
            q = bytes_to_g2(buffer_read(data, U256(192 * i + 64), U256(128)))
225
        except InvalidParameter as e:
226
            raise OutOfGasError from e
227
        if not is_inf(multiply(p, curve_order)):
228
            raise OutOfGasError
229
        if not is_inf(multiply(q, curve_order)):
230
            raise OutOfGasError
231
232
        result *= pairing(q, p)
233
234
    if result == FQ12.one():
235
        evm.output = U256(1).to_be_bytes32()
236
    else:
237
        evm.output = U256(0).to_be_bytes32()