From 49a78dc737908b34e0f26fb2598064c5fa562321 Mon Sep 17 00:00:00 2001 From: apetta Date: Tue, 22 Aug 2023 20:58:27 +0100 Subject: [PATCH] extending supported tezos curves in cacao & pkh --- packages/cacao/src/cacao.ts | 13 +++- packages/pkh-tezos/src/verifier.ts | 116 ++++++++++++++++++++++++----- 2 files changed, 111 insertions(+), 18 deletions(-) diff --git a/packages/cacao/src/cacao.ts b/packages/cacao/src/cacao.ts index 47642cbb..7f8c6b2e 100644 --- a/packages/cacao/src/cacao.ts +++ b/packages/cacao/src/cacao.ts @@ -217,8 +217,19 @@ export namespace Cacao { } if (siwTezosMessage.signature) { + let signatureType = 'tezos:ed25519'; // Default to ed25519 + + // Determine the signature type based on the prefix + if (siwTezosMessage.signature.startsWith('edsig')) { + signatureType = 'tezos:ed25519'; + } else if (siwTezosMessage.signature.startsWith('spsig')) { + signatureType = 'tezos:secp256k1'; + } else if (siwTezosMessage.signature.startsWith('p2sig')) { + signatureType = 'tezos:p256'; + } + cacao.s = { - t: 'tezos:ed25519', + t: signatureType, s: siwTezosMessage.signature, } } diff --git a/packages/pkh-tezos/src/verifier.ts b/packages/pkh-tezos/src/verifier.ts index e00934b0..6e0ea500 100644 --- a/packages/pkh-tezos/src/verifier.ts +++ b/packages/pkh-tezos/src/verifier.ts @@ -11,6 +11,18 @@ import * as u8a from 'uint8arrays' import { blake2b } from '@noble/hashes/blake2b' import { sha256 } from '@noble/hashes/sha256' import { ed25519 } from '@noble/curves/ed25519' +import { secp256k1 } from '@noble/curves/secp256k1' +import { p256 } from '@noble/curves/p256' + +// SECP256K1 +const TZ2Prefix = new Uint8Array([6, 161, 161]); +const SPPKPrefix = new Uint8Array([3, 254, 226, 86]); +const SPSIGPrefix = new Uint8Array([13, 115, 101, 19, 63]); + +// P256 +const TZ3Prefix = new Uint8Array([6, 161, 164]); +const P2PKPrefix = new Uint8Array([3, 178, 139, 127]); +const P2SIGPrefix = new Uint8Array([54, 240, 44, 52]); // ED const TZ1Prefix = new Uint8Array([6, 161, 159]) @@ -26,19 +38,64 @@ export function getTezosVerifier(): Verifiers { 'tezos:ed25519': async (cacao: Cacao, opts: VerifyOptions): Promise => { verifyTezosSignature(cacao, opts) }, + 'tezos:secp256k1': async (cacao: Cacao, opts: VerifyOptions): Promise => { + verifyTezosSignature(cacao, opts) + }, + 'tezos:p256': async (cacao: Cacao, opts: VerifyOptions): Promise => { + verifyTezosSignature(cacao, opts) + }, } } -export function getPkhfromPk(publicKey: string): string { - const pkPrefix = publicKey.substring(0, 4) - if (pkPrefix !== 'edpk') - throw new Error('Tezos Signature type not supported, only type tezos:ed25519') - const decoded = b58cdecode(publicKey, EDPKPrefix) - const hashed = blake2b(decoded, { dkLen: TZ1Length }) - const result = b58cencode(hashed, TZ1Prefix) - return result + +function getPkhfromPk(publicKey: string): string { + const pkPrefix = publicKey.substring(0, 4); + let prefix; + let hashFn; + + switch (pkPrefix) { + case 'edpk': + prefix = TZ1Prefix; + hashFn = blake2b; + break; + case 'sppk': + prefix = TZ2Prefix; + hashFn = blake2b; + break; + case 'p2pk': + prefix = TZ3Prefix; + hashFn = blake2b; + break; + default: + throw new Error('Unsupported Tezos key type'); + } + const decoded = b58cdecode(publicKey, getPrefix(pkPrefix, 'pk')); + const hashed = hashFn(decoded, { dkLen: 20 }); + const result = b58cencode(hashed, prefix); + return result; +} + +function getPrefix(type: string, kind: 'pk' | 'sig') { + switch (kind) { + case 'pk': + switch (type) { + case 'edpk': return EDPKPrefix; + case 'sppk': return SPPKPrefix; + case 'p2pk': return P2PKPrefix; + } + break; + case 'sig': + switch (type) { + case 'edsig': case 'sig': return EDSIGPrefix; + case 'spsig': return SPSIGPrefix; + case 'p2sig': return P2SIGPrefix; + } + break; + } + throw new Error('Unsupported Tezos type or kind'); } + function verifyEdSignature( decodedSig: Uint8Array, bytesHash: Uint8Array, @@ -51,6 +108,22 @@ function verifyEdSignature( } } +function verifySecp256k1Signature(decodedSig: Uint8Array, bytesHash: Uint8Array, decodedPublicKey: Uint8Array): boolean { + try { + return secp256k1.verify(decodedSig, bytesHash, decodedPublicKey); + } catch (e) { + return false; + } +} + +function verifyP256Signature(decodedSig: Uint8Array, bytesHash: Uint8Array, decodedPublicKey: Uint8Array): boolean { + try { + return p256.verify(decodedSig, bytesHash, decodedPublicKey); + } catch (e) { + return false; + } +} + //bs58btc decoding, bs58check - checksum function b58cdecode(enc: string, prefixArg: Uint8Array): Uint8Array { const u8akey = u8a.fromString(enc, 'base58btc') @@ -74,19 +147,28 @@ function getCheckSum(u8a: Uint8Array): Uint8Array { return hashed.slice(0, 4) } -export function verifySignature(payload: string, publicKey: string, signature: string): boolean { - const pkPrefix = publicKey.substring(0, 4) - const sigPrefix = signature.startsWith('sig') ? signature.substr(0, 3) : signature.substr(0, 5) - if (pkPrefix !== 'edpk' || !(sigPrefix === 'edsig' || sigPrefix === 'sig')) - throw new Error('Tezos Signature type not supported, only type tezos:ed25519') +function verifySignature(payload: string, publicKey: string, signature: string): boolean { + const pkPrefix = publicKey.substring(0, 4); + const sigPrefix = signature.startsWith('sig') ? signature.substr(0, 3) : signature.substr(0, 5); + + const decodedPublicKey = b58cdecode(publicKey, getPrefix(pkPrefix, 'pk')); + const decodedSig = b58cdecode(signature, getPrefix(sigPrefix, 'sig')); + const bytesHash = blake2b(u8a.fromString(payload, 'base16'), { dkLen: 32 }); - const decodedPublicKey = b58cdecode(publicKey, EDPKPrefix) - const decodedSig = b58cdecode(signature, sigPrefix === 'edsig' ? EDSIGPrefix : SIGPrefix) - const bytesHash = blake2b(u8a.fromString(payload, 'base16'), { dkLen: 32 }) - return verifyEdSignature(decodedSig, bytesHash, decodedPublicKey) + switch (pkPrefix) { + case 'edpk': + return verifyEdSignature(decodedSig, bytesHash, decodedPublicKey); + case 'sppk': + return verifySecp256k1Signature(decodedSig, bytesHash, decodedPublicKey); + case 'p2pk': + return verifyP256Signature(decodedSig, bytesHash, decodedPublicKey); + } + + throw new Error('Tezos Signature type not supported'); } + export function verifyTezosSignature(cacao: Cacao, options: VerifyOptions) { assertSigned(cacao) verifyTimeChecks(cacao, options)