UNPKG

@polkadot/util-crypto

Version:
82 lines (81 loc) 3.61 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.signatureVerify = signatureVerify; const util_1 = require("@polkadot/util"); const decode_js_1 = require("../address/decode.js"); const verify_js_1 = require("../ed25519/verify.js"); const verify_js_2 = require("../secp256k1/verify.js"); const verify_js_3 = require("../sr25519/verify.js"); const secp256k1VerifyHasher = (hashType) => (message, signature, publicKey) => (0, verify_js_2.secp256k1Verify)(message, signature, publicKey, hashType); const VERIFIERS_ECDSA = [ ['ecdsa', secp256k1VerifyHasher('blake2')], ['ethereum', secp256k1VerifyHasher('keccak')] ]; const VERIFIERS = [ ['ed25519', verify_js_1.ed25519Verify], ['sr25519', verify_js_3.sr25519Verify] ]; function verifyDetect(result, { message, publicKey, signature }, verifiers = [...VERIFIERS, ...VERIFIERS_ECDSA]) { result.isValid = verifiers.some(([crypto, verify]) => { try { if (verify(message, signature, publicKey)) { result.crypto = crypto; return true; } } catch { // do nothing, result.isValid still set to false } return false; }); return result; } function verifyMultisig(result, { message, publicKey, signature }) { if (![0, 1, 2].includes(signature[0]) || ![65, 66].includes(signature.length)) { throw new Error(`Unknown crypto type, expected signature prefix [0..2], found ${signature[0]}`); } // If the signature is 66 bytes it must be an ecdsa signature // containing: prefix [1 byte] + signature [65] bytes. // Remove the and then verify if (signature.length === 66) { result = verifyDetect(result, { message, publicKey, signature: signature.subarray(1) }, VERIFIERS_ECDSA); } else { // The signature contains 65 bytes which is either // - A ed25519 or sr25519 signature [1 byte prefix + 64 bytes] // - An ecdsa signature [65 bytes] result = verifyDetect(result, { message, publicKey, signature: signature.subarray(1) }, VERIFIERS); if (!result.isValid) { result = verifyDetect(result, { message, publicKey, signature }, VERIFIERS_ECDSA); } // If both failed, explicitly set crypto to 'none' if (!result.isValid) { result.crypto = 'none'; } } return result; } function getVerifyFn(signature) { return [0, 1, 2].includes(signature[0]) && [65, 66].includes(signature.length) ? verifyMultisig : verifyDetect; } function signatureVerify(message, signature, addressOrPublicKey) { const signatureU8a = (0, util_1.u8aToU8a)(signature); if (![64, 65, 66].includes(signatureU8a.length)) { throw new Error(`Invalid signature length, expected [64..66] bytes, found ${signatureU8a.length}`); } const publicKey = (0, decode_js_1.decodeAddress)(addressOrPublicKey); const input = { message: (0, util_1.u8aToU8a)(message), publicKey, signature: signatureU8a }; const result = { crypto: 'none', isValid: false, isWrapped: (0, util_1.u8aIsWrapped)(input.message, true), publicKey }; const isWrappedBytes = (0, util_1.u8aIsWrapped)(input.message, false); const verifyFn = getVerifyFn(signatureU8a); verifyFn(result, input); if (result.crypto !== 'none' || (result.isWrapped && !isWrappedBytes)) { return result; } input.message = isWrappedBytes ? (0, util_1.u8aUnwrapBytes)(input.message) : (0, util_1.u8aWrapBytes)(input.message); return verifyFn(result, input); }