Claims: recover the signer with @pezkuwi/util-crypto, not elliptic

recoverAddress used secp256k1/elliptic.js, which put elliptic (open
advisories, no fixed version) into the shipped bundle. secp256k1Recover
from @pezkuwi/util-crypto (@noble/curves, or wasm) with the 'keccak'
hash type returns the same expanded key without its 0x04 prefix.

The spec's signature vector had been broken by the rebrand: the signed
message was rewritten from "Kusama" to "Dicle", so recovery gave another
address and the test failed on the old code too (it only runs in
test:all). Restored; old and new code pass it, and changing one word of
the message makes it fail.
This commit is contained in:
Satoshi Qazi Muhammed authored and SatoshiQaziMuhammed committed 2026-10-10 04:09:47 +04:00
1 parent a5a5a6f9e0
commit 09f16d3549
4 files changed
+5 -17

No files matched your search

+1 -2
View File
@@ -16,8 +16,7 @@
"type": "module",
"version": "1.0.2-1-x",
"dependencies": {
"@pezkuwi/react-components": "^1.0.2-1-x",
"secp256k1": "^3.8.0"
"@pezkuwi/react-components": "^1.0.2-1-x"
},
"peerDependencies": {
"react": "*",
-7
View File
@@ -1,7 +0,0 @@
// Copyright 2017-2026 @pezkuwi/app-claims authors & contributors
// SPDX-License-Identifier: Apache-2.0
declare module 'secp256k1/elliptic.js' {
export function publicKeyConvert (publicKey: Buffer, expanded: boolean): Buffer;
export function recover (msgHash: Buffer, signature: Buffer, recovery: number): Buffer;
}
+1 -1
View File
@@ -20,7 +20,7 @@ describe('util', (): void => {
it('converts to valid signature via recoverFromJSON', (): void => {
expect(
JSON.stringify(recoverFromJSON('{"address":"0x002309df96687e44280bb72c3818358faeeb699c","msg":"Pay KSMs to the Dicle account:88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee","sig":"0x55bd020bdbbdc02de34e915effc9b18a99002f4c29f64e22e8dcbb69e722ea6c28e1bb53b9484063fbbfd205e49dcc1f620929f520c9c4c3695150f05a28f52a01","version":"2"}'))
JSON.stringify(recoverFromJSON('{"address":"0x002309df96687e44280bb72c3818358faeeb699c","msg":"Pay KSMs to the Kusama account:88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee","sig":"0x55bd020bdbbdc02de34e915effc9b18a99002f4c29f64e22e8dcbb69e722ea6c28e1bb53b9484063fbbfd205e49dcc1f620929f520c9c4c3695150f05a28f52a01","version":"2"}'))
).toEqual('{"error":null,"ethereumAddress":"0x002309DF96687e44280BB72c3818358FAEeB699c","signature":"0x55bd020bdbbdc02de34e915effc9b18a99002f4c29f64e22e8dcbb69e722ea6c28e1bb53b9484063fbbfd205e49dcc1f620929f520c9c4c3695150f05a28f52a01"}');
});
});
+3 -7
View File
@@ -3,11 +3,9 @@
import type { EcdsaSignature, EthereumAddress, StatementKind } from '@pezkuwi/types/interfaces';
import secp256k1 from 'secp256k1/elliptic.js';
import { statics } from '@pezkuwi/react-api/statics';
import { assert, hexToU8a, stringToU8a, u8aConcat, u8aToBuffer } from '@pezkuwi/util';
import { keccakAsHex, keccakAsU8a } from '@pezkuwi/util-crypto';
import { keccakAsHex, keccakAsU8a, secp256k1Recover } from '@pezkuwi/util-crypto';
interface RecoveredSignature {
error: Error | null;
@@ -74,11 +72,9 @@ export function sigToParts (_signature: string): SignatureParts {
// recover an address from a given message and a recover/signature combination
export function recoverAddress (message: string, { recovery, signature }: SignatureParts): string {
const msgHash = hashMessage(message);
const senderPubKey = secp256k1.recover(msgHash, signature, recovery);
// 'keccak' returns the expanded key without its 0x04 prefix
return publicToAddr(
secp256k1.publicKeyConvert(senderPubKey, false).subarray(1)
secp256k1Recover(hashMessage(message), signature, recovery, 'keccak')
);
}