diff --git a/package.json b/package.json index 7bd192d53..50425a197 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "elliptic": "^6.5.4", "ethers": "^5.7.2", "long": "^5.2.3", - "viem": "^2.7.6" + "viem": "^2.7.8" }, "devDependencies": { "@commitlint/cli": "17.8.1", diff --git a/src/authn/LocalAuthenticator.ts b/src/authn/LocalAuthenticator.ts index 425b75381..bf8edcd66 100644 --- a/src/authn/LocalAuthenticator.ts +++ b/src/authn/LocalAuthenticator.ts @@ -1,9 +1,8 @@ import { authn, signature, publicKey } from '@xmtp/proto' import AuthData from './AuthData' import { PrivateKey } from '../crypto' -import { hexToBytes } from '../crypto/utils' import Token from './Token' -import { keccak256 } from 'viem' +import { hexToBytes, keccak256 } from 'viem' export default class LocalAuthenticator { private identityKey: PrivateKey diff --git a/src/crypto/Signature.ts b/src/crypto/Signature.ts index 90c66c249..55e0cfea1 100644 --- a/src/crypto/Signature.ts +++ b/src/crypto/Signature.ts @@ -4,8 +4,8 @@ import * as secp from '@noble/secp256k1' import { PublicKey, UnsignedPublicKey, SignedPublicKey } from './PublicKey' import { SignedPrivateKey } from './PrivateKey' import { Signer } from '../types/Signer' -import { bytesToHex, equalBytes, hexToBytes, splitSignature } from './utils' -import { Hex, hashMessage } from 'viem' +import { bytesToHex, equalBytes, splitSignature } from './utils' +import { Hex, hashMessage, hexToBytes } from 'viem' // ECDSA signature with recovery bit. export type ECDSACompactWithRecovery = { diff --git a/src/crypto/utils.ts b/src/crypto/utils.ts index 48ee70470..4fe5381ae 100644 --- a/src/crypto/utils.ts +++ b/src/crypto/utils.ts @@ -4,24 +4,12 @@ import { getAddress, hexToSignature, keccak256, - hexToBytes as viemHexToBytes, + hexToBytes, bytesToHex as viemBytesToHex, } from 'viem' export const bytesToHex = secp.utils.bytesToHex -export function hexToBytes(s: string): Uint8Array { - if (s.startsWith('0x')) { - s = s.slice(2) - } - const bytes = new Uint8Array(s.length / 2) - for (let i = 0; i < bytes.length; i++) { - const j = i * 2 - bytes[i] = Number.parseInt(s.slice(j, j + 2), 16) - } - return bytes -} - export function bytesToBase64(bytes: Uint8Array): string { return Buffer.from(bytes).toString('base64') } @@ -42,7 +30,7 @@ export function equalBytes(b1: Uint8Array, b2: Uint8Array): boolean { * Compute the Ethereum address from uncompressed PublicKey bytes */ export function computeAddress(bytes: Uint8Array) { - const publicKey = viemBytesToHex(bytes.slice(1)) as `0x${string}` + const publicKey = viemBytesToHex(bytes.slice(1)) as Hex const hash = keccak256(publicKey) const address = hash.substring(hash.length - 40) return getAddress(`0x${address}`) @@ -53,8 +41,8 @@ export function computeAddress(bytes: Uint8Array) { */ export function splitSignature(signature: Hex) { const eSig = hexToSignature(signature) - const r = viemHexToBytes(eSig.r) - const s = viemHexToBytes(eSig.s) + const r = hexToBytes(eSig.r) + const s = hexToBytes(eSig.s) let v = Number(eSig.v) if (v === 0 || v === 1) { v += 27 diff --git a/src/keystore/providers/NetworkKeyManager.ts b/src/keystore/providers/NetworkKeyManager.ts index 4ba8ee392..065946bde 100644 --- a/src/keystore/providers/NetworkKeyManager.ts +++ b/src/keystore/providers/NetworkKeyManager.ts @@ -9,11 +9,11 @@ import { } from '../../crypto' import type { PreEventCallback } from '../../Client' import { LocalAuthenticator } from '../../authn' -import { bytesToHex, hexToBytes } from '../../crypto/utils' +import { bytesToHex } from '../../crypto/utils' import Ciphertext from '../../crypto/Ciphertext' import { privateKey as proto } from '@xmtp/proto' import TopicPersistence from '../persistence/TopicPersistence' -import { getAddress, verifyMessage } from 'viem' +import { Hex, getAddress, hexToBytes, verifyMessage } from 'viem' const KEY_BUNDLE_NAME = 'key_bundle' /** @@ -100,14 +100,14 @@ export default class NetworkKeyManager { const valid = verifyMessage({ address: walletAddr as `0x${string}`, message: input, - signature: sig as `0x${string}`, + signature: sig as Hex, }) if (!valid) { throw new Error('invalid signature') } - const secret = hexToBytes(sig as `0x${string}`) + const secret = hexToBytes(sig as Hex) const ciphertext = await encrypt(bytes, secret) return proto.EncryptedPrivateKeyBundle.encode({ v1: { @@ -137,7 +137,7 @@ export default class NetworkKeyManager { const secret = hexToBytes( (await wallet.signMessage( storageSigRequestText(eBundle.walletPreKey) - )) as `0x${string}` + )) as Hex ) // Ledger uses the last byte = v=[0,1,...] but Metamask and other wallets generate with diff --git a/test/authn/Authn.test.ts b/test/authn/Authn.test.ts index 0e0170fdd..c720744e8 100644 --- a/test/authn/Authn.test.ts +++ b/test/authn/Authn.test.ts @@ -2,11 +2,10 @@ import Long from 'long' import { PrivateKey, PrivateKeyBundleV1, Signature } from '../../src/crypto' import Authenticator from '../../src/authn/LocalAuthenticator' import Token from '../../src/authn/Token' -import { hexToBytes } from '../../src/crypto/utils' import { newWallet, sleep } from '../helpers' import { Wallet } from 'ethers' import AuthCache from '../../src/authn/AuthCache' -import { keccak256 } from 'viem' +import { hexToBytes, keccak256 } from 'viem' describe('authn', () => { let authenticator: Authenticator diff --git a/test/crypto/PrivateKeyBundle.test.ts b/test/crypto/PrivateKeyBundle.test.ts index c53b78889..dcf4cab67 100644 --- a/test/crypto/PrivateKeyBundle.test.ts +++ b/test/crypto/PrivateKeyBundle.test.ts @@ -5,9 +5,9 @@ import { PrivateKeyBundleV2, SignedPublicKeyBundle, } from '../../src/crypto' -import { hexToBytes } from '../../src/crypto/utils' import { newWallet } from '../helpers' import { storageSigRequestText } from '../../src/keystore/providers/NetworkKeyManager' +import { hexToBytes } from 'viem' describe('Crypto', function () { describe('PrivateKeyBundle', function () { @@ -30,14 +30,14 @@ describe('Crypto', function () { it('human-friendly storage signature request text', async function () { const pri = PrivateKey.fromBytes( hexToBytes( - '08aaa9dad3ed2f12220a206fd789a6ee2376bb6595b4ebace57c7a79e6e4f1f12c8416d611399eda6c74cb1a4c08aaa9dad3ed2f1a430a4104e208133ea0973a9968fe5362e5ac0a8bbbe2aa16d796add31f3d027a1b894389873d7f282163bceb1fc3ca60d589d1e667956c40fed4cdaa7edc1392d2100b8a' + '0x08aaa9dad3ed2f12220a206fd789a6ee2376bb6595b4ebace57c7a79e6e4f1f12c8416d611399eda6c74cb1a4c08aaa9dad3ed2f1a430a4104e208133ea0973a9968fe5362e5ac0a8bbbe2aa16d796add31f3d027a1b894389873d7f282163bceb1fc3ca60d589d1e667956c40fed4cdaa7edc1392d2100b8a' ) ) expect(pri.secp256k1).toBeTruthy() const wallet = newWallet() const bundle = await PrivateKeyBundleV1.generate(wallet) const preKey = hexToBytes( - 'f51bd1da9ec2239723ae2cf6a9f8d0ac37546b27e634002c653d23bacfcc67ad' + '0xf51bd1da9ec2239723ae2cf6a9f8d0ac37546b27e634002c653d23bacfcc67ad' ) const actual = storageSigRequestText(preKey) const expected = diff --git a/test/crypto/PublicKey.test.ts b/test/crypto/PublicKey.test.ts index 521d2ca0f..c91d28c0a 100644 --- a/test/crypto/PublicKey.test.ts +++ b/test/crypto/PublicKey.test.ts @@ -5,12 +5,12 @@ import { SignedPublicKey, SignedPrivateKey, WalletSigner, - utils, Signature, } from '../../src/crypto' import { Wallet } from 'ethers' -import { hexToBytes, equalBytes } from '../../src/crypto/utils' +import { equalBytes } from '../../src/crypto/utils' import { newWallet } from '../helpers' +import { hexToBytes } from 'viem' describe('Crypto', function () { describe('Signed Keys', function () { @@ -67,8 +67,8 @@ describe('Crypto', function () { describe('PublicKey', function () { it('derives address from public key', function () { // using the sample from https://kobl.one/blog/create-full-ethereum-keypair-and-address/ - const bytes = utils.hexToBytes( - '04836b35a026743e823a90a0ee3b91bf615c6a757e2b60b9e1dc1826fd0dd16106f7bc1e8179f665015f43c6c81f39062fc2086ed849625c06e04697698b21855e' + const bytes = hexToBytes( + '0x04836b35a026743e823a90a0ee3b91bf615c6a757e2b60b9e1dc1826fd0dd16106f7bc1e8179f665015f43c6c81f39062fc2086ed849625c06e04697698b21855e' ) const pub = new PublicKey({ secp256k1Uncompressed: { bytes }, @@ -81,7 +81,7 @@ describe('Crypto', function () { it('human-friendly identity key signature request', async function () { const alice = PrivateKey.fromBytes( hexToBytes( - '08aaa9dad3ed2f12220a206fd789a6ee2376bb6595b4ebace57c7a79e6e4f1f12c8416d611399eda6c74cb1a4c08aaa9dad3ed2f1a430a4104e208133ea0973a9968fe5362e5ac0a8bbbe2aa16d796add31f3d027a1b894389873d7f282163bceb1fc3ca60d589d1e667956c40fed4cdaa7edc1392d2100b8a' + '0x08aaa9dad3ed2f12220a206fd789a6ee2376bb6595b4ebace57c7a79e6e4f1f12c8416d611399eda6c74cb1a4c08aaa9dad3ed2f1a430a4104e208133ea0973a9968fe5362e5ac0a8bbbe2aa16d796add31f3d027a1b894389873d7f282163bceb1fc3ca60d589d1e667956c40fed4cdaa7edc1392d2100b8a' ) ) const actual = WalletSigner.identitySigRequestText( diff --git a/test/keystore/providers/NetworkKeystoreProvider.test.ts b/test/keystore/providers/NetworkKeystoreProvider.test.ts index 10c5c7e2a..ba2449fab 100644 --- a/test/keystore/providers/NetworkKeystoreProvider.test.ts +++ b/test/keystore/providers/NetworkKeystoreProvider.test.ts @@ -10,10 +10,10 @@ import NetworkKeyManager, { storageSigRequestText, } from '../../../src/keystore/providers/NetworkKeyManager' import TopicPersistence from '../../../src/keystore/persistence/TopicPersistence' -import { hexToBytes } from '../../../src/crypto/utils' import { LocalAuthenticator } from '../../../src/authn' import crypto from '../../../src/crypto/crypto' import { vi } from 'vitest' +import { Hex, hexToBytes } from 'viem' describe('NetworkKeystoreProvider', () => { let apiClient: ApiClient @@ -59,7 +59,7 @@ describe('NetworkKeystoreProvider', () => { const walletAddr = await wallet.getAddress() let sig = await wallet.signMessage(input) - const secret = hexToBytes(sig) + const secret = hexToBytes(sig as Hex) const ciphertext = await encrypt(bytes, secret) const bytesToStore = privateKey.EncryptedPrivateKeyBundleV1.encode({ ciphertext,