|
| 1 | +// evmone: Fast Ethereum Virtual Machine implementation |
| 2 | +// Copyright 2024 The evmone Authors. |
| 3 | +// SPDX-License-Identifier: Apache-2.0 |
| 4 | +#pragma once |
| 5 | + |
| 6 | +#include "../../bn254.hpp" |
| 7 | +#include "../../ecc.hpp" |
| 8 | +#include "../field_template.hpp" |
| 9 | + |
| 10 | +namespace evmmax::bn254 |
| 11 | +{ |
| 12 | +using namespace intx; |
| 13 | + |
| 14 | +/// Specifies base field value type and modular arithmetic for bn254 curve. |
| 15 | +struct BaseFieldConfig |
| 16 | +{ |
| 17 | + using ValueT = uint256; |
| 18 | + static constexpr auto MOD_ARITH = ModArith{FieldPrime}; |
| 19 | + static constexpr uint256 ONE = MOD_ARITH.to_mont(1); |
| 20 | +}; |
| 21 | +using Fq = ecc::BaseFieldElem<BaseFieldConfig>; |
| 22 | + |
| 23 | +// Extension fields implemented based on https://hackmd.io/@jpw/bn254#Field-extension-towers |
| 24 | + |
| 25 | +/// Specifies Fq^2 extension field for bn254 curve. Base field extended with irreducible `u^2 + 1` |
| 26 | +/// polynomial over the base field. `u` is the Fq^2 element. |
| 27 | +struct Fq2Config |
| 28 | +{ |
| 29 | + using BaseFieldT = Fq; |
| 30 | + using ValueT = Fq; |
| 31 | + static constexpr auto DEGREE = 2; |
| 32 | +}; |
| 33 | +using Fq2 = ecc::ExtFieldElem<Fq2Config>; |
| 34 | + |
| 35 | +/// Specifies Fq^6 extension field for bn254 curve. Fq^2 field extended with irreducible |
| 36 | +/// `v^3 - (9 + u)` polynomial over the Fq^2 field. `v` is the Fq^6 field element. |
| 37 | +struct Fq6Config |
| 38 | +{ |
| 39 | + using BaseFieldT = Fq; |
| 40 | + using ValueT = Fq2; |
| 41 | + static constexpr uint8_t DEGREE = 3; |
| 42 | + static constexpr auto ksi = Fq2({Fq::from_int(9_u256), Fq::from_int(1_u256)}); |
| 43 | + static constexpr auto _3_ksi_inv = Fq2({ |
| 44 | + Fq::from_int(0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5_u256), |
| 45 | + Fq::from_int(0x9713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2_u256), |
| 46 | + }); |
| 47 | +}; |
| 48 | +using Fq6 = ecc::ExtFieldElem<Fq6Config>; |
| 49 | + |
| 50 | +/// Specifies Fq^12 extension field for bn254 curve. Fq^6 field extended with irreducible |
| 51 | +/// `w^2 - v` polynomial over the Fq^2 field. `v` is the Fq^6 field element. |
| 52 | +/// `w` is Fq^12 field element. |
| 53 | +struct Fq12Config |
| 54 | +{ |
| 55 | + using BaseFieldT = Fq; |
| 56 | + using ValueT = Fq6; |
| 57 | + |
| 58 | + static constexpr uint8_t DEGREE = 2; |
| 59 | +}; |
| 60 | +using Fq12 = ecc::ExtFieldElem<Fq12Config>; |
| 61 | + |
| 62 | +/// Multiplies two Fq^2 field elements |
| 63 | +constexpr Fq2 multiply(const Fq2& a, const Fq2& b) |
| 64 | +{ |
| 65 | + return Fq2({ |
| 66 | + a.coeffs[0] * b.coeffs[0] - a.coeffs[1] * b.coeffs[1], |
| 67 | + a.coeffs[1] * b.coeffs[0] + a.coeffs[0] * b.coeffs[1], |
| 68 | + }); |
| 69 | +} |
| 70 | + |
| 71 | +/// Multiplies two Fq^6 field elements |
| 72 | +constexpr Fq6 multiply(const Fq6& a, const Fq6& b) |
| 73 | +{ |
| 74 | + const auto& a0 = a.coeffs[0]; |
| 75 | + const auto& a1 = a.coeffs[1]; |
| 76 | + const auto& a2 = a.coeffs[2]; |
| 77 | + const auto& b0 = b.coeffs[0]; |
| 78 | + const auto& b1 = b.coeffs[1]; |
| 79 | + const auto& b2 = b.coeffs[2]; |
| 80 | + |
| 81 | + const Fq2& ksi = Fq6Config::ksi; |
| 82 | + |
| 83 | + const auto t0 = a0 * b0; |
| 84 | + const auto t1 = a1 * b1; |
| 85 | + const auto t2 = a2 * b2; |
| 86 | + |
| 87 | + const auto c0 = ((a1 + a2) * (b1 + b2) - t1 - t2) * ksi + t0; |
| 88 | + const auto c1 = (a0 + a1) * (b0 + b1) - t0 - t1 + ksi * t2; |
| 89 | + const auto c2 = (a0 + a2) * (b0 + b2) - t0 - t2 + t1; |
| 90 | + |
| 91 | + return Fq6({c0, c1, c2}); |
| 92 | +} |
| 93 | + |
| 94 | +/// Multiplies two Fq^12 field elements |
| 95 | +constexpr Fq12 multiply(const Fq12& a, const Fq12& b) |
| 96 | +{ |
| 97 | + const auto& a0 = a.coeffs[0]; |
| 98 | + const auto& a1 = a.coeffs[1]; |
| 99 | + const auto& b0 = b.coeffs[0]; |
| 100 | + const auto& b1 = b.coeffs[1]; |
| 101 | + |
| 102 | + const auto t0 = a0 * b0; |
| 103 | + const auto t1 = a1 * b1; |
| 104 | + |
| 105 | + const Fq2& ksi = Fq6Config::ksi; |
| 106 | + |
| 107 | + const auto c0 = t0 + Fq6({ksi * t1.coeffs[2], t1.coeffs[0], t1.coeffs[1]}); // gamma is sparse. |
| 108 | + const auto c1 = (a0 + a1) * (b0 + b1) - t0 - t1; |
| 109 | + |
| 110 | + return Fq12({c0, c1}); |
| 111 | +} |
| 112 | + |
| 113 | +/// Inverses the base field element |
| 114 | +inline Fq inverse(const Fq& x) |
| 115 | +{ |
| 116 | + return Fq(field_inv(BaseFieldConfig::MOD_ARITH, x.value())); |
| 117 | +} |
| 118 | + |
| 119 | +/// Inverses the Fq^2 field element |
| 120 | +inline Fq2 inverse(const Fq2& f) |
| 121 | +{ |
| 122 | + const auto& a0 = f.coeffs[0]; |
| 123 | + const auto& a1 = f.coeffs[1]; |
| 124 | + auto t0 = a0 * a0; |
| 125 | + auto t1 = a1 * a1; |
| 126 | + |
| 127 | + t0 = t0 + t1; |
| 128 | + t1 = t0.inv(); |
| 129 | + |
| 130 | + const auto c0 = a0 * t1; |
| 131 | + const auto c1 = -(a1 * t1); |
| 132 | + |
| 133 | + return Fq2({c0, c1}); |
| 134 | +} |
| 135 | + |
| 136 | +/// Inverses the Fq^6 field element |
| 137 | +inline Fq6 inverse(const Fq6& f) |
| 138 | +{ |
| 139 | + const auto& a0 = f.coeffs[0]; |
| 140 | + const auto& a1 = f.coeffs[1]; |
| 141 | + const auto& a2 = f.coeffs[2]; |
| 142 | + |
| 143 | + const Fq2& ksi = Fq6Config::ksi; |
| 144 | + |
| 145 | + const auto t0 = a0 * a0; |
| 146 | + const auto t1 = a1 * a1; |
| 147 | + const auto t2 = a2 * a2; |
| 148 | + |
| 149 | + const auto t3 = a0 * a1; |
| 150 | + const auto t4 = a0 * a2; |
| 151 | + const auto t5 = a2 * a1; |
| 152 | + |
| 153 | + const auto c0 = t0 - ksi * t5; |
| 154 | + const auto c1 = ksi * t2 - t3; |
| 155 | + const auto c2 = t1 - t4; |
| 156 | + |
| 157 | + const auto t = a0 * c0 + (a2 * c1 + a1 * c2) * ksi; |
| 158 | + const auto t6 = t.inv(); |
| 159 | + |
| 160 | + return Fq6({c0 * t6, c1 * t6, c2 * t6}); |
| 161 | +} |
| 162 | + |
| 163 | +/// Inverses the Fq^12 field element |
| 164 | +inline Fq12 inverse(const Fq12& f) |
| 165 | +{ |
| 166 | + const auto& a0 = f.coeffs[0]; |
| 167 | + const auto& a1 = f.coeffs[1]; |
| 168 | + |
| 169 | + auto t0 = a0 * a0; |
| 170 | + auto t1 = a1 * a1; |
| 171 | + |
| 172 | + const Fq2& ksi = Fq6Config::ksi; |
| 173 | + |
| 174 | + t0 = t0 - Fq6({ksi * t1.coeffs[2], t1.coeffs[0], t1.coeffs[1]}); // gamma is sparse. |
| 175 | + t1 = t0.inv(); |
| 176 | + |
| 177 | + const auto c0 = a0 * t1; |
| 178 | + const auto c1 = -(a1 * t1); |
| 179 | + |
| 180 | + return Fq12({c0, c1}); |
| 181 | +} |
| 182 | +} // namespace evmmax::bn254 |
0 commit comments