UNPKG

@shard-auth/client

Version:

Next-generation API authentication without secret keys - MPC-based authentication with FROST threshold signatures

83 lines 3.7 kB
"use strict"; /** * API用のFROST署名実装 * 協調署名のための部分署名生成と結合 */ Object.defineProperty(exports, "__esModule", { value: true }); exports.createAPIPartialSignature = createAPIPartialSignature; exports.combineAPIPartialSignatures = combineAPIPartialSignatures; exports.verifyAPISignature = verifyAPISignature; const secp256k1_1 = require("@noble/curves/secp256k1"); const sha256_1 = require("@noble/hashes/sha256"); const order = secp256k1_1.secp256k1.CURVE.n; // API用の部分署名生成 async function createAPIPartialSignature(share, message, nonce, otherNonceCommitment, groupPublicKey) { // 自分のノンスコミットメントを計算 const ownNonceCommitment = computeNonceCommitmentFromNonce(nonce); // グループコミットメントを計算(R = R1 + R2) const R1 = secp256k1_1.secp256k1.ProjectivePoint.fromHex(share.index === 1 ? ownNonceCommitment.hiding : otherNonceCommitment.hiding); const R2 = secp256k1_1.secp256k1.ProjectivePoint.fromHex(share.index === 2 ? ownNonceCommitment.hiding : otherNonceCommitment.hiding); const groupCommitment = R1.add(R2); const groupCommitmentBytes = groupCommitment.toRawBytes(true); // チャレンジを計算 e = H(R || P || m) const challenge = (0, sha256_1.sha256)(Buffer.concat([ groupCommitmentBytes, groupPublicKey, message ])); const e = BigInt('0x' + Buffer.from(challenge).toString('hex')) % order; // 部分署名を計算 si = ri + e * xi const ri = BigInt('0x' + nonce.hiding.toString('hex')); const xi = BigInt('0x' + share.share.toString('hex')); const si = (ri + e * xi) % order; return { partialSignature: { index: share.index, signature: Buffer.from(si.toString(16).padStart(64, '0'), 'hex'), proof: Buffer.alloc(64), // 簡略化 nonceCommitment: share.index === 1 ? ownNonceCommitment : otherNonceCommitment }, groupCommitment: Buffer.from(groupCommitmentBytes) }; } // 部分署名の結合 async function combineAPIPartialSignatures(partialSig1, partialSig2, groupCommitment) { // s = s1 + s2 const s1 = BigInt('0x' + partialSig1.signature.toString('hex')); const s2 = BigInt('0x' + partialSig2.signature.toString('hex')); const s = (s1 + s2) % order; return { r: groupCommitment, s: Buffer.from(s.toString(16).padStart(64, '0'), 'hex'), async verify(message, publicKey) { return verifyAPISignature(groupCommitment, s, message, publicKey); } }; } // 署名検証 function verifyAPISignature(r, s, message, publicKey) { try { const R = secp256k1_1.secp256k1.ProjectivePoint.fromHex(r); const P = secp256k1_1.secp256k1.ProjectivePoint.fromHex(publicKey); // e = H(R || P || m) const challenge = (0, sha256_1.sha256)(Buffer.concat([r, publicKey, message])); const e = BigInt('0x' + Buffer.from(challenge).toString('hex')) % order; // 検証: s*G = R + e*P const sG = secp256k1_1.secp256k1.ProjectivePoint.BASE.multiply(s); const RplusEP = R.add(P.multiply(e)); return sG.equals(RplusEP); } catch { return false; } } // ノンスからコミットメントを計算 function computeNonceCommitmentFromNonce(nonce) { const hidingPoint = secp256k1_1.secp256k1.ProjectivePoint.BASE.multiply(BigInt('0x' + nonce.hiding.toString('hex'))); // bindingは簡略化のため省略 return { hiding: Buffer.from(hidingPoint.toRawBytes(true)), binding: Buffer.alloc(33) // ダミー }; } //# sourceMappingURL=frost-api-signature.js.map