diff options
| author | Pawel Zelawski <pawel.zelawski@outlook.com> | 2026-01-23 11:37:56 +0100 |
|---|---|---|
| committer | Pawel Zelawski <pawel.zelawski@outlook.com> | 2026-01-23 11:37:56 +0100 |
| commit | fbc80fe79ce823534a58197dd3173f29f81d6bcb (patch) | |
| tree | 3cbb05850a7ee33ff951b55b469704cbbcfb99ec /src | |
| parent | 491058ae03ba1f0ae70fe3c684002c9e8e864a53 (diff) | |
fix: correct public key recovery to use toBytes() and addRecoveryBit()
- Changed point.toRawBytes() to point.toBytes() to match @noble/curves v2 API
- Added .addRecoveryBit(actualRecoveryId) to signature for proper recovery
- Returns both compressed/uncompressed public keys for verification
- Fixes signature verification regression in v2.0.0
Diffstat (limited to 'src')
| -rw-r--r-- | src/digiid.ts | 27 |
1 files changed, 15 insertions, 12 deletions
diff --git a/src/digiid.ts b/src/digiid.ts index 11bc309..168e097 100644 --- a/src/digiid.ts +++ b/src/digiid.ts @@ -178,7 +178,7 @@ function recoverPublicKey(messageHash: Uint8Array, signature: Uint8Array): Uint8 const compressed = recoveryId >= 4; const actualRecoveryId = recoveryId % 4; - if (actualRecoveryId > 3) { + if (actualRecoveryId < 0 || actualRecoveryId > 3) { throw new Error('Invalid recovery ID'); } @@ -189,20 +189,23 @@ function recoverPublicKey(messageHash: Uint8Array, signature: Uint8Array): Uint8 const sig = new secp256k1.Signature( BigInt('0x' + Array.from(r).map(b => b.toString(16).padStart(2, '0')).join('')), BigInt('0x' + Array.from(s).map(b => b.toString(16).padStart(2, '0')).join('')) - ); + ).addRecoveryBit(actualRecoveryId); try { const point = sig.recoverPublicKey(messageHash); - return [point.toHex(compressed)].map(hex => { - // Convert hex string to Uint8Array - const bytes = new Uint8Array(hex.length / 2); - for (let i = 0; i < hex.length; i += 2) { - bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16); - } - return bytes; - }); - } catch { - throw new Error('Failed to recover public key'); + // Return both compressed and uncompressed versions to try both + const compressedBytes = point.toBytes(true); + const uncompressedBytes = point.toBytes(false); + + // Based on the recoveryId flag, return the appropriate format(s) + if (compressed) { + return [compressedBytes]; + } else { + // For uncompressed signatures, try both formats as different wallets may encode differently + return [uncompressedBytes, compressedBytes]; + } + } catch (e) { + throw new Error('Failed to recover public key: ' + (e instanceof Error ? e.message : String(e))); } } |
