ethereum.forks.constantinople.vm.precompiled_contracts.alt_bn128ethereum.forks.istanbul.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]:
| 40 | """ |
|---|---|
| 41 | Decode 64 bytes to a point on the curve. |
| 42 | |
| 43 | Parameters |
| 44 | ---------- |
| 45 | data : |
| 46 | The bytes data to decode. |
| 47 | |
| 48 | Returns |
| 49 | ------- |
| 50 | point : Point3D |
| 51 | A point on the curve. |
| 52 | |
| 53 | Raises |
| 54 | ------ |
| 55 | InvalidParameter |
| 56 | Either a field element is invalid or the point is not on the curve. |
| 57 | |
| 58 | """ |
| 59 | if len(data) != 64: |
| 60 | raise InvalidParameter("Input should be 64 bytes long") |
| 61 | |
| 62 | x_bytes = buffer_read(data, U256(0), U256(32)) |
| 63 | x = int(U256.from_be_bytes(x_bytes)) |
| 64 | y_bytes = buffer_read(data, U256(32), U256(32)) |
| 65 | y = int(U256.from_be_bytes(y_bytes)) |
| 66 | |
| 67 | if x >= field_modulus: |
| 68 | raise InvalidParameter("Invalid field element") |
| 69 | if y >= field_modulus: |
| 70 | raise InvalidParameter("Invalid field element") |
| 71 | |
| 72 | z = 1 |
| 73 | if x == 0 and y == 0: |
| 74 | z = 0 |
| 75 | |
| 76 | point = (FQ(x), FQ(y), FQ(z)) |
| 77 | |
| 78 | # Check if the point is on the curve |
| 79 | if not is_on_curve(point, b): |
| 80 | raise InvalidParameter("Point is not on curve") |
| 81 | |
| 82 | 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]:
| 86 | """ |
|---|---|
| 87 | Decode 128 bytes to a G2 point. |
| 88 | |
| 89 | Parameters |
| 90 | ---------- |
| 91 | data : |
| 92 | The bytes data to decode. |
| 93 | |
| 94 | Returns |
| 95 | ------- |
| 96 | point : Point2D |
| 97 | A point on the curve. |
| 98 | |
| 99 | Raises |
| 100 | ------ |
| 101 | InvalidParameter |
| 102 | Either a field element is invalid or the point is not on the curve. |
| 103 | |
| 104 | """ |
| 105 | if len(data) != 128: |
| 106 | raise InvalidParameter("G2 should be 128 bytes long") |
| 107 | |
| 108 | x0_bytes = buffer_read(data, U256(0), U256(32)) |
| 109 | x0 = int(U256.from_be_bytes(x0_bytes)) |
| 110 | x1_bytes = buffer_read(data, U256(32), U256(32)) |
| 111 | x1 = int(U256.from_be_bytes(x1_bytes)) |
| 112 | |
| 113 | y0_bytes = buffer_read(data, U256(64), U256(32)) |
| 114 | y0 = int(U256.from_be_bytes(y0_bytes)) |
| 115 | y1_bytes = buffer_read(data, U256(96), U256(32)) |
| 116 | y1 = int(U256.from_be_bytes(y1_bytes)) |
| 117 | |
| 118 | if x0 >= field_modulus or x1 >= field_modulus: |
| 119 | raise InvalidParameter("Invalid field element") |
| 120 | if y0 >= field_modulus or y1 >= field_modulus: |
| 121 | raise InvalidParameter("Invalid field element") |
| 122 | |
| 123 | x = FQ2((x1, x0)) |
| 124 | y = FQ2((y1, y0)) |
| 125 | |
| 126 | z = (1, 0) |
| 127 | if x == FQ2((0, 0)) and y == FQ2((0, 0)): |
| 128 | z = (0, 0) |
| 129 | |
| 130 | point = (x, y, FQ2(z)) |
| 131 | |
| 132 | # Check if the point is on the curve |
| 133 | if not is_on_curve(point, b2): |
| 134 | raise InvalidParameter("Point is not on curve") |
| 135 | |
| 136 | return point |
alt_bn128_add
The ALT_BN128 addition precompiled contract.
Parameters
evm : The current EVM frame.
def alt_bn128_add(evm: Evm) -> None:
| 140 | """ |
|---|---|
| 141 | The ALT_BN128 addition precompiled contract. |
| 142 | |
| 143 | Parameters |
| 144 | ---------- |
| 145 | evm : |
| 146 | The current EVM frame. |
| 147 | |
| 148 | """ |
| 149 | data = evm.message.data |
| 150 | |
| 151 | # GAS |
| 152 | charge_gas(evm, Uint(500)) |
| 152 | charge_gas(evm, Uint(150)) |
| 153 | |
| 154 | # OPERATION |
| 155 | try: |
| 156 | p0 = bytes_to_g1(buffer_read(data, U256(0), U256(64))) |
| 157 | p1 = bytes_to_g1(buffer_read(data, U256(64), U256(64))) |
| 158 | except InvalidParameter as e: |
| 159 | raise OutOfGasError from e |
| 160 | |
| 161 | p = add(p0, p1) |
| 162 | x, y = normalize(p) |
| 163 | |
| 164 | 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:
| 168 | """ |
|---|---|
| 169 | The ALT_BN128 multiplication precompiled contract. |
| 170 | |
| 171 | Parameters |
| 172 | ---------- |
| 173 | evm : |
| 174 | The current EVM frame. |
| 175 | |
| 176 | """ |
| 177 | data = evm.message.data |
| 178 | |
| 179 | # GAS |
| 180 | charge_gas(evm, Uint(40000)) |
| 180 | charge_gas(evm, Uint(6000)) |
| 181 | |
| 182 | # OPERATION |
| 183 | try: |
| 184 | p0 = bytes_to_g1(buffer_read(data, U256(0), U256(64))) |
| 185 | except InvalidParameter as e: |
| 186 | raise OutOfGasError from e |
| 187 | n = int(U256.from_be_bytes(buffer_read(data, U256(64), U256(32)))) |
| 188 | |
| 189 | p = multiply(p0, n) |
| 190 | x, y = normalize(p) |
| 191 | |
| 192 | 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:
| 196 | """ |
|---|---|
| 197 | The ALT_BN128 pairing check precompiled contract. |
| 198 | |
| 199 | Parameters |
| 200 | ---------- |
| 201 | evm : |
| 202 | The current EVM frame. |
| 203 | |
| 204 | """ |
| 205 | data = evm.message.data |
| 206 | |
| 207 | # GAS |
| 208 | charge_gas(evm, Uint(80000 * (len(data) // 192) + 100000)) |
| 208 | charge_gas(evm, Uint(34000 * (len(data) // 192) + 45000)) |
| 209 | |
| 210 | # OPERATION |
| 211 | if len(data) % 192 != 0: |
| 212 | raise OutOfGasError |
| 213 | result = FQ12.one() |
| 214 | for i in range(len(data) // 192): |
| 215 | try: |
| 216 | p = bytes_to_g1(buffer_read(data, U256(192 * i), U256(64))) |
| 217 | q = bytes_to_g2(buffer_read(data, U256(192 * i + 64), U256(128))) |
| 218 | except InvalidParameter as e: |
| 219 | raise OutOfGasError from e |
| 220 | if not is_inf(multiply(p, curve_order)): |
| 221 | raise OutOfGasError |
| 222 | if not is_inf(multiply(q, curve_order)): |
| 223 | raise OutOfGasError |
| 224 | |
| 225 | result *= pairing(q, p) |
| 226 | |
| 227 | if result == FQ12.one(): |
| 228 | evm.output = U256(1).to_be_bytes32() |
| 229 | else: |
| 230 | evm.output = U256(0).to_be_bytes32() |