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() |