diff --git a/precompiles/Playground.yul b/precompiles/Playground.yul index 33fde021..6e74e561 100644 --- a/precompiles/Playground.yul +++ b/precompiles/Playground.yul @@ -5,19 +5,19 @@ object "Playground" { // CONSTANTS function ZERO() -> zero { - zero := 0x0 + zero := 0x00 } function ONE() -> one { - one := 0x1 + one := 0x01 } function TWO() -> two { - two := 0x2 + two := 0x02 } function THREE() -> three { - three := 0x3 + three := 0x03 } function MONTGOMERY_ONE() -> m_one { @@ -32,6 +32,15 @@ object "Playground" { m_three := 19052624634359457937016868847204597229365286637454337178037183604060995791063 } + function MONTGOMERY_TWO_INV() -> two_inv { + two_inv := 14119558874979547267292681013829403749242370018224634694350716214666112402802 + } + + function MONTGOMERY_TWISTED_CURVE_COEFFS() -> z0, z1 { + z0 := 16772280239760917788496391897731603718812008455956943122563801666366297604776 + z1 := 568440292453150825972223760836185707764922522371208948902804025364325400423 + } + // Group order of alt_bn128, see https://eips.ethereum.org/EIPS/eip-196 function P() -> ret { ret := 21888242871839275222246405745257275088696311157297823662689037894645226208583 @@ -49,12 +58,49 @@ object "Playground" { ret := 111032442853175714102588374283752698368366046808579839647964533820976443843465 } + function NAF_REPRESENTATIVE() -> ret { + ret := 7186291078002685655833716264194454051281486193901198152801 + } + + function FP6_ZERO() -> z00, z01, z10, z11, z20, z21 { + z00 := 0 + z01 := 0 + z10 := 0 + z11 := 0 + z20 := 0 + z21 := 0 + } + + function G2_INFINITY() -> z00, z01, z02, z10, z11, z12 { + z00 := 0 + z01 := 0 + z02 := 0 + z10 := 0 + z11 := 0 + z12 := 0 + } + + function FP12_ONE() -> z000, z001, z010, z011, z100, z101, z110, z111, z200, z201, z210, z211 { + z000 := MONTGOMERY_ONE() + z001 := 0 + z010 := 0 + z011 := 0 + z100 := 0 + z101 := 0 + z110 := 0 + z111 := 0 + z200 := 0 + z201 := 0 + z210 := 0 + z211 := 0 + } + // CONSOLE.LOG Caller // It prints 'val' in the node console and it works using the 'mem'+0x40 memory sector - function console_log(mem, val) -> { + function console_log(val) -> { let log_address := 0x000000000000000000636F6e736F6c652e6c6f67 // load the free memory pointer - let freeMemPointer := mload(mem) + let freeMemPointer := mload(0x600) // store the function selector of log(uint256) in memory mstore(freeMemPointer, 0xf82c50f1) // store the first argument of log(uint256) in the next memory slot @@ -182,6 +228,14 @@ object "Playground" { ret := REDC(lowest_half_of_m, higher_half_of_m) } + function montgomeryAdd(augend, addend) -> ret { + ret := addmod(augend, addend, P()) + } + + function montgomerySub(minuend, subtrahend) -> ret { + ret := montgomeryAdd(minuend, sub(P(), subtrahend)) + } + // Multipling field elements in Montgomery form -> REDC((a * R mod N)(b * R mod N)) function montgomeryMul(multiplicand, multiplier) -> ret { let higher_half_of_product := getHighestHalfOfMultiplication(multiplicand, multiplier) @@ -260,18 +314,934 @@ object "Playground" { ret := and(left, right) } - // FALLBACK + function affinePointIsInfinity(x, y) -> ret { + ret := and(iszero(x), iszero(y)) + } + + function projectivePointIsInfinity(z) -> ret { + ret := iszero(z) + } + + function projectiveFromAffine(xp, yp) -> xr, yr, zr { + switch affinePointIsInfinity(xp, yp) + case 0 { + xr := xp + yr := yp + zr := MONTGOMERY_ONE() + } + case 1 { + xr := ZERO() + yr := ZERO() + zr := ZERO() + } + } + + function projectiveIntoAffine(xp, yp, zp) -> xr, yr { + switch zp + case 0 { + xr := ZERO() + yr := ZERO() + } + // MONTGOMERY_ONE(), but compiler expects a literal. + case 6350874878119819312338956282401532409788428879151445726012394534686998597021 { + xr := montgomeryDiv(xp, zp) + yr := montgomeryDiv(yp, zp) + } + } + + function projectiveDouble(xp, yp, zp) -> xr, yr, zr { + let x_squared := montgomeryMul(xp, xp) + let t := montgomeryAdd(x_squared, montgomeryAdd(x_squared, x_squared)) + let yz := montgomeryMul(yp, zp) + let u := montgomeryAdd(yz, yz) + let uxy := montgomeryMul(u, montgomeryMul(xp, yp)) + let v := montgomeryAdd(uxy, uxy) + let w := montgomerySub(montgomeryMul(t, t), montgomeryAdd(v, v)) + + xr := montgomeryMul(u, w) + let uy := montgomeryMul(u, yp) + let uy_squared := montgomeryMul(uy, uy) + yr := montgomerySub(montgomeryMul(t, montgomerySub(v, w)), montgomeryAdd(uy_squared, uy_squared)) + zr := montgomeryMul(u, montgomeryMul(u, u)) + } + + function projectiveAdd(xp, yp, zp, xq, yq, zq) -> xr, yr, zr { + let pIsInfinity := projectivePointIsInfinity(zp) + let qIsInfinity := projectivePointIsInfinity(zq) + if and(pIsInfinity, zq) { + xr := xq + yr := yq + zr := zq + } + if and(zp, qIsInfinity) { + xr := xp + yr := yp + zr := zp + } + switch and(eq(xp, xq), eq(yp, yq)) + case 0 { + let t0 := yp + let t1 := yq + let t := montgomerySub(t0, t1) + let u0 := montgomeryMul(xp, zq) + let u1 := xq + let u := montgomerySub(u0, u1) + let u2 := montgomeryMul(u, u) + let u3 := montgomeryMul(u2, u) + let w := montgomerySub(montgomeryMul(t, t), montgomeryMul(u2, montgomeryAdd(u0, u1))) + + xr := montgomeryMul(u, w) + yr := montgomerySub(montgomeryMul(t, montgomerySub(montgomeryMul(u0, u2), w)), montgomeryMul(t0, u3)) + zr := u3 + } + case 1 { + switch and(pIsInfinity, qIsInfinity) + case 0 { + xr, yr, zr := projectiveDouble(xp, yp, zp) + } + case 1 { + xr := ZERO() + yr := ZERO() + zr := ZERO() + } + } + } + + function projectiveMul(xp, yp, zp, scalar) -> xr, yr, zr { + xr := ZERO() + yr := ZERO() + zr := ZERO() + let xq := xp + let yq := yp + let zq := zp + let s := scalar + + switch scalar + case 0 {} + case 1 { + xr := xp + yr := yp + zr := zp + } + case 2 { + xr, yr, zr := projectiveDouble(xp, yp, zp) + } + default { + for {} gt(s, ZERO()) {} { + if and(s, ONE()) { + xr, yr, zr := projectiveAdd(xr, yr, zr, xq, yq, zq) + } + xq, yq, zq := projectiveDouble(xq, yq, zq) + s := shr(1, s) + } + } + } + + // FP2 ARITHMETICS + + function fp2Add(a00, a01, b00, b01) -> c00, c01 { + c00 := montgomeryAdd(a00, b00) + c01 := montgomeryAdd(a01, b01) + } + + function fp2Sub(a00, a01, b00, b01) -> c00, c01 { + c00 := montgomerySub(a00, b00) + c01 := montgomerySub(a01, b01) + } + + function fp2ScalarMul(a00, a01, scalar) -> c00, c01 { + c00 := montgomeryMul(a00, scalar) + c01 := montgomeryMul(a01, scalar) + } + + function fp2Mul(a00, a01, b00, b01) -> c00, c01 { + c00 := montgomerySub(montgomeryMul(a00, b00), montgomeryMul(a01, b01)) + c01 := montgomeryAdd(montgomeryMul(a00, b01), montgomeryMul(a01, b00)) + } + + function fp2Neg(a00, a01) -> c00, c01 { + c00, c01 := fp2Sub(ZERO(), ZERO(), a00, a01) + } + + function fp2Inv(a00, a01) -> c00, c01 { + let t0 := montgomeryMul(a00, a00) + let t1 := montgomeryMul(a01, a01) + t0 := montgomeryAdd(t0, t1) + t1 := montgomeryModularInverse(t0) + + c00 := montgomeryMul(a00, t1) + c01 := montgomerySub(ZERO(), montgomeryMul(a01, t1)) + } + + function mulByXi(a00, a01) -> c00, c01 { + let t0, t1 := fp2ScalarMul(a00, a01, intoMontgomeryForm(8)) + c00 := montgomerySub(montgomeryAdd(t0, a00), a01) + c01 := montgomeryAdd(montgomeryAdd(t1, a00), a01) + } + + function fp2Conjugate(a00, a01) -> c00, c01 { + c00 := a00 + c01 := montgomerySub(ZERO(), a01) + } + + // FP6 ARITHMETICS + + function fp6Add(a00, a01, a10, a11, a20, a21, b00, b01, b10, b11, b20, b21) -> c00, c01, c10, c11, c20, c21 { + c00, c01 := fp2Add(a00, a01, b00, b01) + c10, c11 := fp2Add(a10, a11, b10, b11) + c20, c21 := fp2Add(a20, a21, b20, b21) + } + + function fp6Sub(a00, a01, a10, a11, a20, a21, b00, b01, b10, b11, b20, b21) -> c00, c01, c10, c11, c20, c21 { + c00, c01 := fp2Sub(a00, a01, b00, b01) + c10, c11 := fp2Sub(a10, a11, b10, b11) + c20, c21 := fp2Sub(a20, a21, b20, b21) + } + + function mulByGamma(a00, a01, a10, a11, a20, a21) -> c00, c01, c10, c11, c20, c21 { + c00, c01 := mulByXi(a20, a21) + c10 := a00 + c11 := a01 + c20 := a10 + c21 := a11 + } + + function fp6Mul(a00, a01, a10, a11, a20, a21, b00, b01, b10, b11, b20, b21) -> c00, c01, c10, c11, c20, c21 { + let t00, t01 := fp2Mul(a00, a01, b00, b01) + let t10, t11 := fp2Mul(a10, a11, b10, b11) + let t20, t21 := fp2Mul(a20, a21, b20, b21) + + let tmp0, temp1 := fp2Add(a10, a11, a20, a21) + let tmp2, tmp3 := fp2Add(b10, b11, b20, b21) + let tmp4, tmp5 := fp2Mul(tmp0, temp1, tmp2, tmp3) + let tmp6, tmp7 := fp2Sub(tmp4, tmp5, t10, t11) + let tmp8, tmp9 := fp2Sub(tmp6, tmp7, t20, t21) + let tmp10, tmp11 := mulByXi(tmp8, tmp9) + c00, c01 := fp2Add(tmp10, tmp11, t00, t01) + + tmp0, temp1 := fp2Add(a00, a01, a10, a11) + tmp2, tmp3 := fp2Add(b00, b01, b10, b11) + tmp4, tmp5 := fp2Mul(tmp0, temp1, tmp2, tmp3) + tmp6, tmp7 := fp2Sub(tmp4, tmp5, t00, t01) + tmp8, tmp9 := fp2Sub(tmp6, tmp7, t10, t11) + tmp10, tmp11 := mulByXi(t20, t21) + c10, c11 := fp2Add(tmp8, tmp9, tmp10, tmp11) + + tmp0, temp1 := fp2Add(a00, a01, a20, a21) + tmp2, tmp3 := fp2Add(b00, b01, b20, b21) + tmp4, tmp5 := fp2Mul(tmp0, temp1, tmp2, tmp3) + tmp6, tmp7 := fp2Sub(tmp4, tmp5, t00, t01) + tmp8, tmp9 := fp2Sub(tmp6, tmp7, t20, t21) + c20, c21 := fp2Add(tmp8, tmp9, t10, t11) + } + + function fp6Neg(a00, a01, a10, a11, a20, a21) -> c00, c01, c10, c11, c20, c21 { + c00, c01 := fp2Neg(a00, a01) + c10, c11 := fp2Neg(a10, a11) + c20, c21 := fp2Neg(a20, a21) + } + + function fp6MulByIndependentTerm(a00, a01, a10, a11, a20, a21, b00, b01) -> c00, c01, c10, c11, c20, c21 { + c00, c01 := fp2Mul(a00, a01, b00, b01) + c10, c11 := fp2Mul(a01, a10, b00, b01) + c20, c21 := fp2Mul(a10, a11, b00, b01) + } + + function fp6MulByIndependentAndLinearTerm(a00, a01, a10, a11, a20, a21, b00, b01, b10, b11) -> c00, c01, c10, c11, c20, c21 { + let t00, t01 := fp2Mul(a00, a01, b00, b01) + let t10, t11 := fp2Mul(a10, a11, b10, b11) + + let tmp00, tmp01 := fp2Add(a10, a11, a20, a21) + tmp00, tmp01 := fp2Mul(tmp00, tmp01, b10, b11) + tmp00, tmp01 := fp2Sub(tmp00, tmp01, t10, t11) + tmp00, tmp01 := mulByXi(tmp00, tmp01) + c00, c01 := fp2Add(t00, t01, tmp00, tmp01) + + tmp00, tmp01 := fp2Add(a00, a01, a10, a11) + let tmp10, tmp11 := fp2Add(b00, b01, b10, b11) + tmp00, tmp01 := fp2Mul(tmp00, tmp01, tmp10, tmp11) + tmp00, tmp01 := fp2Sub(tmp00, tmp01, t00, t01) + c10, c11 := fp2Sub(tmp00, tmp01, t10, t11) + + tmp00, tmp01 := fp2Mul(a20, a21, b00, b01) + c20, c21 := fp2Add(tmp00, tmp01, t10, t11) + } + + function fp6Square(a00, a01, a10, a11, a20, a21) -> c00, c01, c10, c11, c20, c21 { + let tmp0, tmp1 := fp2Mul(a00, a01, a10, a11) + tmp0, tmp1 := fp2Add(tmp0, tmp1, tmp0, tmp1) + + let tmp2, tmp3 := fp2Mul(a20, a21, a20, a21) + let tmp4, tmp5 := mulByXi(tmp2, tmp3) + c10, c11 := fp2Add(tmp4, tmp5, tmp0, tmp1) + + c20, c21 := fp2Sub(tmp0, tmp1, tmp2, tmp3) + + let tmp6, tmp7 := fp2Mul(a00, a01, a00, a01) + let tmp8, tmp9 := fp2Sub(a00, a01, a10, a11) + tmp0, tmp1 := fp2Add(tmp8, tmp9, a20, a21) + + let tmp10, tmp11 := fp2Mul(a10, a11, a20, a21) + tmp2, tmp3 := fp2Add(tmp10, tmp11, tmp10, tmp11) + tmp0, tmp1 := fp2Mul(tmp0, tmp1, tmp0, tmp1) + + let tmp12, tmp13 := mulByXi(tmp2, tmp3) + c00, c01 := fp2Add(tmp12, tmp13, tmp6, tmp7) + + let tmp14, tmp15 := fp2Add(c20, c21, tmp0, tmp1) + tmp14, tmp15 := fp2Add(tmp14, tmp15, tmp2, tmp3) + c20, c21 := fp2Sub(tmp14, tmp15, tmp6, tmp7) + + } + + function fp6Inv(a00, a01, a10, a11, a20, a21) -> c00, c01, c10, c11, c20, c21 { + let t00, t01 := fp2Mul(a00, a01, a00, a01) + let t10, t11 := fp2Mul(a10, a11, a10, a11) + let t20, t21 := fp2Mul(a20, a21, a20, a21) + let t30, t31 := fp2Mul(a00, a01, a10, a11) + let t40, t41 := fp2Mul(a00, a01, a20, a21) + let t50, t51 := fp2Mul(a20, a21, a10, a11) + let t50Xi, t51Xi := mulByXi(t50, t51) + c00, c01 := fp2Sub(t00, t01, t50Xi, t51Xi) + let t20Xi, t21Xi := mulByXi(t20, t21) + c10, c11 := fp2Sub(t20Xi, t21Xi, t30, t31) + c20, c21 := fp2Sub(t10, t11, t40, t41) + let t60, t61 := fp2Mul(a00, a01, c00, c01) + let a20Xi, a21Xi := mulByXi(a20, a21) + let a20XiC10, a21XiC11 := fp2Mul(a20Xi, a21Xi, c10, c11) + t60, t61 := fp2Add(t60, t61, a20XiC10, a21XiC11) + let a10Xi, a11Xi := mulByXi(a10, a11) + let a10XiC20, a11XiC21 := fp2Mul(a10Xi, a11Xi, c20, c21) + t60, t61 := fp2Add(t60, t61, a10XiC20, a11XiC21) + t60, t61 := fp2Inv(t60, t61) + c00, c01 := fp2Mul(c00, c01, t60, t61) + c10, c11 := fp2Mul(c10, c11, t60, t61) + c20, c21 := fp2Mul(c20, c21, t60, t61) + } + + // FP12 ARITHMETICS + + function fp12Add(a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121, b000, b001, b010, b011, b020, b021, b100, b101, b110, b111, b120, b121) -> c000, c001, c010, c011, c020, c021, c100, c101, c110, c111, c120, c121 { + c000, c001, c010, c011, c020, c021 := fp6Add(a000, a001, a010, a011, a020, a021, b000, b001, b010, b011, b020, b021) + c100, c101, c110, c111, c120, c121 := fp6Add(a100, a101, a110, a111, a120, a121, b100, b101, b110, b111, b120, b121) + } + + function fp12Sub(a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121, b000, b001, b010, b011, b020, b021, b100, b101, b110, b111, b120, b121) -> c000, c001, c010, c011, c020, c021, c100, c101, c110, c111, c120, c121 { + c000, c001, c010, c011, c020, c021 := fp6Sub(a000, a001, a010, a011, a020, a021, b000, b001, b010, b011, b020, b021) + c100, c101, c110, c111, c120, c121 := fp6Sub(a100, a101, a110, a111, a120, a121, b100, b101, b110, b111, b120, b121) + } + + function fp12Mul(a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121, b000, b001, b010, b011, b020, b021, b100, b101, b110, b111, b120, b121) -> c000, c001, c010, c011, c020, c021, c100, c101, c110, c111, c120, c121 { + let t000, t001, t010, t011, t020, t021 := fp6Mul(a000, a001, a010, a011, a020, a021, b000, b001, b010, b011, b020, b021) + let t100, t101, t110, t111, t120, t121 := fp6Mul(a100, a101, a110, a111, a120, a121, b100, b101, b110, b111, b120, b121) + let t200, t201, t210, t211, t220, t221 := mulByGamma(t100, t101, t110, t111, t120, t121) + c000, c001, c010, c011, c020, c021 := fp6Add(t000, t001, t010, t011, t020, t021, t200, t201, t210, t211, t220, t221) + let t300, t301, t310, t311, t320, t321 := fp6Add(a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121) + let t400, t401, t410, t411, t420, t421 := fp6Add(b000, b001, b010, b011, b020, b021, b100, b101, b110, b111, b120, b121) + c100, c101, c110, c111, c120, c121 := fp6Mul(t300, t301, t310, t311, t320, t321, t400, t401, t410, t411, t420, t421) + c100, c101, c110, c111, c120, c121 := fp6Sub(c100, c101, c110, c111, c120, c121, t000, t001, t010, t011, t020, t021) + c100, c101, c110, c111, c120, c121 := fp6Sub(c100, c101, c110, c111, c120, c121, t100, t101, t110, t111, t120, t121) + } + + function fp12Square(a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121) -> c000, c001, c010, c011, c020, c021, c100, c101, c110, c111, c120, c121 { + let t100, t101, t110, t111, t120, t121 := fp6Sub(a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121) + let t200, t201, t210, t211, t220, t221 := mulByGamma(a100, a101, a110, a111, a120, a121) + let t300, t301, t310, t311, t320, t321 := fp6Sub(a000, a001, a010, a011, a020, a021, t200, t201, t210, t211, t220, t221) + let t400, t401, t410, t411, t420, t421 := fp6Mul(a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121) + let t500, t501, t510, t511, t520, t521 := fp6Mul(t100, t101, t110, t111, t120, t121, t300, t301, t310, t311, t320, t321) + let t600, t601, t610, t611, t620, t621 := fp6Add(t400, t401, t410, t411, t420, t421, t500, t501, t510, t511, t520, t521) + c100, c101, c110, c111, c120, c121 := fp6Add(t400, t401, t410, t411, t420, t421, t400, t401, t410, t411, t420, t421) + let t700, t701, t710, t711, t720, t721 := mulByGamma(t400, t401, t410, t411, t420, t421) + c000, c001, c010, c011, c020, c021 := fp6Add(t600, t601, t610, t611, t620, t621, t700, t701, t710, t711, t720, t721) + } + + function fp12Inv(a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121) -> c000, c001, c010, c011, c020, c021, c100, c101, c110, c111, c120, c121 { + let t000, t001, t010, t011, t020, t021 := fp6Square(a000, a001, a010, a011, a020, a021) + let t100, t101, t110, t111, t120, t121 := fp6Square(a100, a101, a110, a111, a120, a121) + let t200, t201, t210, t211, t220, t221 := mulByGamma(t100, t101, t110, t111, t120, t121) + t000, t001, t010, t011, t020, t021 := fp6Sub(t000, t001, t010, t011, t020, t021, t200, t201, t210, t211, t220, t221) + t100, t101, t110, t111, t120, t121 := fp6Inv(t000, t001, t010, t011, t020, t021) + c000, c001, c010, c011, c020, c021 := fp6Mul(a000, a001, a010, a011, a020, a021, t100, t101, t110, t111, t120, t121) + let z00, z01, z10, z11, z20, z21 := FP6_ZERO() + c100, c101, c110, c111, c120, c121 := fp6Mul(a100, a101, a110, a111, a120, a121,t100, t101, t110, t111, t120, t121) + c100, c101, c110, c111, c120, c121 := fp6Sub(z00, z01, z10, z11, z20, z21, c100, c101, c110, c111, c120, c121) + } + + function fp12Expt(a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121) -> c000, c001, c010, c011, c020, c021, c100, c101, c110, c111, c120, c121 { + let t000, t001, t010, t011, t020, t021, t100, t101, t110, t111, t120, t121 := fp12CyclotomicSquare(a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121) + let t200, t201, t210, t211, t220, t221, t300, t301, t310, t311, t320, t321 := fp12CyclotomicSquare(t000, t001, t010, t011, t020, t021, t100, t101, t110, t111, t120, t121) + c000, c001, c010, c011, c020, c021, c100, c101, c110, c111, c120, c121 := fp12CyclotomicSquare(t200, t201, t210, t211, t220, t221, t300, t301, t310, t311, t320, t321) + let t400, t401, t410, t411, t420, t421, t500, t501, t510, t511, t520, t521 := fp12CyclotomicSquare(c000, c001, c010, c011, c020, c021, c100, c101, c110, c111, c120, c121) + + let t600, t601, t610, t611, t620, t621, t700, t701, t710, t711, t720, t721 := fp12Mul(a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121, t400, t401, t410, t411, t420, t421, t500, t501, t510, t511, t520, t521) + t400, t401, t410, t411, t420, t421, t500, t501, t510, t511, t520, t521 := fp12Mul(t600, t601, t610, t611, t620, t621, t700, t701, t710, t711, t720, t721, t000, t001, t010, t011, t020, t021, t100, t101, t110, t111, t120, t121) + let t800, t801, t810, t811, t820, t821, t900, t901, t910, t911, t920, t921 := fp12Mul(a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121, t400, t401, t410, t411, t420, t421, t500, t501, t510, t511, t520, t521) + let t1000, t1001, t1010, t1011, t1020, t1021, t1100, t1101, t1110, t1111, t1120, t1121 := fp12Mul(c000, c001, c010, c011, c020, c021, c100, c101, c110, c111, c120, c121, t600, t601, t610, t611, t620, t621, t700, t701, t710, t711, t720, t721) + let t1200, t1201, t1210, t1211, t1220, t1221, t1300, t1301, t1310, t1311, t1320, t1321 := fp12CyclotomicSquare(t600, t601, t610, t611, t620, t621, t700, t701, t710, t711, t720, t721) + t800, t801, t810, t811, t820, t821, t900, t901, t910, t911, t920, t921 := fp12Mul(t800, t801, t810, t811, t820, t821, t900, t901, t910, t911, t920, t921, t400, t401, t410, t411, t420, t421, t500, t501, t510, t511, t520, t521) + t400, t401, t410, t411, t420, t421, t500, t501, t510, t511, t520, t521 := fp12Mul(t800, t801, t810, t811, t820, t821, t900, t901, t910, t911, t920, t921, t000, t001, t010, t011, t020, t021, t100, t101, t110, t111, t120, t121) + t1200, t1201, t1210, t1211, t1220, t1221, t1300, t1301, t1310, t1311, t1320, t1321 := nSquare(t1200, t1201, t1210, t1211, t1220, t1221, t1300, t1301, t1310, t1311, t1320, t1321, 6) + t200, t201, t210, t211, t220, t221, t300, t301, t310, t311, t320, t321 := fp12Mul(t1200, t1201, t1210, t1211, t1220, t1221, t1300, t1301, t1310, t1311, t1320, t1321, t200, t201, t210, t211, t220, t221, t300, t301, t310, t311, t320, t321) + t200, t201, t210, t211, t220, t221, t300, t301, t310, t311, t320, t321 := fp12Mul(t200, t201, t210, t211, t220, t221, t300, t301, t310, t311, t320, t321, t1000, t1001, t1010, t1011, t1020, t1021, t1100, t1101, t1110, t1111, t1120, t1121) + t200, t201, t210, t211, t220, t221, t300, t301, t310, t311, t320, t321 := nSquare(t200, t201, t210, t211, t220, t221, t300, t301, t310, t311, t320, t321, 7) + t1000, t1001, t1010, t1011, t1020, t1021, t1100, t1101, t1110, t1111, t1120, t1121 := fp12Mul(t200, t201, t210, t211, t220, t221, t300, t301, t310, t311, t320, t321, t1000, t1001, t1010, t1011, t1020, t1021, t1100, t1101, t1110, t1111, t1120, t1121) + t1000, t1001, t1010, t1011, t1020, t1021, t1100, t1101, t1110, t1111, t1120, t1121 := nSquare(t1000, t1001, t1010, t1011, t1020, t1021, t1100, t1101, t1110, t1111, t1120, t1121, 8) + t1000, t1001, t1010, t1011, t1020, t1021, t1100, t1101, t1110, t1111, t1120, t1121 := fp12Mul(t1000, t1001, t1010, t1011, t1020, t1021, t1100, t1101, t1110, t1111, t1120, t1121, t400, t401, t410, t411, t420, t421, t500, t501, t510, t511, t520, t521) + t000, t001, t010, t011, t020, t021, t100, t101, t110, t111, t120, t121 := fp12Mul(t1000, t1001, t1010, t1011, t1020, t1021, t1100, t1101, t1110, t1111, t1120, t1121, t000, t001, t010, t011, t020, t021, t100, t101, t110, t111, t120, t121) + t000, t001, t010, t011, t020, t021, t100, t101, t110, t111, t120, t121 := nSquare(t000, t001, t010, t011, t020, t021, t100, t101, t110, t111, t120, t121, 6) + t600, t601, t610, t611, t620, t621, t700, t701, t710, t711, t720, t721 := fp12Mul(t000, t001, t010, t011, t020, t021, t100, t101, t110, t111, t120, t121, t600, t601, t610, t611, t620, t621, t700, t701, t710, t711, t720, t721) + t600, t601, t610, t611, t620, t621, t700, t701, t710, t711, t720, t721 := nSquare(t600, t601, t610, t611, t620, t621, t700, t701, t710, t711, t720, t721, 8) + t600, t601, t610, t611, t620, t621, t700, t701, t710, t711, t720, t721 := fp12Mul(t600, t601, t610, t611, t620, t621, t700, t701, t710, t711, t720, t721, t400, t401, t410, t411, t420, t421, t500, t501, t510, t511, t520, t521) + t600, t601, t610, t611, t620, t621, t700, t701, t710, t711, t720, t721 := nSquare(t600, t601, t610, t611, t620, t621, t700, t701, t710, t711, t720, t721, 6) + t600, t601, t610, t611, t620, t621, t700, t701, t710, t711, t720, t721 := fp12Mul(t600, t601, t610, t611, t620, t621, t700, t701, t710, t711, t720, t721, t400, t401, t410, t411, t420, t421, t500, t501, t510, t511, t520, t521) + t600, t601, t610, t611, t620, t621, t700, t701, t710, t711, t720, t721 := nSquare(t600, t601, t610, t611, t620, t621, t700, t701, t710, t711, t720, t721, 10) + t800, t801, t810, t811, t820, t821, t900, t901, t910, t911, t920, t921 := fp12Mul(t600, t601, t610, t611, t620, t621, t700, t701, t710, t711, t720, t721, t800, t801, t810, t811, t820, t821, t900, t901, t910, t911, t920, t921) + t800, t801, t810, t811, t820, t821, t900, t901, t910, t911, t920, t921 := nSquare(t800, t801, t810, t811, t820, t821, t900, t901, t910, t911, t920, t921, 6) + t400, t401, t410, t411, t420, t421, t500, t501, t510, t511, t520, t521 := fp12Mul(t400, t401, t410, t411, t420, t421, t500, t501, t510, t511, t520, t521, t800, t801, t810, t811, t820, t821, t900, t901, t910, t911, t920, t921) + c000, c001, c010, c011, c020, c021, c100, c101, c110, c111, c120, c121 := fp12Mul(t400, t401, t410, t411, t420, t421, t500, t501, t510, t511, t520, t521, c000, c001, c010, c011, c020, c021, c100, c101, c110, c111, c120, c121) + } + + function fp12Conjugate(a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121) -> c000, c001, c010, c011, c020, c021, c100, c101, c110, c111, c120, c121 { + c000 := a000 + c001 := a001 + c010 := a010 + c011 := a011 + c020 := a020 + c021 := a021 + c100, c101, c110, c111, c120, c121 := fp6Neg(a100, a101, a110, a111, a120, a121) + } + + function fp12CyclotomicSquare(a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121) -> c000, c001, c010, c011, c020, c021, c100, c101, c110, c111, c120, c121 { + let t00, t01 := fp2Mul(a110, a111, a110, a111) + let t10, t11 := fp2Mul(a000, a001, a000, a001) + let t20, t21 := fp2Add(a110, a111, a000, a001) + t20, t21 := fp2Mul(t20, t21, t20, t21) + t20, t21 := fp2Sub(t20, t21, t00, t01) + t20, t21 := fp2Sub(t20, t21, t10, t11) + let t30, t31 := fp2Mul(a020, a021, a020, a021) + let t40, t41 := fp2Mul(a100, a101, a100, a101) + let t50, t51 := fp2Add(a020, a021, a100, a101) + t50, t51 := fp2Mul(t50, t51, t50, t51) + t50, t51 := fp2Sub(t50, t51, t30, t31) + t50, t51 := fp2Sub(t50, t51, t40, t41) + let t60, t61 := fp2Mul(a120, a121, a120, a121) + let t70, t71 := fp2Mul(a010, a011, a010, a011) + let t80, t81 := fp2Add(a120, a121, a010, a011) + t80, t81 := fp2Mul(t80, t81, t80, t81) + t80, t81 := fp2Sub(t80, t81, t60, t61) + t80, t81 := fp2Sub(t80, t81, t70, t71) + t80, t81 := mulByXi(t80, t81) + t00, t01 := mulByXi(t00, t01) + t00, t01 := fp2Add(t00, t01, t10, t11) + t30, t31 := mulByXi(t30, t31) + t30, t31 := fp2Add(t30, t31, t40, t41) + t60, t61 := mulByXi(t60, t61) + t60, t61 := fp2Add(t60, t61, t70, t71) + + c000, c001 := fp2Sub(t00, t01, a000, a001) + c000, c001 := fp2Add(c000, c001, c000, c001) + c000, c001 := fp2Add(c000, c001, t00, t01) + + c010, c011 := fp2Sub(t30, t31, a010, a011) + c010, c011 := fp2Add(c010, c011, c010, c011) + c010, c011 := fp2Add(c010, c011, t30, t31) + + c020, c021 := fp2Sub(t60, t61, a020, a021) + c020, c021 := fp2Add(c020, c021, c020, c021) + c020, c021 := fp2Add(c020, c021, t60, t61) + + c100, c101 := fp2Add(t80, t81, a100, a101) + c100, c101 := fp2Add(c100, c101, c100, c101) + c100, c101 := fp2Add(c100, c101, t80, t81) + + c110, c111 := fp2Add(t20, t21, a110, a111) + c110, c111 := fp2Add(c110, c111, c110, c111) + c110, c111 := fp2Add(c110, c111, t20, t21) + + c120, c121 := fp2Add(t50, t51, a120, a121) + c120, c121 := fp2Add(c120, c121, c120, c121) + c120, c121 := fp2Add(c120, c121, t50, t51) + } + + function nSquare(a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121, n) -> c000, c001, c010, c011, c020, c021, c100, c101, c110, c111, c120, c121 { + c000 := a000 + c001 := a001 + c010 := a010 + c011 := a011 + c020 := a020 + c021 := a021 + c100 := a100 + c101 := a101 + c110 := a110 + c111 := a111 + c120 := a120 + c121 := a121 + for { let i := 0 } lt(i, n) { i := add(i, ONE()) } { + c000, c001, c010, c011, c020, c021, c100, c101, c110, c111, c120, c121 := fp12CyclotomicSquare(c000, c001, c010, c011, c020, c021, c100, c101, c110, c111, c120, c121) + } + } + + // FROBENIUS + + function frobenius(a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121) -> c00, c01, c10, c11, c20, c21, c30, c31, c40, c41, c50, c51 { + let t10, t11 := fp2Conjugate(a000, a001) + let t20, t21 := fp2Conjugate(a100, a101) + let t30, t31 := fp2Conjugate(a010, a011) + let t40, t41 := fp2Conjugate(a110, a111) + let t50, t51 := fp2Conjugate(a020, a021) + let t60, t61 := fp2Conjugate(a120, a121) + + t20, t21 := mulByGamma11(t20, t21) + t30, t31 := mulByGamma12(t30, t31) + t40, t41 := mulByGamma13(t40, t41) + t50, t51 := mulByGamma14(t50, t51) + t60, t61 := mulByGamma15(t60, t61) + + c00 := t10 + c01 := t11 + c10 := t30 + c11 := t31 + c20 := t50 + c21 := t51 + c30 := t20 + c31 := t21 + c40 := t40 + c41 := t41 + c50 := t60 + c51 := t61 + } + + function frobeniusSquare(a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121) -> c00, c01, c10, c11, c20, c21, c30, c31, c40, c41, c50, c51 { + let t10 := a000 + let t11 := a001 + let t20, t21 := mulByGamma21(a100, a101) + let t30, t31 := mulByGamma22(a010, a011) + let t40, t41 := mulByGamma23(a110, a111) + let t50, t51 := mulByGamma24(a020, a021) + let t60, t61 := mulByGamma25(a120, a121) + + c00 := t10 + c01 := t11 + c10 := t30 + c11 := t31 + c20 := t50 + c21 := t51 + c30 := t20 + c31 := t21 + c40 := t40 + c41 := t41 + c50 := t60 + c51 := t61 + } + + function frobeniusCube(a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121) -> c00, c01, c10, c11, c20, c21, c30, c31, c40, c41, c50, c51 { + let t10, t11 := fp2Conjugate(a000, a001) + let t20, t21 := fp2Conjugate(a100, a101) + let t30, t31 := fp2Conjugate(a010, a011) + let t40, t41 := fp2Conjugate(a110, a111) + let t50, t51 := fp2Conjugate(a020, a021) + let t60, t61 := fp2Conjugate(a120, a121) + + t20, t21 := mulByGamma31(t20, t21) + t30, t31 := mulByGamma32(t30, t31) + t40, t41 := mulByGamma33(t40, t41) + t50, t51 := mulByGamma34(t50, t51) + t60, t61 := mulByGamma35(t60, t61) + + c00 := t10 + c01 := t11 + c10 := t30 + c11 := t31 + c20 := t50 + c21 := t51 + c30 := t20 + c31 := t21 + c40 := t40 + c41 := t41 + c50 := t60 + c51 := t61 + } + + // GAMMA_1_i + + function mulByGamma11(a00, a01) -> c00, c01 { + let g00 := 1334504125441109323775816677333762124980877086439557453392802825656291576071 + let g01 := 7532670101108748540749979597679923402841328813027773483599019704565791010162 + c00, c01 := fp2Mul(a00, a01, g00, g01) + } + + function mulByGamma12(a00, a01) -> c00, c01 { + let g00 := 11461073415658098971834280704587444395456423268720245247603935854280982113072 + let g01 := 17373957475705492831721812124331982823197004514106338927670775596783233550167 + c00, c01 := fp2Mul(a00, a01, g00, g01) + } + + function mulByGamma13(a00, a01) -> c00, c01 { + let g00 := 16829996427371746075450799880956928810557034522864196246648550205375670302249 + let g01 := 20140510615310063345578764457068708762835443761990824243702724480509675468743 + c00, c01 := fp2Mul(a00, a01, g00, g01) + } + + function mulByGamma14(a00, a01) -> c00, c01 { + let g00 := 9893659366031634526915473325149983243417508801286144596494093251884139331218 + let g01 := 16514792769865828027011044701859348114858257981779976519405133026725453154633 + c00, c01 := fp2Mul(a00, a01, g00, g01) + } + + function mulByGamma15(a00, a01) -> c00, c01 { + let g00 := 8443299194457421137480282511969901974227997168695360756777672575877693116391 + let g01 := 21318636632361225103955470331868462398471880609949088574192481281746934874025 + c00, c01 := fp2Mul(a00, a01, g00, g01) + } + + // GAMMA_2_i + + function mulByGamma21(a00, a01) -> c00, c01 { + let g0 := 1881798392815877688876180778159931906057091683336018750908411925848733129714 + c00, c01 := fp2ScalarMul(a00, a01, g0) + } + + function mulByGamma22(a00, a01) -> c00, c01 { + let g0 := 17419166386535333598783630241015674584964973961482396687585055285806960741276 + c00, c01 := fp2ScalarMul(a00, a01, g0) + } + + function mulByGamma23(a00, a01) -> c00, c01 { + let g0 := 15537367993719455909907449462855742678907882278146377936676643359958227611562 + c00, c01 := fp2ScalarMul(a00, a01, g0) + } + + function mulByGamma24(a00, a01) -> c00, c01 { + let g0 := 20006444479023397533370224967097343182639219473961804911780625968796493078869 + c00, c01 := fp2ScalarMul(a00, a01, g0) + } + + function mulByGamma25(a00, a01) -> c00, c01 { + let g0 := 4469076485303941623462775504241600503731337195815426975103982608838265467307 + c00, c01 := fp2ScalarMul(a00, a01, g0) + } + + // GAMMA_3_i + + function mulByGamma31(a00, a01) -> c00, c01 { + let g00 := 3649295186494431467217240962842301358951278585756714214031945394966344685949 + let g01 := 17372117152826387298350653207345606612066102743297871578090761045572893546809 + c00, c01 := fp2Mul(a00, a01, g00, g01) + } - let g1_x := calldataload(0) - let g1_y := calldataload(32) - let g2_ix := calldataload(64) - let g2_x := calldataload(96) - let g2_iy := calldataload(128) - let g2_y := calldataload(160) + function mulByGamma32(a00, a01) -> c00, c01 { + let g00 := 14543349330631744552586812320441124107441202078168618766450326117520897829805 + let g01 := 4646831431411403714092965637071058625728899792817054432901795759277546050476 + c00, c01 := fp2Mul(a00, a01, g00, g01) + } + + function mulByGamma33(a00, a01) -> c00, c01 { + let g00 := 5058246444467529146795605864300346278139276634433627416040487689269555906334 + let g01 := 1747732256529211876667641288188566325860867395306999418986313414135550739840 + c00, c01 := fp2Mul(a00, a01, g00, g01) + } + + function mulByGamma34(a00, a01) -> c00, c01 { + let g00 := 3025265262868802913511075437173590487338001780554453930995247874855578067679 + let g01 := 10425289180741305073643362413949631488281652900778689227251281048515799234257 + c00, c01 := fp2Mul(a00, a01, g00, g01) + } + + function mulByGamma35(a00, a01) -> c00, c01 { + let g00 := 9862576063628467829192720579684130652367741026604221989510773554027227469215 + let g01 := 16681752610922605480353377694363181135019829138759259603037557916788351015335 + c00, c01 := fp2Mul(a00, a01, g00, g01) + } - if iszero(pointIsOnG1(g1_x, g1_y)) { - // burnGas() + // PAIRING FUNCTIONS + function doubleStep(xq0, xq1, yq0, yq1, zq0, zq1) -> l00, l01, l10, l11, l20, l21, l30, l31, l40, l41, l50, l51, xt0, xt1, yt0, yt1, zt0, zt1 { + let zero := ZERO() + let twoInv := MONTGOMERY_TWO_INV() + let t00, t01 := fp2Mul(xq0, xq1, yq0, yq1) + let t10, t11 := fp2ScalarMul(t00, t01, twoInv) + let t20, t21 := fp2Mul(yq0, yq1, yq0, yq1) + let t30, t31 := fp2Mul(zq0, zq1, zq0, zq1) + let t40, t41 := fp2Add(t30, t31, t30, t31) + t40, t41 := fp2Add(t40, t41, t30, t31) + let t50, t51 := MONTGOMERY_TWISTED_CURVE_COEFFS() + t50, t51 := fp2Mul(t40, t41, t50, t51) + let t60, t61 :=fp2Add(t50, t51, t50, t51) + t60, t61 := fp2Add(t60, t61, t50, t51) + let t70, t71 := fp2Add(t20, t21, t60, t61) + t70, t71 := fp2ScalarMul(t70, t71, twoInv) + let t80, t81 := fp2Add(yq0, yq1, zq0, zq1) + t80, t81 := fp2Mul(t80, t81, t80, t81) + let t90, t91 := fp2Add(t30, t31, t20, t21) + t80, t81 := fp2Sub(t80, t81, t90, t91) + let t100, t101 := fp2Sub(t50, t51, t20, t21) + let t110, t111 := fp2Mul(xq0, xq1, xq0, xq1) + let t120, t121 := fp2Mul(t50, t51, t50, t51) + let t130, t131 := fp2Add(t120, t121, t120, t121) + t130, t131 := fp2Add(t130, t131, t120, t121) + + // l0 + l00, l01 := fp2Neg(t80, t81) + l10 := zero + l11 := zero + l20 := zero + l21 := zero + + // l1 + l30, l31 := fp2Add(t110, t111, t110, t111) + l30, l31 := fp2Add(l30, l31, t110, t111) + + // l2 + l40 := t100 + l41 := t101 + + l50 := zero + l51 := zero + + // Tx + xt0, xt1 := fp2Sub(t20, t21, t60, t61) + xt0, xt1 := fp2Mul(xt0, xt1, t10, t11) + + // Ty + yt0, yt1 := fp2Mul(t70, t71, t70, t71) + yt0, yt1 := fp2Sub(yt0, yt1, t130, t131) + + // Tz + zt0, zt1 := fp2Mul(t20, t21, t80, t81) } + + + function mixed_addition_step(xq0, xq1, yq0, yq1, xt0, xt1, yt0, yt1, zt0, zt1) -> l00, l01, l10, l11, l20, l21, l30, l31, l40, l41, l50, l51, xc0, xc1, yc0, yc1, zc0, zc1 { + let zero := ZERO() + let t00, t01 := fp2Mul(yq0,yq1,zt0,zt1) + let t10, t11 := fp2Sub(yt0, yt1, t00, t01) + t00, t01 := fp2Mul(xq0, xq1, zt0, zt1) + let t20, t21 := fp2Sub(xt0, xt1, t00, t01) + let t30, t31 := fp2Mul(t10, t11, t10, t11) + let t40, t41 := fp2Mul(t20, t21, t20, t21) + let t50, t51 := fp2Mul(t20, t21, t40, t41) + let t60, t61 := fp2Mul(zt0, zt1, t30, t31) + let t70, t71 := fp2Mul(xt0, xt1, t40, t41) + t00, t01 := fp2Add(t70, t71, t70, t71) + let t80, t81 := fp2Add(t50, t51, t60, t61) + t80, t81 := fp2Sub(t80, t81, t00, t01) + t00, t01 := fp2Mul(yt0, yt1, t50, t51) + + // Xc0 + xc0, xc1 := fp2Mul(t20, t21, t80, t81) + + // Yc0 + yc0, yc1 := fp2Sub(t70, t71, t80, t81) + yc0, yc1 := fp2Mul(yc0, yc1, t10, t11) + yc0, yc1 := fp2Sub(yc0, yc1, t00, t01) + + // Zc0 + zc0, zc1 := fp2Mul(t50, t51, zt0, zt1) + t00, t01 := fp2Mul(t20, t21, yq0, yq1) + let t90, t91 := fp2Mul(xq0, xq1, t10, t11) + t90, t91 := fp2Sub(t90, t91, t00, t01) + + // l0 + l00 := t20 + l01 := t21 + l10 := zero + l11 := zero + l20 := zero + l21 := zero + + // l1 + l30, l31 := fp2Neg(t10, t11) + + // l2 + l40 := t90 + l41 := t91 + l50 := zero + l51 := zero + } + + function finalExponentiation(a000, a001, a010, a011, a020, a021, a100, a101, a110, a111, a120, a121) -> f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121 { + f000 := a000 + f001 := a001 + f010 := a010 + f011 := a011 + f020 := a020 + f021 := a021 + f100 := a100 + f101 := a101 + f110 := a110 + f111 := a111 + f120 := a120 + f121 := a121 + + // Easy Part + let t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121 := fp12Conjugate(f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121) + f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121 := fp12Inv(f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121) + t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121 := fp12Mul(t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121, f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121) + let t1000, t1001, t1010, t1011, t1020, t1021, t1100, t1101, t1110, t1111, t1120, t1121 := frobeniusSquare(t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121) + f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121 := fp12Mul(t1000, t1001, t1010, t1011, t1020, t1021, t1100, t1101, t1110, t1111, t1120, t1121, t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121) + + // Hard Part + t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121 := fp12Expt(f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121) + t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121 := fp12Conjugate(t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121) + t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121 := fp12CyclotomicSquare(t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121) + t1000, t1001, t1010, t1011, t1020, t1021, t1100, t1101, t1110, t1111, t1120, t1121 := fp12CyclotomicSquare(t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121) + t1000, t1001, t1010, t1011, t1020, t1021, t1100, t1101, t1110, t1111, t1120, t1121 := fp12Mul(t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121, t1000, t1001, t1010, t1011, t1020, t1021, t1100, t1101, t1110, t1111, t1120, t1121) + let t2000, t2001, t2010, t2011, t2020, t2021, t2100, t2101, t2110, t2111, t2120, t2121 := fp12Expt(t1000, t1001, t1010, t1011, t1020, t1021, t1100, t1101, t1110, t1111, t1120, t1121) + t2000, t2001, t2010, t2011, t2020, t2021, t2100, t2101, t2110, t2111, t2120, t2121 := fp12Conjugate(t2000, t2001, t2010, t2011, t2020, t2021, t2100, t2101, t2110, t2111, t2120, t2121) + let t3000, t3001, t3010, t3011, t3020, t3021, t3100, t3101, t3110, t3111, t3120, t3121 := fp12Conjugate(t1000, t1001, t1010, t1011, t1020, t1021, t1100, t1101, t1110, t1111, t1120, t1121) + t1000, t1001, t1010, t1011, t1020, t1021, t1100, t1101, t1110, t1111, t1120, t1121 := fp12Mul(t2000, t2001, t2010, t2011, t2020, t2021, t2100, t2101, t2110, t2111, t2120, t2121, t3000, t3001, t3010, t3011, t3020, t3021, t3100, t3101, t3110, t3111, t3120, t3121) + t3000, t3001, t3010, t3011, t3020, t3021, t3100, t3101, t3110, t3111, t3120, t3121 := fp12CyclotomicSquare(t2000, t2001, t2010, t2011, t2020, t2021, t2100, t2101, t2110, t2111, t2120, t2121) + let t4000, t4001, t4010, t4011, t4020, t4021, t4100, t4101, t4110, t4111, t4120, t4121 := fp12Expt(t3000, t3001, t3010, t3011, t3020, t3021, t3100, t3101, t3110, t3111, t3120, t3121) + t4000, t4001, t4010, t4011, t4020, t4021, t4100, t4101, t4110, t4111, t4120, t4121 := fp12Mul(t4000, t4001, t4010, t4011, t4020, t4021, t4100, t4101, t4110, t4111, t4120, t4121, t1000, t1001, t1010, t1011, t1020, t1021, t1100, t1101, t1110, t1111, t1120, t1121) + t3000, t3001, t3010, t3011, t3020, t3021, t3100, t3101, t3110, t3111, t3120, t3121 := fp12Mul(t4000, t4001, t4010, t4011, t4020, t4021, t4100, t4101, t4110, t4111, t4120, t4121, t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121) + t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121 := fp12Mul(t2000, t2001, t2010, t2011, t2020, t2021, t2100, t2101, t2110, t2111, t2120, t2121, t4000, t4001, t4010, t4011, t4020, t4021, t4100, t4101, t4110, t4111, t4120, t4121) + t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121 := fp12Mul(t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121, f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121) + t2000, t2001, t2010, t2011, t2020, t2021, t2100, t2101, t2110, t2111, t2120, t2121 := frobenius(t3000, t3001, t3010, t3011, t3020, t3021, t3100, t3101, t3110, t3111, t3120, t3121) + t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121 := fp12Mul(t2000, t2001, t2010, t2011, t2020, t2021, t2100, t2101, t2110, t2111, t2120, t2121, t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121) + t2000, t2001, t2010, t2011, t2020, t2021, t2100, t2101, t2110, t2111, t2120, t2121 := frobeniusSquare(t4000, t4001, t4010, t4011, t4020, t4021, t4100, t4101, t4110, t4111, t4120, t4121) + t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121 := fp12Mul(t2000, t2001, t2010, t2011, t2020, t2021, t2100, t2101, t2110, t2111, t2120, t2121, t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121) + t2000, t2001, t2010, t2011, t2020, t2021, t2100, t2101, t2110, t2111, t2120, t2121 := fp12Conjugate(f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121) + t2000, t2001, t2010, t2011, t2020, t2021, t2100, t2101, t2110, t2111, t2120, t2121 := fp12Mul(t2000, t2001, t2010, t2011, t2020, t2021, t2100, t2101, t2110, t2111, t2120, t2121, t3000, t3001, t3010, t3011, t3020, t3021, t3100, t3101, t3110, t3111, t3120, t3121) + t2000, t2001, t2010, t2011, t2020, t2021, t2100, t2101, t2110, t2111, t2120, t2121 := frobeniusCube(t2000, t2001, t2010, t2011, t2020, t2021, t2100, t2101, t2110, t2111, t2120, t2121) + f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121 := fp12Mul(t2000, t2001, t2010, t2011, t2020, t2021, t2100, t2101, t2110, t2111, t2120, t2121, t0000, t0001, t0010, t0011, t0020, t0021, t0100, t0101, t0110, t0111, t0120, t0121) + } + + function millerLoop(xq0, xq1, yq0, yq1, xp, yp) -> f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121 { + let t00, t01, t10, t11, t20, t21 := g2FromAffine(xq0, xq1, yq0, yq1) + let mq00, mq01, mq10, mq11 := g2Neg(xq0, xq1, yq0, yq1) + f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121 := FP12_ONE() + let naf := NAF_REPRESENTATIVE() + let n_iter := 65 + let l00, l01, l10, l11, l20, l21, l30, l31, l40, l41, l50, l51 := FP12_ONE() + + for {let i := 0} lt(i, n_iter) { i := add(i, 1) } { + f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121 := fp12Square(f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121) + + l00, l01, l10, l11, l20, l21, l30, l31, l40, l41, l50, l51, t00, t01, t10, t11, t20, t21 := doubleStep(t00, t01, t10, t11, t20, t21) + l00, l01 := fp2ScalarMul(l00, l01, yp) + l30, l31 := fp2ScalarMul(l30, l31, xp) + f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121 := fp12Mul(f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121, l00, l01, l10, l11, l20, l21, l30, l31, l40, l41, l50, l51) + + // naf digit = 1 + if and(naf, 2) { + l00, l01, l10, l11, l20, l21, l30, l31, l40, l41, l50, l51, t00, t01, t10, t11, t20, t21 := mixed_addition_step(xq0, xq1, yq0, yq1, t00, t01, t10, t11, t20, t21) + l00, l01 := fp2ScalarMul(l00, l01, yp) + l30, l31 := fp2ScalarMul(l30, l31, xp) + f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121 := fp12Mul(f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121, l00, l01, l10, l11, l20, l21, l30, l31, l40, l41, l50, l51) + } + + // naf digit = -1 + if and(naf, 4) { + l00, l01, l10, l11, l20, l21, l30, l31, l40, l41, l50, l51, t00, t01, t10, t11, t20, t21 := mixed_addition_step(mq00, mq01, mq10, mq11, t00, t01, t10, t11, t20, t21) + l00, l01 := fp2ScalarMul(l00, l01, yp) + l30, l31 := fp2ScalarMul(l30, l31, xp) + f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121 := fp12Mul(f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121, l00, l01, l10, l11, l20, l21, l30, l31, l40, l41, l50, l51) + } + + naf := shr(3, naf) + } + + let r00, r01 := fp2Conjugate(xq0, xq1) + let r10, r11 := fp2Conjugate(yq0, yq1) + r00, r01 := mulByGamma12(r00, r01) + r10, r11 := mulByGamma13(r10, r11) + + let r20, r21 := mulByGamma22(xq0, xq1) + let r30, r31 := mulByGamma23(yq0, yq1) + r30, r31 := fp2Neg(r30, r31) + + l00, l01, l10, l11, l20, l21, l30, l31, l40, l41, l50, l51, t00, t01, t10, t11, t20, t21 := mixed_addition_step(r00, r01, r10, r11, t00, t01, t10, t11, t20, t21) + l00, l01 := fp2ScalarMul(l00, l01, yp) + l30, l31 := fp2ScalarMul(l30, l31, xp) + f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121 := fp12Mul(f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121, l00, l01, l10, l11, l20, l21, l30, l31, l40, l41, l50, l51) + + l00, l01, l10, l11, l20, l21, l30, l31, l40, l41, l50, l51, t00, t01, t10, t11, t20, t21 := mixed_addition_step(r20, r21, r30, r31, t00, t01, t10, t11, t20, t21) + l00, l01 := fp2ScalarMul(l00, l01, yp) + l30, l31 := fp2ScalarMul(l30, l31, xp) + f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121 := fp12Mul(f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121, l00, l01, l10, l11, l20, l21, l30, l31, l40, l41, l50, l51) + } + + // G2 TWIST + // Neg function for G2 in affine coordinates + function g2Neg(x0, x1, y0, y1) -> nx0, nx1, ny0, ny1 { + nx0 := x0 + nx1 := x1 + ny0, ny1 := fp2Neg(y0, y1) + } + + // G2 functions to go back and forth between affine and projective coordinates + function g2IntoAffine(xp0, xp1, yp0, yp1, zp0, zp1) -> xr0, xr1, yr0, yr1 { + let z0, z1 := fp2Inv(zp0, zp1) + xr0, xr1 := fp2Mul(xp0, xp1, zp0, zp1) + yr0, yr1 := fp2Mul(yp0, yp1, zp0, zp1) + } + + function g2FromAffine(xp0, xp1, yp0, yp1) -> xr0, xr1, yr0, yr1, zr0, zr1 { + xr0 := xp0 + xr1 := xp1 + yr0 := yp0 + yr1 := yp1 + zr0 := MONTGOMERY_ONE() + zr1 := ZERO() + if and(eq(xp0, ZERO()), eq(xp1, ZERO())) { + if and(eq(yp0, ZERO()), eq(yp1, ZERO())) { + xr0 := MONTGOMERY_ONE() + // xr1 is already ZERO() + yr0 := MONTGOMERY_ONE() + // yr1 is already ZERO() + zr0 := ZERO() + // zr1 is already ZERO() + } + } + } + + // PAIRING TEST WITH CALLDATA: + + // 1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f59 + // 3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41 + // 209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf7 + // 04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a41678 + // 2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d + // 120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550 + // 111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c + // 2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411 + // 198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2 + // 1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed + // 090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b + // 12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa + let g1_xp := intoMontgomeryForm(calldataload(0)) + let g1_yp := intoMontgomeryForm(calldataload(32)) + let g2_ixq := intoMontgomeryForm(calldataload(64)) + let g2_xq := intoMontgomeryForm(calldataload(96)) + let g2_iyq := intoMontgomeryForm(calldataload(128)) + let g2_yq := intoMontgomeryForm(calldataload(160)) + + let g1_xr := intoMontgomeryForm(calldataload(192)) + let g1_yr := intoMontgomeryForm(calldataload(224)) + let g2_ixs := intoMontgomeryForm(calldataload(256)) + let g2_xs := intoMontgomeryForm(calldataload(288)) + let g2_iys := intoMontgomeryForm(calldataload(320)) + let g2_ys := intoMontgomeryForm(calldataload(352)) + + let t000, t001, t010, t011, t020, t021, t100, t101, t110, t111, t120, t121 := millerLoop(g2_xq, g2_ixq, g2_yq, g2_iyq, g1_xp, g1_yp) + t000, t001, t010, t011, t020, t021, t100, t101, t110, t111, t120, t121 := finalExponentiation(t000, t001, t010, t011, t020, t021, t100, t101, t110, t111, t120, t121) + + let t200, t201, t210, t211, t220, t221, t300, t301, t310, t311, t320, t321 := millerLoop(g2_xs, g2_ixs, g2_ys, g2_iys, g1_xr, g1_yr) + t200, t201, t210, t211, t220, t221, t300, t301, t310, t311, t320, t321 := finalExponentiation(t200, t201, t210, t211, t220, t221, t300, t301, t310, t311, t320, t321) + + let c000, c001, c010, c011, c020, c021, c100, c101, c110, c111, c120, c121 := fp12Mul(t000, t001, t010, t011, t020, t021, t100, t101, t110, t111, t120, t121, t200, t201, t210, t211, t220, t221, t300, t301, t310, t311, t320, t321) + + console_log(c000) + console_log(c001) + console_log(c010) + console_log(c011) + console_log(c020) + console_log(c021) + console_log(c100) + console_log(c101) + console_log(c110) + console_log(c111) + console_log(c120) + console_log(c121) } } } diff --git a/scripts/alt_bn128_pairing.py b/scripts/alt_bn128_pairing.py new file mode 100644 index 00000000..05ea9cba --- /dev/null +++ b/scripts/alt_bn128_pairing.py @@ -0,0 +1,240 @@ +import pairing_utils +import montgomery as monty +import fp2 as fp2 +import fp12 +import frobenius as frb +import g2 +import pairing_utils as utils + +def double_step(Xq0, Xq1, Yq0, Yq1, Zq0, Zq1): + two_inv = monty.inv(monty.TWO) + t0 = fp2.mul(Xq0,Xq1,Yq0,Yq1) + A = fp2.scalar_mul(*t0, two_inv) + B = fp2.mul(Yq0, Yq1, Yq0, Yq1) + C = fp2.mul(Zq0, Zq1, Zq0, Zq1) + D = fp2.add(*C, *C) + D = fp2.add(*D, *C) + E = fp2.mul(*D, *utils.TWISTED_CURVE_COEFFS) + F = fp2.add(*E, *E) + F = fp2.add(*F, *E) + G = fp2.add(*B, *F) + G = fp2.scalar_mul(*G, two_inv) + H = fp2.add(Yq0, Yq1, Zq0, Zq1) + H = fp2.mul(*H, *H) + t1 = fp2.add(*B, *C) + H = fp2.sub(*H, *t1) + I = fp2.sub(*E, *B) + J = fp2.mul(Xq0, Xq1, Xq0, Xq1) + EE = fp2.mul(*E, *E) + K = fp2.add(*EE,*EE) + K = fp2.add(*K,*EE) + + Tx = fp2.sub(*B, *F) + Tx = fp2.mul(*Tx, *A) + + Ty = fp2.mul(*G, *G) + Ty = fp2.sub(*Ty, *K) + + Tz = fp2.mul(*B, *H) + + l0 = fp2.neg(*H) + l1 = fp2.add(*J, *J) + l1 = fp2.add(*l1, *J) + l2 = I + + l = (*l0,0,0,0,0,*l1,*l2,0,0) + T = Tx + Ty + Tz + return l,T + +def mixed_addition_step(Xq0, Xq1, Yq0, Yq1, Xt0, Xt1, Yt0, Yt1, Zt0, Zt1): + temp = fp2.mul(Yq0,Yq1,Zt0,Zt1) + O = fp2.sub(Yt0,Yt1,*temp) + temp = fp2.mul(Xq0,Xq1,Zt0,Zt1) + L = fp2.sub(Xt0,Xt1,*temp) + C = fp2.mul(*O,*O) + D = fp2.mul(*L,*L) + E = fp2.mul(*L,*D) + F = fp2.mul(Zt0,Zt1,*C) + G = fp2.mul(Xt0,Xt1,*D) + temp = fp2.add(*G,*G) + H = fp2.add(*E,*F) + H = fp2.sub(*H,*temp) + temp = fp2.mul(Yt0, Yt1, *E) + + Tx0, Tx1 = fp2.mul(*L,*H) + Ty0, Ty1 = fp2.sub(*G,*H) + Ty0, Ty1 = fp2.mul(Ty0,Ty1,*O) + Ty0, Ty1 = fp2.sub(Ty0,Ty1,*temp) + Tz0, Tz1 = fp2.mul(*E, Zt0, Zt1) + + temp = fp2.mul(*L,Yq0,Yq1) + J = fp2.mul(Xq0,Xq1,*O) + J = fp2.sub(*J, *temp) + + l0 = L + l1 = fp2.neg(*O) + l2 = J + + l = (*l0,0,0,0,0,*l1,*l2,0,0) + T = Tx0, Tx1, Ty0, Ty1, Tz0, Tz1 + + return l, T + +# Algorithm 6 from https://eprint.iacr.org/2015/192.pdf +def final_exponentiation(a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121): + f = (a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121) + + # First part + t0 = fp12.conjugate(*f) + f= fp12.inv(*f) + t0 = fp12.mul(*t0, *f) + f_aux = frb.frobenius_square(*t0) + f = fp12.mul(*f_aux, *t0) + + # Second part + t0 = fp12.expt(*f) + t0 = fp12.conjugate(*t0) + t0 = fp12.cyclotomic_square(*t0) + t1 = fp12.cyclotomic_square(*t0) + t1 = fp12.mul(*t0,*t1) + t2 = fp12.expt(*t1) + t2 = fp12.conjugate(*t2) + t3 = fp12.conjugate(*t1) + t1 = fp12.mul(*t2,*t3) + t3 = fp12.cyclotomic_square(*t2) + t4 = fp12.expt(*t3) + t4 = fp12.mul(*t4,*t1) + t3 = fp12.mul(*t4,*t0) + t0 = fp12.mul(*t2,*t4) + t0 = fp12.mul(*t0,*f) + t2 = frb.frobenius(*t3) + t0 = fp12.mul(*t2,*t0) + t2 = frb.frobenius_square(*t4) + t0 = fp12.mul(*t2,*t0) + t2 = fp12.conjugate(*f) + t2 = fp12.mul(*t2,*t3) + t2 = frb.frobenius_cube(*t2) + t0 = fp12.mul(*t2,*t0) + + return t0 + +def miller_loop(Xq0, Xq1, Yq0, Yq1, xp, yp): + + Q = Xq0, Xq1, Yq0, Yq1 + T = g2.from_affine(Xq0, Xq1, Yq0, Yq1) + f = fp12.ONE + + for i in range(len(utils.S_NAF) - 2, -1, -1): + f = fp12.square(*f) + + line_eval, point_double = double_step(*T) + aux = list(line_eval) + aux[0], aux[1] = fp2.scalar_mul(aux[0], aux[1], yp) + aux[6], aux[7] = fp2.scalar_mul(aux[6], aux[7], xp) + line_eval = tuple(aux) + f = fp12.mul(*f,*line_eval) + T = point_double + + if pairing_utils.S_NAF[i] == -1: + minus_Q = g2.neg(*Q) + line_eval, point_adding = mixed_addition_step(*minus_Q, *T) + aux = list(line_eval) + aux[0], aux[1] = fp2.scalar_mul(aux[0], aux[1], yp) + aux[6], aux[7] = fp2.scalar_mul(aux[6], aux[7], xp) + line_eval = tuple(aux) + f = fp12.mul(*f, *line_eval) + T = point_adding + + elif pairing_utils.S_NAF[i] == 1: + line_eval, point_adding = mixed_addition_step(*Q,*T) + aux = list(line_eval) + aux[0], aux[1] = fp2.scalar_mul(aux[0], aux[1], yp) + aux[6], aux[7] = fp2.scalar_mul(aux[6], aux[7], xp) + line_eval = tuple(aux) + f = fp12.mul(*f,*line_eval) + T = point_adding + + # Q1 <- pi_p(Q) + X_q0, X_q1 = fp2.conjugate(Xq0, Xq1) + Y_q0, Y_q1 = fp2.conjugate(Yq0, Yq1) + X_q0, X_q1 = frb.mul_by_gamma_1_2(X_q0, X_q1) + Y_q0, Y_q1 = frb.mul_by_gamma_1_3(Y_q0, Y_q1) + Q1 = X_q0, X_q1, Y_q0, Y_q1 + + # Q2 <- pi_p_square(Q) + X_q20, X_q21 = frb.mul_by_gamma_2_2(Xq0, Xq1) + Y_q20, Y_q21 = frb.mul_by_gamma_2_3(Yq0, Yq1) + Y_q20, Y_q21 = fp2.neg(Y_q20, Y_q21) + Q2 = X_q20, X_q21, Y_q20, Y_q21 + + line_eval, point_adding = mixed_addition_step(*Q1,*T) + aux = list(line_eval) + aux[0], aux[1] = fp2.scalar_mul(aux[0], aux[1], yp) + aux[6], aux[7] = fp2.scalar_mul(aux[6], aux[7], xp) + line_eval = tuple(aux) + f = fp12.mul(*f,*line_eval) + T = point_adding + + line_eval, point_adding = mixed_addition_step(*Q2,*T) + aux = list(line_eval) + aux[0], aux[1] = fp2.scalar_mul(aux[0], aux[1], yp) + aux[6], aux[7] = fp2.scalar_mul(aux[6], aux[7], xp) + line_eval = tuple(aux) + f = fp12.mul(*f,*line_eval) + T = point_adding + + return f + +def pair(xp, yp, Xq0, Xq1, Yq0, Yq1): + f = miller_loop(Xq0, Xq1, Yq0, Yq1, xp, yp) + f = final_exponentiation(*f) + return f + +def main(): + # From Ethereum tests + # 1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f59 -> Xp1 + # 3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41 -> Yp1 + + # 209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf7 -> Xq11 + # 04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a41678 -> Xq10 + # 2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d -> Yq11 + # 120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550 -> Yq10 + + # 111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c -> Xp2 + # 2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411 -> Yp2 + + # 198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2 -> Xq21 + # 1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed -> Xq20 + # 090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b -> Yq21 + # 12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa -> Yq20 + + xp0 = monty.into(12873740738727497448187997291915224677121726020054032516825496230827252793177) + yp0 = monty.into(21804419174137094775122804775419507726154084057848719988004616848382402162497) + Xq0 = monty.into(2146841959437886920191033516947821737903543682424168472444605468016078231160) + Xq1 = monty.into(14752851163271972921165116810778899752274893127848647655434033030151679466487) + Yq0 = monty.into(8159591693044959083845993640644415462154314071906244874217244895511876957520) + Yq1 = monty.into(19774899457345372253936887903062884289284519982717033379297427576421785416781) + + assert(utils.is_in_curve(xp0, yp0)) + assert(utils.is_in_twisted_curve(Xq0, Xq1, Yq0, Yq1)) + + xp1 = monty.into(7742452358972543465462254569134860944739929848367563713587808717088650354556) + yp1 = monty.into(14563720768440487558151020426243236708567496944263114635856508834497000371217) + Xt0 = monty.into(10857046999023057135944570762232829481370756359578518086990519993285655852781) + Xt1 = monty.into(11559732032986387107991004021392285783925812861821192530917403151452391805634) + Yt0 = monty.into(8495653923123431417604973247489272438418190587263600148770280649306958101930) + Yt1 = monty.into(4082367875863433681332203403145435568316851327593401208105741076214120093531) + + assert(utils.is_in_curve(xp1, yp1)) + assert(utils.is_in_twisted_curve(Xt0, Xt1, Yt0, Yt1)) + + + # Pairing Test + a = pair(xp0, yp0, Xq0, Xq1, Yq0, Yq1) + b = pair(xp1, yp1, Xt0, Xt1, Yt0, Yt1) + result = fp12.mul(*a, *b) + assert(result == fp12.ONE) + pass + +if __name__ == '__main__': + main() diff --git a/scripts/fp12.py b/scripts/fp12.py new file mode 100644 index 00000000..f56349b6 --- /dev/null +++ b/scripts/fp12.py @@ -0,0 +1,223 @@ +import montgomery as monty +import fp6 +import fp2 +import frobenius as frb + +ZERO = (0,0,0,0,0,0,0,0,0,0,0,0) +ONE = tuple([monty.ONE] + [0 for _ in range(11)]) + +# Algorithm 18 from https://eprint.iacr.org/2010/354.pdf +def add(a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121, b_000, b_001, b_010, b_011, b_020, b_021, b_100, b_101, b_110, b_111, b_120, b_121): + c0 = fp6.add(a_000, a_001, a_010, a_011, a_020, a_021, b_000, b_001, b_010, b_011, b_020, b_021) + c1 = fp6.add(a_100, a_101, a_110, a_111, a_120, a_121, b_100, b_101, b_110, b_111, b_120, b_121) + return c0 + c1 + +# Algorithm 19 from https://eprint.iacr.org/2010/354.pdf +def sub(a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121, b_000, b_001, b_010, b_011, b_020, b_021, b_100, b_101, b_110, b_111, b_120, b_121): + c0 = fp6.sub(a_000, a_001, a_010, a_011, a_020, a_021, b_000, b_001, b_010, b_011, b_020, b_021) + c1 = fp6.sub(a_100, a_101, a_110, a_111, a_120, a_121, b_100, b_101, b_110, b_111, b_120, b_121) + return c0 + c1 + +# Algorithm 20 from https://eprint.iacr.org/2010/354.pdf +def mul(a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121, b_000, b_001, b_010, b_011, b_020, b_021, b_100, b_101, b_110, b_111, b_120, b_121): + t0 = fp6.mul(a_000, a_001, a_010, a_011, a_020, a_021, b_000, b_001, b_010, b_011, b_020, b_021) + t1 = fp6.mul(a_100, a_101, a_110, a_111, a_120, a_121, b_100, b_101, b_110, b_111, b_120, b_121) + t2 = fp6.mul_by_gamma(*t1) + c0 = fp6.add(*t0,*t2) + t3 = fp6.add(a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121) + t4 = fp6.add(b_000, b_001, b_010, b_011, b_020, b_021, b_100, b_101, b_110, b_111, b_120, b_121) + c1 = fp6.mul(*t3,*t4) + c1 = fp6.sub(*c1,*t0) + c1 = fp6.sub(*c1,*t1) + return c0 + c1 + +# Algorithm 22 from https://eprint.iacr.org/2010/354.pdf +def square(a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121): + t1 = fp6.sub(a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121) + t2 = fp6.mul_by_gamma(a_100, a_101, a_110, a_111, a_120, a_121) + t3 = fp6.sub(a_000, a_001, a_010, a_011, a_020, a_021,*t2) + t4 = fp6.mul(a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121) + t5 = fp6.mul(*t1,*t3) + t6 = fp6.add(*t4,*t5) + c1 = fp6.add(*t4,*t4) + t8 = fp6.mul_by_gamma(*t4) + c0 = fp6.add(*t6,*t8) + return c0 + c1 + +# Algorithm 23 from https://eprint.iacr.org/2010/354.pdf +def inv(a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121): + t0 = fp6.square(a_000, a_001, a_010, a_011, a_020, a_021) + t1 = fp6.square(a_100, a_101, a_110, a_111, a_120, a_121) + t2 = fp6.mul_by_gamma(*t1) + t0 = fp6.sub(*t0,*t2) + t1 = fp6.inv(*t0) + c0 = fp6.mul(a_000, a_001, a_010, a_011, a_020, a_021, *t1) + minus_one = fp6.sub(*fp6.ZERO, *fp6.ONE) + c1 = fp6.mul(*minus_one, a_100, a_101, a_110, a_111, a_120, a_121) + c1 = fp6.mul(*c1,*t1) + return c0 + c1 + +def conjugate(a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121): + return (a_000, a_001, a_010, a_011, a_020, a_021) + fp6.neg(a_100, a_101, a_110, a_111, a_120, a_121) + +def cyclotomic_square(a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121): + t0 = fp2.mul(a_110, a_111, a_110, a_111) + t1 = fp2.mul(a_000, a_001, a_000, a_001) + t6 = fp2.add(a_110, a_111, a_000, a_001) + t6 = fp2.mul(*t6, *t6) + t6 = fp2.sub(*t6, *t0) + t6 = fp2.sub(*t6, *t1) + t2 = fp2.mul(a_020, a_021, a_020, a_021) + t3 = fp2.mul(a_100, a_101, a_100, a_101) + t7 = fp2.add(a_020, a_021, a_100, a_101) + t7 = fp2.mul(*t7, *t7) + t7 = fp2.sub(*t7, *t2) + t7 = fp2.sub(*t7, *t3) + t4 = fp2.mul(a_120, a_121, a_120, a_121) + t5 = fp2.mul(a_010, a_011, a_010, a_011) + t8 = fp2.add(a_120, a_121, a_010, a_011) + t8 = fp2.mul(*t8, *t8) + t8 = fp2.sub(*t8, *t4) + t8 = fp2.sub(*t8, *t5) + t8 = fp2.mul_by_xi(*t8) + t0 = fp2.mul_by_xi(*t0) + t0 = fp2.add(*t0, *t1) + t2 = fp2.mul_by_xi(*t2) + t2 = fp2.add(*t2, *t3) + t4 = fp2.mul_by_xi(*t4) + t4 = fp2.add(*t4, *t5) + + c0c0 = fp2.sub(*t0, a_000, a_001) + c0c0 = fp2.add(*c0c0, *c0c0) + c0c0 = fp2.add(*c0c0, *t0) + + c0c1 = fp2.sub(*t2, a_010, a_011) + c0c1 = fp2.add(*c0c1, *c0c1) + c0c1 = fp2.add(*c0c1, *t2) + + c0c2 = fp2.sub(*t4, a_020, a_021) + c0c2 = fp2.add(*c0c2, *c0c2) + c0c2 = fp2.add(*c0c2, *t4) + + c1c0 = fp2.add(*t8, a_100, a_101) + c1c0 = fp2.add(*c1c0, *c1c0) + c1c0 = fp2.add(*c1c0, *t8) + + c1c1 = fp2.add(*t6, a_110, a_111) + c1c1 = fp2.add(*c1c1, *c1c1) + c1c1 = fp2.add(*c1c1, *t6) + + c1c2 = fp2.add(*t7, a_120, a_121) + c1c2 = fp2.add(*c1c2, *c1c2) + c1c2 = fp2.add(*c1c2, *t7) + + c0 = c0c0 + c0c1 + c0c2 + c1 = c1c0 + c1c1 + c1c2 + + return c0 + c1 + +def n_square(a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121, n): + out = a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121 + + for _ in range(0, n): + out = cyclotomic_square(*out) + + return out + +def expt(a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121): + t3 = cyclotomic_square(a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121) + t5 = cyclotomic_square(*t3) + result = cyclotomic_square(*t5) + t0 = cyclotomic_square(*result) + t2 = mul(a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121, *t0) + t0 = mul(*t2, *t3) + t1 = mul(a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121, *t0) + t4 = mul(*result, *t2) + t6 = cyclotomic_square(*t2) + t1 = mul(*t1, *t0) + t0 = mul(*t1, *t3) + t6 = n_square(*t6, 6) + t5 = mul(*t5, *t6) + t5 = mul(*t4, *t5) + t5 = n_square(*t5, 7) + t4 = mul(*t4, *t5) + t4 = n_square(*t4, 8) + t4 = mul(*t4, *t0) + t3 = mul(*t3, *t4) + t3 = n_square(*t3, 6) + t2 = mul(*t2, *t3) + t2 = n_square(*t2, 8) + t2 = mul(*t0, *t2) + t2 = n_square(*t2, 6) + t2 = mul(*t0, *t2) + t2 = n_square(*t2, 10) + t1 = mul(*t1, *t2) + t1 = n_square(*t1, 6) + t0 = mul(*t0, *t1) + result = mul(*result, *t0) + return result + +def main(): + fp12_zero = tuple([0 for _ in range(12)]) + fp12_one = tuple([monty.ONE] + [0 for _ in range(11)]) + fp12_two = tuple([monty.TWO] + [0 for _ in range(11)]) + fp12_all_one = tuple([monty.ONE for _ in range(12)]) + fp12_all_two = tuple([monty.TWO for _ in range(12)]) + fp12_random = (monty.ONE, monty.TWO, monty.ONE, monty.TWO, monty.ONE, monty.TWO, monty.ONE, monty.TWO, monty.ONE, monty.TWO, monty.ONE, monty.TWO) + + # ADDITION + assert(add(*fp12_zero, *fp12_zero) == fp12_zero) + assert(add(*fp12_zero, *fp12_all_one) == fp12_all_one) + assert(add(*fp12_all_one, *fp12_zero) == fp12_all_one) + assert(add(*fp12_all_one, *fp12_all_one) == fp12_all_two) + + # SUBTRACTION + assert(sub(*fp12_zero, *fp12_zero) == fp12_zero) + assert(sub(*fp12_all_two, *fp12_all_one) == fp12_all_one) + assert(sub(*fp12_all_one, *fp12_zero) == fp12_all_one) + assert(sub(*fp12_all_one, *fp12_all_one) == fp12_zero) + + # MULTIPLICATION BY 0 + assert(mul(*fp12_zero, *fp12_zero) == fp12_zero) + assert(mul(*fp12_all_one, *fp12_zero) == fp12_zero) + assert(mul(*fp12_zero, *fp12_all_two) == fp12_zero) + + # MULTIPLICATION BY 1 + assert(mul(*fp12_all_one, *fp12_one) == fp12_all_one) + assert(mul(*fp12_one, *fp12_all_two) == fp12_all_two) + + # MULTIPLICATION BY 2 + assert(mul(*fp12_all_one, *fp12_two) == add(*fp12_all_one, *fp12_all_one)) + assert(mul(*fp12_two, *fp12_all_two) == add(*fp12_all_two, *fp12_all_two)) + + # SQUARE OF 0 and 1 + assert(square(*fp12_zero) == fp12_zero) + assert(square(*fp12_one) == fp12_one) + + # MULTIPLICATION AND SQUARE + assert(mul(*fp12_one, *fp12_one) == square(*fp12_one)) + assert(mul(*fp12_all_one, *fp12_all_one) == square(*fp12_all_one)) + assert(mul(*fp12_all_two, *fp12_all_two) == square(*fp12_all_two)) + + # MULTIPLY BY INVERSE + assert(inv(*fp12_one) == fp12_one) + fp12_all_one_inverse = inv(*fp12_all_one) + fp12_all_two_inverse = inv(*fp12_all_two) + assert(mul(*fp12_all_one,*fp12_all_one_inverse) == fp12_one) + assert(mul(*fp12_all_two_inverse, *fp12_all_two) == fp12_one) + + # CONJUGATE + assert(conjugate(*conjugate(*fp12_random)) == fp12_random) + + # CYCLOTOMIC SQUARE + b = conjugate(*fp12_random) + a = inv(*fp12_random) + b = mul(*b, *a) + a = frb.frobenius_square(*b) + a = mul(*a, *b) + c = square(*a) + d = cyclotomic_square(*a) + assert(c == d) + +if __name__ == '__main__': + main() diff --git a/scripts/fp2.py b/scripts/fp2.py new file mode 100644 index 00000000..27b91cda --- /dev/null +++ b/scripts/fp2.py @@ -0,0 +1,109 @@ +import montgomery as monty + +# Base field order +N = 21888242871839275222246405745257275088696311157297823662689037894645226208583 + +# Algorithm 5 from https://eprint.iacr.org/2010/354.pdf +def add(a0, a1, b0, b1): + return monty.add(a0, b0), monty.add(a1, b1) + +# Algorithm 6 from https://eprint.iacr.org/2010/354.pdf +def sub(a0, a1, b0, b1): + return monty.sub(a0, b0), monty.sub(a1, b1) + +# Algorithm 7 from https://eprint.iacr.org/2010/354.pdf +def scalar_mul(a0, a1, scalar): + return monty.mul(a0, scalar), monty.mul(a1, scalar) + +def mul(a0, a1, b0, b1): + e = monty.sub(monty.mul(a0, b0), monty.mul(a1, b1)) + f = monty.add(monty.mul(a0, b1), monty.mul(a1, b0)) + return e, f + +# Algorithm 8 from https://eprint.iacr.org/2010/354.pdf +# β = -1 +def inv(a0, a1): + t0 = monty.mul(a0, a0) + t1 = monty.mul(a1, a1) + # This step is actually to - β * t1 but β = -1 so we can just add t1 to t0. + t0 = monty.add(t0, t1) + t1 = monty.inv(t0) + return monty.mul(a0, t1), monty.sub(0, monty.mul(a1, t1)) + +def exp(base0, base1, exponent): + pow0 = monty.ONE + pow1 = 0 + while exponent > 0: + if exponent % 2 == 1: + pow0, pow1 = mul(pow0, pow1, base0, base1) + base0, base1 = mul(base0, base1, base0, base1) + exponent >>= 1 + return pow0, pow1 + +# Multiply an element by xi = 9 + u +def mul_by_xi(a0, a1): + t0 = scalar_mul(a0, a1, monty.EIGHT) + c0 = monty.add(t0[0], a0) + c0 = monty.sub(c0, a1) + c1 = monty.add(t0[1], a1) + c1 = monty.add(c1, a0) + return c0, c1 + +def neg(a0, a1): + return monty.sub(0, a0), monty.sub(0, a1) + +def conjugate(a0, a1): + return a0, monty.sub(0, a1) + +def main(): + # (1 + 2i) * (2 + 2i) = [ac - bd, (ad + bc)i] = -2 + 6i + fp2_a = monty.ONE, monty.TWO + fp2_b = monty.TWO, monty.TWO + fp2_ab = mul(*fp2_a, *fp2_b) + + assert(monty.out_of(fp2_ab[0]) == N - 2) + assert(monty.out_of(fp2_ab[1]) == 6) + + # (1 + 2i) ^ 0 = 1 + fp2_one = exp(*fp2_a, 0) + assert(monty.out_of(fp2_one[0]) == 1) + assert(monty.out_of(fp2_one[1]) == 0) + + # (1 + 2i) ^ 2 = -3 + 4i + fp2_a_squared = exp(*fp2_a, 2) + assert(monty.out_of(fp2_a_squared[0]) == N - 3) + assert(monty.out_of(fp2_a_squared[1]) == 4) + + # (1 + 2i) ^ 3 = (1 + 2i) * (-3 + 4i) = [ac - bd, (ad + bc)i] = -11 - 2i + fp2_a_cubed = exp(*fp2_a, 3) + assert(monty.out_of(fp2_a_cubed[0]) == N - 11) + assert(monty.out_of(fp2_a_cubed[1]) == N - 2) + + # (1 + 2i) * 0 = 0 + fp2_zero = scalar_mul(*fp2_a, 0) + assert(fp2_zero == (0, 0)) + + # (1 + 2i) * 1 = 1 + 2i + fp2_one = scalar_mul(*fp2_a, monty.ONE) + assert(fp2_one == fp2_a) + + # (1 + 2i) * 2 = 2 + 4i + fp2_two = scalar_mul(*fp2_a, monty.TWO) + assert(fp2_two == (monty.TWO, monty.FOUR)) + + # (1 + 2i) * 3 = 3 + 6i + fp2_three = scalar_mul(*fp2_a, monty.THREE) + assert(fp2_three == (monty.THREE, monty.SIX)) + + # (1 + 2i) + (1 - 2i) = 2 + 0i + conjugated_fp2_a = conjugate(*fp2_a) + result = add(*fp2_a, *conjugated_fp2_a) + assert(result == (monty.TWO, 0)) + + # conj(conj((1 + 2i))) = 1 + 2i + fp2_a_aux = conjugate(*conjugated_fp2_a) + assert(fp2_a_aux == (monty.ONE, monty.TWO)) + +if __name__ == '__main__': + main() + \ No newline at end of file diff --git a/scripts/fp6.py b/scripts/fp6.py new file mode 100644 index 00000000..bcd0870e --- /dev/null +++ b/scripts/fp6.py @@ -0,0 +1,138 @@ +import montgomery as monty +import fp2 + +ZERO = (0,0,0,0,0,0) +ONE = [monty.ONE] + [0 for _ in range(5)] + +# Algorithm 10 from https://eprint.iacr.org/2010/354.pdf +def add(a_00, a_01, a_10, a_11, a_20, a_21, b_00, b_01, b_10, b_11, b_20, b_21): + c0 = fp2.add(a_00, a_01, b_00, b_01) + c1 = fp2.add(a_10, a_11, b_10, b_11) + c2 = fp2.add(a_20, a_21, b_20, b_21) + return c0 + c1 + c2 + +# Algorithm 11 from https://eprint.iacr.org/2010/354.pdf +def sub(a_00, a_01, a_10, a_11, a_20, a_21, b_00, b_01, b_10, b_11, b_20, b_21): + c0 = fp2.sub(a_00, a_01, b_00, b_01) + c1 = fp2.sub(a_10, a_11, b_10, b_11) + c2 = fp2.sub(a_20, a_21, b_20, b_21) + return c0 + c1 + c2 + +# Algorithm 13 from https://eprint.iacr.org/2010/354.pdf +def mul(a_00, a_01, a_10, a_11, a_20, a_21, b_00, b_01, b_10, b_11, b_20, b_21): + t0 = fp2.mul(a_00, a_01, b_00, b_01) + t1 = fp2.mul(a_10, a_11, b_10, b_11) + t2 = fp2.mul(a_20, a_21, b_20, b_21) + c0 = fp2.add(*fp2.mul_by_xi(*fp2.sub(*fp2.sub(*fp2.mul(*fp2.add(a_10, a_11, a_20, a_21), *fp2.add(b_10, b_11, b_20, b_21)), *t1), *t2)), *t0) + c1 = fp2.add(*fp2.sub(*fp2.sub(*fp2.mul(*fp2.add(a_00, a_01, a_10, a_11), *fp2.add(b_00, b_01, b_10, b_11)), *t0), *t1), *fp2.mul_by_xi(*t2)) + c2 = fp2.add(*fp2.sub(*fp2.sub(*fp2.mul(*fp2.add(a_00, a_01, a_20, a_21), *fp2.add(b_00, b_01, b_20, b_21)), *t0), *t2), *t1) + return c0 + c1 + c2 + +# Algorithm 16 from https://eprint.iacr.org/2010/354.pdf +def square(a_00, a_01, a_10, a_11, a_20, a_21): + c4 = fp2.scalar_mul(*fp2.mul(a_00, a_01, a_10, a_11), monty.TWO) + c5 = fp2.exp(a_20, a_21, 2) + c1 = fp2.add(*fp2.mul_by_xi(*c5), *c4) + c2 = fp2.sub(*c4, *c5) + c3 = fp2.exp(a_00, a_01, 2) + c4 = fp2.add(*fp2.sub(a_00, a_01, a_10, a_11), a_20, a_21) + c5 = fp2.scalar_mul(*fp2.mul(a_10, a_11, a_20, a_21), monty.TWO) + c4 = fp2.exp(*c4, 2) + c0 = fp2.add(*fp2.mul_by_xi(*c5), *c3) + c2 = fp2.sub(*fp2.add(*fp2.add(*c2, *c4), *c5), *c3) + return c0 + c1 + c2 + +# Algorithm 17 from https://eprint.iacr.org/2010/354.pdf +# Step 9 is wrong in the paper, it should be: t1 - t4 +def inv(a_00, a_01, a_10, a_11, a_20, a_21): + t0 = fp2.exp(a_00, a_01, 2); + t1 = fp2.exp(a_10, a_11, 2); + t2 = fp2.exp(a_20, a_21, 2); + t3 = fp2.mul(a_00, a_01, a_10, a_11); + t4 = fp2.mul(a_00, a_01, a_20, a_21); + t5 = fp2.mul(a_20, a_21, a_10, a_11); + c0 = fp2.sub(*t0, *fp2.mul_by_xi(*t5)) + c1 = fp2.sub(*fp2.mul_by_xi(*t2), *t3) + c2 = fp2.sub(*t1, *t4) + t6 = fp2.mul(a_00, a_01, *c0) + t6 = fp2.add(*t6, *fp2.mul(*fp2.mul_by_xi(a_20, a_21), *c1)) + t6 = fp2.add(*t6, *fp2.mul(*fp2.mul_by_xi(a_10, a_11), *c2)) + t6 = fp2.inv(*t6) + c0 = fp2.mul(*c0, *t6) + c1 = fp2.mul(*c1, *t6) + c2 = fp2.mul(*c2, *t6) + + return c0 + c1 + c2 + +def mul_by_gamma(a_00, a_01, a_10, a_11, a_20, a_21): + c0 = fp2.mul_by_xi(a_20, a_21) + c1 = a_00, a_01 + c2 = a_10, a_11 + + return c0 + c1 + c2 + +def neg(a_00, a_01, a_10, a_11, a_20, a_21): + return fp2.neg(a_00, a_01) + fp2.neg(a_10, a_11) + fp2.neg(a_20, a_21) + +def main(): + # (1, 2) + (1, 2)x + (1, 2)x^2 + fp2_a_0 = monty.ONE, monty.TWO + fp2_a_1 = monty.ONE, monty.TWO + fp2_a_2 = monty.ONE, monty.TWO + + # (2, 2) + (2, 2)x + (2, 2)x^2 + fp2_b_0 = monty.TWO, monty.TWO + fp2_b_1 = monty.TWO, monty.TWO + fp2_b_2 = monty.TWO, monty.TWO + + # ADDITION + fp6_ab = add(*fp2_a_0, *fp2_a_1, *fp2_a_2, *fp2_b_0, *fp2_b_1, *fp2_b_2) + + assert(monty.out_of(fp6_ab[0]) == 3) + assert(monty.out_of(fp6_ab[1]) == 4) + assert(monty.out_of(fp6_ab[2]) == 3) + assert(monty.out_of(fp6_ab[3]) == 4) + assert(monty.out_of(fp6_ab[4]) == 3) + assert(monty.out_of(fp6_ab[5]) == 4) + + # SUBTRACTION + + # (1, 2) + (1, 1)x + (1, 0)x^2 + fp2_b_0 = monty.ONE, monty.TWO + fp2_b_1 = monty.ONE, monty.ONE + fp2_b_2 = monty.ONE, 0 + + fp6_ab = sub(*fp2_a_0, *fp2_a_1, *fp2_a_2, *fp2_b_0, *fp2_b_1, *fp2_b_2) + + assert(monty.out_of(fp6_ab[0]) == 0) + assert(monty.out_of(fp6_ab[1]) == 0) + assert(monty.out_of(fp6_ab[2]) == 0) + assert(monty.out_of(fp6_ab[3]) == 1) + assert(monty.out_of(fp6_ab[4]) == 0) + assert(monty.out_of(fp6_ab[5]) == 2) + + # SQUARE AND MULTIPLICATION + + fp6_squared = square(*fp2_a_0, *fp2_a_1, *fp2_a_2) + fp6_mul_squared = mul(*fp2_a_0, *fp2_a_1, *fp2_a_2, *fp2_a_0, *fp2_a_1, *fp2_a_2) + + assert(fp6_squared[0] == fp6_mul_squared[0]) + assert(fp6_squared[1] == fp6_mul_squared[1]) + assert(fp6_squared[2] == fp6_mul_squared[2]) + assert(fp6_squared[3] == fp6_mul_squared[3]) + assert(fp6_squared[4] == fp6_mul_squared[4]) + assert(fp6_squared[5] == fp6_mul_squared[5]) + + # INVERSE + fp6_inversed = inv(*fp2_a_0, *fp2_a_1, *fp2_a_2) + fp6_one = mul(*fp2_a_0, *fp2_a_1, *fp2_a_2, *fp6_inversed) + + assert(fp6_one[0] == monty.ONE) + assert(fp6_one[1] == 0) + assert(fp6_one[2] == 0) + assert(fp6_one[3] == 0) + assert(fp6_one[4] == 0) + assert(fp6_one[5] == 0) + +if __name__ == '__main__': + main() diff --git a/scripts/frobenius.py b/scripts/frobenius.py new file mode 100644 index 00000000..1abab15a --- /dev/null +++ b/scripts/frobenius.py @@ -0,0 +1,201 @@ +import fp2 +import montgomery as monty + +def frobenius(a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121): + t1 = fp2.conjugate(a_000, a_001) + t2 = fp2.conjugate(a_100, a_101) + t3 = fp2.conjugate(a_010, a_011) + t4 = fp2.conjugate(a_110, a_111) + t5 = fp2.conjugate(a_020, a_021) + t6 = fp2.conjugate(a_120, a_121) + + t2 = mul_by_gamma_1_1(*t2) + t3 = mul_by_gamma_1_2(*t3) + t4 = mul_by_gamma_1_3(*t4) + t5 = mul_by_gamma_1_4(*t5) + t6 = mul_by_gamma_1_5(*t6) + + c0 = t1[0], t1[1], t3[0], t3[1], t5[0], t5[1] + c1 = t2[0], t2[1], t4[0], t4[1], t6[0], t6[1] + + return c0 + c1 + +def frobenius_square(a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121): + t1 = a_000, a_001 + t2 = mul_by_gamma_2_1(a_100, a_101) + t3 = mul_by_gamma_2_2(a_010, a_011) + t4 = mul_by_gamma_2_3(a_110, a_111) + t5 = mul_by_gamma_2_4(a_020, a_021) + t6 = mul_by_gamma_2_5(a_120, a_121) + + c0 = t1[0], t1[1], t3[0], t3[1], t5[0], t5[1] + c1 = t2[0], t2[1], t4[0], t4[1], t6[0], t6[1] + + return c0 + c1 + +def frobenius_cube(a_000, a_001, a_010, a_011, a_020, a_021, a_100, a_101, a_110, a_111, a_120, a_121): + t1 = fp2.conjugate(a_000, a_001) + t2 = fp2.conjugate(a_100, a_101) + t3 = fp2.conjugate(a_010, a_011) + t4 = fp2.conjugate(a_110, a_111) + t5 = fp2.conjugate(a_020, a_021) + t6 = fp2.conjugate(a_120, a_121) + + t2 = mul_by_gamma_3_1(*t2) + t3 = mul_by_gamma_3_2(*t3) + t4 = mul_by_gamma_3_3(*t4) + t5 = mul_by_gamma_3_4(*t5) + t6 = mul_by_gamma_3_5(*t6) + + c0 = t1[0], t1[1], t3[0], t3[1], t5[0], t5[1] + c1 = t2[0], t2[1], t4[0], t4[1], t6[0], t6[1] + + return c0 + c1 + +# Implement the precomputed constant multiplications for utilizing the Frobenius Operator. +# Note: gn values are in Montgomery form. + +# GAMMA_1_i + +def mul_by_gamma_1_1(a0, a1): + g0 = 1334504125441109323775816677333762124980877086439557453392802825656291576071 + g1 = 7532670101108748540749979597679923402841328813027773483599019704565791010162 + return fp2.mul(a0, a1, g0, g1) + +def mul_by_gamma_1_2(a0, a1): + g0 = 11461073415658098971834280704587444395456423268720245247603935854280982113072 + g1 = 17373957475705492831721812124331982823197004514106338927670775596783233550167 + return fp2.mul(a0, a1, g0, g1) + +def mul_by_gamma_1_3(a0, a1): + g0 = 16829996427371746075450799880956928810557034522864196246648550205375670302249 + g1 = 20140510615310063345578764457068708762835443761990824243702724480509675468743 + return fp2.mul(a0, a1, g0, g1) + +def mul_by_gamma_1_4(a0, a1): + g0 = 9893659366031634526915473325149983243417508801286144596494093251884139331218 + g1 = 16514792769865828027011044701859348114858257981779976519405133026725453154633 + return fp2.mul(a0, a1, g0, g1) + +def mul_by_gamma_1_5(a0, a1): + g0 = 8443299194457421137480282511969901974227997168695360756777672575877693116391 + g1 = 21318636632361225103955470331868462398471880609949088574192481281746934874025 + return fp2.mul(a0, a1, g0, g1) + +# GAMMA_2_i + +def mul_by_gamma_2_1(a0, a1): + g0 = 1881798392815877688876180778159931906057091683336018750908411925848733129714 + return fp2.scalar_mul(a0, a1, g0) + +def mul_by_gamma_2_2(a0, a1): + g0 = 17419166386535333598783630241015674584964973961482396687585055285806960741276 + return fp2.scalar_mul(a0, a1, g0) + +def mul_by_gamma_2_3(a0, a1): + g0 = 15537367993719455909907449462855742678907882278146377936676643359958227611562 + return fp2.scalar_mul(a0, a1, g0) + +def mul_by_gamma_2_4(a0, a1): + g0 = 20006444479023397533370224967097343182639219473961804911780625968796493078869 + return fp2.scalar_mul(a0, a1, g0) + +def mul_by_gamma_2_5(a0, a1): + g0 = 4469076485303941623462775504241600503731337195815426975103982608838265467307 + return fp2.scalar_mul(a0, a1, g0) + +# GAMMA_3_i + +def mul_by_gamma_3_1(a0, a1): + g0 = 3649295186494431467217240962842301358951278585756714214031945394966344685949 + g1 = 17372117152826387298350653207345606612066102743297871578090761045572893546809 + return fp2.mul(a0, a1, g0, g1) + +def mul_by_gamma_3_2(a0, a1): + g0 = 14543349330631744552586812320441124107441202078168618766450326117520897829805 + g1 = 4646831431411403714092965637071058625728899792817054432901795759277546050476 + return fp2.mul(a0, a1, g0, g1) + +def mul_by_gamma_3_3(a0, a1): + g0 = 5058246444467529146795605864300346278139276634433627416040487689269555906334 + g1 = 1747732256529211876667641288188566325860867395306999418986313414135550739840 + return fp2.mul(a0, a1, g0, g1) + +def mul_by_gamma_3_4(a0, a1): + g0 = 3025265262868802913511075437173590487338001780554453930995247874855578067679 + g1 = 10425289180741305073643362413949631488281652900778689227251281048515799234257 + return fp2.mul(a0, a1, g0, g1) + +def mul_by_gamma_3_5(a0, a1): + g0 = 9862576063628467829192720579684130652367741026604221989510773554027227469215 + g1 = 16681752610922605480353377694363181135019829138759259603037557916788351015335 + return fp2.mul(a0, a1, g0, g1) + +def main(): + fp12_a = (monty.ONE, monty.TWO, monty.ONE, monty.TWO, monty.ONE, monty.TWO, monty.ONE, monty.TWO, monty.ONE, monty.TWO, monty.ONE, monty.TWO) + result = frobenius(*fp12_a) + result = frobenius(*result) + result = frobenius(*result) + result = frobenius(*result) + result = frobenius(*result) + result = frobenius(*result) + result = frobenius(*result) + result = frobenius(*result) + result = frobenius(*result) + result = frobenius(*result) + result = frobenius(*result) + result = frobenius(*result) + + assert(result[0] == fp12_a[0]) + assert(result[1] == fp12_a[1]) + assert(result[2] == fp12_a[2]) + assert(result[3] == fp12_a[3]) + assert(result[4] == fp12_a[4]) + assert(result[5] == fp12_a[5]) + assert(result[6] == fp12_a[6]) + assert(result[7] == fp12_a[7]) + assert(result[8] == fp12_a[8]) + assert(result[9] == fp12_a[9]) + assert(result[10] == fp12_a[10]) + assert(result[11] == fp12_a[11]) + + result = frobenius_square(*fp12_a) + result = frobenius_square(*result) + result = frobenius_square(*result) + result = frobenius_square(*result) + result = frobenius_square(*result) + result = frobenius_square(*result) + + assert(result[0] == fp12_a[0]) + assert(result[1] == fp12_a[1]) + assert(result[2] == fp12_a[2]) + assert(result[3] == fp12_a[3]) + assert(result[4] == fp12_a[4]) + assert(result[5] == fp12_a[5]) + assert(result[6] == fp12_a[6]) + assert(result[7] == fp12_a[7]) + assert(result[8] == fp12_a[8]) + assert(result[9] == fp12_a[9]) + assert(result[10] == fp12_a[10]) + assert(result[11] == fp12_a[11]) + + result = frobenius_cube(*fp12_a) + result = frobenius_cube(*result) + result = frobenius_cube(*result) + result = frobenius_cube(*result) + + assert(result[0] == fp12_a[0]) + assert(result[1] == fp12_a[1]) + assert(result[2] == fp12_a[2]) + assert(result[3] == fp12_a[3]) + assert(result[4] == fp12_a[4]) + assert(result[5] == fp12_a[5]) + assert(result[6] == fp12_a[6]) + assert(result[7] == fp12_a[7]) + assert(result[8] == fp12_a[8]) + assert(result[9] == fp12_a[9]) + assert(result[10] == fp12_a[10]) + assert(result[11] == fp12_a[11]) + +if __name__ == '__main__': + main() diff --git a/scripts/g2.py b/scripts/g2.py new file mode 100644 index 00000000..b3b7265e --- /dev/null +++ b/scripts/g2.py @@ -0,0 +1,24 @@ +import fp2 +import montgomery as monty + +# Neg function for G2 in affine coordinates +def neg(x0,x1, y0, y1): + y0,y1= fp2.neg(y0,y1) + return (x0,x1,y0,y1) + +# G2 function to go back and forth between affine and projective coordinates +def from_affine(x0,x1,y0,y1): + if x0 == 0 and x1 == 0 and y0 == 0 and y1 == 0: + return (monty.ONE, 0, monty.ONE, 0, 0, 0) + + z0 = monty.ONE + z1 = 0 + return (x0,x1,y0,y1,z0,z1) + +def into_affine(x0,x1,y0,y1,z0,z1): + + z0, z1 = fp2.inv(z0,z1) + x0, x1 = fp2.mul(x0,x1,z0,z1) + y0, y1 = fp2.mul(y0,y1,z0,z1) + + return (x0,x1,y0,y1) diff --git a/scripts/homogeneous_projective_point.py b/scripts/homogeneous_projective_point.py new file mode 100644 index 00000000..b80076b0 --- /dev/null +++ b/scripts/homogeneous_projective_point.py @@ -0,0 +1,104 @@ +import montgomery as monty + +INFINITY = (0, monty.ONE, 0) + +def from_affine(x, y): + if x == 0 and y == 0: + return INFINITY + return x, y, monty.ONE + +def into_affine(x, y, z): + if z == 0: + return 0, 0 + return monty.div(x, z), monty.div(y, z) + +def double(x, y, z): + x_squared = monty.mul(x, x) + t = monty.add(x_squared, monty.add(x_squared, x_squared)) + yz = monty.mul(y, z) + u = monty.add(yz, yz) + uxy = monty.mul(u, monty.mul(x, y)) + v = monty.add(uxy, uxy) + w = monty.sub(monty.mul(t, t), monty.add(v, v)) + + doubled_x = monty.mul(u, w) + uy = monty.mul(u, y) + uy_squared = monty.mul(uy, uy) + doubled_y = monty.sub(monty.mul(t, monty.sub(v, w)), monty.add(uy_squared, uy_squared)) + doubled_z = monty.mul(u, monty.mul(u, u)) + + return doubled_x, doubled_y, doubled_z + +# P + Q = R +# xp, yp, zp, xq, yq, zq, xr, yr, zr are all in Montgomery form +def add(xp, yp, zp, xq, yq, zq): + if zp == 0: + return xq, yq, zq + if zq == 0: + return xp, yp, zp + if xp == xq and yp == yq: + return double(xp, yp, zp) + + t0 = monty.mul(yp, zq) + t1 = monty.mul(yq, zp) + t = monty.sub(t0, t1) + u0 = monty.mul(xp, zq) + u1 = monty.mul(xq, zp) + u = monty.sub(u0, u1) + u2 = monty.mul(u, u) + u3 = monty.mul(u2, u) + v = monty.mul(zp, zq) + w = monty.sub(monty.mul(monty.mul(t, t), v), monty.mul(u2, monty.add(u0, u1))) + + xr = monty.mul(u, w) + yr = monty.sub(monty.mul(t, monty.sub(monty.mul(u0, u2), w)), monty.mul(t0, u3)) + zr = monty.mul(u3, v) + + return xr, yr, zr + +def mul(x, y, z, scalar): + x_res, y_res, z_res = INFINITY + + while scalar > 0: + if scalar & 1 != 0: + x_res, y_res, z_res = add(x_res, y_res, z_res, x, y, z) + x, y, z = double(x, y, z) + scalar >>= 1 + + return x_res, y_res, z_res + +def main(): + affine_p = (monty.ONE, monty.TWO) + projective_p = from_affine(*affine_p) + assert(projective_p == (monty.ONE, monty.TWO, monty.ONE)) + assert(affine_p == into_affine(*projective_p)) + + # P + P = 2P + projective_doubled_p = double(*projective_p) + affine_doubled_p = into_affine(*projective_doubled_p) + assert((monty.out_of(affine_doubled_p[0]), monty.out_of(affine_doubled_p[1])) == (1368015179489954701390400359078579693043519447331113978918064868415326638035, 9918110051302171585080402603319702774565515993150576347155970296011118125764)) + + # P + O = P = P * 1 + projective_addition = add(*projective_p, *INFINITY) + affine_addition = into_affine(*projective_addition) + assert(affine_addition == (monty.ONE, monty.TWO)) + assert(mul(*projective_p, 1) == projective_p) + assert(mul(*projective_p, 1) == projective_addition) + + # O + P = P = P * 1 + projective_addition = add(*INFINITY, *projective_p) + affine_addition = into_affine(*projective_addition) + assert(affine_addition == (monty.ONE, monty.TWO)) + assert(mul(*projective_p, 1) == projective_p) + assert(mul(*projective_p, 1) == projective_addition) + + # P + Q = R + # P + 2P = 3P + # 3353031288059533942658390886683067124040920775575537747144343083137631628272, 19321533766552368860946552437480515441416830039777911637913418824951667761761 + projective_addition = add(*projective_p, *projective_doubled_p) + affine_addition = into_affine(*projective_addition) + assert((monty.out_of(affine_addition[0]), monty.out_of(affine_addition[1])) == (3353031288059533942658390886683067124040920775575537747144343083137631628272, 19321533766552368860946552437480515441416830039777911637913418824951667761761)) + assert(mul(*projective_p, 3) == projective_addition) + +if __name__ == '__main__': + main() diff --git a/scripts/jacobian_projective_point.py b/scripts/jacobian_projective_point.py new file mode 100644 index 00000000..a6d761f8 --- /dev/null +++ b/scripts/jacobian_projective_point.py @@ -0,0 +1,131 @@ +import montgomery as monty + +INFINITY = (0, 0, 0) + +def from_affine(x, y): + if x == 0 and y == 0: + return INFINITY + return x, y, monty.ONE + +def into_affine(x, y, z): + if is_infinity(x, y, z): + return 0, 0 + t1 = monty.inv(z) + t2 = monty.exp(t1, 2) + + x = monty.mul(x, t2) + y = monty.mul(y, monty.mul(t1, t2)) + + return x, y + +def is_infinity(_x, _y, z): + return z == 0 + +def neg(x, y, z): + return x, monty.sub(0, y), z + +def double(x, y, z): + if is_infinity(x, y, z): + return x, y, z + if y == 0: + return INFINITY + xx = monty.mul(x, x) + yy = monty.mul(y, y) + zz = monty.mul(z, z) + yyyy = monty.mul(yy, yy) + + zzzz = monty.mul(zz, zz) + + # All the following multiplications by scalars could be replaced by successive additions. + s = monty.mul(monty.FOUR, monty.mul(x, yy)) + # y^2 = x^3 + ax + b with a == 0 + m = monty.mul(monty.THREE, xx) + x0 = monty.sub(monty.exp(m, 2), monty.mul(monty.TWO, s)) + y0 = monty.sub(monty.mul(m, monty.sub(s, x0)), monty.mul(monty.EIGHT, yyyy)) + z0 = monty.mul(monty.mul(y, z), monty.TWO) + + return x0, y0, z0 + +def add(xp, yp, zp, xq, yq, zq): + if is_infinity(xp, yp, zp): + return xq, yq, zq + elif is_infinity(xq, yq, zq): + return xp, yp, zp + else: + zpzp = monty.mul(zp, zp) + zqzq = monty.mul(zq, zq) + + t1 = monty.mul(xp, zqzq) + t2 = monty.mul(xq, zpzp) + + s1 = monty.mul(yp, monty.mul(zq, zqzq)) + s2 = monty.mul(yq, monty.mul(zp, zpzp)) + + if t1 == t2: + if s1 != s2: + return INFINITY + else: + return double(xp, yp, zp) + else: + h = monty.sub(t2, t1) + r = monty.sub(s2, s1) + + hh = monty.mul(h, h) + hhh = monty.mul(hh, h) + x3 = monty.sub(monty.mul(r, r), hhh) + x3 = monty.sub(x3, monty.mul(monty.mul(t1, hh), monty.TWO)) + y3 = monty.mul(r, monty.sub(monty.mul(t1, hh), x3)) + y3 = monty.sub(y3, monty.mul(s1, hhh)) + z3 = monty.mul(h, monty.mul(zp, zq)) + + return x3, y3, z3 + +def sub(xp, yp, zp, xq, yq, zq): + add(xp, yp, zp, neg(xq, yq, zq)) + +def mul(x, y, z, scalar): + x_res, y_res, z_res = INFINITY + + while scalar > 0: + if scalar & 1 != 0: + x_res, y_res, z_res = add(x_res, y_res, z_res, x, y, z) + x, y, z = double(x, y, z) + scalar >>= 1 + + return x_res, y_res, z_res + +def main(): + affine_p = (monty.ONE, monty.TWO) + jacobian_projective_p = from_affine(*affine_p) + assert(jacobian_projective_p == (monty.ONE, monty.TWO, monty.ONE)) + assert(affine_p == into_affine(*jacobian_projective_p)) + + # P + P = 2P + projective_doubled_p = double(*jacobian_projective_p) + affine_doubled_p = into_affine(*projective_doubled_p) + assert((monty.out_of(affine_doubled_p[0]), monty.out_of(affine_doubled_p[1])) == (1368015179489954701390400359078579693043519447331113978918064868415326638035, 9918110051302171585080402603319702774565515993150576347155970296011118125764)) + + # P + O = P = P * 1 + projective_addition = add(*jacobian_projective_p, *INFINITY) + affine_addition = into_affine(*projective_addition) + assert(affine_addition == (monty.ONE, monty.TWO)) + assert(mul(*jacobian_projective_p, 1) == jacobian_projective_p) + assert(mul(*jacobian_projective_p, 1) == projective_addition) + + # O + P = P = P * 1 + projective_addition = add(*INFINITY, *jacobian_projective_p) + affine_addition = into_affine(*projective_addition) + assert(affine_addition == (monty.ONE, monty.TWO)) + assert(mul(*jacobian_projective_p, 1) == jacobian_projective_p) + assert(mul(*jacobian_projective_p, 1) == projective_addition) + + # P + Q = R + # P + 2P = 3P + # 3353031288059533942658390886683067124040920775575537747144343083137631628272, 19321533766552368860946552437480515441416830039777911637913418824951667761761 + projective_addition = add(*jacobian_projective_p, *projective_doubled_p) + affine_addition = into_affine(*projective_addition) + assert((monty.out_of(affine_addition[0]), monty.out_of(affine_addition[1])) == (3353031288059533942658390886683067124040920775575537747144343083137631628272, 19321533766552368860946552437480515441416830039777911637913418824951667761761)) + assert(mul(*jacobian_projective_p, 3) == projective_addition) + +if __name__ == '__main__': + main() diff --git a/scripts/montgomery.py b/scripts/montgomery.py new file mode 100644 index 00000000..e62a39bc --- /dev/null +++ b/scripts/montgomery.py @@ -0,0 +1,131 @@ +import math + +# 2^256 +R = 115792089237316195423570985008687907853269984665640564039457584007913129639936 +R_PRIME = 20988524275117001072002809824448087578619730785600314334253784976379291040311 +# R^2 = (2^256)^2 = 2^512 +R2 = 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096 +# R^3 = (2^256)^3 = 2^768 +R3 = 1552518092300708935148979488462502555256886017116696611139052038026050952686376886330878408828646477950487730697131073206171580044114814391444287275041181139204454976020849905550265285631598444825262999193716468750892846853816057856 +# R3 % N +R3_MOD_N = 14921786541159648185948152738563080959093619838510245177710943249661917737183 +# Fp +N = 21888242871839275222246405745257275088696311157297823662689037894645226208583 +# R2 % N +R2_MOD_N = 3096616502983703923843567936837374451735540968419076528771170197431451843209 +# N' -> NN' ≡ −1 mod R +N_PRIME = 111032442853175714102588374283752698368366046808579839647964533820976443843465 + +ONE = 6350874878119819312338956282401532409788428879151445726012394534686998597021 +TWO = 12701749756239638624677912564803064819576857758302891452024789069373997194042 +THREE = 19052624634359457937016868847204597229365286637454337178037183604060995791063 +FOUR = 3515256640640002027109419384348854550457404359307959241360540244102768179501 +FIVE = 9866131518759821339448375666750386960245833238459404967372934778789766776522 +SIX = 16217006396879640651787331949151919370034262117610850693385329313476765373543 +SEVEN = 679638403160184741879882486296176691126379839464472756708685953518537761981 +EIGHT = 7030513281280004054218838768697709100914808718615918482721080488205536359002 +NINE = 13381388159399823366557795051099241510703237597767364208733475022892534956023 +TEN = 19732263037519642678896751333500773920491666476918809934745869557579533553044 + +# Extended euclidean algorithm to find modular inverses for integers. +def prime_field_inv(a, modulus): + if a == 0: + return 0 + lm, hm = 1, 0 + low, high = a % modulus, modulus + while low > 1: + r = high // low + nm, new = hm - lm * r, high - low * r + lm, low, hm, high = nm, new, lm, low + return lm % modulus + +def binary_extended_euclidean_algorithm(a, modulus): + modulus_has_spare_bits = modulus >> 255 == 0 + + u = a + v = modulus + b = R2_MOD_N + c = 0 + + while u != 1 and v != 1: + while u & 1 == 0: + u >>= 1 + if b & 1 == 0: + b >>= 1 + else: + b += modulus + carry = b >> 256 + b >>= 1 + if not modulus_has_spare_bits and carry > 0: + b |= 1 << 255 + + while v & 1 == 0: + v >>= 1 + if c & 1 == 0: + c >>= 1 + else: + c += modulus + carry = c >> 256 + c >>= 1 + if not modulus_has_spare_bits and carry > 0: + c |= 1 << 255 + if v <= u: + u -= v + if b < c: + b += modulus + b -= c + else: + v -= u + if c < b: + c += modulus + c -= b + + if u == 1: + return b + + return c +# Montgomery reduction algorithm +def REDC(n): + m = (n % R) * N_PRIME % R + t = ((m * N) + n) // R + if t >= N: + t -= N + return t + +# REDC((a mod N)(R2 mod N)) +def into(a): + return REDC((a % N) * R2_MOD_N) + +# REDC(aR mod N) +def out_of(a_mont): + return REDC(a_mont) + +# REDC((aR mod N)(bR mod N)) +def mul(a_mont, b_mont): + return REDC(a_mont * b_mont) + +def exp(base, exponent): + pow = into(1) + while exponent > 0: + if exponent % 2 == 1: + pow = mul(pow, base) + exponent = exponent >> 1 + base = mul(base, base) + return pow + +# def montgomery_modular_inverse(a): +# a_inv = prime_field_inv(a, N) +# return REDC(a_inv * R3_MOD_N) + +def inv(a): + return binary_extended_euclidean_algorithm(a, N) + +def div(dividend, divisor): + divisor_inv = inv(divisor) + return mul(dividend, divisor_inv) + +def add(augend, addend): + return (augend + addend) % N + +def sub(minuend, subtrahend): + return add(minuend, N - subtrahend) diff --git a/scripts/pairing_utils.py b/scripts/pairing_utils.py new file mode 100644 index 00000000..ed964de2 --- /dev/null +++ b/scripts/pairing_utils.py @@ -0,0 +1,27 @@ +import montgomery as monty +import fp2 + +# r = 36x**4 + 36x**3 + 18x**2 + 6x + 1 +# t = 6x**2 + 1 +# x = 4965661367192848881 +# s = 6x + 2 -> s = 29793968203157093288 +S_NAF = [0, 0, 0, 1, 0, 1, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, + 0, 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0, 1, 0, -1, 0, 0, 1, 0, 0, 0, 0, + 0, -1, 0, 0, -1, 0, 1, 0, -1, 0, 0, 0, -1, 0, -1, 0, 0, 0, 1, 0, -1, 0, 1] +TWISTED_CURVE_COEFFS = (monty.into(19485874751759354771024239261021720505790618469301721065564631296452457478373), monty.into(266929791119991161246907387137283842545076965332900288569378510910307636690)) + +def is_in_curve(x, y): + x = monty.out_of(x) + y = monty.out_of(y) + + N = 21888242871839275222246405745257275088696311157297823662689037894645226208583 + a = y ** 2 % N + b = x ** 3 % N + b = (b + 3) % N + return a == b + +def is_in_twisted_curve(x0, x1, y0, y1): + b = fp2.exp(x0, x1, 3) + b = fp2.add(*b, *TWISTED_CURVE_COEFFS) + c = fp2.exp(y0, y1, 2) + return b == c diff --git a/scripts/test_case_gen.py b/scripts/test_case_gen.py index 89d469b5..071cf30b 100644 --- a/scripts/test_case_gen.py +++ b/scripts/test_case_gen.py @@ -5,10 +5,10 @@ import re TEST_DIRS = [ - '/Users/ivanlitteri/Lambda/tests/GeneralStateTests/stZeroKnowledge', - '/Users/ivanlitteri/Lambda/tests/GeneralStateTests/stZeroKnowledge2', - '/Users/ivanlitteri/Lambda/tests/GeneralStateTests/stPreCompiledContracts', - '/Users/ivanlitteri/Lambda/tests/GeneralStateTests/stPreCompiledContracts2' + '../submodules/eth-tests/GeneralStateTests/stZeroKnowledge', + '../submodules/eth-tests/GeneralStateTests/stZeroKnowledge2', + '../submodules/eth-tests/GeneralStateTests/stPreCompiledContracts', + '../submodules/eth-tests/GeneralStateTests/stPreCompiledContracts2' ] ParserState = enum.Enum('ParserState', ['INPUT', 'NOT_INPUT']) @@ -93,7 +93,8 @@ def main(): }) continue elif precompile == "ecpairing": - continue + # Skips "0x" and the first 136 bytes + calldata = calldata[0][138:] if precompile not in tests_data: tests_data[precompile] = [] @@ -105,8 +106,9 @@ def main(): }) for precompile, precompile_test_data in tests_data.items(): - with open(f'/Users/ivanlitteri/Lambda/zksync_era_precompiles/tests/tests/{precompile}_tests.rs', 'w') as test_file: - write_test_suit(precompile, precompile_test_data, test_file) + if precompile == "ecpairing": + with open(f'../tests/tests/{precompile}_tests.rs', 'w') as test_file: + write_test_suit(precompile, precompile_test_data, test_file) if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/tests/tests/ecpairing_tests.rs b/tests/tests/ecpairing_tests.rs new file mode 100644 index 00000000..5a7de1f4 --- /dev/null +++ b/tests/tests/ecpairing_tests.rs @@ -0,0 +1,230 @@ +use hex; +use zksync_web3_rs::{zks_utils::ECPAIRING_PRECOMPILE_ADDRESS, types::Bytes}; + +mod test_utils; +use test_utils::{eth_call, era_call}; + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_empty_data_insufficient_gas() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_perturb_g2_by_curve_order() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c248652d61f350be9ffaba461cdfdd9cd68f770b1d71184b6e8ac0b2f0c992f6ee090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c248652d61f350be9ffaba461cdfdd9cd68f770b1d71184b6e8ac0b2f0c992f6ee090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_bad_length_191() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7d00").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7d00").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_perturb_zeropoint_by_one() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_one_point_with_g1_zero() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_perturb_g2_by_field_modulus() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed396ad8433991909fa4eedf63ea8d8bf353cc9bc4d925598091cd66f3a99f94a212c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed396ad8433991909fa4eedf63ea8d8bf353cc9bc4d925598091cd66f3a99f94a212c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Use the ecpairing checker with one point, where g1 is not on the curve but g2 is zero. cpp-ethereum once had a bug in this case; as soon as cpp-ethereum recognized g2 zero, it returned something without checking the validity of g1 +#[tokio::test] +async fn ecpairing_one_point_with_g2_zero_and_g1_invalid() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Use the ecpairing checker with one point, where g1 is not on the curve but g2 is zero. cpp-ethereum once had a bug in this case; as soon as cpp-ethereum recognized g2 zero, it returned something without checking the validity of g1"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_two_point_match_1() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_two_point_fail_1() { + assert!(eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.is_err()); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + assert_eq!(era_response, Bytes::from(&[0])); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_two_point_oog() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_three_point_fail_1() { + assert!(eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f00cacf3523caf879d7d05e30549f1e6fdce364cbb8724b0329c6c2a39d4f018e0692e55db067300e6e3fe56218fa2f940054e57e7ef92bf7d475a9d8a8502fd200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.is_err()); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f00cacf3523caf879d7d05e30549f1e6fdce364cbb8724b0329c6c2a39d4f018e0692e55db067300e6e3fe56218fa2f940054e57e7ef92bf7d475a9d8a8502fd200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + assert_eq!(era_response, Bytes::from(&[0])); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_one_point_insufficient_gas() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_empty_data() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_two_point_match_4() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_perturb_g2_by_one() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c31800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c31800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_three_point_match_1() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_two_point_match_5() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_two_point_match_2() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_two_point_fail_2() { + assert!(eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd03042700000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002105384b6dd6c48634b9fe89cb3e19667c1fe6736c69df070d674c95a42b3b8242c0d8e67f0f2c14c43734b430d8be4265af8c4f7a67deb0b029fd2dff99cc6b9015eaec465d922580c7de5d4a5c26de75eaf2af6841b7412ef2eebd1e051076f1b4c21849e48de12d1bae2bad3299717aa8664ade430e19dec72a6e10a39b0ab").unwrap()))).await.is_err()); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd03042700000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002105384b6dd6c48634b9fe89cb3e19667c1fe6736c69df070d674c95a42b3b8242c0d8e67f0f2c14c43734b430d8be4265af8c4f7a67deb0b029fd2dff99cc6b9015eaec465d922580c7de5d4a5c26de75eaf2af6841b7412ef2eebd1e051076f1b4c21849e48de12d1bae2bad3299717aa8664ade430e19dec72a6e10a39b0ab").unwrap()))).await.unwrap(); + assert_eq!(era_response, Bytes::from(&[0])); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_two_points_with_one_g2_zero() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_perturb_g2_by_field_modulus_again() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b432cad18bcbe0e1502fbb7370f4c98ed7b5351fa74b59e08890758183f777af1").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b432cad18bcbe0e1502fbb7370f4c98ed7b5351fa74b59e08890758183f777af1").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_perturb_zeropoint_by_field_modulus() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd470000000000000000000000000000000000000000000000000000000000000000198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd470000000000000000000000000000000000000000000000000000000000000000198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_perturb_zeropoint_by_curve_order() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010000000000000000000000000000000000000000000000000000000000000000198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010000000000000000000000000000000000000000000000000000000000000000198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_one_point_with_g2_zero() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_one_point_not_in_subgroup() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800d3270b7da683f988d3889abcdad9776ecd45abaca689f1118c3fd33404b4392588360d269af2cd3e0803839ea274c2b8f062a6308e8da85fd774c26f1bcb87").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800d3270b7da683f988d3889abcdad9776ecd45abaca689f1118c3fd33404b4392588360d269af2cd3e0803839ea274c2b8f062a6308e8da85fd774c26f1bcb87").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_bad_length_193() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa0000000000000000000000000000000000000000000000000000000000000000").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa0000000000000000000000000000000000000000000000000000000000000000").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_two_point_match_3() { + let eth_response = eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + assert_eq!(eth_response, era_response, "Puts the given data into the ECPAIRING precompile"); +} + +// Puts the given data into the ECPAIRING precompile +#[tokio::test] +async fn ecpairing_one_point_fail() { + assert!(eth_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.is_err()); + let era_response = era_call(ECPAIRING_PRECOMPILE_ADDRESS, None, Some(Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa").unwrap()))).await.unwrap(); + assert_eq!(era_response, Bytes::from(&[0])); +} +