UNPKG

@nikkolasg/noble-bls12-381

Version:

Noble BLS12-381 pairing-friendly curve. High-security, easily auditable, 0-dep aggregated signatures & pubkey.

167 lines (166 loc) 7.92 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const fp_1 = require("./fp"); const point_1 = require("./point"); const fp2_1 = require("./fp2"); const fp12_1 = require("./fp12"); const utils_1 = require("./utils"); var fp_2 = require("./fp"); exports.Fp = fp_2.Fp; var fp2_2 = require("./fp2"); exports.Fp2 = fp2_2.Fp2; var fp12_2 = require("./fp12"); exports.Fp12 = fp12_2.Fp12; var point_2 = require("./point"); exports.Point = point_2.Point; var utils_2 = require("./utils"); exports.P = utils_2.P; exports.PRIME_ORDER = utils_2.PRIME_ORDER; exports.G1 = new point_1.Point(new fp_1.Fp(3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507n), new fp_1.Fp(1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569n), new fp_1.Fp(1n), fp_1.Fp); exports.G2 = new point_1.Point(new fp2_1.Fp2(352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160n, 3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758n), new fp2_1.Fp2(1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905n, 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582n), new fp2_1.Fp2(1n, 0n), fp2_1.Fp2); const G12 = exports.G2.twist(); const ONE = exports.G1; const TWO = exports.G1.double(); const THREE = exports.G1.multiply(3); const NE_ONE = exports.G1.multiply(utils_1.PRIME_ORDER - 1n); const NE_TWO = exports.G1.multiply(utils_1.PRIME_ORDER - 2n); const NE_THREE = exports.G1.multiply(utils_1.PRIME_ORDER - 3n); function createLineBetween(p1, p2, n) { let mNumerator = p2.y.multiply(p1.z).subtract(p1.y.multiply(p2.z)); let mDenominator = p2.x.multiply(p1.z).subtract(p1.x.multiply(p2.z)); if (!mNumerator.equals(mNumerator.zero) && mDenominator.equals(mDenominator.zero)) { return [ n.x.multiply(p1.z).subtract(p1.x.multiply(n.z)), p1.z.multiply(n.z) ]; } else if (mNumerator.equals(mNumerator.zero)) { mNumerator = p1.x.square().multiply(3n); mDenominator = p1.y.multiply(p1.z).multiply(2n); } const numeratorLine = mNumerator.multiply(n.x.multiply(p1.z).subtract(p1.x.multiply(n.z))); const denominatorLine = mDenominator.multiply(n.y.multiply(p1.z).subtract(p1.y.multiply(n.z))); const z = mDenominator.multiply(n.z).multiply(p1.z); return [numeratorLine.subtract(denominatorLine), z]; } function castPointToFp12(pt) { if (pt.isEmpty()) { return new point_1.Point(new fp12_1.Fp12(), new fp12_1.Fp12(), new fp12_1.Fp12(), fp12_1.Fp12); } return new point_1.Point(new fp12_1.Fp12(pt.x.value, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n), new fp12_1.Fp12(pt.y.value, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n), new fp12_1.Fp12(pt.z.value, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n), fp12_1.Fp12); } const PSEUDO_BINARY_ENCODING = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1 ]; function millerLoop(Q, P, withFinalExponent = false) { const one = new fp12_1.Fp12(1n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n); if (Q.isEmpty() || P.isEmpty()) { return one; } let R = Q; let fNumerator = one; let fDenominator = one; for (let i = PSEUDO_BINARY_ENCODING.length - 2; i >= 0n; i--) { const [n, d] = createLineBetween(R, R, P); fNumerator = fNumerator.square().multiply(n); fDenominator = fDenominator.square().multiply(d); R = R.double(); if (PSEUDO_BINARY_ENCODING[i] === 1) { const [n, d] = createLineBetween(R, Q, P); fNumerator = fNumerator.multiply(n); fDenominator = fDenominator.multiply(d); R = R.add(Q); } } const f = fNumerator.div(fDenominator); return withFinalExponent ? f.pow(utils_1.P_ORDER_X_12_DIVIDED) : f; } function finalExponentiate(p) { return p.pow(utils_1.P_ORDER_X_12_DIVIDED); } function pairing(Q, P, withFinalExponent = true) { if (!Q.isOnCurve(utils_1.B2)) { throw new Error("Fisrt point isn't on elliptic curve"); } if (!P.isOnCurve(utils_1.B)) { throw new Error("Second point isn't on elliptic curve"); } return millerLoop(Q.twist(), castPointToFp12(P), withFinalExponent); } exports.pairing = pairing; function getPublicKey(privateKey) { privateKey = utils_1.toBigInt(privateKey); return utils_1.publicKeyFromG1(exports.G1.multiply(privateKey)); } exports.getPublicKey = getPublicKey; async function sign(message, privateKey, domain) { domain = domain instanceof Uint8Array ? domain : utils_1.toBytesBE(domain, utils_1.DOMAIN_LENGTH); privateKey = utils_1.toBigInt(privateKey); const messageValue = await utils_1.hashToG2(message, domain); const signature = messageValue.multiply(privateKey); return utils_1.signatureFromG2(signature); } exports.sign = sign; async function verify(message, publicKey, signature, domain) { domain = domain instanceof Uint8Array ? domain : utils_1.toBytesBE(domain, utils_1.DOMAIN_LENGTH); const publicKeyPoint = utils_1.publicKeyToG1(publicKey).negative(); const signaturePoint = utils_1.signatureToG2(signature); try { const signaturePairing = pairing(signaturePoint, exports.G1); const hashPairing = pairing(await utils_1.hashToG2(message, domain), publicKeyPoint); const finalExponent = finalExponentiate(signaturePairing.multiply(hashPairing)); return finalExponent.equals(finalExponent.one); } catch { return false; } } exports.verify = verify; function aggregatePublicKeys(publicKeys) { if (publicKeys.length === 0) { throw new Error("Provide public keys which should be aggregated"); } const aggregatedPublicKey = publicKeys.reduce((sum, publicKey) => sum.add(utils_1.publicKeyToG1(publicKey)), utils_1.Z1); return utils_1.publicKeyFromG1(aggregatedPublicKey); } exports.aggregatePublicKeys = aggregatePublicKeys; function aggregateSignatures(signatures) { if (signatures.length === 0) { throw new Error("Provide signatures which should be aggregated"); } const aggregatedSignature = signatures.reduce((sum, signature) => sum.add(utils_1.signatureToG2(signature)), utils_1.Z2); return utils_1.signatureFromG2(aggregatedSignature); } exports.aggregateSignatures = aggregateSignatures; async function verifyMultiple(messages, publicKeys, signature, domain) { domain = domain instanceof Uint8Array ? domain : utils_1.toBytesBE(domain, utils_1.DOMAIN_LENGTH); if (messages.length === 0) { throw new Error("Provide messsages which should be verified"); } if (publicKeys.length !== messages.length) { throw new Error("Count of public keys should be the same as messages"); } try { let producer = new fp12_1.Fp12().one; for (const message of new Set(messages)) { const groupPublicKey = messages.reduce((groupPublicKey, m, i) => m !== message ? groupPublicKey : groupPublicKey.add(utils_1.publicKeyToG1(publicKeys[i])), utils_1.Z1); producer = producer.multiply(pairing(await utils_1.hashToG2(message, domain), groupPublicKey)); } producer = producer.multiply(pairing(utils_1.signatureToG2(signature), exports.G1.negative())); const finalExponent = finalExponentiate(producer); return finalExponent.equals(finalExponent.one); } catch { return false; } } exports.verifyMultiple = verifyMultiple;