@taquito/utils
Version:
converts michelson data and types into convenient JS/TS objects
110 lines (109 loc) • 4.99 kB
JavaScript
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;
}
;