struct CurvePoint { int x; int y; int z; int t; } struct TwistPoint { FQ2 x; FQ2 y; FQ2 z; FQ2 t; } struct FQ2 { int x; int y; } struct FQ6 { FQ2 x; FQ2 y; FQ2 z; } struct FQ12 { FQ6 x; FQ6 y; } struct G1Point { int x; int y; } struct G2Point { FQ2 x; FQ2 y; } struct LineFuncRes { FQ2 a; FQ2 b; FQ2 c; TwistPoint rOut; } library BN256 { static const CurvePoint G1 = {1, 2, 1, 1}; static const TwistPoint G2 = {{11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781}, {4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930}, {0, 1}, {0, 1}}; static const FQ2 FQ2Zero = {0, 0}; static const FQ2 FQ2One = {0, 1}; static const FQ6 FQ6Zero = {BN256.FQ2Zero, BN256.FQ2Zero, BN256.FQ2Zero}; static const FQ6 FQ6One = {BN256.FQ2Zero, BN256.FQ2Zero, BN256.FQ2One}; static const FQ12 FQ12Zero = {BN256.FQ6Zero, BN256.FQ6Zero}; static const FQ12 FQ12One = {BN256.FQ6Zero, BN256.FQ6One}; static const int P = 21888242871839275222246405745257275088696311157297823662689037894645226208583; static const FQ2 xiToPMinus1Over6 = {16469823323077808223889137241176536799009286646108169935659301613961712198316, 8376118865763821496583973867626364092589906065868298776909617916018768340080}; static const FQ2 xiTo2PMinus2Over3 = {19937756971775647987995932169929341994314640652964949448313374472400716661030, 2581911344467009335267311115468803099551665605076196740867805258568234346338}; static const FQ2 xiToPMinus1Over2 = {3505843767911556378687030309984248845540243509899259641013678093033130930403, 2821565182194536844548159561693502659359617185244120367078079554186484126554}; static const FQ2 xiToPMinus1Over3 = {10307601595873709700152284273816112264069230130616436755625194854815875713954, 21575463638280843010398324269430826099269044274347216827212613867836435027261}; static const int xiTo2PSquaredMinus2Over3 = 2203960485148121921418603742825762020974279258880205651966; static const int xiToPSquaredMinus1Over3 = 21888242871839275220042445260109153167277707414472061641714758635765020556616; static const int xiToPSquaredMinus1Over6 = 21888242871839275220042445260109153167277707414472061641714758635765020556617; static function compareFQ2(FQ2 a, FQ2 b) : bool { return a.x == b.x && a.y == b.y; } static function compareFQ6(FQ6 a, FQ6 b) : bool { return (a.x.x == b.x.x && a.x.y == b.x.y && a.y.x == b.y.x && a.y.y == b.y.y && a.z.x == b.z.x && a.z.y == b.z.y); } static function compareFQ12(FQ12 a, FQ12 b) : bool { return (a.x.x.x == b.x.x.x && a.x.x.y == b.x.x.y && a.x.y.x == b.x.y.x && a.x.y.y == b.x.y.y && a.x.z.x == b.x.z.x && a.x.z.y == b.x.z.y && a.y.x.x == b.y.x.x && a.y.x.y == b.y.x.y && a.y.y.x == b.y.y.x && a.y.y.y == b.y.y.y && a.y.z.x == b.y.z.x && a.y.z.y == b.y.z.y); } static function compareCurvePoints(CurvePoint a, CurvePoint b) : bool { return a.x == b.x && a.y == b.y && a.z == b.z && a.t == b.t; } static function compareTwistPoints(TwistPoint a, TwistPoint b) : bool { return (a.x.x == b.x.x && a.x.y == b.x.y && a.y.x == b.y.x && a.y.y == b.y.y && a.z.x == b.z.x && a.z.y == b.z.y && a.t.x == b.t.x && a.t.y == b.t.y); } static function modReduce(int x, int modulus) : int { int res = x % modulus; return res < 0 ? res + modulus : res; } static function modFQ2(FQ2 t0) : FQ2 { t0.x = BN256.modReduce(t0.x, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.y = BN256.modReduce(t0.y, 21888242871839275222246405745257275088696311157297823662689037894645226208583); return t0; } static function modFQ12(FQ12 t0) : FQ12 { t0.x.x.x = BN256.modReduce(t0.x.x.x, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.x.x.y = BN256.modReduce(t0.x.x.y, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.x.y.x = BN256.modReduce(t0.x.y.x, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.x.y.y = BN256.modReduce(t0.x.y.y, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.x.z.x = BN256.modReduce(t0.x.z.x, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.x.z.y = BN256.modReduce(t0.x.z.y, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.y.x.x = BN256.modReduce(t0.y.x.x, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.y.x.y = BN256.modReduce(t0.y.x.y, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.y.y.x = BN256.modReduce(t0.y.y.x, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.y.y.y = BN256.modReduce(t0.y.y.y, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.y.z.x = BN256.modReduce(t0.y.z.x, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.y.z.y = BN256.modReduce(t0.y.z.y, 21888242871839275222246405745257275088696311157297823662689037894645226208583); return t0; } static function modCurvePoint(CurvePoint t0) : CurvePoint { t0.x = BN256.modReduce(t0.x, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.y = BN256.modReduce(t0.y, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.z = BN256.modReduce(t0.z, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.t = BN256.modReduce(t0.t, 21888242871839275222246405745257275088696311157297823662689037894645226208583); return t0; } static function modTwistPoint(TwistPoint t0) : TwistPoint { t0.x.x = BN256.modReduce(t0.x.x, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.x.y = BN256.modReduce(t0.x.y, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.y.x = BN256.modReduce(t0.y.x, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.y.y = BN256.modReduce(t0.y.y, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.z.x = BN256.modReduce(t0.z.x, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.z.y = BN256.modReduce(t0.z.y, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.t.x = BN256.modReduce(t0.t.x, 21888242871839275222246405745257275088696311157297823662689037894645226208583); t0.t.y = BN256.modReduce(t0.t.y, 21888242871839275222246405745257275088696311157297823662689037894645226208583); return t0; } static function mulFQ2(FQ2 a, FQ2 b) : FQ2 { int tx = a.x * b.y; int t = b.x * a.y; int tx_2 = tx + t; int ty = a.y * b.y; int t_2 = a.x * b.x; int ty_2 = ty - t_2; return {BN256.modReduce(tx_2, 21888242871839275222246405745257275088696311157297823662689037894645226208583), BN256.modReduce(ty_2, 21888242871839275222246405745257275088696311157297823662689037894645226208583)}; } static function mulXiFQ2(FQ2 a) : FQ2 { int tx = 9 * a.x + a.y; int ty = 9 * a.y - a.x; return {BN256.modReduce(tx, 21888242871839275222246405745257275088696311157297823662689037894645226208583), BN256.modReduce(ty, 21888242871839275222246405745257275088696311157297823662689037894645226208583)}; } static function mulScalarFQ2(FQ2 a, int scalar) : FQ2 { return {BN256.modReduce(a.x * scalar, 21888242871839275222246405745257275088696311157297823662689037894645226208583), BN256.modReduce(a.y * scalar, 21888242871839275222246405745257275088696311157297823662689037894645226208583)}; } static function addFQ2(FQ2 a, FQ2 b) : FQ2 { FQ2 res = {BN256.modReduce(a.x + b.x, 21888242871839275222246405745257275088696311157297823662689037894645226208583), BN256.modReduce(a.y + b.y, 21888242871839275222246405745257275088696311157297823662689037894645226208583)}; return res; } static function subFQ2(FQ2 a, FQ2 b) : FQ2 { FQ2 res = {BN256.modReduce(a.x - b.x, 21888242871839275222246405745257275088696311157297823662689037894645226208583), BN256.modReduce(a.y - b.y, 21888242871839275222246405745257275088696311157297823662689037894645226208583)}; return res; } static function negFQ2(FQ2 a) : FQ2 { FQ2 res = {BN256.modReduce(a.x * -1, 21888242871839275222246405745257275088696311157297823662689037894645226208583), BN256.modReduce(a.y * -1, 21888242871839275222246405745257275088696311157297823662689037894645226208583)}; return res; } static function conjugateFQ2(FQ2 a) : FQ2 { FQ2 res = {BN256.modReduce(a.x * -1, 21888242871839275222246405745257275088696311157297823662689037894645226208583), BN256.modReduce(a.y, 21888242871839275222246405745257275088696311157297823662689037894645226208583)}; return res; } static function doubleFQ2(FQ2 a) : FQ2 { FQ2 res = {BN256.modReduce(a.x * 2, 21888242871839275222246405745257275088696311157297823662689037894645226208583), BN256.modReduce(a.y * 2, 21888242871839275222246405745257275088696311157297823662689037894645226208583)}; return res; } static function squareFQ2(FQ2 a) : FQ2 { int tx = a.y - a.x; int ty = a.x + a.y; int ty_2 = ty * tx; int tx_2 = a.x * a.y * 2; FQ2 res = {BN256.modReduce(tx_2, 21888242871839275222246405745257275088696311157297823662689037894645226208583), BN256.modReduce(ty_2, 21888242871839275222246405745257275088696311157297823662689037894645226208583)}; return res; } static function modInverseBranchlessP(int x) : int { asm { 47fd7cd8168c203c8dca7168916a81975d588181b64550b829a031e1724e6430 OP_SWAP OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_MUL OP_OVER OP_MOD OP_DUP OP_TOALTSTACK OP_DUP OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_FROMALTSTACK OP_MUL OP_OVER OP_MOD OP_NIP}} static function modInverseEGCD(int x, int m) : int { x = BN256.modReduce(x, 21888242871839275222246405745257275088696311157297823662689037894645226208583); int t = 0; int newt = 1; int r = m; int newr = x; int quotient = 0; int tmp = 0; loop (368) : i { if(newr != 0) { quotient = r / newr; tmp = newt; newt = t - quotient * newt; t = tmp; tmp = newr; newr = r - quotient * newr; r = tmp; } } if(t < 0) { t = t + m; } return t; } static function inverseFQ2(FQ2 a) : FQ2 { int t2 = a.y * a.y; int t1 = a.x * a.x + t2; int inv = BN256.modInverseBranchlessP(t1); int axNeg = a.x * -1; FQ2 res = {BN256.modReduce(axNeg * inv, 21888242871839275222246405745257275088696311157297823662689037894645226208583), BN256.modReduce(a.y * inv, 21888242871839275222246405745257275088696311157297823662689037894645226208583)}; return res; } static function mulFQ6(FQ6 a, FQ6 b) : FQ6 { FQ2 v0 = BN256.mulFQ2(a.z, b.z); FQ2 v1 = BN256.mulFQ2(a.y, b.y); FQ2 v2 = BN256.mulFQ2(a.x, b.x); FQ2 t0 = BN256.addFQ2(a.x, a.y); FQ2 t1 = BN256.addFQ2(b.x, b.y); FQ2 tz = BN256.mulFQ2(t0, t1); tz = BN256.subFQ2(tz, v1); tz = BN256.subFQ2(tz, v2); tz = BN256.mulXiFQ2(tz); tz = BN256.addFQ2(tz, v0); t0 = BN256.addFQ2(a.y, a.z); t1 = BN256.addFQ2(b.y, b.z); FQ2 ty = BN256.mulFQ2(t0, t1); ty = BN256.subFQ2(ty, v0); ty = BN256.subFQ2(ty, v1); t0 = BN256.mulXiFQ2(v2); ty = BN256.addFQ2(ty, t0); t0 = BN256.addFQ2(a.x, a.z); t1 = BN256.addFQ2(b.x, b.z); FQ2 tx = BN256.mulFQ2(t0, t1); tx = BN256.subFQ2(tx, v0); tx = BN256.addFQ2(tx, v1); tx = BN256.subFQ2(tx, v2); FQ6 res = {tx, ty, tz}; return res; } static function doubleFQ6(FQ6 a) : FQ6 { FQ6 res = {BN256.doubleFQ2(a.x), BN256.doubleFQ2(a.y), BN256.doubleFQ2(a.z)}; return res; } static function mulScalarFQ6(FQ6 a, FQ2 scalar) : FQ6 { FQ6 res = {BN256.mulFQ2(a.x, scalar), BN256.mulFQ2(a.y, scalar), BN256.mulFQ2(a.z, scalar)}; return res; } static function addFQ6(FQ6 a, FQ6 b) : FQ6 { FQ6 res = {BN256.addFQ2(a.x, b.x), BN256.addFQ2(a.y, b.y), BN256.addFQ2(a.z, b.z)}; return res; } static function subFQ6(FQ6 a, FQ6 b) : FQ6 { FQ6 res = {BN256.subFQ2(a.x, b.x), BN256.subFQ2(a.y, b.y), BN256.subFQ2(a.z, b.z)}; return res; } static function negFQ6(FQ6 a) : FQ6 { FQ6 res = {BN256.negFQ2(a.x), BN256.negFQ2(a.y), BN256.negFQ2(a.z)}; return res; } static function squareFQ6(FQ6 a) : FQ6 { FQ2 v0 = BN256.squareFQ2(a.z); FQ2 v1 = BN256.squareFQ2(a.y); FQ2 v2 = BN256.squareFQ2(a.x); FQ2 c0 = BN256.addFQ2(a.x, a.y); c0 = BN256.squareFQ2(c0); c0 = BN256.subFQ2(c0, v1); c0 = BN256.subFQ2(c0, v2); c0 = BN256.mulXiFQ2(c0); c0 = BN256.addFQ2(c0, v0); FQ2 c1 = BN256.addFQ2(a.y, a.z); c1 = BN256.squareFQ2(c1); c1 = BN256.subFQ2(c1, v0); c1 = BN256.subFQ2(c1, v1); FQ2 xiV2 = BN256.mulXiFQ2(v2); c1 = BN256.addFQ2(c1, xiV2); FQ2 c2 = BN256.addFQ2(a.x, a.z); c2 = BN256.squareFQ2(c2); c2 = BN256.subFQ2(c2, v0); c2 = BN256.addFQ2(c2, v1); c2 = BN256.subFQ2(c2, v2); FQ6 res = {c2, c1, c0}; return res; } static function mulTauFQ6(FQ6 a) : FQ6 { FQ6 res = {a.y, a.z, BN256.mulXiFQ2(a.x)}; return res; } static function inverseFQ6(FQ6 a) : FQ6 { FQ2 A = BN256.squareFQ2(a.z); FQ2 t1 = BN256.mulFQ2(a.x, a.y); t1 = BN256.mulXiFQ2(t1); A = BN256.subFQ2(A, t1); FQ2 B = BN256.squareFQ2(a.x); B = BN256.mulXiFQ2(B); t1 = BN256.mulFQ2(a.y, a.z); B = BN256.subFQ2(B, t1); FQ2 C = BN256.squareFQ2(a.y); t1 = BN256.mulFQ2(a.x, a.z); C = BN256.subFQ2(C, t1); FQ2 F = BN256.mulFQ2(C, a.y); F = BN256.mulXiFQ2(F); t1 = BN256.mulFQ2(A, a.z); F = BN256.addFQ2(F, t1); t1 = BN256.mulFQ2(B, a.x); t1 = BN256.mulXiFQ2(t1); F = BN256.addFQ2(F, t1); F = BN256.inverseFQ2(F); FQ6 res = {BN256.mulFQ2(C, F), BN256.mulFQ2(B, F), BN256.mulFQ2(A, F)}; return res; } static function mulScalarFQ12(FQ12 a, FQ6 scalar) : FQ12 { FQ12 res = {BN256.mulFQ6(a.x, scalar), BN256.mulFQ6(a.y, scalar)}; return res; } static function inverseFQ12(FQ12 a) : FQ12 { FQ6 t1 = BN256.squareFQ6(a.x); FQ6 t2 = BN256.squareFQ6(a.y); FQ6 t1_2 = BN256.mulTauFQ6(t1); FQ6 t1_3 = BN256.subFQ6(t2, t1_2); FQ6 t2_2 = BN256.inverseFQ6(t1_3); FQ12 e = {BN256.negFQ6(a.x), a.y}; return BN256.mulScalarFQ12(e, t2_2); } static function mulFQ12(FQ12 a, FQ12 b) : FQ12 { asm { OP_13 OP_PICK OP_OVER OP_MUL OP_2 OP_PICK OP_14 OP_PICK OP_MUL OP_ADD OP_13 OP_PICK OP_2 OP_PICK OP_MUL OP_15 OP_PICK OP_4 OP_PICK OP_MUL OP_SUB 11 OP_PICK OP_5 OP_PICK OP_MUL OP_6 OP_PICK 12 OP_PICK OP_MUL OP_ADD 11 OP_PICK OP_6 OP_PICK OP_MUL 13 OP_PICK OP_8 OP_PICK OP_MUL OP_SUB 15 OP_PICK OP_9 OP_PICK OP_MUL OP_10 OP_PICK 16 OP_PICK OP_MUL OP_ADD 15 OP_PICK OP_10 OP_PICK OP_MUL 17 OP_PICK OP_12 OP_PICK OP_MUL OP_SUB 17 OP_PICK 16 OP_PICK OP_ADD 17 OP_PICK 16 OP_PICK OP_ADD OP_13 OP_PICK OP_12 OP_PICK OP_ADD OP_13 OP_PICK OP_12 OP_PICK OP_ADD OP_SWAP OP_3 OP_ROLL OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_SWAP OP_5 OP_PICK OP_SUB OP_SWAP OP_4 OP_PICK OP_SUB OP_SWAP OP_3 OP_PICK OP_SUB OP_SWAP OP_2 OP_PICK OP_SUB OP_OVER OP_9 OP_MUL OP_OVER OP_ADD OP_9 OP_ROT OP_MUL OP_ROT OP_SUB OP_SWAP OP_7 OP_PICK OP_ADD OP_SWAP OP_6 OP_PICK OP_ADD 17 OP_PICK 16 OP_PICK OP_ADD 17 OP_PICK 16 OP_PICK OP_ADD OP_13 OP_PICK OP_12 OP_PICK OP_ADD OP_13 OP_PICK OP_12 OP_PICK OP_ADD OP_SWAP OP_3 OP_ROLL OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_SWAP OP_9 OP_PICK OP_SUB OP_SWAP OP_8 OP_PICK OP_SUB OP_SWAP OP_7 OP_PICK OP_SUB OP_SWAP OP_6 OP_PICK OP_SUB OP_5 OP_PICK OP_5 OP_PICK OP_OVER OP_9 OP_MUL OP_OVER OP_ADD OP_9 OP_ROT OP_MUL OP_ROT OP_SUB OP_3 OP_ROLL OP_ROT OP_ADD OP_ROT OP_ROT OP_ADD 1b OP_PICK 18 OP_PICK OP_ADD 1b OP_PICK 18 OP_PICK OP_ADD 11 OP_PICK OP_14 OP_PICK OP_ADD 11 OP_PICK OP_14 OP_PICK OP_ADD OP_SWAP OP_3 OP_ROLL OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_SWAP OP_11 OP_ROLL OP_SUB OP_SWAP OP_10 OP_ROLL OP_SUB OP_SWAP OP_9 OP_ROLL OP_ADD OP_SWAP OP_8 OP_ROLL OP_ADD OP_SWAP OP_7 OP_ROLL OP_SUB OP_SWAP OP_6 OP_ROLL OP_SUB 19 OP_PICK OP_13 OP_PICK OP_MUL OP_14 OP_PICK 1a OP_PICK OP_MUL OP_ADD 19 OP_PICK OP_14 OP_PICK OP_MUL 1b OP_PICK OP_16 OP_PICK OP_MUL OP_SUB 1d OP_PICK 11 OP_PICK OP_MUL 12 OP_PICK 1e OP_PICK OP_MUL OP_ADD 1d OP_PICK 12 OP_PICK OP_MUL 1f OP_PICK 14 OP_PICK OP_MUL OP_SUB 21 OP_PICK 15 OP_PICK OP_MUL 16 OP_PICK 22 OP_PICK OP_MUL OP_ADD 21 OP_PICK 16 OP_PICK OP_MUL 23 OP_PICK 18 OP_PICK OP_MUL OP_SUB 23 OP_PICK 22 OP_PICK OP_ADD 23 OP_PICK 22 OP_PICK OP_ADD 19 OP_PICK 18 OP_PICK OP_ADD 19 OP_PICK 18 OP_PICK OP_ADD OP_SWAP OP_3 OP_ROLL OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_SWAP OP_5 OP_PICK OP_SUB OP_SWAP OP_4 OP_PICK OP_SUB OP_SWAP OP_3 OP_PICK OP_SUB OP_SWAP OP_2 OP_PICK OP_SUB OP_OVER OP_9 OP_MUL OP_OVER OP_ADD OP_9 OP_ROT OP_MUL OP_ROT OP_SUB OP_SWAP OP_7 OP_PICK OP_ADD OP_SWAP OP_6 OP_PICK OP_ADD 23 OP_PICK 22 OP_PICK OP_ADD 23 OP_PICK 22 OP_PICK OP_ADD 19 OP_PICK 18 OP_PICK OP_ADD 19 OP_PICK 18 OP_PICK OP_ADD OP_SWAP OP_3 OP_ROLL OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_SWAP OP_9 OP_PICK OP_SUB OP_SWAP OP_8 OP_PICK OP_SUB OP_SWAP OP_7 OP_PICK OP_SUB OP_SWAP OP_6 OP_PICK OP_SUB OP_5 OP_PICK OP_5 OP_PICK OP_OVER OP_9 OP_MUL OP_OVER OP_ADD OP_9 OP_ROT OP_MUL OP_ROT OP_SUB OP_3 OP_ROLL OP_ROT OP_ADD OP_ROT OP_ROT OP_ADD 27 OP_PICK 24 OP_PICK OP_ADD 27 OP_PICK 24 OP_PICK OP_ADD 1d OP_PICK 1a OP_PICK OP_ADD 1d OP_PICK 1a OP_PICK OP_ADD OP_SWAP OP_3 OP_ROLL OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_SWAP OP_11 OP_ROLL OP_SUB OP_SWAP OP_10 OP_ROLL OP_SUB OP_SWAP OP_9 OP_ROLL OP_ADD OP_SWAP OP_8 OP_ROLL OP_ADD OP_SWAP OP_7 OP_ROLL OP_SUB OP_SWAP OP_6 OP_ROLL OP_SUB OP_3 OP_PICK OP_3 OP_PICK OP_7 OP_PICK OP_7 OP_PICK OP_5 OP_PICK OP_5 OP_PICK OP_OVER OP_9 OP_MUL OP_OVER OP_ADD OP_9 OP_ROT OP_MUL OP_ROT OP_SUB 29 OP_PICK 24 OP_PICK OP_ADD 29 OP_PICK 24 OP_PICK OP_ADD 29 OP_PICK 24 OP_PICK OP_ADD 29 OP_PICK 24 OP_PICK OP_ADD 29 OP_PICK 24 OP_PICK OP_ADD 29 OP_PICK 24 OP_PICK OP_ADD 23 OP_PICK 1e OP_PICK OP_ADD 23 OP_PICK 1e OP_PICK OP_ADD 23 OP_PICK 1e OP_PICK OP_ADD 23 OP_PICK 1e OP_PICK OP_ADD 23 OP_PICK 1e OP_PICK OP_ADD 23 OP_PICK 1e OP_PICK OP_ADD OP_7 OP_PICK OP_OVER OP_MUL OP_2 OP_PICK OP_8 OP_PICK OP_MUL OP_ADD OP_7 OP_PICK OP_2 OP_PICK OP_MUL OP_9 OP_PICK OP_4 OP_PICK OP_MUL OP_SUB OP_11 OP_PICK OP_5 OP_PICK OP_MUL OP_6 OP_PICK OP_12 OP_PICK OP_MUL OP_ADD OP_11 OP_PICK OP_6 OP_PICK OP_MUL OP_13 OP_PICK OP_8 OP_PICK OP_MUL OP_SUB OP_15 OP_PICK OP_9 OP_PICK OP_MUL OP_10 OP_PICK OP_16 OP_PICK OP_MUL OP_ADD OP_15 OP_PICK OP_10 OP_PICK OP_MUL 11 OP_PICK OP_12 OP_PICK OP_MUL OP_SUB 11 OP_PICK OP_16 OP_PICK OP_ADD 11 OP_PICK OP_16 OP_PICK OP_ADD OP_13 OP_PICK OP_12 OP_PICK OP_ADD OP_13 OP_PICK OP_12 OP_PICK OP_ADD OP_SWAP OP_3 OP_ROLL OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_SWAP OP_5 OP_PICK OP_SUB OP_SWAP OP_4 OP_PICK OP_SUB OP_SWAP OP_3 OP_PICK OP_SUB OP_SWAP OP_2 OP_PICK OP_SUB OP_OVER OP_9 OP_MUL OP_OVER OP_ADD OP_9 OP_ROT OP_MUL OP_ROT OP_SUB OP_SWAP OP_7 OP_PICK OP_ADD OP_SWAP OP_6 OP_PICK OP_ADD 11 OP_ROLL OP_16 OP_PICK OP_ADD 11 OP_ROLL OP_16 OP_PICK OP_ADD OP_13 OP_ROLL OP_12 OP_PICK OP_ADD OP_13 OP_ROLL OP_12 OP_PICK OP_ADD OP_SWAP OP_3 OP_ROLL OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_SWAP OP_9 OP_PICK OP_SUB OP_SWAP OP_8 OP_PICK OP_SUB OP_SWAP OP_7 OP_PICK OP_SUB OP_SWAP OP_6 OP_PICK OP_SUB OP_5 OP_PICK OP_5 OP_PICK OP_OVER OP_9 OP_MUL OP_OVER OP_ADD OP_9 OP_ROT OP_MUL OP_ROT OP_SUB OP_3 OP_ROLL OP_ROT OP_ADD OP_ROT OP_ROT OP_ADD 11 OP_ROLL OP_16 OP_ROLL OP_ADD OP_16 OP_ROLL OP_16 OP_ROLL OP_ADD OP_15 OP_ROLL OP_14 OP_ROLL OP_ADD OP_14 OP_ROLL OP_14 OP_ROLL OP_ADD OP_SWAP OP_3 OP_ROLL OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_SWAP OP_11 OP_ROLL OP_SUB OP_SWAP OP_10 OP_ROLL OP_SUB OP_SWAP OP_9 OP_ROLL OP_ADD OP_SWAP OP_8 OP_ROLL OP_ADD OP_SWAP OP_7 OP_ROLL OP_SUB OP_SWAP OP_6 OP_ROLL OP_SUB OP_SWAP 13 OP_PICK OP_SUB OP_SWAP 12 OP_PICK OP_SUB OP_3 OP_ROLL 15 OP_PICK OP_SUB OP_3 OP_ROLL 14 OP_PICK OP_SUB OP_5 OP_ROLL 17 OP_PICK OP_SUB OP_5 OP_ROLL 16 OP_PICK OP_SUB OP_5 OP_ROLL OP_13 OP_ROLL OP_SUB OP_5 OP_ROLL OP_12 OP_ROLL OP_SUB OP_5 OP_ROLL OP_13 OP_ROLL OP_SUB OP_5 OP_ROLL OP_12 OP_ROLL OP_SUB OP_5 OP_ROLL OP_13 OP_ROLL OP_SUB OP_5 OP_ROLL OP_12 OP_ROLL OP_SUB OP_13 OP_ROLL OP_12 OP_ROLL OP_ADD OP_12 OP_ROLL OP_12 OP_ROLL OP_ADD OP_13 OP_ROLL OP_12 OP_ROLL OP_ADD OP_12 OP_ROLL OP_12 OP_ROLL OP_ADD OP_13 OP_ROLL OP_12 OP_ROLL OP_ADD OP_12 OP_ROLL OP_12 OP_ROLL OP_ADD}} static function frobeniusFQ6(FQ6 a) : FQ6 { FQ6 res = {BN256.mulFQ2(BN256.conjugateFQ2(a.x), BN256.xiTo2PMinus2Over3), BN256.mulFQ2(BN256.conjugateFQ2(a.y), BN256.xiToPMinus1Over3), BN256.conjugateFQ2(a.z)}; return res; } static function frobeniusP2FQ6(FQ6 a) : FQ6 { FQ6 res = {BN256.mulScalarFQ2(a.x, 2203960485148121921418603742825762020974279258880205651966), BN256.mulScalarFQ2(a.y, 21888242871839275220042445260109153167277707414472061641714758635765020556616), a.z}; return res; } static function mulGFP(FQ6 a, int b) : FQ6 { return {BN256.mulScalarFQ2(a.x, b), BN256.mulScalarFQ2(a.y, b), BN256.mulScalarFQ2(a.z, b)}; } static function conjugateFQ12(FQ12 a) : FQ12 { FQ12 res = {BN256.negFQ6(a.x), a.y}; return res; } static function frobeniusFQ12(FQ12 a) : FQ12 { return {BN256.mulScalarFQ6(BN256.frobeniusFQ6(a.x), BN256.xiToPMinus1Over6), BN256.frobeniusFQ6(a.y)}; } static function frobeniusP2FQ12(FQ12 a) : FQ12 { return {BN256.mulGFP(BN256.frobeniusP2FQ6(a.x), 21888242871839275220042445260109153167277707414472061641714758635765020556617), BN256.frobeniusP2FQ6(a.y)}; } static function squareFQ12(FQ12 a) : FQ12 { asm { OP_7 OP_PICK OP_OVER OP_MUL OP_2 OP_PICK OP_8 OP_PICK OP_MUL OP_ADD OP_7 OP_PICK OP_2 OP_PICK OP_MUL OP_9 OP_PICK OP_4 OP_PICK OP_MUL OP_SUB OP_11 OP_PICK OP_5 OP_PICK OP_MUL OP_6 OP_PICK OP_12 OP_PICK OP_MUL OP_ADD OP_11 OP_PICK OP_6 OP_PICK OP_MUL OP_13 OP_PICK OP_8 OP_PICK OP_MUL OP_SUB OP_15 OP_PICK OP_9 OP_PICK OP_MUL OP_10 OP_PICK OP_16 OP_PICK OP_MUL OP_ADD OP_15 OP_PICK OP_10 OP_PICK OP_MUL 11 OP_PICK OP_12 OP_PICK OP_MUL OP_SUB 11 OP_PICK OP_16 OP_PICK OP_ADD 11 OP_PICK OP_16 OP_PICK OP_ADD OP_13 OP_PICK OP_12 OP_PICK OP_ADD OP_13 OP_PICK OP_12 OP_PICK OP_ADD OP_SWAP OP_3 OP_ROLL OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_SWAP OP_5 OP_PICK OP_SUB OP_SWAP OP_4 OP_PICK OP_SUB OP_SWAP OP_3 OP_PICK OP_SUB OP_SWAP OP_2 OP_PICK OP_SUB OP_OVER OP_9 OP_MUL OP_OVER OP_ADD OP_9 OP_ROT OP_MUL OP_ROT OP_SUB OP_SWAP OP_7 OP_PICK OP_ADD OP_SWAP OP_6 OP_PICK OP_ADD 11 OP_PICK OP_16 OP_PICK OP_ADD 11 OP_PICK OP_16 OP_PICK OP_ADD OP_13 OP_PICK OP_12 OP_PICK OP_ADD OP_13 OP_PICK OP_12 OP_PICK OP_ADD OP_SWAP OP_3 OP_ROLL OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_SWAP OP_9 OP_PICK OP_SUB OP_SWAP OP_8 OP_PICK OP_SUB OP_SWAP OP_7 OP_PICK OP_SUB OP_SWAP OP_6 OP_PICK OP_SUB OP_5 OP_PICK OP_5 OP_PICK OP_OVER OP_9 OP_MUL OP_OVER OP_ADD OP_9 OP_ROT OP_MUL OP_ROT OP_SUB OP_3 OP_ROLL OP_ROT OP_ADD OP_ROT OP_ROT OP_ADD 15 OP_PICK 12 OP_PICK OP_ADD 15 OP_PICK 12 OP_PICK OP_ADD 11 OP_PICK OP_14 OP_PICK OP_ADD 11 OP_PICK OP_14 OP_PICK OP_ADD OP_SWAP OP_3 OP_ROLL OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_SWAP OP_11 OP_ROLL OP_SUB OP_SWAP OP_10 OP_ROLL OP_SUB OP_SWAP OP_9 OP_ROLL OP_ADD OP_SWAP OP_8 OP_ROLL OP_ADD OP_SWAP OP_7 OP_ROLL OP_SUB OP_SWAP OP_6 OP_ROLL OP_SUB OP_15 OP_PICK OP_15 OP_PICK OP_15 OP_PICK OP_15 OP_PICK 15 OP_PICK 15 OP_PICK OP_OVER OP_9 OP_MUL OP_OVER OP_ADD OP_9 OP_ROT OP_MUL OP_ROT OP_SUB 11 OP_PICK OP_6 OP_ROLL OP_ADD OP_16 OP_PICK OP_6 OP_ROLL OP_ADD OP_15 OP_PICK OP_6 OP_ROLL OP_ADD OP_14 OP_PICK OP_6 OP_ROLL OP_ADD OP_13 OP_PICK OP_6 OP_ROLL OP_ADD OP_12 OP_PICK OP_6 OP_ROLL OP_ADD 17 OP_PICK 12 OP_PICK OP_ADD 17 OP_PICK 12 OP_PICK OP_ADD 17 OP_PICK 12 OP_PICK OP_ADD 17 OP_PICK 12 OP_PICK OP_ADD 17 OP_PICK 12 OP_PICK OP_ADD 17 OP_PICK 12 OP_PICK OP_ADD OP_OVER OP_7 OP_PICK OP_MUL OP_8 OP_PICK OP_2 OP_PICK OP_MUL OP_ADD OP_OVER OP_8 OP_PICK OP_MUL OP_3 OP_PICK OP_10 OP_PICK OP_MUL OP_SUB OP_5 OP_PICK OP_11 OP_PICK OP_MUL OP_12 OP_PICK OP_6 OP_PICK OP_MUL OP_ADD OP_5 OP_PICK OP_12 OP_PICK OP_MUL OP_7 OP_PICK OP_14 OP_PICK OP_MUL OP_SUB OP_9 OP_PICK OP_15 OP_PICK OP_MUL OP_16 OP_PICK OP_10 OP_PICK OP_MUL OP_ADD OP_9 OP_PICK OP_16 OP_PICK OP_MUL OP_11 OP_PICK 12 OP_PICK OP_MUL OP_SUB OP_11 OP_PICK OP_10 OP_PICK OP_ADD OP_11 OP_PICK OP_10 OP_PICK OP_ADD 13 OP_PICK 12 OP_PICK OP_ADD 13 OP_PICK 12 OP_PICK OP_ADD OP_SWAP OP_3 OP_ROLL OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_SWAP OP_5 OP_PICK OP_SUB OP_SWAP OP_4 OP_PICK OP_SUB OP_SWAP OP_3 OP_PICK OP_SUB OP_SWAP OP_2 OP_PICK OP_SUB OP_OVER OP_9 OP_MUL OP_OVER OP_ADD OP_9 OP_ROT OP_MUL OP_ROT OP_SUB OP_SWAP OP_7 OP_PICK OP_ADD OP_SWAP OP_6 OP_PICK OP_ADD OP_11 OP_ROLL OP_10 OP_PICK OP_ADD OP_11 OP_ROLL OP_10 OP_PICK OP_ADD 11 OP_ROLL OP_16 OP_PICK OP_ADD 11 OP_ROLL OP_16 OP_PICK OP_ADD OP_SWAP OP_3 OP_ROLL OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_SWAP OP_9 OP_PICK OP_SUB OP_SWAP OP_8 OP_PICK OP_SUB OP_SWAP OP_7 OP_PICK OP_SUB OP_SWAP OP_6 OP_PICK OP_SUB OP_5 OP_PICK OP_5 OP_PICK OP_OVER OP_9 OP_MUL OP_OVER OP_ADD OP_9 OP_ROT OP_MUL OP_ROT OP_SUB OP_3 OP_ROLL OP_ROT OP_ADD OP_ROT OP_ROT OP_ADD OP_13 OP_ROLL OP_12 OP_ROLL OP_ADD OP_12 OP_ROLL OP_12 OP_ROLL OP_ADD OP_15 OP_ROLL OP_14 OP_ROLL OP_ADD OP_14 OP_ROLL OP_14 OP_ROLL OP_ADD OP_SWAP OP_3 OP_ROLL OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_SWAP OP_11 OP_ROLL OP_SUB OP_SWAP OP_10 OP_ROLL OP_SUB OP_SWAP OP_9 OP_ROLL OP_ADD OP_SWAP OP_8 OP_ROLL OP_ADD OP_SWAP OP_7 OP_ROLL OP_SUB OP_SWAP OP_6 OP_ROLL OP_SUB OP_SWAP OP_7 OP_PICK OP_SUB OP_SWAP OP_6 OP_PICK OP_SUB OP_3 OP_ROLL OP_9 OP_PICK OP_SUB OP_3 OP_ROLL OP_8 OP_PICK OP_SUB OP_5 OP_ROLL OP_11 OP_PICK OP_SUB OP_5 OP_ROLL OP_10 OP_PICK OP_SUB OP_9 OP_PICK OP_9 OP_PICK OP_13 OP_PICK OP_13 OP_PICK OP_11 OP_PICK OP_11 OP_PICK OP_OVER OP_9 OP_MUL OP_OVER OP_ADD OP_9 OP_ROT OP_MUL OP_ROT OP_SUB OP_13 OP_ROLL OP_2 OP_MUL OP_13 OP_ROLL OP_2 OP_MUL OP_15 OP_ROLL OP_2 OP_MUL OP_15 OP_ROLL OP_2 OP_MUL 11 OP_ROLL OP_2 OP_MUL 11 OP_ROLL OP_2 OP_MUL 11 OP_ROLL OP_12 OP_ROLL OP_SUB OP_16 OP_ROLL OP_12 OP_ROLL OP_SUB OP_15 OP_ROLL OP_12 OP_ROLL OP_SUB OP_14 OP_ROLL OP_12 OP_ROLL OP_SUB OP_13 OP_ROLL OP_12 OP_ROLL OP_SUB OP_12 OP_ROLL OP_12 OP_ROLL OP_SUB}} static function expFQ12_u(FQ12 a) : FQ12 { FQ12 sum = BN256.FQ12One; FQ12 sum0 = BN256.squareFQ12(sum); sum0 = BN256.modFQ12(sum0); FQ12 sum1 = BN256.mulFQ12(sum0, a); FQ12 sum2 = BN256.squareFQ12(sum1); FQ12 sum3 = BN256.squareFQ12(sum2); FQ12 sum4 = BN256.squareFQ12(sum3); FQ12 sum5 = BN256.squareFQ12(sum4); FQ12 sum6 = BN256.mulFQ12(sum5, a); FQ12 sum7 = BN256.squareFQ12(sum6); FQ12 sum8 = BN256.squareFQ12(sum7); FQ12 sum9 = BN256.squareFQ12(sum8); FQ12 sum10 = BN256.mulFQ12(sum9, a); sum10 = BN256.modFQ12(sum10); FQ12 sum11 = BN256.squareFQ12(sum10); FQ12 sum12 = BN256.mulFQ12(sum11, a); FQ12 sum13 = BN256.squareFQ12(sum12); FQ12 sum14 = BN256.mulFQ12(sum13, a); FQ12 sum15 = BN256.squareFQ12(sum14); FQ12 sum16 = BN256.squareFQ12(sum15); FQ12 sum17 = BN256.mulFQ12(sum16, a); FQ12 sum18 = BN256.squareFQ12(sum17); FQ12 sum19 = BN256.squareFQ12(sum18); FQ12 sum20 = BN256.squareFQ12(sum19); sum20 = BN256.modFQ12(sum20); FQ12 sum21 = BN256.mulFQ12(sum20, a); FQ12 sum22 = BN256.squareFQ12(sum21); FQ12 sum23 = BN256.mulFQ12(sum22, a); FQ12 sum24 = BN256.squareFQ12(sum23); FQ12 sum25 = BN256.squareFQ12(sum24); FQ12 sum26 = BN256.squareFQ12(sum25); FQ12 sum27 = BN256.mulFQ12(sum26, a); FQ12 sum28 = BN256.squareFQ12(sum27); FQ12 sum29 = BN256.squareFQ12(sum28); FQ12 sum30 = BN256.squareFQ12(sum29); sum30 = BN256.modFQ12(sum30); FQ12 sum31 = BN256.mulFQ12(sum30, a); FQ12 sum32 = BN256.squareFQ12(sum31); FQ12 sum33 = BN256.squareFQ12(sum32); FQ12 sum34 = BN256.mulFQ12(sum33, a); FQ12 sum35 = BN256.squareFQ12(sum34); FQ12 sum36 = BN256.squareFQ12(sum35); FQ12 sum37 = BN256.mulFQ12(sum36, a); FQ12 sum38 = BN256.squareFQ12(sum37); FQ12 sum39 = BN256.mulFQ12(sum38, a); FQ12 sum40 = BN256.squareFQ12(sum39); sum40 = BN256.modFQ12(sum40); FQ12 sum41 = BN256.squareFQ12(sum40); FQ12 sum42 = BN256.mulFQ12(sum41, a); FQ12 sum43 = BN256.squareFQ12(sum42); FQ12 sum44 = BN256.squareFQ12(sum43); FQ12 sum45 = BN256.squareFQ12(sum44); FQ12 sum46 = BN256.squareFQ12(sum45); FQ12 sum47 = BN256.mulFQ12(sum46, a); FQ12 sum48 = BN256.squareFQ12(sum47); FQ12 sum49 = BN256.squareFQ12(sum48); FQ12 sum50 = BN256.squareFQ12(sum49); sum50 = BN256.modFQ12(sum50); FQ12 sum51 = BN256.mulFQ12(sum50, a); FQ12 sum52 = BN256.squareFQ12(sum51); FQ12 sum53 = BN256.squareFQ12(sum52); FQ12 sum54 = BN256.mulFQ12(sum53, a); FQ12 sum55 = BN256.squareFQ12(sum54); FQ12 sum56 = BN256.squareFQ12(sum55); FQ12 sum57 = BN256.squareFQ12(sum56); FQ12 sum58 = BN256.mulFQ12(sum57, a); FQ12 sum59 = BN256.squareFQ12(sum58); FQ12 sum60 = BN256.mulFQ12(sum59, a); sum60 = BN256.modFQ12(sum60); FQ12 sum61 = BN256.squareFQ12(sum60); FQ12 sum62 = BN256.squareFQ12(sum61); FQ12 sum63 = BN256.mulFQ12(sum62, a); FQ12 sum64 = BN256.squareFQ12(sum63); FQ12 sum65 = BN256.squareFQ12(sum64); FQ12 sum66 = BN256.squareFQ12(sum65); FQ12 sum67 = BN256.mulFQ12(sum66, a); FQ12 sum68 = BN256.squareFQ12(sum67); FQ12 sum69 = BN256.squareFQ12(sum68); FQ12 sum70 = BN256.squareFQ12(sum69); sum70 = BN256.modFQ12(sum70); FQ12 sum71 = BN256.squareFQ12(sum70); FQ12 sum72 = BN256.squareFQ12(sum71); FQ12 sum73 = BN256.mulFQ12(sum72, a); FQ12 sum74 = BN256.squareFQ12(sum73); FQ12 sum75 = BN256.squareFQ12(sum74); FQ12 sum76 = BN256.squareFQ12(sum75); FQ12 sum77 = BN256.mulFQ12(sum76, a); FQ12 sum78 = BN256.squareFQ12(sum77); FQ12 sum79 = BN256.mulFQ12(sum78, a); FQ12 sum80 = BN256.squareFQ12(sum79); sum80 = BN256.modFQ12(sum80); FQ12 sum81 = BN256.mulFQ12(sum80, a); FQ12 sum82 = BN256.squareFQ12(sum81); FQ12 sum83 = BN256.mulFQ12(sum82, a); FQ12 sum84 = BN256.squareFQ12(sum83); FQ12 sum85 = BN256.mulFQ12(sum84, a); FQ12 sum86 = BN256.squareFQ12(sum85); FQ12 sum87 = BN256.squareFQ12(sum86); FQ12 sum88 = BN256.squareFQ12(sum87); FQ12 sum89 = BN256.squareFQ12(sum88); FQ12 sum90 = BN256.mulFQ12(sum89, a); sum90 = BN256.modFQ12(sum90); return sum90; } static function expFQ12(FQ12 a, int power) : FQ12 { FQ12 sum = BN256.FQ12One; FQ12 t = BN256.FQ12One; bool firstOne = false; loop (264) : i { if(firstOne) { t = BN256.modFQ12(BN256.squareFQ12(sum)); } int shifted = (1 << ((264) - 1 - i)); if((power & shifted) != 0) { firstOne = true; sum = BN256.mulFQ12(t, a); } else { sum = t; } } return sum; } static function doubleG1Point(G1Point a) : G1Point { CurvePoint res = BN256.doubleCurvePoint(BN256.createCurvePoint(a)); return BN256.getG1Point(res); } static function doubleCurvePoint(CurvePoint a) : CurvePoint { asm { OP_3 OP_PICK OP_4 OP_PICK OP_MUL OP_3 OP_PICK OP_4 OP_PICK OP_MUL OP_DUP OP_OVER OP_MUL OP_6 OP_PICK OP_ROT OP_ADD OP_DUP OP_OVER OP_MUL OP_NIP OP_DUP OP_3 OP_PICK OP_SUB OP_NIP OP_DUP OP_2 OP_PICK OP_SUB OP_2 OP_OVER OP_MUL OP_ROT OP_DROP OP_2 OP_4 OP_PICK OP_MUL OP_DUP OP_5 OP_ROLL OP_ADD OP_DUP OP_OVER OP_MUL OP_ROT OP_DROP OP_2 OP_3 OP_PICK OP_MUL OP_SWAP OP_OVER OP_SUB OP_NIP OP_2 OP_5 OP_ROLL OP_MUL OP_4 OP_ROLL OP_DROP OP_2 OP_OVER OP_MUL OP_NIP OP_2 OP_OVER OP_MUL OP_4 OP_ROLL OP_3 OP_PICK OP_SUB OP_ROT OP_DROP OP_3 OP_ROLL OP_OVER OP_MUL OP_NIP OP_SWAP OP_SUB OP_4 OP_PICK OP_4 OP_PICK OP_MUL OP_2 OP_MUL OP_0}} static function addG1Points(G1Point a, G1Point b) : G1Point { CurvePoint res = BN256.addCurvePoints(BN256.createCurvePoint(a), BN256.createCurvePoint(b)); return BN256.getG1Point(res); } static function addCurvePoints(CurvePoint a, CurvePoint b) : CurvePoint { return BN256._addCurvePoints(21888242871839275222246405745257275088696311157297823662689037894645226208583, a, b); } static function _addCurvePoints(int P, CurvePoint a, CurvePoint b) : CurvePoint { asm { OP_5 OP_ROLL OP_8 OP_PICK OP_MOD OP_ROT OP_8 OP_PICK OP_MOD OP_OVER OP_2 OP_PICK OP_MUL OP_OVER OP_2 OP_PICK OP_MUL OP_9 OP_PICK OP_OVER OP_MUL OP_7 OP_PICK OP_3 OP_PICK OP_MUL OP_4 OP_PICK OP_3 OP_PICK OP_MUL OP_11 OP_PICK OP_OVER OP_MUL OP_NIP OP_6 OP_PICK OP_5 OP_PICK OP_MUL OP_9 OP_PICK OP_OVER OP_MUL OP_3 OP_ROLL OP_4 OP_PICK OP_SUB OP_0 OP_OVER 11 OP_PICK OP_MOD OP_EQUAL OP_3 OP_ROLL OP_DROP OP_2 OP_2 OP_PICK OP_MUL OP_DUP OP_OVER OP_MUL OP_3 OP_PICK OP_OVER OP_MUL OP_ROT OP_DROP OP_4 OP_ROLL OP_5 OP_PICK OP_SUB OP_0 OP_OVER 13 OP_PICK OP_MOD OP_EQUAL OP_4 OP_ROLL OP_SWAP OP_BOOLAND OP_OVER OP_2 OP_PICK OP_ADD OP_7 OP_ROLL OP_5 OP_ROLL OP_MUL OP_OVER OP_2 OP_PICK OP_MUL OP_DUP OP_6 OP_PICK OP_SUB OP_5 OP_ROLL OP_DROP OP_2 OP_3 OP_PICK OP_MUL OP_2DUP OP_SUB OP_NIP OP_3 OP_ROLL OP_OVER OP_SUB OP_3 OP_ROLL OP_DROP OP_7 OP_ROLL OP_6 OP_ROLL OP_MUL OP_3 OP_ROLL OP_DROP OP_2 OP_OVER OP_MUL OP_NIP OP_3 OP_ROLL OP_2 OP_PICK OP_MUL OP_DUP OP_ROT OP_SUB OP_ROT OP_DROP OP_8 OP_PICK OP_8 OP_PICK OP_ADD OP_ROT OP_DROP OP_DUP OP_OVER OP_MUL OP_NIP OP_DUP OP_7 OP_ROLL OP_SUB OP_NIP OP_5 OP_ROLL OP_SUB OP_4 OP_ROLL OP_MUL OP_0 OP_6 OP_PICK OP_0 OP_EQUAL OP_IF OP_NIP OP_2DROP OP_DROP OP_5 OP_PICK OP_5 OP_PICK OP_3 OP_PICK OP_6 OP_PICK OP_ENDIF OP_6 OP_PICK OP_0 OP_EQUAL OP_NOT OP_6 OP_PICK OP_0 OP_EQUAL OP_BOOLAND OP_IF OP_NIP OP_2DROP OP_DROP OP_8 OP_PICK OP_8 OP_PICK OP_4 OP_PICK OP_9 OP_PICK OP_ENDIF OP_6 OP_PICK OP_0 OP_EQUAL OP_NOT OP_6 OP_PICK OP_0 OP_EQUAL OP_NOT OP_BOOLAND OP_5 OP_PICK OP_BOOLAND OP_IF OP_NIP OP_2DROP OP_DROP OP_8 OP_PICK OP_8 OP_PICK OP_4 OP_PICK OP_9 OP_PICK OP_3 OP_PICK OP_4 OP_PICK OP_MUL OP_3 OP_PICK OP_4 OP_PICK OP_MUL OP_DUP OP_OVER OP_MUL OP_6 OP_PICK OP_ROT OP_ADD OP_DUP OP_OVER OP_MUL OP_NIP OP_DUP OP_3 OP_PICK OP_SUB OP_NIP OP_DUP OP_2 OP_PICK OP_SUB OP_2 OP_OVER OP_MUL OP_ROT OP_DROP OP_2 OP_4 OP_PICK OP_MUL OP_DUP OP_5 OP_ROLL OP_ADD OP_DUP OP_OVER OP_MUL OP_ROT OP_DROP OP_2 OP_3 OP_PICK OP_MUL OP_SWAP OP_OVER OP_SUB OP_NIP OP_2 OP_5 OP_ROLL OP_MUL OP_4 OP_ROLL OP_DROP OP_2 OP_OVER OP_MUL OP_NIP OP_2 OP_OVER OP_MUL OP_4 OP_ROLL OP_3 OP_PICK OP_SUB OP_ROT OP_DROP OP_3 OP_ROLL OP_OVER OP_MUL OP_NIP OP_SWAP OP_SUB OP_4 OP_PICK OP_4 OP_PICK OP_MUL OP_2 OP_MUL OP_0 OP_7 OP_ROLL OP_DROP OP_6 OP_ROLL OP_DROP OP_5 OP_ROLL OP_DROP OP_4 OP_ROLL OP_DROP OP_ENDIF OP_4 OP_ROLL OP_DROP}} static function mulG1Point(G1Point a, int m) : G1Point { CurvePoint res = BN256.mulCurvePoint(BN256.createCurvePoint(a), m); return BN256.getG1Point(res); } static function mulCurvePoint(CurvePoint a, int m) : CurvePoint { CurvePoint res = {0, 1, 0, 0}; if(m != 0) { CurvePoint t = {0, 0, 0, 0}; CurvePoint sum = {0, 0, 0, 0}; bool firstOne = false; loop (88) : k { sum = BN256.modCurvePoint(sum); loop (3) : j { if(firstOne) { t = BN256.doubleCurvePoint(sum); } int shifted = (1 << ((264) - 1 - (3 * k + j))); if((m & shifted) != 0) { firstOne = true; sum = BN256.addCurvePoints(t, a); } else { sum = t; } } } res = sum; } return res; } static function makeAffineCurvePoint(CurvePoint a) : CurvePoint { CurvePoint res = a; if(BN256.modReduce(a.z, 21888242871839275222246405745257275088696311157297823662689037894645226208583) != 1) { if(a.z == 0) { res = {0, 1, 0, 0}; } else { int zInv = BN256.modInverseBranchlessP(a.z); int t = BN256.modReduce(a.y * zInv, 21888242871839275222246405745257275088696311157297823662689037894645226208583); int zInv2 = BN256.modReduce(zInv * zInv, 21888242871839275222246405745257275088696311157297823662689037894645226208583); int ay = BN256.modReduce(t * zInv2, 21888242871839275222246405745257275088696311157297823662689037894645226208583); int ax = BN256.modReduce(a.x * zInv2, 21888242871839275222246405745257275088696311157297823662689037894645226208583); res = {ax, ay, 1, 1}; } } return res; } static function negCurvePoint(CurvePoint a) : CurvePoint { CurvePoint res = {a.x, -a.y, a.z, 0}; return res; } static function isInfCurvePoint(CurvePoint a) : bool { return a.z == 0; } static function createCurvePoint(G1Point ccp) : CurvePoint { CurvePoint res = {ccp.x, ccp.y, 1, 1}; if(ccp.x == 0 && ccp.y == 0) { res = {0, 1, 0, 0}; } return res; } static function getG1Point(CurvePoint cp) : G1Point { CurvePoint acp = BN256.makeAffineCurvePoint(cp); G1Point res = {acp.x, acp.y}; if(acp.x == 0 && acp.y == 1 && acp.z == 0 && acp.t == 0) { res = {0, 0}; } return res; } static function doubleG2Point(G2Point a) : G2Point { TwistPoint res = BN256.doubleTwistPoint(BN256.createTwistPoint(a)); return BN256.getG2Point(res); } static function doubleTwistPoint(TwistPoint a) : TwistPoint { TwistPoint res = {BN256.FQ2Zero, BN256.FQ2Zero, BN256.FQ2Zero, BN256.FQ2Zero}; FQ2 A = BN256.squareFQ2(a.x); FQ2 B = BN256.squareFQ2(a.y); FQ2 C = BN256.squareFQ2(B); FQ2 t = BN256.addFQ2(a.x, B); FQ2 t2 = BN256.squareFQ2(t); t = BN256.subFQ2(t2, A); t2 = BN256.subFQ2(t, C); FQ2 d = BN256.mulScalarFQ2(t2, 2); t = BN256.mulScalarFQ2(A, 2); FQ2 e = BN256.addFQ2(t, A); FQ2 f = BN256.squareFQ2(e); t = BN256.mulScalarFQ2(d, 2); res.x = BN256.subFQ2(f, t); t = BN256.mulScalarFQ2(C, 2); t2 = BN256.mulScalarFQ2(t, 2); t = BN256.mulScalarFQ2(t2, 2); res.y = BN256.subFQ2(d, res.x); t2 = BN256.mulFQ2(e, res.y); res.y = BN256.subFQ2(t2, t); res.z = BN256.mulScalarFQ2(BN256.mulFQ2(a.y, a.z), 2); return res; } static function addG2Points(G2Point a, G2Point b) : G2Point { TwistPoint res = BN256.addTwistPoints(BN256.createTwistPoint(a), BN256.createTwistPoint(b)); return BN256.getG2Point(res); } static function addTwistPoints(TwistPoint a, TwistPoint b) : TwistPoint { TwistPoint res = {BN256.FQ2Zero, BN256.FQ2Zero, BN256.FQ2Zero, a.t}; if(a.z == BN256.FQ2Zero) { res = b; } else if(b.z == BN256.FQ2Zero) { res = a; } else { FQ2 z12 = BN256.squareFQ2(a.z); FQ2 z22 = BN256.squareFQ2(b.z); FQ2 u1 = BN256.mulFQ2(a.x, z22); FQ2 u2 = BN256.mulFQ2(b.x, z12); FQ2 t = BN256.mulFQ2(b.z, z22); FQ2 s1 = BN256.mulFQ2(a.y, t); t = BN256.mulFQ2(a.z, z12); FQ2 s2 = BN256.mulFQ2(b.y, t); FQ2 h = BN256.subFQ2(u2, u1); bool xEqual = h == BN256.FQ2Zero; t = BN256.mulScalarFQ2(h, 2); FQ2 i = BN256.squareFQ2(t); FQ2 j = BN256.mulFQ2(h, i); t = BN256.subFQ2(s2, s1); bool yEqual = t == BN256.FQ2Zero; if(xEqual && yEqual) { res = BN256.doubleTwistPoint(a); } else { FQ2 r = BN256.mulScalarFQ2(t, 2); FQ2 v = BN256.mulFQ2(u1, i); FQ2 t4 = BN256.squareFQ2(r); FQ2 t6 = BN256.subFQ2(t4, j); t = BN256.mulScalarFQ2(v, 2); res.x = BN256.subFQ2(t6, t); t = BN256.subFQ2(v, res.x); t4 = BN256.mulFQ2(s1, j); t6 = BN256.mulScalarFQ2(t4, 2); t4 = BN256.mulFQ2(r, t); res.y = BN256.subFQ2(t4, t6); t = BN256.addFQ2(a.z, b.z); t4 = BN256.squareFQ2(t); t = BN256.subFQ2(t4, z12); t4 = BN256.subFQ2(t, z22); res.z = BN256.mulFQ2(t4, h); } } return res; } static function makeAffineTwistPoint(TwistPoint a) : TwistPoint { TwistPoint res = a; if(a.z.x != 0 || a.z.y != 1) { if(a.z == BN256.FQ2Zero) { res = {BN256.FQ2Zero, BN256.FQ2One, BN256.FQ2Zero, BN256.FQ2Zero}; } else { FQ2 zInv = BN256.inverseFQ2(a.z); FQ2 t = BN256.mulFQ2(a.y, zInv); FQ2 zInv2 = BN256.squareFQ2(zInv); res.y = BN256.mulFQ2(t, zInv2); t = BN256.mulFQ2(a.x, zInv2); res.x = t; FQ2 zTmp = {0, 1}; res.z = zTmp; res.t = zTmp; } } return res; } static function negTwistPoint(TwistPoint a) : TwistPoint { TwistPoint res = {a.x, BN256.subFQ2(BN256.FQ2Zero, a.y), a.z, BN256.FQ2Zero}; return res; } static function isInfTwistPoint(TwistPoint a) : bool { return a.z.x == BN256.FQ2Zero.x && a.z.y == BN256.FQ2Zero.y; } static function createTwistPoint(G2Point ctp) : TwistPoint { FQ2 x = {ctp.x.y, ctp.x.x}; FQ2 y = {ctp.y.y, ctp.y.x}; TwistPoint res = {x, y, BN256.FQ2One, BN256.FQ2One}; if(ctp.x == BN256.FQ2Zero && ctp.y == BN256.FQ2Zero) { res = {BN256.FQ2Zero, BN256.FQ2One, BN256.FQ2Zero, BN256.FQ2Zero}; } return res; } static function getG2Point(TwistPoint tp) : G2Point { TwistPoint atp = BN256.makeAffineTwistPoint(tp); G2Point res = {atp.x, atp.y}; if(atp.x == BN256.FQ2Zero && atp.y == BN256.FQ2One && atp.z == BN256.FQ2Zero && atp.t == BN256.FQ2Zero) { res = {BN256.FQ2Zero, BN256.FQ2Zero}; } return res; } } library BN256Pairing { static function compareLineFuncRes(LineFuncRes a, LineFuncRes b) : bool { return (a.a.x == b.a.x && a.a.y == b.a.y && a.b.x == b.b.x && a.b.y == b.b.y && a.c.x == b.c.x && a.c.y == b.c.y && a.rOut.x.x == b.rOut.x.x && a.rOut.x.y == b.rOut.x.y && a.rOut.y.x == b.rOut.y.x && a.rOut.y.y == b.rOut.y.y && a.rOut.z.x == b.rOut.z.x && a.rOut.z.y == b.rOut.z.y && a.rOut.t.x == b.rOut.t.x && a.rOut.t.y == b.rOut.t.y); } static function modLineFuncRes(LineFuncRes l) : LineFuncRes { l.a = BN256.modFQ2(l.a); l.b = BN256.modFQ2(l.b); l.c = BN256.modFQ2(l.c); l.rOut.x = BN256.modFQ2(l.rOut.x); l.rOut.y = BN256.modFQ2(l.rOut.y); l.rOut.z = BN256.modFQ2(l.rOut.z); l.rOut.t = BN256.modFQ2(l.rOut.t); return l; } static function lineFuncAdd(TwistPoint r, TwistPoint p, CurvePoint q, FQ2 r2) : LineFuncRes { asm { OP_13 OP_PICK OP_15 OP_PICK OP_MUL OP_16 OP_PICK OP_14 OP_PICK OP_MUL OP_ADD OP_13 OP_PICK OP_16 OP_PICK OP_MUL OP_15 OP_PICK 12 OP_PICK OP_MUL OP_SUB OP_13 OP_PICK 14 OP_PICK OP_ADD OP_13 OP_PICK 14 OP_PICK OP_ADD OP_DUP OP_2 OP_PICK OP_SUB OP_2 OP_PICK OP_2 OP_PICK OP_ADD OP_2 OP_4 OP_ROLL OP_4 OP_ROLL OP_MUL OP_MUL OP_SWAP OP_ROT OP_MUL OP_SWAP OP_5 OP_PICK OP_SUB OP_SWAP OP_4 OP_PICK OP_SUB OP_SWAP 13 OP_PICK OP_SUB OP_SWAP 12 OP_PICK OP_SUB 12 OP_PICK 14 OP_PICK OP_3 OP_ROLL OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_3 OP_ROLL 19 OP_PICK OP_SUB OP_3 OP_ROLL 18 OP_PICK OP_SUB OP_2DUP OP_DUP OP_2 OP_PICK OP_SUB OP_2 OP_PICK OP_2 OP_PICK OP_ADD OP_2 OP_4 OP_ROLL OP_4 OP_ROLL OP_MUL OP_MUL OP_SWAP OP_ROT OP_MUL OP_OVER OP_2 OP_PICK OP_ADD OP_OVER OP_2 OP_PICK OP_ADD OP_OVER OP_ROT OP_ADD OP_OVER OP_ROT OP_ADD OP_4 OP_PICK OP_OVER OP_3 OP_PICK OP_8 OP_PICK OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_9 OP_ROLL 1d OP_PICK OP_SUB OP_9 OP_ROLL 1c OP_PICK OP_SUB OP_SWAP 1d OP_PICK OP_SUB OP_SWAP 1c OP_PICK OP_SUB 1e OP_PICK OP_5 OP_ROLL OP_6 OP_ROLL 20 OP_PICK OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_3 OP_PICK OP_3 OP_PICK OP_DUP OP_2 OP_PICK OP_SUB OP_2 OP_PICK OP_2 OP_PICK OP_ADD OP_2 OP_4 OP_ROLL OP_4 OP_ROLL OP_MUL OP_MUL OP_SWAP OP_ROT OP_MUL OP_SWAP OP_7 OP_PICK OP_SUB OP_SWAP OP_6 OP_PICK OP_SUB OP_SWAP OP_3 OP_PICK OP_SUB OP_SWAP OP_2 OP_PICK OP_SUB OP_SWAP OP_3 OP_PICK OP_SUB OP_SWAP OP_2 OP_PICK OP_SUB 1d OP_PICK OP_12 OP_ROLL OP_ADD 1c OP_PICK OP_12 OP_ROLL OP_ADD OP_DUP OP_2 OP_PICK OP_SUB OP_2 OP_PICK OP_2 OP_PICK OP_ADD OP_2 OP_4 OP_ROLL OP_4 OP_ROLL OP_MUL OP_MUL OP_SWAP OP_ROT OP_MUL OP_SWAP 1b OP_PICK OP_SUB OP_SWAP 1a OP_PICK OP_SUB OP_SWAP OP_11 OP_ROLL OP_SUB OP_SWAP OP_10 OP_ROLL OP_SUB OP_5 OP_ROLL OP_4 OP_PICK OP_SUB OP_5 OP_ROLL OP_4 OP_PICK OP_SUB OP_6 OP_PICK OP_8 OP_PICK OP_3 OP_ROLL OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB 1c OP_PICK OP_9 OP_ROLL OP_10 OP_ROLL 1e OP_PICK OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_OVER OP_ROT OP_ADD OP_OVER OP_ROT OP_ADD OP_3 OP_ROLL OP_ROT OP_SUB OP_ROT OP_ROT OP_SUB OP_3 OP_PICK OP_3 OP_PICK OP_DUP OP_2 OP_PICK OP_SUB OP_2 OP_PICK OP_2 OP_PICK OP_ADD OP_2 OP_4 OP_ROLL OP_4 OP_ROLL OP_MUL OP_MUL OP_SWAP OP_ROT OP_MUL 15 OP_PICK OP_6 OP_PICK OP_ADD 15 OP_PICK OP_6 OP_PICK OP_ADD OP_DUP OP_2 OP_PICK OP_SUB OP_2 OP_PICK OP_2 OP_PICK OP_ADD OP_2 OP_4 OP_ROLL OP_4 OP_ROLL OP_MUL OP_MUL OP_SWAP OP_ROT OP_MUL OP_SWAP OP_13 OP_PICK OP_SUB OP_SWAP OP_12 OP_PICK OP_SUB OP_SWAP OP_3 OP_PICK OP_SUB OP_SWAP OP_2 OP_PICK OP_SUB OP_11 OP_PICK 19 OP_PICK OP_MUL 1a OP_PICK OP_12 OP_PICK OP_MUL OP_ADD OP_11 OP_PICK 1a OP_PICK OP_MUL OP_13 OP_PICK 1c OP_PICK OP_MUL OP_SUB OP_OVER OP_ROT OP_ADD OP_OVER OP_ROT OP_ADD OP_SWAP OP_3 OP_ROLL OP_SUB OP_SWAP OP_ROT OP_SUB OP_7 OP_PICK 11 OP_PICK OP_MUL OP_7 OP_PICK 12 OP_PICK OP_MUL OP_OVER OP_ROT OP_ADD OP_OVER OP_ROT OP_ADD OP_0 OP_14 OP_ROLL OP_SUB OP_0 OP_14 OP_ROLL OP_SUB OP_SWAP 13 OP_PICK OP_MUL OP_SWAP 13 OP_PICK OP_MUL OP_OVER OP_ROT OP_ADD OP_OVER OP_ROT OP_ADD OP_5 OP_ROLL OP_5 OP_ROLL OP_3 OP_ROLL OP_3 OP_ROLL OP_5 OP_ROLL OP_5 OP_ROLL OP_13 OP_ROLL OP_13 OP_ROLL OP_11 OP_ROLL OP_11 OP_ROLL OP_13 OP_ROLL OP_13 OP_ROLL OP_13 OP_ROLL OP_13 OP_ROLL}} static function lineFuncDouble(TwistPoint r, CurvePoint q) : LineFuncRes { asm { OP_11 OP_PICK OP_11 OP_PICK OP_DUP OP_2 OP_PICK OP_SUB OP_2 OP_PICK OP_2 OP_PICK OP_ADD OP_2 OP_4 OP_ROLL OP_4 OP_ROLL OP_MUL OP_MUL OP_SWAP OP_ROT OP_MUL OP_11 OP_PICK OP_11 OP_PICK OP_DUP OP_2 OP_PICK OP_SUB OP_2 OP_PICK OP_2 OP_PICK OP_ADD OP_2 OP_4 OP_ROLL OP_4 OP_ROLL OP_MUL OP_MUL OP_SWAP OP_ROT OP_MUL OP_2DUP OP_DUP OP_2 OP_PICK OP_SUB OP_2 OP_PICK OP_2 OP_PICK OP_ADD OP_2 OP_4 OP_ROLL OP_4 OP_ROLL OP_MUL OP_MUL OP_SWAP OP_ROT OP_MUL 11 OP_PICK OP_4 OP_PICK OP_ADD 11 OP_PICK OP_4 OP_PICK OP_ADD OP_DUP OP_2 OP_PICK OP_SUB OP_2 OP_PICK OP_2 OP_PICK OP_ADD OP_2 OP_4 OP_ROLL OP_4 OP_ROLL OP_MUL OP_MUL OP_SWAP OP_ROT OP_MUL OP_SWAP OP_7 OP_PICK OP_SUB OP_SWAP OP_6 OP_PICK OP_SUB OP_SWAP OP_3 OP_PICK OP_SUB OP_SWAP OP_2 OP_PICK OP_SUB OP_OVER OP_ROT OP_ADD OP_OVER OP_ROT OP_ADD OP_7 OP_PICK OP_8 OP_PICK OP_ADD OP_7 OP_PICK OP_8 OP_PICK OP_ADD OP_SWAP OP_9 OP_PICK OP_ADD OP_SWAP OP_8 OP_PICK OP_ADD OP_2DUP OP_DUP OP_2 OP_PICK OP_SUB OP_2 OP_PICK OP_2 OP_PICK OP_ADD OP_2 OP_4 OP_ROLL OP_4 OP_ROLL OP_MUL OP_MUL OP_SWAP OP_ROT OP_MUL OP_OVER OP_6 OP_PICK OP_SUB OP_OVER OP_6 OP_PICK OP_SUB OP_SWAP OP_7 OP_PICK OP_SUB OP_SWAP OP_6 OP_PICK OP_SUB 17 OP_PICK 16 OP_PICK OP_ADD 17 OP_PICK 16 OP_PICK OP_ADD OP_DUP OP_2 OP_PICK OP_SUB OP_2 OP_PICK OP_2 OP_PICK OP_ADD OP_2 OP_4 OP_ROLL OP_4 OP_ROLL OP_MUL OP_MUL OP_SWAP OP_ROT OP_MUL OP_SWAP OP_13 OP_PICK OP_SUB OP_SWAP OP_12 OP_PICK OP_SUB OP_SWAP 15 OP_PICK OP_SUB OP_SWAP 14 OP_PICK OP_SUB OP_9 OP_ROLL OP_4 OP_PICK OP_SUB OP_9 OP_ROLL OP_4 OP_PICK OP_SUB OP_8 OP_PICK OP_10 OP_PICK OP_3 OP_ROLL OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_11 OP_PICK OP_12 OP_ROLL OP_ADD OP_11 OP_PICK OP_12 OP_ROLL OP_ADD OP_OVER OP_ROT OP_ADD OP_OVER OP_ROT OP_ADD OP_OVER OP_ROT OP_ADD OP_OVER OP_ROT OP_ADD OP_3 OP_ROLL OP_ROT OP_SUB OP_ROT OP_ROT OP_SUB OP_3 OP_PICK OP_3 OP_PICK OP_DUP OP_2 OP_PICK OP_SUB OP_2 OP_PICK OP_2 OP_PICK OP_ADD OP_2 OP_4 OP_ROLL OP_4 OP_ROLL OP_MUL OP_MUL OP_SWAP OP_ROT OP_MUL OP_10 OP_PICK 15 OP_PICK 17 OP_PICK OP_14 OP_PICK OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_OVER OP_ROT OP_ADD OP_OVER OP_ROT OP_ADD OP_0 OP_ROT OP_SUB OP_0 OP_ROT OP_SUB OP_SWAP 15 OP_PICK OP_MUL OP_SWAP 15 OP_PICK OP_MUL 1d OP_PICK OP_14 OP_ROLL OP_ADD 1c OP_PICK OP_14 OP_ROLL OP_ADD OP_DUP OP_2 OP_PICK OP_SUB OP_2 OP_PICK OP_2 OP_PICK OP_ADD OP_2 OP_4 OP_ROLL OP_4 OP_ROLL OP_MUL OP_MUL OP_SWAP OP_ROT OP_MUL OP_SWAP 11 OP_ROLL OP_SUB OP_SWAP OP_16 OP_ROLL OP_SUB OP_SWAP OP_13 OP_ROLL OP_SUB OP_SWAP OP_12 OP_ROLL OP_SUB OP_13 OP_PICK OP_14 OP_ROLL OP_ADD OP_13 OP_PICK OP_14 OP_ROLL OP_ADD OP_OVER OP_ROT OP_ADD OP_OVER OP_ROT OP_ADD OP_3 OP_ROLL OP_ROT OP_SUB OP_ROT OP_ROT OP_SUB OP_9 OP_PICK 11 OP_PICK OP_MUL 12 OP_PICK OP_10 OP_PICK OP_MUL OP_ADD OP_9 OP_PICK 12 OP_PICK OP_MUL OP_11 OP_PICK 14 OP_PICK OP_MUL OP_SUB OP_OVER OP_ROT OP_ADD OP_OVER OP_ROT OP_ADD OP_SWAP OP_16 OP_PICK OP_MUL OP_SWAP OP_16 OP_PICK OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_5 OP_ROLL OP_5 OP_ROLL OP_5 OP_ROLL OP_5 OP_ROLL OP_13 OP_ROLL OP_13 OP_ROLL OP_11 OP_ROLL OP_11 OP_ROLL OP_13 OP_ROLL OP_13 OP_ROLL OP_13 OP_ROLL OP_13 OP_ROLL}} static function mulLine(FQ12 ret, FQ2 a, FQ2 b, FQ2 c) : FQ12 { asm { OP_3 OP_PICK 11 OP_PICK OP_MUL 12 OP_PICK OP_4 OP_PICK OP_MUL OP_ADD OP_3 OP_PICK 12 OP_PICK OP_MUL OP_5 OP_PICK 14 OP_PICK OP_MUL OP_SUB OP_7 OP_PICK 11 OP_PICK OP_MUL 12 OP_PICK OP_8 OP_PICK OP_MUL OP_ADD OP_7 OP_PICK 12 OP_PICK OP_MUL OP_9 OP_PICK 14 OP_PICK OP_MUL OP_SUB OP_3 OP_ROLL OP_ROT OP_ADD OP_ROT OP_ROT OP_ADD OP_4 OP_PICK 11 OP_PICK 13 OP_PICK OP_8 OP_PICK OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_9 OP_PICK 11 OP_PICK OP_MUL 12 OP_PICK OP_10 OP_PICK OP_MUL OP_ADD OP_9 OP_PICK 12 OP_PICK OP_MUL OP_11 OP_PICK 14 OP_PICK OP_MUL OP_SUB OP_3 OP_ROLL OP_ROT OP_ADD OP_ROT OP_ROT OP_ADD OP_6 OP_PICK 11 OP_PICK 13 OP_PICK OP_10 OP_PICK OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_10 OP_PICK 17 OP_PICK 19 OP_PICK OP_14 OP_PICK OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_OVER OP_9 OP_MUL OP_OVER OP_ADD OP_9 OP_ROT OP_MUL OP_ROT OP_SUB OP_3 OP_ROLL OP_ROT OP_ADD OP_ROT OP_ROT OP_ADD 11 OP_PICK OP_7 OP_PICK OP_MUL OP_8 OP_PICK 12 OP_PICK OP_MUL OP_ADD 11 OP_PICK OP_8 OP_PICK OP_MUL 13 OP_PICK OP_10 OP_PICK OP_MUL OP_SUB 11 OP_PICK OP_9 OP_PICK OP_MUL OP_10 OP_PICK 12 OP_PICK OP_MUL OP_ADD 11 OP_PICK OP_10 OP_PICK OP_MUL 13 OP_PICK OP_12 OP_PICK OP_MUL OP_SUB 11 OP_PICK OP_11 OP_PICK OP_MUL OP_12 OP_PICK 12 OP_PICK OP_MUL OP_ADD 11 OP_PICK OP_12 OP_PICK OP_MUL 13 OP_PICK OP_14 OP_PICK OP_MUL OP_SUB OP_15 OP_PICK OP_14 OP_PICK OP_ADD OP_15 OP_PICK OP_14 OP_PICK OP_ADD 1f OP_PICK 1a OP_PICK OP_ADD 1f OP_PICK 1a OP_PICK OP_ADD 1f OP_PICK 1a OP_PICK OP_ADD 1f OP_PICK 1a OP_PICK OP_ADD 1f OP_PICK 1a OP_PICK OP_ADD 1f OP_PICK 1a OP_PICK OP_ADD OP_7 OP_PICK OP_5 OP_PICK OP_MUL OP_6 OP_PICK OP_8 OP_PICK OP_MUL OP_ADD OP_7 OP_PICK OP_6 OP_PICK OP_MUL OP_9 OP_PICK OP_8 OP_PICK OP_MUL OP_SUB 1b OP_PICK OP_5 OP_PICK OP_MUL OP_6 OP_PICK 1c OP_PICK OP_MUL OP_ADD 1b OP_PICK OP_6 OP_PICK OP_MUL 1d OP_PICK OP_8 OP_PICK OP_MUL OP_SUB OP_3 OP_ROLL OP_ROT OP_ADD OP_ROT OP_ROT OP_ADD OP_8 OP_PICK OP_5 OP_ROLL OP_6 OP_ROLL OP_10 OP_PICK OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB 1b OP_PICK OP_5 OP_PICK OP_MUL OP_6 OP_PICK 1c OP_PICK OP_MUL OP_ADD 1b OP_PICK OP_6 OP_PICK OP_MUL 1d OP_PICK OP_8 OP_PICK OP_MUL OP_SUB OP_3 OP_ROLL OP_ROT OP_ADD OP_ROT OP_ROT OP_ADD OP_8 OP_ROLL OP_5 OP_ROLL OP_6 OP_ROLL OP_9 OP_ROLL OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB 18 OP_PICK OP_7 OP_ROLL OP_8 OP_ROLL 1a OP_PICK OP_DUP OP_3 OP_PICK OP_MUL OP_2 OP_PICK OP_5 OP_PICK OP_MUL OP_ADD OP_SWAP OP_ROT OP_MUL OP_3 OP_ROLL OP_3 OP_ROLL OP_MUL OP_SWAP OP_SUB OP_OVER OP_9 OP_MUL OP_OVER OP_ADD OP_9 OP_ROT OP_MUL OP_ROT OP_SUB OP_3 OP_ROLL OP_ROT OP_ADD OP_ROT OP_ROT OP_ADD OP_5 OP_ROLL 11 OP_PICK OP_SUB OP_5 OP_ROLL OP_16 OP_PICK OP_SUB OP_5 OP_ROLL OP_15 OP_PICK OP_SUB OP_5 OP_ROLL OP_14 OP_PICK OP_SUB OP_5 OP_ROLL OP_13 OP_PICK OP_SUB OP_5 OP_ROLL OP_12 OP_PICK OP_SUB OP_5 OP_ROLL OP_11 OP_PICK OP_SUB OP_5 OP_ROLL OP_10 OP_PICK OP_SUB OP_5 OP_ROLL OP_9 OP_PICK OP_SUB OP_5 OP_ROLL OP_8 OP_PICK OP_SUB OP_5 OP_ROLL OP_7 OP_PICK OP_SUB OP_5 OP_ROLL OP_6 OP_PICK OP_SUB OP_15 OP_ROLL OP_15 OP_ROLL OP_15 OP_ROLL OP_15 OP_ROLL 11 OP_ROLL 11 OP_ROLL OP_OVER OP_9 OP_MUL OP_OVER OP_ADD OP_9 OP_ROT OP_MUL OP_ROT OP_SUB 11 OP_ROLL OP_6 OP_ROLL OP_ADD OP_16 OP_ROLL OP_6 OP_ROLL OP_ADD OP_15 OP_ROLL OP_6 OP_ROLL OP_ADD OP_14 OP_ROLL OP_6 OP_ROLL OP_ADD OP_13 OP_ROLL OP_6 OP_ROLL OP_ADD OP_12 OP_ROLL OP_6 OP_ROLL OP_ADD}} static function miller(TwistPoint q, CurvePoint p) : FQ12 { FQ12 ret = BN256.FQ12One; TwistPoint aAffine = BN256.makeAffineTwistPoint(q); CurvePoint bAffine = BN256.makeAffineCurvePoint(p); TwistPoint minusA = BN256.negTwistPoint(aAffine); TwistPoint r = aAffine; FQ2 r2 = BN256.squareFQ2(aAffine.y); LineFuncRes lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, aAffine, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, aAffine, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, minusA, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, aAffine, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, aAffine, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, minusA, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, aAffine, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, aAffine, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, minusA, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, aAffine, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, minusA, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, aAffine, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, aAffine, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, aAffine, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, minusA, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, aAffine, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, minusA, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, aAffine, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, aAffine, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, aAffine, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, minusA, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, aAffine, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, minusA, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, aAffine, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncAdd(r, aAffine, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r = BN256.modTwistPoint(r); ret = BN256.modFQ12(ret); lfr = BN256Pairing.lineFuncDouble(r, bAffine); ret = BN256.squareFQ12(ret); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; FQ2 q1x = BN256.conjugateFQ2(aAffine.x); q1x = BN256.mulFQ2(q1x, BN256.xiToPMinus1Over3); FQ2 q1y = BN256.conjugateFQ2(aAffine.y); q1y = BN256.mulFQ2(q1y, BN256.xiToPMinus1Over2); TwistPoint q1 = {q1x, q1y, {0, 1}, {0, 1}}; FQ2 minusQ2x = BN256.mulScalarFQ2(aAffine.x, 21888242871839275220042445260109153167277707414472061641714758635765020556616); TwistPoint minusQ2 = {minusQ2x, aAffine.y, {0, 1}, {0, 1}}; r2 = BN256.squareFQ2(q1.y); lfr = BN256Pairing.lineFuncAdd(r, q1, bAffine, r2); ret = BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c); r = lfr.rOut; r2 = BN256.squareFQ2(minusQ2.y); lfr = BN256Pairing.lineFuncAdd(r, minusQ2, bAffine, r2); return BN256.modFQ12(BN256Pairing.mulLine(ret, lfr.a, lfr.b, lfr.c)); } static function finalExponentiation(FQ12 a) : FQ12 { FQ12 t1 = {BN256.negFQ6(a.x), a.y}; FQ12 inv = BN256.inverseFQ12(a); t1 = BN256.mulFQ12(t1, inv); FQ12 t2 = BN256.frobeniusP2FQ12(t1); t1 = BN256.mulFQ12(t1, t2); FQ12 fp = BN256.frobeniusFQ12(t1); FQ12 fp2 = BN256.frobeniusP2FQ12(t1); FQ12 fp3 = BN256.frobeniusFQ12(fp2); fp = BN256.modFQ12(fp); fp2 = BN256.modFQ12(fp2); fp3 = BN256.modFQ12(fp3); FQ12 fu = BN256.expFQ12_u(t1); FQ12 fu2 = BN256.expFQ12_u(fu); FQ12 fu3 = BN256.expFQ12_u(fu2); FQ12 y3 = BN256.frobeniusFQ12(fu); FQ12 fu2p = BN256.frobeniusFQ12(fu2); FQ12 fu3p = BN256.frobeniusFQ12(fu3); FQ12 y2 = BN256.frobeniusP2FQ12(fu2); FQ12 y0 = BN256.mulFQ12(fp, fp2); y0 = BN256.mulFQ12(y0, fp3); FQ12 y1 = BN256.conjugateFQ12(t1); FQ12 y5 = BN256.conjugateFQ12(fu2); y3 = BN256.conjugateFQ12(y3); FQ12 y4 = BN256.mulFQ12(fu, fu2p); y4 = BN256.conjugateFQ12(y4); FQ12 y6 = BN256.mulFQ12(fu3, fu3p); y6 = BN256.conjugateFQ12(y6); FQ12 t0 = BN256.squareFQ12(y6); t0 = BN256.modFQ12(t0); t0 = BN256.mulFQ12(t0, y4); t0 = BN256.mulFQ12(t0, y5); t1 = BN256.mulFQ12(y3, y5); t1 = BN256.mulFQ12(t1, t0); t0 = BN256.mulFQ12(t0, y2); t1 = BN256.squareFQ12(t1); t1 = BN256.mulFQ12(t1, t0); t1 = BN256.squareFQ12(t1); t0 = BN256.mulFQ12(t1, y1); t1 = BN256.mulFQ12(t1, y0); t0 = BN256.squareFQ12(t0); t0 = BN256.mulFQ12(t0, t1); t0 = BN256.modFQ12(t0); return t0; } static function _pair(CurvePoint g1, TwistPoint g2) : FQ12 { FQ12 e = BN256Pairing.miller(g2, g1); FQ12 ret = BN256Pairing.finalExponentiation(e); if(BN256.isInfTwistPoint(g2) || BN256.isInfCurvePoint(g1)) { ret = BN256.FQ12One; } return ret; } static function pair(G1Point g1, G2Point g2) : FQ12 { return BN256Pairing._pair(BN256.createCurvePoint(g1), BN256.createTwistPoint(g2)); } static function _pairCheckP4Precalc(CurvePoint a0, TwistPoint b0, FQ12 millerBetaAlpha, CurvePoint a2, TwistPoint b2, CurvePoint a3, TwistPoint b3) : bool { a0 = BN256.makeAffineCurvePoint(a0); a2 = BN256.makeAffineCurvePoint(a2); a3 = BN256.makeAffineCurvePoint(a3); FQ12 acc = millerBetaAlpha; if(!BN256.isInfCurvePoint(a0) && !BN256.isInfTwistPoint(b0)) { acc = BN256.mulFQ12(acc, BN256Pairing.miller(b0, a0)); } acc = BN256.modFQ12(acc); if(!BN256.isInfCurvePoint(a2) && !BN256.isInfTwistPoint(b2)) { acc = BN256.mulFQ12(acc, BN256Pairing.miller(b2, a2)); } acc = BN256.modFQ12(acc); if(!BN256.isInfCurvePoint(a3) && !BN256.isInfTwistPoint(b3)) { acc = BN256.mulFQ12(acc, BN256Pairing.miller(b3, a3)); } acc = BN256.modFQ12(acc); acc = BN256Pairing.finalExponentiation(acc); return BN256.compareFQ12(acc, BN256.FQ12One); } static function pairCheckP4Precalc(G1Point a0, G2Point b0, FQ12 millerBetaAlpha, G1Point a2, G2Point b2, G1Point a3, G2Point b3) : bool { return BN256Pairing._pairCheckP4Precalc(BN256.createCurvePoint(a0), BN256.createTwistPoint(b0), millerBetaAlpha, BN256.createCurvePoint(a2), BN256.createTwistPoint(b2), BN256.createCurvePoint(a3), BN256.createTwistPoint(b3)); } static function _pairCheckP2Precalc(CurvePoint a0, TwistPoint b0, CurvePoint a1, TwistPoint b1) : bool { FQ12 acc = BN256.FQ12One; a0 = BN256.makeAffineCurvePoint(a0); a1 = BN256.makeAffineCurvePoint(a1); if(!BN256.isInfCurvePoint(a0) && !BN256.isInfTwistPoint(b0)) { acc = BN256.mulFQ12(acc, BN256Pairing.miller(b0, a0)); } if(!BN256.isInfCurvePoint(a1) && !BN256.isInfTwistPoint(b1)) { acc = BN256.mulFQ12(acc, BN256Pairing.miller(b1, a1)); } acc = BN256Pairing.finalExponentiation(acc); return acc == BN256.FQ12One; } static function pairCheckP2Precalc(G1Point a0, G2Point b0, G1Point a1, G2Point b1) : bool { return BN256Pairing._pairCheckP2Precalc(BN256.createCurvePoint(a0), BN256.createTwistPoint(b0), BN256.createCurvePoint(a1), BN256.createTwistPoint(b1)); } }