From 87f042a0f70c512e3793cdb7ec963b03ce1047ee Mon Sep 17 00:00:00 2001 From: alekswaslet <1346150+alekswaslet@users.noreply.github.com> Date: Thu, 16 May 2024 11:03:25 +0200 Subject: [PATCH 1/4] Fix JuneoBuffer from string with hex prefix --- src/utils/bytes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/bytes.ts b/src/utils/bytes.ts index 5cb8155d..7fbfb7b6 100644 --- a/src/utils/bytes.ts +++ b/src/utils/bytes.ts @@ -201,7 +201,7 @@ export class JuneoBuffer { } } if (fromEncoding.toLowerCase() === 'hex') { - return JuneoBuffer.fromBytes(Buffer.from(data, 'hex')) + return encoding.decodeHex(data) } else if (fromEncoding.toLowerCase() === 'chex') { return encoding.decodeCHex(data) } else if (fromEncoding.toLowerCase() === 'cb58') { From e50056a8487951b657437c27a73775d0a0fd07c8 Mon Sep 17 00:00:00 2001 From: alekswaslet <1346150+alekswaslet@users.noreply.github.com> Date: Thu, 16 May 2024 13:22:00 +0200 Subject: [PATCH 2/4] Support additional signature scheme --- src/utils/bytes.ts | 4 +++- src/utils/crypto.ts | 16 +++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/utils/bytes.ts b/src/utils/bytes.ts index 7fbfb7b6..f1a79a7d 100644 --- a/src/utils/bytes.ts +++ b/src/utils/bytes.ts @@ -201,7 +201,9 @@ export class JuneoBuffer { } } if (fromEncoding.toLowerCase() === 'hex') { - return encoding.decodeHex(data) + return encoding.hasHexPrefix(data) + ? JuneoBuffer.fromBytes(Buffer.from(data.substring(2), 'hex')) + : JuneoBuffer.fromBytes(Buffer.from(data, 'hex')) } else if (fromEncoding.toLowerCase() === 'chex') { return encoding.decodeCHex(data) } else if (fromEncoding.toLowerCase() === 'cb58') { diff --git a/src/utils/crypto.ts b/src/utils/crypto.ts index 8ceaa7b9..90e8b4fd 100644 --- a/src/utils/crypto.ts +++ b/src/utils/crypto.ts @@ -14,15 +14,20 @@ export function sha256 (data: string | JuneoBuffer): JuneoBuffer { } export function recoverPubKey (signature: JuneoBuffer, hash: JuneoBuffer, recovery: number): string { - return JuneoBuffer.fromBytes( - Buffer.from(recoverPublicKey(hash.getBytes(), Signature.fromHex(signature.getBytes()), recovery, true)) - ) + const sig: Signature = parseSignature(signature) + return JuneoBuffer.fromBytes(Buffer.from(recoverPublicKey(hash.getBytes(), sig, recovery, true))) .toHex() .padStart(66, '0') } export function verifySignature (signature: JuneoBuffer, hash: JuneoBuffer, publicKey: string): boolean { - return verify(Signature.fromHex(signature.toHex()), hash.toHex(), publicKey) + return verify(parseSignature(signature), hash.toHex(), publicKey) +} + +function parseSignature (signature: JuneoBuffer): Signature { + return signature.length === 65 + ? Signature.fromCompact(signature.getBytes().subarray(0, 64)) + : Signature.fromCompact(signature.getBytes()) } export class ECKeyPair { @@ -39,7 +44,8 @@ export class ECKeyPair { sign (buffer: JuneoBuffer): JuneoBuffer { const signature: Signature = Signature.fromHex(signSync(buffer.getBytes(), this.privateKey)) // noble as of v1.7.1 does not provide recovery param so do it here - const v: number = recoverPubKey(JuneoBuffer.fromString(signature.toHex()), buffer, 0) === this.publicKey ? 0 : 1 + const v: number = + recoverPubKey(JuneoBuffer.fromString(signature.toCompactHex()), buffer, 0) === this.publicKey ? 0 : 1 return JuneoBuffer.fromString(`${signature.toCompactHex()}${v.toString(16).padStart(2, '0')}`) } } From 78f29b6104a5f8626cd974ec3b80cca91d28e605 Mon Sep 17 00:00:00 2001 From: alekswaslet <1346150+alekswaslet@users.noreply.github.com> Date: Thu, 16 May 2024 14:02:10 +0200 Subject: [PATCH 3/4] Enforce hashing of message signing --- src/transaction/input.ts | 4 ++-- src/transaction/jevm/transaction.ts | 4 ++-- src/transaction/platform/supernet.ts | 4 ++-- src/utils/crypto.ts | 19 +++++++++---------- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/transaction/input.ts b/src/transaction/input.ts index 583a5e88..d1446a90 100644 --- a/src/transaction/input.ts +++ b/src/transaction/input.ts @@ -1,5 +1,5 @@ import { type Blockchain } from '../chain' -import { JuneoBuffer, ParsingError, sha256, type Serializable, SignatureError, InputError } from '../utils' +import { JuneoBuffer, ParsingError, type Serializable, SignatureError, InputError } from '../utils' import { type VMWallet } from '../wallet' import { type Utxo } from './output' import { type Signable } from './signature' @@ -78,7 +78,7 @@ export class TransferableInput implements Serializable, Signable, Spendable { const address: Address = this.input.utxo.output.addresses[indices[i]] for (const wallet of wallets) { if (address.matches(wallet.getJuneoAddress())) { - signatures.push(new Signature(wallet.sign(sha256(bytes)))) + signatures.push(new Signature(wallet.sign(bytes))) break } } diff --git a/src/transaction/jevm/transaction.ts b/src/transaction/jevm/transaction.ts index 6424036a..0d8a84bd 100644 --- a/src/transaction/jevm/transaction.ts +++ b/src/transaction/jevm/transaction.ts @@ -1,4 +1,4 @@ -import { JuneoBuffer, sha256, type Serializable, SignatureError } from '../../utils' +import { JuneoBuffer, type Serializable, SignatureError } from '../../utils' import { type VMWallet } from '../../wallet' import { type Spendable, TransferableInput } from '../input' import { TransferableOutput } from '../output' @@ -74,7 +74,7 @@ export class EVMInput implements Serializable, Signable, Spendable { const address: Address = this.address for (const wallet of wallets) { if (address.matches(wallet.getAddress())) { - signatures.push(new Signature(wallet.sign(sha256(bytes)))) + signatures.push(new Signature(wallet.sign(bytes))) break } } diff --git a/src/transaction/platform/supernet.ts b/src/transaction/platform/supernet.ts index 5978e116..9bd01403 100644 --- a/src/transaction/platform/supernet.ts +++ b/src/transaction/platform/supernet.ts @@ -1,4 +1,4 @@ -import { type Serializable, JuneoBuffer, SignatureError, sha256 } from '../../utils' +import { type Serializable, JuneoBuffer, SignatureError } from '../../utils' import { type VMWallet } from '../../wallet' import { getSignersIndices } from '../builder' import { type Signable } from '../signature' @@ -29,7 +29,7 @@ export class SupernetAuth implements Serializable, Signable { const address: Address = this.rewardsOwner.addresses[i] for (const wallet of wallets) { if (address.matches(wallet.getJuneoAddress())) { - signatures.push(new Signature(wallet.sign(sha256(bytes)))) + signatures.push(new Signature(wallet.sign(bytes))) break } } diff --git a/src/utils/crypto.ts b/src/utils/crypto.ts index 90e8b4fd..d106626a 100644 --- a/src/utils/crypto.ts +++ b/src/utils/crypto.ts @@ -13,15 +13,14 @@ export function sha256 (data: string | JuneoBuffer): JuneoBuffer { return JuneoBuffer.fromBytes(Buffer.from(nobleSha256(buffer.getBytes()))) } -export function recoverPubKey (signature: JuneoBuffer, hash: JuneoBuffer, recovery: number): string { +export function recoverPubKey (signature: JuneoBuffer, message: JuneoBuffer, recovery: number): string { const sig: Signature = parseSignature(signature) - return JuneoBuffer.fromBytes(Buffer.from(recoverPublicKey(hash.getBytes(), sig, recovery, true))) - .toHex() - .padStart(66, '0') + const bytes: Buffer = Buffer.from(recoverPublicKey(nobleSha256(message.getBytes()), sig, recovery, true)) + return JuneoBuffer.fromBytes(bytes).toHex().padStart(66, '0') } -export function verifySignature (signature: JuneoBuffer, hash: JuneoBuffer, publicKey: string): boolean { - return verify(parseSignature(signature), hash.toHex(), publicKey) +export function verifySignature (signature: JuneoBuffer, message: JuneoBuffer, publicKey: string): boolean { + return verify(parseSignature(signature), nobleSha256(message.getBytes()), publicKey) } function parseSignature (signature: JuneoBuffer): Signature { @@ -41,11 +40,11 @@ export class ECKeyPair { .padStart(66, '0') } - sign (buffer: JuneoBuffer): JuneoBuffer { - const signature: Signature = Signature.fromHex(signSync(buffer.getBytes(), this.privateKey)) + sign (message: JuneoBuffer): JuneoBuffer { + const signature: Signature = Signature.fromHex(signSync(nobleSha256(message.getBytes()), this.privateKey)) // noble as of v1.7.1 does not provide recovery param so do it here - const v: number = - recoverPubKey(JuneoBuffer.fromString(signature.toCompactHex()), buffer, 0) === this.publicKey ? 0 : 1 + const publicKey: string = recoverPubKey(JuneoBuffer.fromString(signature.toCompactHex()), message, 0) + const v: number = publicKey === this.publicKey ? 0 : 1 return JuneoBuffer.fromString(`${signature.toCompactHex()}${v.toString(16).padStart(2, '0')}`) } } From d700b8df027724b7c7d0c7989ace76a869feec8a Mon Sep 17 00:00:00 2001 From: alekswaslet <1346150+alekswaslet@users.noreply.github.com> Date: Thu, 16 May 2024 14:02:42 +0200 Subject: [PATCH 4/4] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d657f0da..577fdd8c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "juneojs", - "version": "0.0.93", + "version": "0.0.94", "description": "Juneo JS Library", "main": "dist/index.js", "types": "dist/index.d.ts",