"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.bn254_weierstrass = exports.bn254 = exports._postPrecompute = void 0;
/**
 * bn254, previously known as alt_bn_128, when it had 128-bit security.

Barbulescu-Duquesne 2017 shown it's weaker: just about 100 bits,
so the naming has been adjusted to its prime bit count:
https://hal.science/hal-01534101/file/main.pdf.
Compatible with EIP-196 and EIP-197.

There are huge compatibility issues in the ecosystem:

1. Different libraries call it in different ways: "bn254", "bn256", "alt_bn128", "bn128".
2. libff has bn128, but it's a different curve with different G2:
   https://github.com/scipr-lab/libff/blob/a44f482e18b8ac04d034c193bd9d7df7817ad73f/libff/algebra/curves/bn128/bn128_init.cpp#L166-L169
3. halo2curves bn256 is also incompatible and returns different outputs

The goal of our implementation is to support "Ethereum" variant of the curve,
because it at least has specs:

- EIP196 (https://eips.ethereum.org/EIPS/eip-196) describes bn254 ECADD and ECMUL opcodes for EVM
- EIP197 (https://eips.ethereum.org/EIPS/eip-197) describes bn254 pairings
- It's hard: EIPs don't have proper tests. EIP-197 returns boolean output instead of Fp12
- The existing implementations are bad. Some are deprecated:
    - https://github.com/paritytech/bn (old version)
    - https://github.com/ewasm/ethereum-bn128.rs (uses paritytech/bn)
    - https://github.com/zcash-hackworks/bn
    - https://github.com/arkworks-rs/curves/blob/master/bn254/src/lib.rs
- Python implementations use different towers and produce different Fp12 outputs:
    - https://github.com/ethereum/py_pairing
    - https://github.com/ethereum/execution-specs/blob/master/src/ethereum/crypto/alt_bn128.py
- Points are encoded differently in different implementations

### Params
Seed (X): 4965661367192848881
Fr: (36x⁴+36x³+18x²+6x+1)
Fp: (36x⁴+36x³+24x²+6x+1)
(E  / Fp ): Y² = X³+3
(Et / Fp²): Y² = X³+3/(u+9) (D-type twist)
Ate loop size: 6x+2

### Towers
- Fp²[u] = Fp/u²+1
- Fp⁶[v] = Fp²/v³-9-u
- Fp¹²[w] = Fp⁶/w²-v

 * @module
 */
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
const sha256_1 = require("@noble/hashes/sha256");
const _shortw_utils_js_1 = require("./_shortw_utils.js");
const weierstrass_js_1 = require("./abstract/weierstrass.js");
const utils_1 = require("@noble/hashes/utils");
const bls_js_1 = require("./abstract/bls.js");
const modular_js_1 = require("./abstract/modular.js");
const utils_js_1 = require("./abstract/utils.js");
const tower_js_1 = require("./abstract/tower.js");
// prettier-ignore
const _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);
// prettier-ignore
const _6n = BigInt(6);
const BN_X = BigInt('4965661367192848881');
const BN_X_LEN = (0, utils_js_1.bitLen)(BN_X);
const SIX_X_SQUARED = _6n * BN_X ** _2n;
// Finite field over r. It's for convenience and is not used in the code below.
const Fr = (0, modular_js_1.Field)(BigInt('21888242871839275222246405745257275088548364400416034343698204186575808495617'));
// Fp2.div(Fp2.mul(Fp2.ONE, _3n), Fp2.NONRESIDUE)
const Fp2B = {
    c0: BigInt('19485874751759354771024239261021720505790618469301721065564631296452457478373'),
    c1: BigInt('266929791119991161246907387137283842545076965332900288569378510910307636690'),
};
const { Fp, Fp2, Fp6, Fp4Square, Fp12 } = (0, tower_js_1.tower12)({
    ORDER: BigInt('21888242871839275222246405745257275088696311157297823662689037894645226208583'),
    FP2_NONRESIDUE: [BigInt(9), _1n],
    Fp2mulByB: (num) => Fp2.mul(num, Fp2B),
    // The result of any pairing is in a cyclotomic subgroup
    // https://eprint.iacr.org/2009/565.pdf
    Fp12cyclotomicSquare: ({ c0, c1 }) => {
        const { c0: c0c0, c1: c0c1, c2: c0c2 } = c0;
        const { c0: c1c0, c1: c1c1, c2: c1c2 } = c1;
        const { first: t3, second: t4 } = Fp4Square(c0c0, c1c1);
        const { first: t5, second: t6 } = Fp4Square(c1c0, c0c2);
        const { first: t7, second: t8 } = Fp4Square(c0c1, c1c2);
        let t9 = Fp2.mulByNonresidue(t8); // T8 * (u + 1)
        return {
            c0: Fp6.create({
                c0: Fp2.add(Fp2.mul(Fp2.sub(t3, c0c0), _2n), t3), // 2 * (T3 - c0c0)  + T3
                c1: Fp2.add(Fp2.mul(Fp2.sub(t5, c0c1), _2n), t5), // 2 * (T5 - c0c1)  + T5
                c2: Fp2.add(Fp2.mul(Fp2.sub(t7, c0c2), _2n), t7),
            }), // 2 * (T7 - c0c2)  + T7
            c1: Fp6.create({
                c0: Fp2.add(Fp2.mul(Fp2.add(t9, c1c0), _2n), t9), // 2 * (T9 + c1c0) + T9
                c1: Fp2.add(Fp2.mul(Fp2.add(t4, c1c1), _2n), t4), // 2 * (T4 + c1c1) + T4
                c2: Fp2.add(Fp2.mul(Fp2.add(t6, c1c2), _2n), t6),
            }),
        }; // 2 * (T6 + c1c2) + T6
    },
    Fp12cyclotomicExp(num, n) {
        let z = Fp12.ONE;
        for (let i = BN_X_LEN - 1; i >= 0; i--) {
            z = Fp12._cyclotomicSquare(z);
            if ((0, utils_js_1.bitGet)(n, i))
                z = Fp12.mul(z, num);
        }
        return z;
    },
    // https://eprint.iacr.org/2010/354.pdf
    // https://eprint.iacr.org/2009/565.pdf
    Fp12finalExponentiate: (num) => {
        const powMinusX = (num) => Fp12.conjugate(Fp12._cyclotomicExp(num, BN_X));
        const r0 = Fp12.mul(Fp12.conjugate(num), Fp12.inv(num));
        const r = Fp12.mul(Fp12.frobeniusMap(r0, 2), r0);
        const y1 = Fp12._cyclotomicSquare(powMinusX(r));
        const y2 = Fp12.mul(Fp12._cyclotomicSquare(y1), y1);
        const y4 = powMinusX(y2);
        const y6 = powMinusX(Fp12._cyclotomicSquare(y4));
        const y8 = Fp12.mul(Fp12.mul(Fp12.conjugate(y6), y4), Fp12.conjugate(y2));
        const y9 = Fp12.mul(y8, y1);
        return Fp12.mul(Fp12.frobeniusMap(Fp12.mul(Fp12.conjugate(r), y9), 3), Fp12.mul(Fp12.frobeniusMap(y8, 2), Fp12.mul(Fp12.frobeniusMap(y9, 1), Fp12.mul(Fp12.mul(y8, y4), r))));
    },
});
// END OF CURVE FIELDS
const { G2psi, psi } = (0, tower_js_1.psiFrobenius)(Fp, Fp2, Fp2.NONRESIDUE);
/*
No hashToCurve for now (and signatures):

- RFC 9380 doesn't mention bn254 and doesn't provide test vectors
- Overall seems like nobody is using BLS signatures on top of bn254
- Seems like it can utilize SVDW, which is not implemented yet
*/
const htfDefaults = Object.freeze({
    // DST: a domain separation tag defined in section 2.2.5
    DST: 'BN254G2_XMD:SHA-256_SVDW_RO_',
    encodeDST: 'BN254G2_XMD:SHA-256_SVDW_RO_',
    p: Fp.ORDER,
    m: 2,
    k: 128,
    expand: 'xmd',
    hash: sha256_1.sha256,
});
const _postPrecompute = (Rx, Ry, Rz, Qx, Qy, pointAdd) => {
    const q = psi(Qx, Qy);
    ({ Rx, Ry, Rz } = pointAdd(Rx, Ry, Rz, q[0], q[1]));
    const q2 = psi(q[0], q[1]);
    pointAdd(Rx, Ry, Rz, q2[0], Fp2.neg(q2[1]));
};
exports._postPrecompute = _postPrecompute;
/**
 * bn254 (a.k.a. alt_bn128) pairing-friendly curve.
 * Contains G1 / G2 operations and pairings.
 */
