@pezkuwi/util-crypto 14.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/package.json +45 -0
- package/src/address/addressToEvm.spec.ts +16 -0
- package/src/address/addressToEvm.ts +12 -0
- package/src/address/check.spec.ts +44 -0
- package/src/address/check.ts +34 -0
- package/src/address/checksum.spec.ts +45 -0
- package/src/address/checksum.ts +25 -0
- package/src/address/decode.spec.ts +138 -0
- package/src/address/decode.ts +41 -0
- package/src/address/defaults.ts +12 -0
- package/src/address/derive.spec.ts +26 -0
- package/src/address/derive.ts +36 -0
- package/src/address/encode.spec.ts +177 -0
- package/src/address/encode.ts +43 -0
- package/src/address/encodeDerived.spec.ts +14 -0
- package/src/address/encodeDerived.ts +19 -0
- package/src/address/encodeMulti.spec.ts +18 -0
- package/src/address/encodeMulti.ts +18 -0
- package/src/address/eq.spec.ts +45 -0
- package/src/address/eq.ts +24 -0
- package/src/address/evmToAddress.spec.ts +20 -0
- package/src/address/evmToAddress.ts +24 -0
- package/src/address/index.ts +21 -0
- package/src/address/is.spec.ts +113 -0
- package/src/address/is.ts +14 -0
- package/src/address/keyDerived.spec.ts +24 -0
- package/src/address/keyDerived.ts +22 -0
- package/src/address/keyMulti.spec.ts +20 -0
- package/src/address/keyMulti.ts +23 -0
- package/src/address/setSS58Format.spec.ts +21 -0
- package/src/address/setSS58Format.ts +20 -0
- package/src/address/sort.spec.ts +22 -0
- package/src/address/sort.ts +17 -0
- package/src/address/sshash.ts +12 -0
- package/src/address/types.ts +6 -0
- package/src/address/util.ts +8 -0
- package/src/address/validate.spec.ts +113 -0
- package/src/address/validate.ts +10 -0
- package/src/base32/bs32.ts +53 -0
- package/src/base32/decode.spec.ts +34 -0
- package/src/base32/encode.spec.ts +30 -0
- package/src/base32/helpers.ts +93 -0
- package/src/base32/index.ts +8 -0
- package/src/base32/is.spec.ts +32 -0
- package/src/base32/validate.spec.ts +44 -0
- package/src/base58/bs58.ts +43 -0
- package/src/base58/decode.spec.ts +31 -0
- package/src/base58/encode.spec.ts +26 -0
- package/src/base58/index.ts +8 -0
- package/src/base58/validate.spec.ts +20 -0
- package/src/base64/bs64.ts +43 -0
- package/src/base64/decode.spec.ts +42 -0
- package/src/base64/encode.spec.ts +14 -0
- package/src/base64/index.ts +10 -0
- package/src/base64/pad.spec.ts +14 -0
- package/src/base64/pad.ts +10 -0
- package/src/base64/trim.spec.ts +14 -0
- package/src/base64/trim.ts +14 -0
- package/src/base64/validate.spec.ts +32 -0
- package/src/blake2/asHex.spec.ts +57 -0
- package/src/blake2/asU8a.spec.ts +74 -0
- package/src/blake2/asU8a.ts +40 -0
- package/src/blake2/index.ts +8 -0
- package/src/bn.ts +15 -0
- package/src/bundle.ts +33 -0
- package/src/bundleInit.ts +11 -0
- package/src/crypto.spec.ts +18 -0
- package/src/crypto.ts +18 -0
- package/src/ed25519/deriveHard.ts +18 -0
- package/src/ed25519/index.ts +13 -0
- package/src/ed25519/pair/fromRandom.spec.ts +28 -0
- package/src/ed25519/pair/fromRandom.ts +25 -0
- package/src/ed25519/pair/fromSecret.spec.ts +33 -0
- package/src/ed25519/pair/fromSecret.ts +29 -0
- package/src/ed25519/pair/fromSeed.spec.ts +42 -0
- package/src/ed25519/pair/fromSeed.ts +41 -0
- package/src/ed25519/pair/fromString.spec.ts +17 -0
- package/src/ed25519/pair/fromString.ts +31 -0
- package/src/ed25519/sign.spec.ts +40 -0
- package/src/ed25519/sign.ts +38 -0
- package/src/ed25519/verify.spec.ts +84 -0
- package/src/ed25519/verify.ts +41 -0
- package/src/ethereum/encode.spec.ts +59 -0
- package/src/ethereum/encode.ts +39 -0
- package/src/ethereum/index.ts +6 -0
- package/src/ethereum/isAddress.spec.ts +34 -0
- package/src/ethereum/isAddress.ts +16 -0
- package/src/ethereum/isChecksum.ts +27 -0
- package/src/ethereum/isCheksum.spec.ts +30 -0
- package/src/hd/ethereum/index.spec.ts +54 -0
- package/src/hd/ethereum/index.ts +69 -0
- package/src/hd/index.ts +6 -0
- package/src/hd/ledger/derivePrivate.ts +34 -0
- package/src/hd/ledger/index.spec.ts +64 -0
- package/src/hd/ledger/index.ts +42 -0
- package/src/hd/ledger/master.spec.ts +19 -0
- package/src/hd/ledger/master.ts +26 -0
- package/src/hd/validatePath.spec.ts +30 -0
- package/src/hd/validatePath.ts +24 -0
- package/src/helpers.ts +38 -0
- package/src/hmac/index.ts +4 -0
- package/src/hmac/shaAsU8a.spec.ts +45 -0
- package/src/hmac/shaAsU8a.ts +48 -0
- package/src/index.ts +6 -0
- package/src/json/constants.ts +11 -0
- package/src/json/decrypt.ts +25 -0
- package/src/json/decryptData.ts +45 -0
- package/src/json/encrypt.ts +25 -0
- package/src/json/encryptFormat.ts +20 -0
- package/src/json/index.ts +7 -0
- package/src/json/types.ts +22 -0
- package/src/keccak/asHex.spec.ts +30 -0
- package/src/keccak/asU8a.spec.ts +56 -0
- package/src/keccak/asU8a.ts +45 -0
- package/src/keccak/index.ts +8 -0
- package/src/key/DeriveJunction.ts +79 -0
- package/src/key/extractPath.spec.ts +51 -0
- package/src/key/extractPath.ts +37 -0
- package/src/key/extractSuri.spec.ts +147 -0
- package/src/key/extractSuri.ts +40 -0
- package/src/key/fromPath.ts +28 -0
- package/src/key/hdkdDerive.ts +17 -0
- package/src/key/hdkdEcdsa.ts +8 -0
- package/src/key/hdkdEd25519.ts +7 -0
- package/src/key/hdkdSr25519.ts +14 -0
- package/src/key/index.ts +12 -0
- package/src/mnemonic/bip39.spec.ts +80 -0
- package/src/mnemonic/bip39.ts +127 -0
- package/src/mnemonic/generate.spec.ts +58 -0
- package/src/mnemonic/generate.ts +25 -0
- package/src/mnemonic/index.ts +11 -0
- package/src/mnemonic/toEntropy.spec.ts +36 -0
- package/src/mnemonic/toEntropy.ts +13 -0
- package/src/mnemonic/toLegacySeed.spec.ts +52 -0
- package/src/mnemonic/toLegacySeed.ts +39 -0
- package/src/mnemonic/toMiniSecret.spec.ts +67 -0
- package/src/mnemonic/toMiniSecret.ts +23 -0
- package/src/mnemonic/toMiniSecretCmp.spec.ts +64 -0
- package/src/mnemonic/validate.spec.ts +39 -0
- package/src/mnemonic/validate.ts +26 -0
- package/src/mnemonic/wordlists/en.ts +7 -0
- package/src/mnemonic/wordlists/es.ts +7 -0
- package/src/mnemonic/wordlists/fr.ts +7 -0
- package/src/mnemonic/wordlists/index.ts +11 -0
- package/src/mnemonic/wordlists/it.ts +7 -0
- package/src/mnemonic/wordlists/jp.ts +7 -0
- package/src/mnemonic/wordlists/ko.ts +7 -0
- package/src/mnemonic/wordlists/zh-s.ts +7 -0
- package/src/mnemonic/wordlists/zh-t.ts +7 -0
- package/src/mod.ts +4 -0
- package/src/nacl/decrypt.spec.ts +26 -0
- package/src/nacl/decrypt.ts +22 -0
- package/src/nacl/encrypt.spec.ts +20 -0
- package/src/nacl/encrypt.ts +31 -0
- package/src/nacl/index.ts +8 -0
- package/src/nacl/tweetnacl-secretbox-data.spec.ts +4629 -0
- package/src/nacl/tweetnacl-secretbox.spec.ts +161 -0
- package/src/nacl/tweetnacl.ts +1159 -0
- package/src/networks.ts +5 -0
- package/src/packageDetect.ts +14 -0
- package/src/packageInfo.ts +6 -0
- package/src/pbkdf2/encode.spec.ts +54 -0
- package/src/pbkdf2/encode.ts +29 -0
- package/src/pbkdf2/index.ts +4 -0
- package/src/random/asHex.spec.ts +38 -0
- package/src/random/asNumber.spec.ts +16 -0
- package/src/random/asNumber.ts +28 -0
- package/src/random/asU8a.spec.ts +36 -0
- package/src/random/asU8a.ts +30 -0
- package/src/random/index.ts +9 -0
- package/src/scrypt/defaults.ts +19 -0
- package/src/scrypt/encode.spec.ts +43 -0
- package/src/scrypt/encode.ts +30 -0
- package/src/scrypt/fromU8a.ts +44 -0
- package/src/scrypt/index.ts +6 -0
- package/src/scrypt/toU8a.ts +17 -0
- package/src/scrypt/types.ts +9 -0
- package/src/secp256k1/compress.spec.ts +47 -0
- package/src/secp256k1/compress.ts +21 -0
- package/src/secp256k1/deriveHard.ts +17 -0
- package/src/secp256k1/expand.spec.ts +47 -0
- package/src/secp256k1/expand.ts +30 -0
- package/src/secp256k1/hasher.spec.ts +24 -0
- package/src/secp256k1/hasher.ts +13 -0
- package/src/secp256k1/index.ts +10 -0
- package/src/secp256k1/pair/fromSeed.spec.ts +75 -0
- package/src/secp256k1/pair/fromSeed.ts +42 -0
- package/src/secp256k1/recover.spec.ts +35 -0
- package/src/secp256k1/recover.ts +36 -0
- package/src/secp256k1/sign.spec.ts +39 -0
- package/src/secp256k1/sign.ts +37 -0
- package/src/secp256k1/signVerify.spec.ts +94 -0
- package/src/secp256k1/tweakAdd.spec.ts +35 -0
- package/src/secp256k1/tweakAdd.ts +65 -0
- package/src/secp256k1/types.ts +4 -0
- package/src/secp256k1/verify.spec.ts +81 -0
- package/src/secp256k1/verify.ts +32 -0
- package/src/sha/asU8a.ts +30 -0
- package/src/sha/asU8a256.spec.ts +55 -0
- package/src/sha/asU8a512.spec.ts +33 -0
- package/src/sha/index.ts +8 -0
- package/src/signature/index.ts +8 -0
- package/src/signature/verify.spec.ts +230 -0
- package/src/signature/verify.ts +114 -0
- package/src/sr25519/agreement.spec.ts +31 -0
- package/src/sr25519/agreement.ts +23 -0
- package/src/sr25519/derive.ts +21 -0
- package/src/sr25519/deriveHard.ts +9 -0
- package/src/sr25519/derivePublic.ts +18 -0
- package/src/sr25519/deriveSoft.ts +9 -0
- package/src/sr25519/index.ts +12 -0
- package/src/sr25519/pair/fromSeed.spec.ts +35 -0
- package/src/sr25519/pair/fromSeed.ts +28 -0
- package/src/sr25519/pair/fromU8a.ts +23 -0
- package/src/sr25519/pair/testing.spec.ts +161 -0
- package/src/sr25519/pair/toU8a.ts +10 -0
- package/src/sr25519/sign.spec.ts +28 -0
- package/src/sr25519/sign.ts +22 -0
- package/src/sr25519/verify.spec.ts +42 -0
- package/src/sr25519/verify.ts +23 -0
- package/src/sr25519/vrfSign.ts +24 -0
- package/src/sr25519/vrfSignVerify.spec.ts +73 -0
- package/src/sr25519/vrfVerify.ts +25 -0
- package/src/test/index.ts +8 -0
- package/src/test/performance.ts +17 -0
- package/src/types.ts +33 -0
- package/src/xxhash/asHex.spec.ts +36 -0
- package/src/xxhash/asU8a.spec.ts +48 -0
- package/src/xxhash/asU8a.ts +45 -0
- package/src/xxhash/index.ts +8 -0
- package/src/xxhash/xxhash64.ts +155 -0
- package/tsconfig.build.json +18 -0
- package/tsconfig.spec.json +20 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
export { secp256k1Compress } from './compress.js';
|
|
5
|
+
export { secp256k1Expand } from './expand.js';
|
|
6
|
+
export { secp256k1PairFromSeed } from './pair/fromSeed.js';
|
|
7
|
+
export { secp256k1Recover } from './recover.js';
|
|
8
|
+
export { secp256k1Sign } from './sign.js';
|
|
9
|
+
export { secp256k1PrivateKeyTweakAdd } from './tweakAdd.js';
|
|
10
|
+
export { secp256k1Verify } from './verify.js';
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
|
5
|
+
|
|
6
|
+
import { hexToU8a, u8aToHex } from '@pezkuwi/util';
|
|
7
|
+
import { waitReady } from '@pezkuwi/wasm-crypto';
|
|
8
|
+
|
|
9
|
+
import { mnemonicToMiniSecret } from '../../mnemonic/index.js';
|
|
10
|
+
import { perfWasm } from '../../test/index.js';
|
|
11
|
+
import { secp256k1PairFromSeed } from '../index.js';
|
|
12
|
+
|
|
13
|
+
// mnemonic, secret, public, account_id
|
|
14
|
+
type Test = [string, string, string, string];
|
|
15
|
+
|
|
16
|
+
const tests: Test[] = [
|
|
17
|
+
[
|
|
18
|
+
'life fee table ahead modify maximum dumb such tobacco boss dry nurse',
|
|
19
|
+
'0xf2360e871c830d397fe221382b503f07ddd8763df81a94bb2504390a2fb91f59',
|
|
20
|
+
'0x036b0aa6beab469dd2b748a0ff5ddbe3d13df1e15c9d28a2aa057212994e127bea',
|
|
21
|
+
'0xae8e8fcacbaeb607bcdf0bbd7e615f2b4ef484ee54f19d68a7393fb6db2dd9cd'
|
|
22
|
+
],
|
|
23
|
+
[
|
|
24
|
+
'tide survey cradle cover column ugly author wait eye state elder blame',
|
|
25
|
+
'0x5385355a5118ec732b9dbcf1668ba21db38b07cf79082dafa9a7cc4b52e4abb0',
|
|
26
|
+
'0x03929e4f93cdad265751ad8f6365185d8e937610d19b510400f5867d542d60a313',
|
|
27
|
+
'0xf80ea815da66c42f870b687e1530770d5a7936ae81a147b009506d85bd6d621c'
|
|
28
|
+
],
|
|
29
|
+
[
|
|
30
|
+
'laugh fish flee cake approve butter april dynamic myth license ticket lobster',
|
|
31
|
+
'0x83ec65cf9a8a7442d808aef6f8987599f1ba3be880769bb3a20621b13adbd476',
|
|
32
|
+
'0x0388299e4cfaa33d180a026bd54a46ad98df129a131320a9d2fd6f80e64bc3db39',
|
|
33
|
+
'0x35036238dd195f4c2169379354bda6cba5746f67bde03ef59a77a4cea80729bc'
|
|
34
|
+
],
|
|
35
|
+
[
|
|
36
|
+
'animal thing fork recipe exotic pilot inquiry pledge obey slab obtain reveal',
|
|
37
|
+
'0x0fd50580eb5a58b0eee60c77656dffa50094b539262366f1227d3babfd7343e5',
|
|
38
|
+
'0x036edc954685ad89f0a23b0fb1eb2b9c3a8600eee9091c758426dfb2bc7889a7c3',
|
|
39
|
+
'0x2a94b10d1f28810dc4628e7e424b2d08bd3d17fb08f9416d112f17e86c8fa77c'
|
|
40
|
+
]
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
describe('secp256k1PairFromSeed', (): void => {
|
|
44
|
+
beforeEach(async (): Promise<void> => {
|
|
45
|
+
await waitReady();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const TEST = hexToU8a('0x4380de832af797688026ce24f85204d508243f201650c1a134929e5458b7fbae');
|
|
49
|
+
const RESULT = {
|
|
50
|
+
publicKey: hexToU8a('0x03fd8c74f795ced92064b86191cb2772b1e3a0947740aa0a5a6e379592471fd85b'),
|
|
51
|
+
secretKey: hexToU8a('0x4380de832af797688026ce24f85204d508243f201650c1a134929e5458b7fbae')
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
for (const onlyJs of [false, true]) {
|
|
55
|
+
describe(`onlyJs=${(onlyJs && 'true') || 'false'}`, (): void => {
|
|
56
|
+
it('generates a valid publicKey/secretKey pair (u8a)', (): void => {
|
|
57
|
+
expect(secp256k1PairFromSeed(TEST, onlyJs)).toEqual(RESULT);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
tests.forEach(([mnemonic, secretKey, publicKey], index): void => {
|
|
61
|
+
it(`creates valid against known (${index})`, (): void => {
|
|
62
|
+
const seed = mnemonicToMiniSecret(mnemonic);
|
|
63
|
+
const pair = secp256k1PairFromSeed(seed, onlyJs);
|
|
64
|
+
|
|
65
|
+
expect(u8aToHex(pair.secretKey)).toEqual(secretKey);
|
|
66
|
+
expect(u8aToHex(pair.publicKey)).toEqual(publicKey);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
perfWasm('secp256k1PairFromSeed', 500, (input, onlyJs) =>
|
|
73
|
+
secp256k1PairFromSeed(input, onlyJs)
|
|
74
|
+
);
|
|
75
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import type { Keypair } from '../../types.js';
|
|
5
|
+
|
|
6
|
+
import { secp256k1 } from '@noble/curves/secp256k1';
|
|
7
|
+
|
|
8
|
+
import { hasBigInt, u8aEmpty } from '@pezkuwi/util';
|
|
9
|
+
import { isReady, secp256k1FromSeed } from '@pezkuwi/wasm-crypto';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @name secp256k1PairFromSeed
|
|
13
|
+
* @description Returns a object containing a `publicKey` & `secretKey` generated from the supplied seed.
|
|
14
|
+
*/
|
|
15
|
+
export function secp256k1PairFromSeed (seed: Uint8Array, onlyJs?: boolean): Keypair {
|
|
16
|
+
if (seed.length !== 32) {
|
|
17
|
+
throw new Error('Expected valid 32-byte private key as a seed');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!hasBigInt || (!onlyJs && isReady())) {
|
|
21
|
+
const full = secp256k1FromSeed(seed);
|
|
22
|
+
const publicKey = full.slice(32);
|
|
23
|
+
|
|
24
|
+
// There is an issue with the secp256k1 when running in an ASM.js environment where
|
|
25
|
+
// it seems that the lazy static section yields invalid results on the _first_ run.
|
|
26
|
+
// If this happens, fail outright, we cannot allow invalid return values
|
|
27
|
+
// https://github.com/polkadot-js/wasm/issues/307
|
|
28
|
+
if (u8aEmpty(publicKey)) {
|
|
29
|
+
throw new Error('Invalid publicKey generated from WASM interface');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
publicKey,
|
|
34
|
+
secretKey: full.slice(0, 32)
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
publicKey: secp256k1.getPublicKey(seed, true),
|
|
40
|
+
secretKey: seed
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
|
5
|
+
|
|
6
|
+
import { u8aToHex, u8aToU8a } from '@pezkuwi/util';
|
|
7
|
+
import { waitReady } from '@pezkuwi/wasm-crypto';
|
|
8
|
+
|
|
9
|
+
import { keccakAsU8a } from '../keccak/index.js';
|
|
10
|
+
import { perfWasm } from '../test/index.js';
|
|
11
|
+
import { secp256k1Recover } from './index.js';
|
|
12
|
+
|
|
13
|
+
const sig = u8aToU8a('0x7505f2880114da51b3f5d535f8687953c0ab9af4ab81e592eaebebf53b728d2b6dfd9b5bcd70fee412b1f31360e7c2774009305cb84fc50c1d0ff8034dfa5fff');
|
|
14
|
+
const msg = u8aToU8a('0xa30b64ce1eedf409c8afb801d72c05234e64849ea538c15dd3c8cf4ffcf166c9');
|
|
15
|
+
|
|
16
|
+
describe('secp256k1Recover', (): void => {
|
|
17
|
+
beforeEach(async (): Promise<void> => {
|
|
18
|
+
await waitReady();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
for (const onlyJs of [false, true]) {
|
|
22
|
+
describe(`onlyJs=${(onlyJs && 'true') || 'false'}`, (): void => {
|
|
23
|
+
it('recovers a publicKey', (): void => {
|
|
24
|
+
const pubKey = '0x93a9fc7154c6da3c826415df01eb0e37fb4da4b0';
|
|
25
|
+
const res = keccakAsU8a(secp256k1Recover(msg, sig, 0, undefined, onlyJs));
|
|
26
|
+
|
|
27
|
+
expect(u8aToHex(res.subarray(-20))).toEqual(pubKey);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
perfWasm('secp256k1Recover', 200, (_, onlyJs) =>
|
|
33
|
+
secp256k1Recover(msg, sig, 0, undefined, onlyJs)
|
|
34
|
+
);
|
|
35
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import type { HashType } from './types.js';
|
|
5
|
+
|
|
6
|
+
import { secp256k1 } from '@noble/curves/secp256k1';
|
|
7
|
+
|
|
8
|
+
import { hasBigInt, u8aToU8a } from '@pezkuwi/util';
|
|
9
|
+
import { isReady, secp256k1Recover as wasm } from '@pezkuwi/wasm-crypto';
|
|
10
|
+
|
|
11
|
+
import { secp256k1Compress } from './compress.js';
|
|
12
|
+
import { secp256k1Expand } from './expand.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @name secp256k1Recover
|
|
16
|
+
* @description Recovers a publicKey from the supplied signature
|
|
17
|
+
*/
|
|
18
|
+
export function secp256k1Recover (msgHash: string | Uint8Array, signature: string | Uint8Array, recovery: number, hashType: HashType = 'blake2', onlyJs?: boolean): Uint8Array {
|
|
19
|
+
const sig = u8aToU8a(signature).subarray(0, 64);
|
|
20
|
+
const msg = u8aToU8a(msgHash);
|
|
21
|
+
const publicKey = !hasBigInt || (!onlyJs && isReady())
|
|
22
|
+
? wasm(msg, sig, recovery)
|
|
23
|
+
: secp256k1.Signature
|
|
24
|
+
.fromCompact(sig)
|
|
25
|
+
.addRecoveryBit(recovery)
|
|
26
|
+
.recoverPublicKey(msg)
|
|
27
|
+
.toRawBytes();
|
|
28
|
+
|
|
29
|
+
if (!publicKey) {
|
|
30
|
+
throw new Error('Unable to recover publicKey from signature');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return hashType === 'keccak'
|
|
34
|
+
? secp256k1Expand(publicKey, onlyJs)
|
|
35
|
+
: secp256k1Compress(publicKey, onlyJs);
|
|
36
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
|
5
|
+
|
|
6
|
+
import { hexToU8a } from '@pezkuwi/util';
|
|
7
|
+
import { waitReady } from '@pezkuwi/wasm-crypto';
|
|
8
|
+
|
|
9
|
+
import { perfWasm } from '../test/index.js';
|
|
10
|
+
import { secp256k1PairFromSeed, secp256k1Sign } from './index.js';
|
|
11
|
+
|
|
12
|
+
const pair = secp256k1PairFromSeed(hexToU8a('0x4380de832af797688026ce24f85204d508243f201650c1a134929e5458b7fbae'));
|
|
13
|
+
const msg = hexToU8a('0xa30b64ce1eedf409c8afb801d72c05234e64849ea538c15dd3c8cf4ffcf166c9');
|
|
14
|
+
|
|
15
|
+
describe('sign', (): void => {
|
|
16
|
+
beforeEach(async (): Promise<void> => {
|
|
17
|
+
await waitReady();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
for (const onlyJs of [false, true]) {
|
|
21
|
+
describe(`onlyJs=${(onlyJs && 'true') || 'false'}`, (): void => {
|
|
22
|
+
it('generates a known signature', (): void => {
|
|
23
|
+
expect(
|
|
24
|
+
secp256k1Sign(msg, pair, undefined, onlyJs)
|
|
25
|
+
).toEqual(hexToU8a(
|
|
26
|
+
// from elliptic, this is - 0xdf92f73d9f060cefacf187b5414491cb992998ace017fa48839b5cda3e264ba8c4efa521361678d9b8582744d77aa4b8d886d7380b7808a683174afad9c4700300
|
|
27
|
+
// libsecp256k1 & @noble/hashes do agree here...
|
|
28
|
+
'0xdf92f73d9f060cefacf187b5414491cb992998ace017fa48839b5cda3e264ba83b105adec9e9872647a7d8bb28855b45e22805aea3d097953cbb1391f671d13e01'
|
|
29
|
+
));
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// since the libsecp256k1 signatures don't match (but can be verified), we
|
|
35
|
+
// do both signing and verification here (checking the extracted key)
|
|
36
|
+
perfWasm('secp256k1Sign', 1000, (_, onlyJs) =>
|
|
37
|
+
secp256k1Sign(msg, pair, undefined, onlyJs)
|
|
38
|
+
);
|
|
39
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import type { Keypair } from '../types.js';
|
|
5
|
+
import type { HashType } from './types.js';
|
|
6
|
+
|
|
7
|
+
import { secp256k1 } from '@noble/curves/secp256k1';
|
|
8
|
+
|
|
9
|
+
import { bnToU8a, hasBigInt, u8aConcat } from '@pezkuwi/util';
|
|
10
|
+
import { isReady, secp256k1Sign as wasm } from '@pezkuwi/wasm-crypto';
|
|
11
|
+
|
|
12
|
+
import { BN_BE_256_OPTS } from '../bn.js';
|
|
13
|
+
import { hasher } from './hasher.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @name secp256k1Sign
|
|
17
|
+
* @description Returns message signature of `message`, using the supplied pair
|
|
18
|
+
*/
|
|
19
|
+
export function secp256k1Sign (message: Uint8Array | string, { secretKey }: Partial<Keypair>, hashType: HashType = 'blake2', onlyJs?: boolean): Uint8Array {
|
|
20
|
+
if (secretKey?.length !== 32) {
|
|
21
|
+
throw new Error('Expected valid secp256k1 secretKey, 32-bytes');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const data = hasher(hashType, message, onlyJs);
|
|
25
|
+
|
|
26
|
+
if (!hasBigInt || (!onlyJs && isReady())) {
|
|
27
|
+
return wasm(data, secretKey);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const signature = secp256k1.sign(data, secretKey, { lowS: true });
|
|
31
|
+
|
|
32
|
+
return u8aConcat(
|
|
33
|
+
bnToU8a(signature.r, BN_BE_256_OPTS),
|
|
34
|
+
bnToU8a(signature.s, BN_BE_256_OPTS),
|
|
35
|
+
new Uint8Array([signature.recovery || 0])
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
|
5
|
+
|
|
6
|
+
import '../bundleInit.js';
|
|
7
|
+
|
|
8
|
+
import { stringToU8a } from '@pezkuwi/util';
|
|
9
|
+
|
|
10
|
+
import { randomAsU8a } from '../random/asU8a.js';
|
|
11
|
+
import { hasher } from './hasher.js';
|
|
12
|
+
import { secp256k1Expand, secp256k1PairFromSeed, secp256k1Sign, secp256k1Verify } from './index.js';
|
|
13
|
+
|
|
14
|
+
const MESSAGE = stringToU8a('this is a message');
|
|
15
|
+
|
|
16
|
+
describe('sign and verify', (): void => {
|
|
17
|
+
it('verify message signature', (): void => {
|
|
18
|
+
const address = '0x59f587c045d4d4e9aa1016eae43770fc0551df8a385027723342753a876aeef0';
|
|
19
|
+
const sig = '0x92fcacf0946bbd10b31dfe16d567ed1d3014e81007dd9e5256e19c0f07eacc1643b151ca29e449a765e16a7ce59b88d800467d6b3412d30ea8ad22307a59664b00';
|
|
20
|
+
const msg = stringToU8a('secp256k1');
|
|
21
|
+
|
|
22
|
+
expect(secp256k1Verify(msg, sig, address)).toEqual(true);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('has 65-byte signatures', (): void => {
|
|
26
|
+
const pair = secp256k1PairFromSeed(randomAsU8a());
|
|
27
|
+
|
|
28
|
+
expect(secp256k1Sign(MESSAGE, pair)).toHaveLength(65);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('signs/verifies a message by random key (blake2)', (): void => {
|
|
32
|
+
const pair = secp256k1PairFromSeed(randomAsU8a());
|
|
33
|
+
const signature = secp256k1Sign(MESSAGE, pair);
|
|
34
|
+
const address = hasher('blake2', pair.publicKey);
|
|
35
|
+
|
|
36
|
+
expect(secp256k1Verify(MESSAGE, signature, address)).toEqual(true);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('signs/verifies a message by random key (keccak)', (): void => {
|
|
40
|
+
const pair = secp256k1PairFromSeed(randomAsU8a());
|
|
41
|
+
const signature = secp256k1Sign(MESSAGE, pair, 'keccak');
|
|
42
|
+
const address = hasher('keccak', secp256k1Expand(pair.publicKey));
|
|
43
|
+
|
|
44
|
+
expect(secp256k1Verify(MESSAGE, signature, address, 'keccak')).toEqual(true);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('fails verification on hasher mismatches', (): void => {
|
|
48
|
+
const pair = secp256k1PairFromSeed(randomAsU8a());
|
|
49
|
+
const signature = secp256k1Sign(MESSAGE, pair, 'keccak');
|
|
50
|
+
const address = hasher('keccak', secp256k1Expand(pair.publicKey));
|
|
51
|
+
|
|
52
|
+
expect(secp256k1Verify(MESSAGE, signature, address, 'blake2')).toEqual(false);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('works over a range of random keys (blake2)', (): void => {
|
|
56
|
+
for (let i = 0; i < 256; i++) {
|
|
57
|
+
const pair = secp256k1PairFromSeed(randomAsU8a());
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
expect(
|
|
61
|
+
secp256k1Verify(
|
|
62
|
+
MESSAGE,
|
|
63
|
+
secp256k1Sign(MESSAGE, pair, 'blake2'),
|
|
64
|
+
hasher('blake2', pair.publicKey),
|
|
65
|
+
'blake2'
|
|
66
|
+
)
|
|
67
|
+
).toEqual(true);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error(`blake2 failed on #${i}`);
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}, 120000);
|
|
74
|
+
|
|
75
|
+
it('works over a range of random keys (keccak)', (): void => {
|
|
76
|
+
for (let i = 0; i < 256; i++) {
|
|
77
|
+
const pair = secp256k1PairFromSeed(randomAsU8a());
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
expect(
|
|
81
|
+
secp256k1Verify(
|
|
82
|
+
MESSAGE,
|
|
83
|
+
secp256k1Sign(MESSAGE, pair, 'keccak'),
|
|
84
|
+
hasher('keccak', secp256k1Expand(pair.publicKey)),
|
|
85
|
+
'keccak'
|
|
86
|
+
)
|
|
87
|
+
).toEqual(true);
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error(`keccak failed on #${i}`);
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}, 120000);
|
|
94
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
|
5
|
+
|
|
6
|
+
import { secp256k1PrivateKeyTweakAdd } from './tweakAdd.js';
|
|
7
|
+
|
|
8
|
+
describe('TweakAdd', (): void => {
|
|
9
|
+
it('fails for wrong array length', (): void => {
|
|
10
|
+
const A = new Uint8Array([0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]);
|
|
11
|
+
const B = new Uint8Array([3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]);
|
|
12
|
+
|
|
13
|
+
expect(
|
|
14
|
+
() => secp256k1PrivateKeyTweakAdd(A, B)
|
|
15
|
+
).toThrow(/Expected tweak to be an Uint8Array/);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
for (const onlyBn of [false, true]) {
|
|
19
|
+
describe(`onlyBn=${(onlyBn && 'true') || 'false'}`, (): void => {
|
|
20
|
+
it('succeeds for a simple case', (): void => {
|
|
21
|
+
const A = new Uint8Array([0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]);
|
|
22
|
+
const B = new Uint8Array([3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]);
|
|
23
|
+
|
|
24
|
+
expect(
|
|
25
|
+
secp256k1PrivateKeyTweakAdd(A, B, onlyBn)
|
|
26
|
+
).toEqual(new Uint8Array([
|
|
27
|
+
3, 4, 3, 4, 3, 4, 3, 4, 3,
|
|
28
|
+
4, 3, 4, 3, 4, 3, 4, 3, 4,
|
|
29
|
+
3, 4, 3, 4, 3, 4, 3, 4, 3,
|
|
30
|
+
4, 3, 4, 3, 4
|
|
31
|
+
]));
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { _0n, BN, bnToU8a, hasBigInt, isU8a, nToU8a, u8aToBigInt } from '@pezkuwi/util';
|
|
5
|
+
import { BigInt } from '@pezkuwi/x-bigint';
|
|
6
|
+
|
|
7
|
+
import { BN_BE_256_OPTS, BN_BE_OPTS } from '../bn.js';
|
|
8
|
+
|
|
9
|
+
// pre-defined curve param as lifted form elliptic
|
|
10
|
+
// https://github.com/indutny/elliptic/blob/e71b2d9359c5fe9437fbf46f1f05096de447de57/lib/elliptic/curves.js#L182
|
|
11
|
+
const N = 'ffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141'.replace(/ /g, '');
|
|
12
|
+
const N_BI = BigInt(`0x${N}`);
|
|
13
|
+
const N_BN = new BN(N, 'hex');
|
|
14
|
+
|
|
15
|
+
function addBi (seckey: Uint8Array, tweak: Uint8Array): Uint8Array {
|
|
16
|
+
let res = u8aToBigInt(tweak, BN_BE_OPTS);
|
|
17
|
+
|
|
18
|
+
if (res >= N_BI) {
|
|
19
|
+
throw new Error('Tweak parameter is out of range');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
res += u8aToBigInt(seckey, BN_BE_OPTS);
|
|
23
|
+
|
|
24
|
+
if (res >= N_BI) {
|
|
25
|
+
res -= N_BI;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (res === _0n) {
|
|
29
|
+
throw new Error('Invalid resulting private key');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return nToU8a(res, BN_BE_256_OPTS);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function addBn (seckey: Uint8Array, tweak: Uint8Array): Uint8Array {
|
|
36
|
+
const res = new BN(tweak);
|
|
37
|
+
|
|
38
|
+
if (res.cmp(N_BN) >= 0) {
|
|
39
|
+
throw new Error('Tweak parameter is out of range');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
res.iadd(new BN(seckey));
|
|
43
|
+
|
|
44
|
+
if (res.cmp(N_BN) >= 0) {
|
|
45
|
+
res.isub(N_BN);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (res.isZero()) {
|
|
49
|
+
throw new Error('Invalid resulting private key');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return bnToU8a(res, BN_BE_256_OPTS);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function secp256k1PrivateKeyTweakAdd (seckey: Uint8Array, tweak: Uint8Array, onlyBn?: boolean): Uint8Array {
|
|
56
|
+
if (!isU8a(seckey) || seckey.length !== 32) {
|
|
57
|
+
throw new Error('Expected seckey to be an Uint8Array with length 32');
|
|
58
|
+
} else if (!isU8a(tweak) || tweak.length !== 32) {
|
|
59
|
+
throw new Error('Expected tweak to be an Uint8Array with length 32');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return !hasBigInt || onlyBn
|
|
63
|
+
? addBn(seckey, tweak)
|
|
64
|
+
: addBi(seckey, tweak);
|
|
65
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
|
5
|
+
|
|
6
|
+
import '../bundleInit.js';
|
|
7
|
+
|
|
8
|
+
import { hexToU8a } from '@pezkuwi/util';
|
|
9
|
+
import { waitReady } from '@pezkuwi/wasm-crypto';
|
|
10
|
+
|
|
11
|
+
import { perfWasm } from '../test/index.js';
|
|
12
|
+
import { hasher } from './hasher.js';
|
|
13
|
+
import { secp256k1PairFromSeed, secp256k1Verify } from './index.js';
|
|
14
|
+
|
|
15
|
+
const message = 'Pay KSMs to the Kusama account:88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee';
|
|
16
|
+
|
|
17
|
+
describe('secp256k1Verify', (): void => {
|
|
18
|
+
beforeEach(async (): Promise<void> => {
|
|
19
|
+
await waitReady();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
for (const onlyJs of [true]) {
|
|
23
|
+
describe(`onlyJs=${(onlyJs && 'true') || 'false'}`, (): void => {
|
|
24
|
+
it('validates known ETH against address', (): void => {
|
|
25
|
+
expect(
|
|
26
|
+
secp256k1Verify(
|
|
27
|
+
`\x19Ethereum Signed Message:\n${message.length.toString()}${message}`,
|
|
28
|
+
'0x55bd020bdbbdc02de34e915effc9b18a99002f4c29f64e22e8dcbb69e722ea6c28e1bb53b9484063fbbfd205e49dcc1f620929f520c9c4c3695150f05a28f52a01',
|
|
29
|
+
'0x002309df96687e44280bb72c3818358faeeb699c',
|
|
30
|
+
'keccak',
|
|
31
|
+
onlyJs
|
|
32
|
+
)
|
|
33
|
+
).toEqual(true);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
for (const isPublic of [false, true]) {
|
|
37
|
+
describe(`validation against known, isPublic=${(isPublic && 'true') || 'false'}`, (): void => {
|
|
38
|
+
const pair = secp256k1PairFromSeed(hexToU8a('0x4380de832af797688026ce24f85204d508243f201650c1a134929e5458b7fbae'));
|
|
39
|
+
const msg = hexToU8a('0xa30b64ce1eedf409c8afb801d72c05234e64849ea538c15dd3c8cf4ffcf166c9');
|
|
40
|
+
const addr = isPublic
|
|
41
|
+
? pair.publicKey
|
|
42
|
+
: hasher('blake2', pair.publicKey, onlyJs);
|
|
43
|
+
|
|
44
|
+
it('signature from JS', (): void => {
|
|
45
|
+
expect(
|
|
46
|
+
secp256k1Verify(
|
|
47
|
+
msg,
|
|
48
|
+
'0xdf92f73d9f060cefacf187b5414491cb992998ace017fa48839b5cda3e264ba8c4efa521361678d9b8582744d77aa4b8d886d7380b7808a683174afad9c4700300',
|
|
49
|
+
addr,
|
|
50
|
+
'blake2',
|
|
51
|
+
onlyJs
|
|
52
|
+
)
|
|
53
|
+
).toEqual(true);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('signature from wasm', (): void => {
|
|
57
|
+
expect(
|
|
58
|
+
secp256k1Verify(
|
|
59
|
+
msg,
|
|
60
|
+
'0xdf92f73d9f060cefacf187b5414491cb992998ace017fa48839b5cda3e264ba83b105adec9e9872647a7d8bb28855b45e22805aea3d097953cbb1391f671d13e01',
|
|
61
|
+
addr,
|
|
62
|
+
'blake2',
|
|
63
|
+
onlyJs
|
|
64
|
+
)
|
|
65
|
+
).toEqual(true);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
perfWasm('secp256k1Verify', 100, (_, onlyJs) =>
|
|
73
|
+
secp256k1Verify(
|
|
74
|
+
`\x19Ethereum Signed Message:\n${message.length.toString()}${message}`,
|
|
75
|
+
'0x55bd020bdbbdc02de34e915effc9b18a99002f4c29f64e22e8dcbb69e722ea6c28e1bb53b9484063fbbfd205e49dcc1f620929f520c9c4c3695150f05a28f52a01',
|
|
76
|
+
'0x002309df96687e44280bb72c3818358faeeb699c',
|
|
77
|
+
'keccak',
|
|
78
|
+
onlyJs
|
|
79
|
+
)
|
|
80
|
+
);
|
|
81
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import type { HashType } from './types.js';
|
|
5
|
+
|
|
6
|
+
import { u8aEq, u8aToU8a } from '@pezkuwi/util';
|
|
7
|
+
|
|
8
|
+
import { hasher } from './hasher.js';
|
|
9
|
+
import { secp256k1Recover } from './recover.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @name secp256k1Verify
|
|
13
|
+
* @description Verifies the signature of `message`, using the supplied pair
|
|
14
|
+
*/
|
|
15
|
+
export function secp256k1Verify (msgHash: string | Uint8Array, signature: string | Uint8Array, address: string | Uint8Array, hashType: HashType = 'blake2', onlyJs?: boolean): boolean {
|
|
16
|
+
const sig = u8aToU8a(signature);
|
|
17
|
+
|
|
18
|
+
if (sig.length !== 65) {
|
|
19
|
+
throw new Error(`Expected signature with 65 bytes, ${sig.length} found instead`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const publicKey = secp256k1Recover(hasher(hashType, msgHash), sig, sig[64], hashType, onlyJs);
|
|
23
|
+
const signerAddr = hasher(hashType, publicKey, onlyJs);
|
|
24
|
+
const inputAddr = u8aToU8a(address);
|
|
25
|
+
|
|
26
|
+
// for Ethereum (keccak) the last 20 bytes is the address
|
|
27
|
+
return u8aEq(publicKey, inputAddr) || (
|
|
28
|
+
hashType === 'keccak'
|
|
29
|
+
? u8aEq(signerAddr.slice(-20), inputAddr.slice(-20))
|
|
30
|
+
: u8aEq(signerAddr, inputAddr)
|
|
31
|
+
);
|
|
32
|
+
}
|
package/src/sha/asU8a.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Copyright 2017-2025 @polkadot/util-crypto authors & contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { sha256 as sha256Js } from '@noble/hashes/sha256';
|
|
5
|
+
import { sha512 as sha512Js } from '@noble/hashes/sha512';
|
|
6
|
+
|
|
7
|
+
import { sha256, sha512 } from '@pezkuwi/wasm-crypto';
|
|
8
|
+
|
|
9
|
+
import { createBitHasher, createDualHasher } from '../helpers.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @name shaAsU8a
|
|
13
|
+
* @summary Creates a sha Uint8Array from the input.
|
|
14
|
+
*/
|
|
15
|
+
export const shaAsU8a = /*#__PURE__*/ createDualHasher(
|
|
16
|
+
{ 256: sha256, 512: sha512 },
|
|
17
|
+
{ 256: sha256Js, 512: sha512Js }
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @name sha256AsU8a
|
|
22
|
+
* @summary Creates a sha256 Uint8Array from the input.
|
|
23
|
+
*/
|
|
24
|
+
export const sha256AsU8a = /*#__PURE__*/ createBitHasher(256, shaAsU8a);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @name sha512AsU8a
|
|
28
|
+
* @summary Creates a sha512 Uint8Array from the input.
|
|
29
|
+
*/
|
|
30
|
+
export const sha512AsU8a = /*#__PURE__*/ createBitHasher(512, shaAsU8a);
|