UNPKG

@taquito/utils

Version:

converts michelson data and types into convenient JS/TS objects

110 lines (109 loc) 4.99 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.verifySignature = verifySignature; exports.validatePkAndExtractPrefix = validatePkAndExtractPrefix; const ed25519_1 = require("@stablelib/ed25519"); const blake2b_1 = require("@stablelib/blake2b"); const taquito_utils_1 = require("./taquito-utils"); const elliptic_1 = require("elliptic"); const typedarray_to_buffer_1 = require("typedarray-to-buffer"); const core_1 = require("@taquito/core"); /** * @description Verify signature of a payload * * @param messageBytes The forged message including the magic byte (11 for block, * 12 for preattestation, 13 for attestation, 3 for generic, 5 for the PACK format of michelson) * @param publicKey The public key to verify the signature against * @param signature The signature to verify * @returns A boolean indicating if the signature matches * @throws {@link InvalidPublicKeyError} | {@link InvalidSignatureError} | {@link InvalidMessageError} * @example * ``` * const message = '03d0c10e3ed11d7c6e3357f6ef335bab9e8f2bd54d0ce20c482e241191a6e4b8ce6c01be917311d9ac46959750e405d57e268e2ed9e174a80794fbd504e12a4a000141eb3781afed2f69679ff2bbe1c5375950b0e40d00ff000000005e05050505050507070100000024747a32526773486e74516b72794670707352466261313652546656503539684b72654a4d07070100000024747a315a6672455263414c42776d4171776f6e525859565142445439426a4e6a42484a750001'; * const pk = 'sppk7c7hkPj47yjYFEHX85q46sFJGw6RBrqoVSHwAJAT4e14KJwzoey'; * const sig = 'spsig1cdLkp1RLgUHAp13aRFkZ6MQDPp7xCnjAExGL3MBSdMDmT6JgQSX8cufyDgJRM3sinFtiCzLbsyP6d365EHoNevxhT47nx' * * const response = verifySignature(message, pk, sig); * ``` * */ function verifySignature(messageBytes, publicKey, signature, watermark) { const pkPrefix = validatePkAndExtractPrefix(publicKey); const sigPrefix = validateSigAndExtractPrefix(signature); const decodedPublicKey = (0, taquito_utils_1.b58cdecode)(publicKey, taquito_utils_1.prefix[pkPrefix]); const decodedSig = (0, taquito_utils_1.b58cdecode)(signature, taquito_utils_1.prefix[sigPrefix]); let messageBuf = (0, taquito_utils_1.hex2buf)(validateMessageNotEmpty(messageBytes)); if (typeof watermark !== 'undefined') { messageBuf = (0, taquito_utils_1.mergebuf)(watermark, messageBuf); } const bytesHash = (0, blake2b_1.hash)(messageBuf, 32); if (pkPrefix === taquito_utils_1.Prefix.EDPK) { return verifyEdSignature(decodedSig, bytesHash, decodedPublicKey); } else if (pkPrefix === taquito_utils_1.Prefix.SPPK) { return verifySpSignature(decodedSig, bytesHash, decodedPublicKey); } else if (pkPrefix === taquito_utils_1.Prefix.P2PK) { return verifyP2Signature(decodedSig, bytesHash, decodedPublicKey); } else { return false; } } function validateMessageNotEmpty(message) { if (message === '') { throw new core_1.InvalidMessageError(message, `can't be empty`); } return message; } function validatePkAndExtractPrefix(publicKey) { if (publicKey === '') { throw new core_1.InvalidPublicKeyError(publicKey, `can't be empty`); } const pkPrefix = publicKey.substring(0, 4); const publicKeyValidation = (0, taquito_utils_1.validatePublicKey)(publicKey); if (publicKeyValidation !== taquito_utils_1.ValidationResult.VALID) { throw new core_1.InvalidPublicKeyError(publicKey, (0, taquito_utils_1.invalidDetail)(publicKeyValidation)); } return pkPrefix; } function validateSigAndExtractPrefix(signature) { const signaturePrefix = signature.startsWith('sig') ? signature.substring(0, 3) : signature.substring(0, 5); const validation = (0, taquito_utils_1.validateSignature)(signature); if (validation !== taquito_utils_1.ValidationResult.VALID) { throw new core_1.InvalidSignatureError(signature, (0, taquito_utils_1.invalidDetail)(validation)); } return signaturePrefix; } function verifyEdSignature(decodedSig, bytesHash, decodedPublicKey) { try { return (0, ed25519_1.verify)(decodedPublicKey, bytesHash, decodedSig); } catch (e) { return false; } } function verifySpSignature(decodedSig, bytesHash, decodedPublicKey) { const key = new elliptic_1.default.ec('secp256k1').keyFromPublic(decodedPublicKey); return verifySpOrP2Sig(decodedSig, bytesHash, key); } function verifyP2Signature(decodedSig, bytesHash, decodedPublicKey) { const key = new elliptic_1.default.ec('p256').keyFromPublic(decodedPublicKey); return verifySpOrP2Sig(decodedSig, bytesHash, key); } function verifySpOrP2Sig(decodedSig, bytesHash, key) { const hexSig = (0, taquito_utils_1.buf2hex)((0, typedarray_to_buffer_1.default)(decodedSig)); const match = hexSig.match(/([a-f\d]{64})/gi); if (match) { try { const [r, s] = match; return key.verify(bytesHash, { r, s }); } catch (e) { return false; } } return false; }