exports.bn254 = (0, bls_js_1.bls)({
    // Fields
    fields: { Fp, Fp2, Fp6, Fp12, Fr },
    G1: {
        Fp,
        h: BigInt(1),
        Gx: BigInt(1),
        Gy: BigInt(2),
        a: Fp.ZERO,
        b: _3n,
        htfDefaults: { ...htfDefaults, m: 1, DST: 'BN254G2_XMD:SHA-256_SVDW_RO_' },
        wrapPrivateKey: true,
        allowInfinityPoint: true,
        mapToCurve: utils_js_1.notImplemented,
        fromBytes: utils_js_1.notImplemented,
        toBytes: utils_js_1.notImplemented,
        ShortSignature: {
            fromHex: utils_js_1.notImplemented,
            toRawBytes: utils_js_1.notImplemented,
            toHex: utils_js_1.notImplemented,
        },
    },
    G2: {
        Fp: Fp2,
        // cofactor: (36 * X^4) + (36 * X^3) + (30 * X^2) + 6*X + 1
        h: BigInt('21888242871839275222246405745257275088844257914179612981679871602714643921549'),
        Gx: Fp2.fromBigTuple([
            BigInt('10857046999023057135944570762232829481370756359578518086990519993285655852781'),
            BigInt('11559732032986387107991004021392285783925812861821192530917403151452391805634'),
        ]),
        Gy: Fp2.fromBigTuple([
            BigInt('8495653923123431417604973247489272438418190587263600148770280649306958101930'),
            BigInt('4082367875863433681332203403145435568316851327593401208105741076214120093531'),
        ]),
        a: Fp2.ZERO,
        b: Fp2B,
        hEff: BigInt('21888242871839275222246405745257275088844257914179612981679871602714643921549'),
        htfDefaults: { ...htfDefaults },
        wrapPrivateKey: true,
        allowInfinityPoint: true,
        isTorsionFree: (c, P) => P.multiplyUnsafe(SIX_X_SQUARED).equals(G2psi(c, P)), // [p]P = [6X^2]P
        mapToCurve: utils_js_1.notImplemented,
        fromBytes: utils_js_1.notImplemented,
        toBytes: utils_js_1.notImplemented,
        Signature: {
            fromHex: utils_js_1.notImplemented,
            toRawBytes: utils_js_1.notImplemented,
            toHex: utils_js_1.notImplemented,
        },
    },
    params: {
        ateLoopSize: BN_X * _6n + _2n,
        r: Fr.ORDER,
        xNegative: false,
        twistType: 'divisive',
    },
    htfDefaults,
    hash: sha256_1.sha256,
    randomBytes: utils_1.randomBytes,
    postPrecompute: exports._postPrecompute,
});
/**
 * bn254 weierstrass curve with ECDSA.
 * This is very rare and probably not used anywhere.
 * Instead, you should use G1 / G2, defined above.
 */
exports.bn254_weierstrass = (0, weierstrass_js_1.weierstrass)({
    a: BigInt(0),
    b: BigInt(3),
    Fp,
    n: BigInt('21888242871839275222246405745257275088548364400416034343698204186575808495617'),
    Gx: BigInt(1),
    Gy: BigInt(2),
    h: BigInt(1),
    ...(0, _shortw_utils_js_1.getHash)(sha256_1.sha256),
});
//# sourceMappingURL=bn254.js.map