UNPKG

3.16 kBJavaScriptView Raw
1import { u8aIsWrapped, u8aToU8a, u8aUnwrapBytes, u8aWrapBytes } from '@polkadot/util';
2import { decodeAddress } from '../address/decode.js';
3import { ed25519Verify } from '../ed25519/verify.js';
4import { secp256k1Verify } from '../secp256k1/verify.js';
5import { sr25519Verify } from '../sr25519/verify.js';
6const secp256k1VerifyHasher = (hashType) => (message, signature, publicKey) => secp256k1Verify(message, signature, publicKey, hashType);
7const VERIFIERS_ECDSA = [
8 ['ecdsa', secp256k1VerifyHasher('blake2')],
9 ['ethereum', secp256k1VerifyHasher('keccak')]
10];
11const VERIFIERS = [
12 ['ed25519', ed25519Verify],
13 ['sr25519', sr25519Verify],
14 ...VERIFIERS_ECDSA
15];
16const CRYPTO_TYPES = ['ed25519', 'sr25519', 'ecdsa'];
17function verifyDetect(result, { message, publicKey, signature }, verifiers = VERIFIERS) {
18 result.isValid = verifiers.some(([crypto, verify]) => {
19 try {
20 if (verify(message, signature, publicKey)) {
21 result.crypto = crypto;
22 return true;
23 }
24 }
25 catch {
26 // do nothing, result.isValid still set to false
27 }
28 return false;
29 });
30 return result;
31}
32function verifyMultisig(result, { message, publicKey, signature }) {
33 if (![0, 1, 2].includes(signature[0])) {
34 throw new Error(`Unknown crypto type, expected signature prefix [0..2], found ${signature[0]}`);
35 }
36 const type = CRYPTO_TYPES[signature[0]] || 'none';
37 result.crypto = type;
38 try {
39 result.isValid = {
40 ecdsa: () => verifyDetect(result, { message, publicKey, signature: signature.subarray(1) }, VERIFIERS_ECDSA).isValid,
41 ed25519: () => ed25519Verify(message, signature.subarray(1), publicKey),
42 none: () => {
43 throw Error('no verify for `none` crypto type');
44 },
45 sr25519: () => sr25519Verify(message, signature.subarray(1), publicKey)
46 }[type]();
47 }
48 catch {
49 // ignore, result.isValid still set to false
50 }
51 return result;
52}
53function getVerifyFn(signature) {
54 return [0, 1, 2].includes(signature[0]) && [65, 66].includes(signature.length)
55 ? verifyMultisig
56 : verifyDetect;
57}
58export function signatureVerify(message, signature, addressOrPublicKey) {
59 const signatureU8a = u8aToU8a(signature);
60 if (![64, 65, 66].includes(signatureU8a.length)) {
61 throw new Error(`Invalid signature length, expected [64..66] bytes, found ${signatureU8a.length}`);
62 }
63 const publicKey = decodeAddress(addressOrPublicKey);
64 const input = { message: u8aToU8a(message), publicKey, signature: signatureU8a };
65 const result = { crypto: 'none', isValid: false, isWrapped: u8aIsWrapped(input.message, true), publicKey };
66 const isWrappedBytes = u8aIsWrapped(input.message, false);
67 const verifyFn = getVerifyFn(signatureU8a);
68 verifyFn(result, input);
69 if (result.crypto !== 'none' || (result.isWrapped && !isWrappedBytes)) {
70 return result;
71 }
72 input.message = isWrappedBytes
73 ? u8aUnwrapBytes(input.message)
74 : u8aWrapBytes(input.message);
75 return verifyFn(result, input);
76}