From 54203b69f3c404483c23bab89a5ad048a29b9411 Mon Sep 17 00:00:00 2001 From: rileystephens28 Date: Wed, 26 Jun 2024 13:58:05 -0500 Subject: [PATCH] Add new ethereum backwards compatible message hash and verify methods --- src/constants/strings.ts | 12 ++++++++++- src/hash/index.ts | 2 +- src/hash/message.ts | 46 ++++++++++++++++++++++++++++++++++++---- src/quais.ts | 2 ++ 4 files changed, 56 insertions(+), 6 deletions(-) diff --git a/src/constants/strings.ts b/src/constants/strings.ts index 844e1ba5..6c63540d 100644 --- a/src/constants/strings.ts +++ b/src/constants/strings.ts @@ -9,6 +9,16 @@ */ export const quaisymbol: string = '\u039e'; // "\uD835\uDF63"; +/** + * A constant for the Quai Network equivalent of the [EIP-191](https://eips.ethereum.org/EIPS/eip-191) personal message + * prefix. + * + * (**i.e.** `"\\x19Quai Signed Message:\\n"`) + * + * @category Constants + */ +export const MessagePrefix: string = '\x19Quai Signed Message:\n'; + /** * A constant for the [EIP-191](https://eips.ethereum.org/EIPS/eip-191) personal message prefix. * @@ -16,4 +26,4 @@ export const quaisymbol: string = '\u039e'; // "\uD835\uDF63"; * * @category Constants */ -export const MessagePrefix: string = '\x19Quai Signed Message:\n'; +export const EthMessagePrefix: string = '\x19Ethereum Signed Message:\n'; diff --git a/src/hash/index.ts b/src/hash/index.ts index 115f1c88..13eecb1b 100644 --- a/src/hash/index.ts +++ b/src/hash/index.ts @@ -3,7 +3,7 @@ */ export { id } from './id.js'; -export { hashMessage, verifyMessage } from './message.js'; +export { hashMessage, verifyMessage, ethHashMessage, ethVerifyMessage } from './message.js'; export { solidityPacked, solidityPackedKeccak256, solidityPackedSha256 } from './solidity.js'; export { TypedDataEncoder, verifyTypedData } from './typed-data.js'; diff --git a/src/hash/message.ts b/src/hash/message.ts index 03d749c2..b630e678 100644 --- a/src/hash/message.ts +++ b/src/hash/message.ts @@ -4,10 +4,11 @@ import { recoverAddress } from '../address/index.js'; import { concat } from '../utils/index.js'; import { toUtf8Bytes } from '../encoding/index.js'; - import type { SignatureLike } from '../crypto/index.js'; +import { EthMessagePrefix } from '../constants/strings.js'; /** - * Computes the [EIP-191](https://eips.ethereum.org/EIPS/eip-191) personal-sign message digest to sign. + * Computes the Quai Network equivalent of the [EIP-191](https://eips.ethereum.org/EIPS/eip-191) personal-sign message + * digest to sign. * * This prefixes the message with {@link MessagePrefix | **MessagePrefix**} and the decimal length of `message` and * computes the {@link keccak256 | **keccak256**} digest. @@ -37,7 +38,6 @@ import type { SignatureLike } from '../crypto/index.js'; * ``` * * @param {Uint8Array | string} message - The message to hash. - * * @returns {string} The message digest. */ export function hashMessage(message: Uint8Array | string): string { @@ -53,10 +53,48 @@ export function hashMessage(message: Uint8Array | string): string { * @category Hash * @param {Uint8Array | string} message - The message that was signed. * @param {SignatureLike} sig - The signature to verify. - * * @returns {string} The address of the signer. */ export function verifyMessage(message: Uint8Array | string, sig: SignatureLike): string { const digest = hashMessage(message); return recoverAddress(digest, sig); } + +/** + * Computes the [EIP-191](https://eips.ethereum.org/EIPS/eip-191) personal-sign message digest to sign. + * + * This prefixes the message with {@link EthMessagePrefix | **EthMessagePrefix**} and the decimal length of `message` and + * computes the {@link keccak256 | **keccak256**} digest. + * + * If `message` is a string, it is converted to its UTF-8 bytes first. To compute the digest of a + * [**DataHexString**](../types-aliases/DataHex), it must be converted to [**bytes**](../functions/getBytes). + * + * This is the same as `hashMessage` except it uses `EthMessagePrefix` instead of `MessagePrefix` and is available for + * broader compatibility with EVM signing practices. + * + * @category Hash + * @param message + * @returns + */ +export function ethHashMessage(message: Uint8Array | string): string { + if (typeof message === 'string') { + message = toUtf8Bytes(message); + } + return keccak256(concat([toUtf8Bytes(EthMessagePrefix), toUtf8Bytes(String(message.length)), message])); +} + +/** + * Return the address of the private key that produced the signature `sig` during signing for `message`. + * + * This is the same as `verifyMessage` except it uses `EthMessagePrefix` instead of `MessagePrefix` and is available for + * broader compatibility with EVM signing practices. + * + * @category Hash + * @param message - The message that was signed. + * @param sig - The signature to verify. + * @returns {string} The address of the signer. + */ +export function ethVerifyMessage(message: Uint8Array | string, sig: SignatureLike): string { + const digest = ethHashMessage(message); + return recoverAddress(digest, sig); +} diff --git a/src/quais.ts b/src/quais.ts index e2d010da..94ca95e3 100644 --- a/src/quais.ts +++ b/src/quais.ts @@ -89,6 +89,8 @@ export { id, hashMessage, verifyMessage, + ethHashMessage, + ethVerifyMessage, solidityPacked, solidityPackedKeccak256, solidityPackedSha256,