PHP WebShell
Текущая директория: /usr/lib/node_modules/bitgo/node_modules/@brandonblack/musig/lib/esm
Просмотр файла: index.js
/*! musig-js - MIT License (c) 2022 Brandon Black */
const TAGS = {
challenge: 'BIP0340/challenge',
keyagg_list: 'KeyAgg list',
keyagg_coef: 'KeyAgg coefficient',
musig_aux: 'MuSig/aux',
musig_nonce: 'MuSig/nonce',
musig_deterministic_nonce: 'MuSig/deterministic/nonce',
musig_noncecoef: 'MuSig/noncecoef',
};
function compare32b(a, b) {
if (a.length !== 32 || b.length !== 32) throw new Error('Invalid array');
const aD = new DataView(a.buffer, a.byteOffset, a.length);
const bD = new DataView(b.buffer, b.byteOffset, b.length);
for (let i = 0; i < 8; i++) {
const cmp = aD.getUint32(i * 4) - bD.getUint32(i * 4);
if (cmp !== 0) return cmp;
}
return 0;
}
function compare33b(a, b) {
if (a.length !== 33 || b.length !== 33) throw new Error('Invalid array');
const cmp = a[0] - b[0];
if (cmp !== 0) return cmp;
return compare32b(a.subarray(1), b.subarray(1));
}
const makeSessionId =
typeof self === 'object' && (self.crypto || self.msCrypto)
? () => (self.crypto || self.msCrypto).getRandomValues(new Uint8Array(32))
: () => require('crypto').randomBytes(32);
const _keyAggCache = new WeakMap();
const _coefCache = new WeakMap();
const _nonceCache = new WeakMap();
const _sessionCache = new WeakMap();
export function MuSigFactory(ecc) {
const CPOINT_INF = new Uint8Array(33);
const SCALAR_0 = new Uint8Array(32);
const SCALAR_1 = new Uint8Array(32);
SCALAR_1[31] = 1;
const SCALAR_MINUS_1 = ecc.scalarNegate(SCALAR_1);
function keyAggCoeff(publicKeys, publicKey) {
let coefCache = _coefCache.get(publicKeys);
if (coefCache === undefined) {
coefCache = new Map();
_coefCache.set(publicKeys, coefCache);
}
let coefficient = coefCache.get(publicKey);
if (coefficient) return coefficient;
coefficient = SCALAR_1;
let secondPublicKey;
let publicKeyHash;
let keyAggCache = _keyAggCache.get(publicKeys);
if (keyAggCache === undefined) {
const pkIdx2 = publicKeys.findIndex((pk) => compare33b(pk, publicKeys[0]) !== 0);
secondPublicKey = publicKeys[pkIdx2];
publicKeyHash = ecc.taggedHash(TAGS.keyagg_list, ...publicKeys);
keyAggCache = { publicKeyHash, secondPublicKey };
_keyAggCache.set(publicKeys, keyAggCache);
} else {
({ publicKeyHash, secondPublicKey } = keyAggCache);
}
if (secondPublicKey === undefined || compare33b(publicKey, secondPublicKey) !== 0)
coefficient = ecc.taggedHash(TAGS.keyagg_coef, publicKeyHash, publicKey);
coefCache.set(publicKey, coefficient);
return coefficient;
}
function addTweak(ctx, t) {
const tweak = 'tweak' in t ? t : { tweak: t };
if (!ecc.isScalar(tweak.tweak))
throw new TypeError('Expected tweak to be a valid scalar with curve order');
let { gacc, tacc } = ctx;
let aggPublicKey = ctx.aggPublicKey;
if (!ecc.hasEvenY(aggPublicKey) && tweak.xOnly) {
gacc = ecc.scalarNegate(gacc);
tacc = ecc.scalarNegate(tacc);
aggPublicKey = ecc.pointNegate(aggPublicKey);
}
aggPublicKey = ecc.pointAddTweak(aggPublicKey, tweak.tweak, false);
if (aggPublicKey === null) throw new Error('Unexpected point at infinity during tweaking');
tacc = ecc.scalarAdd(tweak.tweak, tacc);
return { aggPublicKey, gacc, tacc };
}
function keyAgg(publicKeys, ...tweaks) {
checkArgs({ publicKeys });
const multipliedPublicKeys = publicKeys.map((publicKey) => {
const coefficient = keyAggCoeff(publicKeys, publicKey);
let multipliedPublicKey;
if (compare32b(coefficient, SCALAR_1) === 0) {
multipliedPublicKey = publicKey;
} else {
multipliedPublicKey = ecc.pointMultiplyUnsafe(publicKey, coefficient, false);
}
if (multipliedPublicKey === null) throw new Error('Point at infinity during aggregation');
return multipliedPublicKey;
});
const aggPublicKey = multipliedPublicKeys.reduce((a, b) => {
const next = ecc.pointAdd(a, b, false);
if (next === null) throw new Error('Point at infinity during aggregation');
return next;
});
return tweaks.reduce((ctx, tweak) => addTweak(ctx, tweak), {
aggPublicKey,
gacc: SCALAR_1,
tacc: SCALAR_0,
});
}
function getSessionValues(sessionKey) {
const sessionValues = _sessionCache.get(sessionKey);
if (!sessionValues) throw new Error('Invalid session key, please call `startSigningSession`');
return sessionValues;
}
function nonceAgg(publicNonces) {
checkArgs({ publicNonces });
const aggNonces = [publicNonces[0].subarray(0, 33), publicNonces[0].subarray(33)];
for (let i = 1; i < publicNonces.length; i++) {
if (aggNonces[0] !== null)
aggNonces[0] = ecc.pointAdd(aggNonces[0], publicNonces[i].subarray(0, 33), false);
if (aggNonces[1] !== null)
aggNonces[1] = ecc.pointAdd(aggNonces[1], publicNonces[i].subarray(33), false);
}
const aggNonce = new Uint8Array(66);
if (aggNonces[0] !== null) aggNonce.set(ecc.pointCompress(aggNonces[0]), 0);
if (aggNonces[1] !== null) aggNonce.set(ecc.pointCompress(aggNonces[1]), 33);
return aggNonce;
}
function startSigningSessionInner(aggNonce, msg, publicKeys, ctx) {
const pubKeyX = ecc.pointX(ctx.aggPublicKey);
const coefficient = ecc.taggedHash(TAGS.musig_noncecoef, aggNonce, pubKeyX, msg);
const aggNonces = [aggNonce.subarray(0, 33), aggNonce.subarray(33)];
let r = null;
if (compare33b(aggNonces[1], CPOINT_INF) !== 0 && compare33b(aggNonces[0], CPOINT_INF) !== 0) {
r = ecc.pointMultiplyAndAddUnsafe(aggNonces[1], coefficient, aggNonces[0], false);
} else if (compare33b(aggNonces[0], CPOINT_INF) !== 0) {
r = ecc.pointCompress(aggNonces[0], false);
} else if (compare33b(aggNonces[1], CPOINT_INF) !== 0) {
r = ecc.pointMultiplyUnsafe(aggNonces[1], coefficient, false);
}
if (r === null) r = ecc.getPublicKey(SCALAR_1, false);
if (r === null) throw new Error('Failed to get G');
const challenge = ecc.scalarMod(ecc.taggedHash(TAGS.challenge, ecc.pointX(r), pubKeyX, msg));
const key = { publicKey: ctx.aggPublicKey, aggNonce, msg };
_sessionCache.set(key, { ...ctx, coefficient, challenge, finalNonce: r, publicKeys });
return key;
}
function partialVerifyInner({ sig, publicKey, publicNonces, sessionKey }) {
const { msg } = sessionKey;
const { aggPublicKey, gacc, challenge, coefficient, finalNonce, publicKeys } =
getSessionValues(sessionKey);
const rePrime = ecc.pointMultiplyAndAddUnsafe(
publicNonces[1],
coefficient,
publicNonces[0],
false
);
if (rePrime === null) throw new Error('Unexpected public nonce at infinity');
const re = ecc.hasEvenY(finalNonce) ? rePrime : ecc.pointNegate(rePrime);
const a = keyAggCoeff(publicKeys, publicKey);
const g = ecc.hasEvenY(aggPublicKey) ? gacc : ecc.scalarNegate(gacc);
const ea = ecc.scalarMultiply(challenge, a);
const eag = ecc.scalarMultiply(ea, g);
const ver = ecc.pointMultiplyAndAddUnsafe(publicKey, eag, re, true);
if (ver === null) throw new Error('Unexpected verification point at infinity');
const sG = ecc.getPublicKey(sig, true);
if (sG === null) throw new Error('Unexpected signature point at infinity');
return compare33b(ver, sG) === 0;
}
function partialSignInner({ secretKey, publicKey, secretNonces, sessionKey }) {
const { msg } = sessionKey;
const { aggPublicKey, gacc, challenge, coefficient, finalNonce, publicKeys } =
getSessionValues(sessionKey);
const [k1, k2] = secretNonces.map((k) => (ecc.hasEvenY(finalNonce) ? k : ecc.scalarNegate(k)));
const a = keyAggCoeff(publicKeys, publicKey);
const g = ecc.hasEvenY(aggPublicKey) ? gacc : ecc.scalarNegate(gacc);
const d = ecc.scalarMultiply(g, secretKey);
const bk2 = ecc.scalarMultiply(coefficient, k2);
const k1bk2 = ecc.scalarAdd(k1, bk2);
const ea = ecc.scalarMultiply(challenge, a);
const ead = ecc.scalarMultiply(ea, d);
const sig = ecc.scalarAdd(k1bk2, ead);
return sig;
}
function partialSign({ secretKey, publicNonce, sessionKey, verify = true }) {
checkArgs({ publicNonce, secretKey });
const secretNonce = _nonceCache.get(publicNonce);
if (secretNonce === undefined)
throw new Error('No secret nonce found for specified public nonce');
_nonceCache.delete(publicNonce);
const publicKey = ecc.getPublicKey(secretKey, true);
if (publicKey === null) throw new Error('Invalid secret key, no corresponding public key');
if (compare33b(publicKey, secretNonce.subarray(64)) !== 0)
throw new Error('Secret nonce pubkey mismatch');
const secretNonces = [secretNonce.subarray(0, 32), secretNonce.subarray(32, 64)];
const sig = partialSignInner({
secretKey,
publicKey,
secretNonces,
sessionKey,
});
if (verify) {
const publicNonces = [publicNonce.subarray(0, 33), publicNonce.subarray(33)];
const valid = partialVerifyInner({
sig,
publicKey,
publicNonces,
sessionKey,
});
if (!valid) throw new Error('Partial signature failed verification');
}
return sig;
}
function deterministicSign({
secretKey,
aggOtherNonce,
publicKeys,
tweaks = [],
msg,
rand,
verify = true,
nonceOnly = false,
}) {
checkArgs({ rand, secretKey, aggOtherNonce });
const publicKey = ecc.getPublicKey(secretKey, true);
if (publicKey === null) throw new Error('Secret key has no corresponding public key');
let secretKeyPrime;
if (rand !== undefined) {
secretKeyPrime = ecc.taggedHash(TAGS.musig_aux, rand);
for (let i = 0; i < 32; i++) {
secretKeyPrime[i] = secretKeyPrime[i] ^ secretKey[i];
}
} else {
secretKeyPrime = secretKey;
}
const ctx = keyAgg(publicKeys, ...tweaks);
const aggPublicKey = ecc.pointX(ctx.aggPublicKey);
const mLength = new Uint8Array(8);
new DataView(mLength.buffer).setBigUint64(0, BigInt(msg.length));
const secretNonce = new Uint8Array(97);
const publicNonce = new Uint8Array(66);
for (let i = 0; i < 2; i++) {
const kH = ecc.taggedHash(
TAGS.musig_deterministic_nonce,
...[secretKeyPrime, aggOtherNonce, aggPublicKey, mLength, msg, Uint8Array.of(i)]
);
const k = ecc.scalarMod(kH);
if (compare32b(SCALAR_0, k) === 0) throw new Error('0 secret nonce');
const pub = ecc.getPublicKey(k, true);
if (pub === null) throw new Error('Secret nonce has no corresponding public nonce');
secretNonce.set(k, i * 32);
publicNonce.set(pub, i * 33);
}
secretNonce.set(publicKey, 64);
if (nonceOnly) return { publicNonce };
_nonceCache.set(publicNonce, secretNonce);
const aggNonce = nonceAgg([aggOtherNonce, publicNonce]);
const sessionKey = startSigningSessionInner(aggNonce, msg, publicKeys, ctx);
const sig = partialSign({
secretKey,
publicNonce,
sessionKey,
verify,
});
return { sig, sessionKey, publicNonce };
}
const pubKeyArgs = ['publicKey', 'publicKeys'];
const scalarArgs = ['tweak', 'sig', 'sigs', 'tacc', 'gacc'];
const otherArgs32b = ['xOnlyPublicKey', 'rand', 'sessionId'];
const args32b = ['secretKey', ...scalarArgs, ...otherArgs32b];
const pubNonceArgs = ['publicNonce', 'publicNonces', 'aggNonce', 'aggOtherNonce', 'finalNonce'];
const otherArgs = ['aggPublicKey', 'secretNonce'];
const argLengths = new Map();
args32b.forEach((a) => argLengths.set(a, 32));
pubKeyArgs.forEach((a) => argLengths.set(a, 33));
pubNonceArgs.forEach((a) => argLengths.set(a, 66));
argLengths.set('secretNonce', 97);
argLengths.set('aggPublicKey', 65);
const scalarNames = new Set();
scalarArgs.forEach((n) => scalarNames.add(n));
function checkArgs(args) {
for (let [name, values] of Object.entries(args)) {
if (values === undefined) continue;
values = Array.isArray(values) ? values : [values];
if (values.length === 0) throw new TypeError(`0-length ${name}s not supported`);
for (const value of values) {
if (argLengths.get(name) !== value.length)
throw new TypeError(`Invalid ${name} length (${value.length})`);
if (name === 'secretKey') {
if (!ecc.isSecret(value)) throw new TypeError(`Invalid secretKey`);
} else if (name === 'secretNonce') {
for (let i = 0; i < 64; i += 32)
if (!ecc.isSecret(value.subarray(i, i + 32)))
throw new TypeError(`Invalid secretNonce`);
} else if (scalarNames.has(name)) {
for (let i = 0; i < value.length; i += 32)
if (!ecc.isScalar(value.subarray(i, i + 32))) throw new TypeError(`Invalid ${name}`);
}
}
}
}
return {
getXOnlyPubkey: (ctx) => {
if ('aggPublicKey' in ctx) return ecc.pointX(ctx.aggPublicKey);
return ecc.pointX(getSessionValues(ctx).aggPublicKey);
},
getPlainPubkey: (ctx) => {
if ('aggPublicKey' in ctx) return ecc.pointCompress(ctx.aggPublicKey);
return ecc.pointCompress(getSessionValues(ctx).aggPublicKey);
},
keySort: (publicKeys) => {
checkArgs({ publicKeys });
return [...publicKeys].sort((a, b) => compare33b(a, b));
},
keyAgg,
addTweaks: (ctx, ...tweaks) => {
checkArgs(ctx);
return tweaks.reduce((c, tweak) => addTweak(c, tweak), ctx);
},
nonceGen: ({
sessionId = makeSessionId(),
secretKey,
publicKey,
xOnlyPublicKey,
msg,
extraInput,
}) => {
if (extraInput !== undefined && extraInput.length > Math.pow(2, 32) - 1)
throw new TypeError('extraInput is limited to 2^32-1 bytes');
checkArgs({ sessionId, secretKey, publicKey, xOnlyPublicKey });
let rand;
if (secretKey !== undefined) {
rand = ecc.taggedHash(TAGS.musig_aux, sessionId);
for (let i = 0; i < 32; i++) {
rand[i] = rand[i] ^ secretKey[i];
}
} else {
rand = sessionId;
}
if (xOnlyPublicKey === undefined) xOnlyPublicKey = new Uint8Array();
const mPrefixed = [Uint8Array.of(0)];
if (msg !== undefined) {
mPrefixed[0][0] = 1;
mPrefixed.push(new Uint8Array(8));
new DataView(mPrefixed[1].buffer).setBigUint64(0, BigInt(msg.length));
mPrefixed.push(msg);
}
if (extraInput === undefined) extraInput = new Uint8Array();
const eLength = new Uint8Array(4);
new DataView(eLength.buffer).setUint32(0, extraInput.length);
const secretNonce = new Uint8Array(97);
const publicNonce = new Uint8Array(66);
for (let i = 0; i < 2; i++) {
const kH = ecc.taggedHash(
TAGS.musig_nonce,
rand,
Uint8Array.of(publicKey.length),
publicKey,
Uint8Array.of(xOnlyPublicKey.length),
xOnlyPublicKey,
...mPrefixed,
eLength,
extraInput,
Uint8Array.of(i)
);
const k = ecc.scalarMod(kH);
if (compare32b(SCALAR_0, k) === 0) throw new Error('0 secret nonce');
const pub = ecc.getPublicKey(k, true);
if (pub === null) throw new Error('Secret nonce has no corresponding public nonce');
secretNonce.set(k, i * 32);
publicNonce.set(pub, i * 33);
}
secretNonce.set(publicKey, 64);
_nonceCache.set(publicNonce, secretNonce);
return publicNonce;
},
addExternalNonce: (publicNonce, secretNonce) => {
checkArgs({ publicNonce, secretNonce });
_nonceCache.set(publicNonce, secretNonce);
},
deterministicNonceGen: (args) => deterministicSign({ ...args, nonceOnly: true }),
deterministicSign,
nonceAgg,
startSigningSession: (aggNonce, msg, publicKeys, ...tweaks) => {
checkArgs({ aggNonce });
const ctx = keyAgg(publicKeys, ...tweaks);
return startSigningSessionInner(aggNonce, msg, publicKeys, ctx);
},
partialSign,
partialVerify: ({ sig, publicKey, publicNonce, sessionKey }) => {
checkArgs({ sig, publicKey, publicNonce });
const publicNonces = [publicNonce.subarray(0, 33), publicNonce.subarray(33)];
const valid = partialVerifyInner({
sig,
publicKey,
publicNonces,
sessionKey,
});
return valid;
},
signAgg: (sigs, sessionKey) => {
checkArgs({ sigs });
const { aggPublicKey, tacc, challenge, finalNonce } = getSessionValues(sessionKey);
let sPart = ecc.scalarMultiply(challenge, tacc);
if (!ecc.hasEvenY(aggPublicKey)) {
sPart = ecc.scalarNegate(sPart);
}
const aggS = sigs.reduce((a, b) => ecc.scalarAdd(a, b), sPart);
const sig = new Uint8Array(64);
sig.set(ecc.pointX(finalNonce), 0);
sig.set(aggS, 32);
return sig;
},
};
}
Выполнить команду
Для локальной разработки. Не используйте в интернете!