UNPKG

ox

Version:

Ethereum Standard Library

932 lines 31.9 kB
import * as Address from '../core/Address.js'; import type * as Bytes from '../core/Bytes.js'; import * as Errors from '../core/Errors.js'; import * as Hex from '../core/Hex.js'; import type { Assign, Compute, IsNarrowable, OneOf, PartialBy, UnionPartialBy } from '../core/internal/types.js'; import type * as PublicKey from '../core/PublicKey.js'; import * as Rlp from '../core/Rlp.js'; import * as ox_Secp256k1 from '../core/Secp256k1.js'; import * as Signature from '../core/Signature.js'; import type * as WebAuthnP256 from '../core/WebAuthnP256.js'; import * as MultisigConfig from './MultisigConfig.js'; /** Serialized magic identifier for Tempo signature envelopes. */ export declare const magicBytes = "0x7777777777777777777777777777777777777777777777777777777777777777"; /** * Statically determines the signature type of an envelope at compile time. * * @example * ```ts twoslash * import type { SignatureEnvelope } from 'ox/tempo' * * type Type = SignatureEnvelope.GetType<{ * r: `0x${string}` * s: `0x${string}` * yParity: number * }> * // @log: 'secp256k1' * ``` */ export type GetType<envelope extends PartialBy<SignatureEnvelope, 'type'> | unknown> = unknown extends envelope ? envelope extends unknown ? Type : never : envelope extends { type: infer T extends Type; } ? T : envelope extends { signature: { r: `0x${string}`; s: `0x${string}`; }; prehash: boolean; publicKey: PublicKey.PublicKey; } ? 'p256' : envelope extends { signature: { r: `0x${string}`; s: `0x${string}`; }; metadata: any; publicKey: PublicKey.PublicKey; } ? 'webAuthn' : envelope extends { r: `0x${string}`; s: `0x${string}`; yParity: number; } ? 'secp256k1' : envelope extends { signature: { r: `0x${string}`; s: `0x${string}`; yParity: number; }; } ? 'secp256k1' : envelope extends { userAddress: Address.Address; } ? 'keychain' : envelope extends { account: Address.Address; signatures: any; } | { init: MultisigConfig.Config; signatures: any; } ? 'multisig' : never; /** * Represents a signature envelope that can contain different signature types. * * Tempo transactions support multiple signature types, each with different wire formats: * * - **secp256k1** (no type prefix, 65 bytes): Standard Ethereum ECDSA signature. The sender * address is recovered via `ecrecover`. Base transaction cost: 21,000 gas. * * - **p256** (type `0x01`, 130 bytes): P256/secp256r1 curve signature for passkey accounts. * Includes embedded public key (64 bytes) and prehash flag. Enables native WebCrypto * key support. Additional gas cost: +5,000 gas over secp256k1. * * - **webAuthn** (type `0x02`, 129-2049 bytes): WebAuthn signature with authenticator data * and clientDataJSON. Enables browser passkey authentication. The signature is also * charged as calldata (16 gas/non-zero byte, 4 gas/zero byte). * * - **keychain** (type `0x03` V1, `0x04` V2): Access key signature that wraps an inner signature * (secp256k1, p256, or webAuthn). Format: type byte + user_address (20 bytes) + inner signature. * V2 binds the signature to the user account via `keccak256(sigHash || userAddress)`. * The protocol validates the access key authorization via the AccountKeychain precompile. * * [Signature Types Specification](https://docs.tempo.xyz/protocol/transactions/spec-tempo-transaction#signature-types) */ export type SignatureEnvelope<numberType = number> = OneOf<Secp256k1<numberType> | P256<numberType> | WebAuthn<numberType> | Keychain<numberType> | Multisig<numberType>>; /** * RPC-formatted signature envelope. */ export type SignatureEnvelopeRpc = OneOf<Secp256k1Rpc | P256Rpc | WebAuthnRpc | KeychainRpc | MultisigRpc>; /** Primitive signature envelope accepted by protocol sidecars. */ export type Primitive<numberType = number> = OneOf<Secp256k1<numberType> | P256<numberType> | WebAuthn<numberType>>; /** RPC-formatted primitive signature envelope. */ export type PrimitiveRpc = OneOf<Secp256k1Rpc | P256Rpc | WebAuthnRpc>; /** * Keychain signature version. * * - `'v1'`: Legacy format. Inner signature signs the raw `sig_hash` directly. Deprecated at T1C. * - `'v2'`: Inner signature signs `keccak256(sig_hash || user_address)`, binding the signature * to the specific user account. */ export type KeychainVersion = 'v1' | 'v2'; export type Keychain<numberType = number> = { /** Root account address that this transaction is being executed for */ userAddress: Address.Address; /** The actual signature from the access key (can be Secp256k1, P256, or WebAuthn) */ inner: SignatureEnvelope<numberType>; /** The access key address (recovered address of the access key signer). */ keyId?: Address.Address | undefined; type: 'keychain'; /** Keychain signature version. @default 'v1' */ version?: KeychainVersion | undefined; }; export type KeychainRpc = { type: 'keychain'; userAddress: Address.Address; keyId?: Address.Address | undefined; signature: SignatureEnvelopeRpc; version?: KeychainVersion | undefined; }; /** * Native multisig signature (type `0x05`). * * Wraps a set of owner approvals (secp256k1, p256, webAuthn, or nested * multisig) over the multisig owner approval digest. The transaction sender is * the derived `account`, authorized once the recovered owner weights meet the * configured threshold. * * [TIP-1061](https://tips.sh/1061) */ export type Multisig<numberType = number> = { type: 'multisig'; /** Native multisig account address. */ account: Address.Address; /** * Owner approvals over the multisig owner approval digest. Each approval is * either a primitive signature or a nested multisig signature (keychain * approvals are invalid). */ signatures: readonly SignatureEnvelope<numberType>[]; /** * Initial native multisig config for bootstrapping this account. Present only on * the first (bootstrap) transaction from the derived account; absent on every * subsequent transaction. */ init?: MultisigConfig.Config<numberType> | undefined; }; /** RPC-formatted native multisig signature. */ export type MultisigRpc = OneOf<{ /** Existing native multisig account. */ account: Address.Address; /** Structured owner approvals. */ signatures: readonly SignatureEnvelopeRpc[]; /** Multisig RPC signatures are untagged. */ type?: undefined; } | { /** Initial config for bootstrapping a native multisig account. */ init: MultisigConfig.Config; /** Structured owner approvals. */ signatures: readonly SignatureEnvelopeRpc[]; /** Multisig RPC signatures are untagged. */ type?: undefined; }>; export type P256<numberType = number> = { prehash: boolean; publicKey: PublicKey.PublicKey; signature: Signature.Signature<false, numberType>; type: 'p256'; }; export type P256Rpc = { preHash: boolean; pubKeyX: Hex.Hex; pubKeyY: Hex.Hex; r: Hex.Hex; s: Hex.Hex; type: 'p256'; }; export type Secp256k1<numberType = number> = { signature: Signature.Signature<true, numberType>; type: 'secp256k1'; }; export type Secp256k1Rpc = Compute<Signature.Rpc<true> & { v?: Hex.Hex | undefined; type: 'secp256k1'; }>; export type Secp256k1Flat<numberType = number> = Signature.Signature<true, numberType> & { type?: 'secp256k1' | undefined; }; export type WebAuthn<numberType = number> = { metadata: Pick<WebAuthnP256.SignMetadata, 'authenticatorData' | 'clientDataJSON'>; signature: Signature.Signature<false, numberType>; publicKey: PublicKey.PublicKey; type: 'webAuthn'; }; export type WebAuthnRpc = { pubKeyX: Hex.Hex; pubKeyY: Hex.Hex; r: Hex.Hex; s: Hex.Hex; type: 'webAuthn'; webauthnData: Hex.Hex; }; /** Hex-encoded serialized signature envelope. */ export type Serialized = Hex.Hex; /** List of supported signature types. */ export declare const types: readonly ["secp256k1", "p256", "webAuthn"]; /** Union type of supported signature types. */ export type Type = (typeof types)[number]; /** * Asserts that a {@link ox#SignatureEnvelope.SignatureEnvelope} is valid. * * @example * ```ts twoslash * import { SignatureEnvelope } from 'ox/tempo' * * SignatureEnvelope.assert({ * type: 'secp256k1', * signature: { * r: '0x0000000000000000000000000000000000000000000000000000000000000000', * s: '0x0000000000000000000000000000000000000000000000000000000000000000', * yParity: 0 * } * }) * ``` * * @param envelope - The signature envelope to assert. * @throws `CoercionError` if the envelope type cannot be determined. */ export declare function assert(envelope: PartialBy<SignatureEnvelope, 'type'>): void; export declare namespace assert { type ErrorType = CoercionError | InvalidMultisigApprovalError | MissingPropertiesError | MultisigConfig.assert.ErrorType | MultisigConfig.getAddress.ErrorType | Signature.assert.ErrorType | Errors.GlobalErrorType; } /** * Extracts the address of the signer from a {@link ox#SignatureEnvelope.SignatureEnvelope}. * * - **secp256k1**: Recovers the address from the payload via `ecrecover`. * - **p256** / **webAuthn**: Derives the address from the embedded public key. * - **keychain**: Extracts from the inner signature (or returns `userAddress` if `user` is `true`). * * @example * ```ts twoslash * import { Secp256k1 } from 'ox' * import { SignatureEnvelope } from 'ox/tempo' * * const payload = '0xdeadbeef' * const signature = Secp256k1.sign({ * payload, * privateKey: '0x...' * }) * const envelope = SignatureEnvelope.from(signature) * * const address = SignatureEnvelope.extractAddress({ * // [!code focus] * payload, // [!code focus] * signature: envelope // [!code focus] * }) // [!code focus] * ``` * * @param options - The extraction options. * @returns The signer address. */ export declare function extractAddress(options: extractAddress.Options): extractAddress.ReturnType; export declare namespace extractAddress { type Options = { /** The sign payload that was signed (only required for secp256k1 signatures). */ payload: Hex.Hex | Bytes.Bytes; /** The signature envelope. */ signature: SignatureEnvelope; /** Whether to return the root `userAddress` for keychain signatures instead of extracting from the inner signature. */ root?: boolean | undefined; }; type ReturnType = Address.Address; type ErrorType = Address.fromPublicKey.ErrorType | extractPublicKey.ErrorType | Errors.GlobalErrorType; } /** * Extracts the public key of the signer from a {@link ox#SignatureEnvelope.SignatureEnvelope}. * * - **secp256k1**: Recovers the public key from the payload via `ecrecover`. * - **p256** / **webAuthn**: Returns the embedded public key. * - **keychain**: Extracts from the inner signature. * * @example * ```ts twoslash * import { Secp256k1 } from 'ox' * import { SignatureEnvelope } from 'ox/tempo' * * const payload = '0xdeadbeef' * const signature = Secp256k1.sign({ * payload, * privateKey: '0x...' * }) * const envelope = SignatureEnvelope.from(signature) * * const publicKey = SignatureEnvelope.extractPublicKey({ * // [!code focus] * payload, // [!code focus] * signature: envelope // [!code focus] * }) // [!code focus] * ``` * * @param options - The extraction options. * @returns The signer's public key. */ export declare function extractPublicKey(options: extractPublicKey.Options): extractPublicKey.ReturnType; export declare namespace extractPublicKey { type Options = { /** The sign payload that was signed (only required for secp256k1 signatures). */ payload: Hex.Hex | Bytes.Bytes; /** The signature envelope. */ signature: SignatureEnvelope; }; type ReturnType = PublicKey.PublicKey; type ErrorType = CoercionError | ox_Secp256k1.recoverPublicKey.ErrorType | Errors.GlobalErrorType; } /** * Deserializes a hex-encoded signature envelope into a typed signature object. * * Wire format detection: * - 65 bytes (no prefix): secp256k1 signature * - Type `0x01` + 129 bytes: P256 signature (r, s, pubKeyX, pubKeyY, prehash) * - Type `0x02` + variable: WebAuthn signature (webauthnData, r, s, pubKeyX, pubKeyY) * - Type `0x03` + 20 bytes + inner: Keychain V1 signature (userAddress + inner signature) * - Type `0x04` + 20 bytes + inner: Keychain V2 signature (userAddress + inner signature) * * [Signature Types](https://docs.tempo.xyz/protocol/transactions/spec-tempo-transaction#signature-types) * * @example * ```ts twoslash * import { SignatureEnvelope } from 'ox/tempo' * * const envelope = SignatureEnvelope.deserialize('0x...') * ``` * * @param serialized - The hex-encoded signature envelope to deserialize. * @returns The deserialized signature envelope. * @throws `CoercionError` if the serialized value cannot be coerced to a valid signature envelope. */ export declare function deserialize(value: Serialized): SignatureEnvelope; /** * Coerces a value to a signature envelope. * * Accepts either a serialized hex string or an existing signature envelope object. * Use this to wrap raw signatures from {@link ox#Secp256k1.(sign:function)}, {@link ox#P256.(sign:function)}, * {@link ox#WebCryptoP256.(sign:function)}, or {@link ox#WebAuthnP256.(sign:function)} into the envelope format * required by Tempo transactions. * * [Signature Types](https://docs.tempo.xyz/protocol/transactions/spec-tempo-transaction#signature-types) * * @example * ### Secp256k1 * * Standard Ethereum ECDSA signature using the secp256k1 curve. * * ```ts twoslash * import { Secp256k1 } from 'ox' * import { SignatureEnvelope } from 'ox/tempo' * * const privateKey = Secp256k1.randomPrivateKey() * const signature = Secp256k1.sign({ * payload: '0xdeadbeef', * privateKey * }) * * const envelope = SignatureEnvelope.from(signature) * ``` * * @example * ### P256 * * ECDSA signature using the P-256 (secp256r1) curve. Requires embedding the * public key. * * ```ts twoslash * import { P256 } from 'ox' * import { SignatureEnvelope } from 'ox/tempo' * * const { privateKey, publicKey } = P256.createKeyPair() * const signature = P256.sign({ * payload: '0xdeadbeef', * privateKey * }) * * const envelope = SignatureEnvelope.from({ * signature, * publicKey * }) * ``` * * @example * ### P256 (WebCrypto) * * When using WebCrypto keys, `prehash` must be `true` since WebCrypto always * SHA256 hashes the digest before signing. * * ```ts twoslash * // @noErrors * import { WebCryptoP256 } from 'ox' * import { SignatureEnvelope } from 'ox/tempo' * * const { privateKey, publicKey } = * await WebCryptoP256.createKeyPair() * const signature = await WebCryptoP256.sign({ * payload: '0xdeadbeef', * privateKey * }) * * const envelope = SignatureEnvelope.from({ * signature, * publicKey, * prehash: true * }) * ``` * * @example * ### WebAuthn * * Passkey-based signature using WebAuthn. Includes authenticator metadata * (authenticatorData and clientDataJSON) along with the P-256 signature and * public key. * * ```ts twoslash * // @noErrors * import { WebAuthnP256 } from 'ox' * import { SignatureEnvelope } from 'ox/tempo' * * const credential = await WebAuthnP256.createCredential({ * name: 'Example' * }) * * const { metadata, signature } = await WebAuthnP256.sign({ * challenge: '0xdeadbeef', * credentialId: credential.id * }) * * const envelope = SignatureEnvelope.from({ * signature, * publicKey: credential.publicKey, * metadata * }) * ``` * * @example * ### Keychain * * Wraps another signature type with a user address, used for delegated signing * via access keys on behalf of a root account. * * ```ts twoslash * import { Secp256k1 } from 'ox' * import { SignatureEnvelope } from 'ox/tempo' * * const privateKey = Secp256k1.randomPrivateKey() * const signature = Secp256k1.sign({ * payload: '0xdeadbeef', * privateKey * }) * * const envelope = SignatureEnvelope.from({ * userAddress: '0x1234567890123456789012345678901234567890', * inner: SignatureEnvelope.from(signature) * }) * ``` * * @example * ### Multisig (from genesis config) * * Pass `genesisConfig` to derive `account` automatically. Set `init: true` to * opt into bootstrap (uses `genesisConfig` as the bootstrap `init`); omit * `init` for subsequent (non-bootstrap) transactions. * * ```ts twoslash * import { Secp256k1 } from 'ox' * import { MultisigConfig, SignatureEnvelope } from 'ox/tempo' * * const genesisConfig = MultisigConfig.from({ * threshold: 1, * owners: [ * { * owner: '0x1111111111111111111111111111111111111111', * weight: 1 * } * ] * }) * * const privateKey = Secp256k1.randomPrivateKey() * const signature = SignatureEnvelope.from( * Secp256k1.sign({ payload: '0xdeadbeef', privateKey }) * ) * * // Bootstrap transaction * const bootstrap = SignatureEnvelope.from({ * genesisConfig, * signatures: [signature], * init: true * }) * * // Subsequent (non-bootstrap) transactions * const subsequent = SignatureEnvelope.from({ * genesisConfig, * signatures: [signature] * }) * ``` * * @param value - The value to coerce (either a hex string or signature envelope). * @returns The signature envelope. */ export declare function from<const value extends from.Value>(value: value | from.Value, options?: from.Options): from.ReturnValue<value>; export declare namespace from { type Options = { /** Payload that was signed. Used to recover `keyId` for keychain envelopes with secp256k1 inner signatures. */ payload?: Hex.Hex | Bytes.Bytes | undefined; }; /** * Multisig envelope input variant where `account` is derived from the * supplied `genesisConfig`. Pass `init: true` to opt into bootstrap (uses * `genesisConfig` as the bootstrap `init`); omit `init` for subsequent * (non-bootstrap) transactions. */ type MultisigFromGenesisConfig = { type?: 'multisig' | undefined; genesisConfig: MultisigConfig.Config; signatures: readonly SignatureEnvelope[]; init?: MultisigConfig.Config | boolean | undefined; }; type Value = UnionPartialBy<SignatureEnvelope, 'prehash' | 'type'> | Secp256k1Flat | Serialized | MultisigFromGenesisConfig; type ReturnValue<value extends Value> = Compute<OneOf<value extends Serialized ? SignatureEnvelope : value extends Secp256k1Flat ? Secp256k1 : value extends MultisigFromGenesisConfig ? Multisig : IsNarrowable<value, SignatureEnvelope> extends true ? SignatureEnvelope : Assign<value, { readonly type: GetType<value>; } & (GetType<value> extends 'keychain' ? { keyId?: Address.Address | undefined; } : {})>>>; } /** * Converts an RPC-formatted signature envelope to a typed signature envelope. * * @example * ```ts twoslash * import { SignatureEnvelope } from 'ox/tempo' * * const envelope = SignatureEnvelope.fromRpc({ * r: '0x0', * s: '0x0', * yParity: '0x0', * type: 'secp256k1' * }) * ``` * * @param envelope - The RPC signature envelope to convert. * @returns The signature envelope with bigint values. */ export declare function fromRpc(envelope: SignatureEnvelopeRpc): SignatureEnvelope; export declare namespace fromRpc { type ErrorType = assert.ErrorType | CoercionError | InvalidSerializedError | MultisigConfig.getAddress.ErrorType | Signature.fromRpc.ErrorType | Errors.GlobalErrorType; } /** * Determines the signature type of an envelope. * * @example * ```ts twoslash * import { SignatureEnvelope } from 'ox/tempo' * * const type = SignatureEnvelope.getType({ * signature: { * r: '0x0000000000000000000000000000000000000000000000000000000000000000', * s: '0x0000000000000000000000000000000000000000000000000000000000000000', * yParity: 0 * } * }) * // @log: 'secp256k1' * ``` * * @param envelope - The signature envelope to inspect. * @returns The signature type ('secp256k1', 'p256', or 'webAuthn'). * @throws `CoercionError` if the envelope type cannot be determined. */ export declare function getType<envelope extends PartialBy<SignatureEnvelope, 'type'> | Secp256k1Flat | unknown>(envelope: envelope): GetType<envelope>; /** * Serializes a signature envelope to a hex-encoded string. * * Wire format: * - secp256k1: 65 bytes (no type prefix, for backward compatibility) * - P256: `0x01` + r (32) + s (32) + pubKeyX (32) + pubKeyY (32) + prehash (1) = 130 bytes * - WebAuthn: `0x02` + webauthnData (variable) + r (32) + s (32) + pubKeyX (32) + pubKeyY (32) * - Keychain V1: `0x03` + userAddress (20) + inner signature (recursive) * - Keychain V2: `0x04` + userAddress (20) + inner signature (recursive) * - Multisig: `0x05` + RLP `[account | init, signatures]` * * [Signature Types](https://docs.tempo.xyz/protocol/transactions/spec-tempo-transaction#signature-types) * * @example * ```ts twoslash * import { SignatureEnvelope } from 'ox/tempo' * * const serialized = SignatureEnvelope.serialize({ * signature: { * r: '0x0000000000000000000000000000000000000000000000000000000000000000', * s: '0x0000000000000000000000000000000000000000000000000000000000000000', * yParity: 0 * }, * type: 'secp256k1' * }) * ``` * * @param envelope - The signature envelope to serialize. * @returns The hex-encoded serialized signature. * @throws `CoercionError` if the envelope cannot be serialized. */ export declare function serialize(envelope: UnionPartialBy<SignatureEnvelope, 'prehash'>, options?: serialize.Options): Serialized; export declare namespace serialize { type Options = { /** * Whether to serialize the signature envelope with the Tempo magic identifier. * This is useful for being able to distinguish between Tempo and non-Tempo (e.g. ERC-1271) signatures. */ magic?: boolean | undefined; }; type ErrorType = assert.ErrorType | CoercionError | Hex.concat.ErrorType | Hex.fromNumber.ErrorType | Hex.fromString.ErrorType | Rlp.fromHex.ErrorType | Signature.toHex.ErrorType | Errors.GlobalErrorType; } /** * Orders native multisig owner approvals into the strictly-ascending * recovered-owner order the Tempo node requires for the multisig `signatures` * array (the node enforces "recovered owners must be strictly ascending"). * * Each approval is signed over the multisig owner approval digest * ({@link ox#MultisigConfig.(getSignPayload:function)}), so the signer of * every approval is recovered against that digest and the list is sorted by the * recovered owner address. Works for any owner key type (secp256k1, p256, * webAuthn). * * Config updates never change `account`, so the genesis config is the correct * input even for post-update transactions. * * @example * ```ts twoslash * import { Secp256k1 } from 'ox' * import { * MultisigConfig, * SignatureEnvelope, * TxEnvelopeTempo * } from 'ox/tempo' * * const genesisConfig = MultisigConfig.from({ * threshold: 2, * owners: [ * { * owner: '0x1111111111111111111111111111111111111111', * weight: 1 * }, * { * owner: '0x2222222222222222222222222222222222222222', * weight: 1 * } * ] * }) * * const tx = TxEnvelopeTempo.from({ chainId: 1, calls: [] }) * const payload = TxEnvelopeTempo.getSignPayload(tx) * * const privateKeys = [ * Secp256k1.randomPrivateKey(), * Secp256k1.randomPrivateKey() * ] * const digest = MultisigConfig.getSignPayload({ * payload, * genesisConfig * }) * const signatures = privateKeys.map((privateKey) => * SignatureEnvelope.from( * Secp256k1.sign({ payload: digest, privateKey }) * ) * ) * * const ordered = SignatureEnvelope.sortMultisigApprovals({ * // [!code focus] * genesisConfig, // [!code focus] * payload, // [!code focus] * signatures // [!code focus] * }) // [!code focus] * ``` * * @param value - The approval ordering parameters. * @returns The owner approvals ordered ascending by recovered owner address. */ export declare function sortMultisigApprovals(value: sortMultisigApprovals.Value): readonly SignatureEnvelope[]; export declare namespace sortMultisigApprovals { type Value = { /** The inner transaction sign payload (`tx.signature_hash()`). */ payload: Hex.Hex | Bytes.Bytes; /** The owner approvals to order. */ signatures: readonly SignatureEnvelope[]; } & OneOf<{ /** The native multisig account address. */ account: Address.Address; } | { /** * The initial multisig config (the bootstrap config that derived the * permanent `account`). Used to derive the account automatically. */ genesisConfig: MultisigConfig.Config; }>; type ErrorType = MultisigConfig.getSignPayload.ErrorType | extractAddress.ErrorType | Errors.GlobalErrorType; } /** * Converts a signature envelope to RPC format. * * @example * ```ts twoslash * import { SignatureEnvelope } from 'ox/tempo' * * const rpc = SignatureEnvelope.toRpc({ * signature: { * r: '0x0000000000000000000000000000000000000000000000000000000000000000', * s: '0x0000000000000000000000000000000000000000000000000000000000000000', * yParity: 0 * }, * type: 'secp256k1' * }) * ``` * * @param envelope - The signature envelope to convert. * @returns The RPC signature envelope with hex values. */ export declare function toRpc<const envelope extends toRpc.Input>(envelope: envelope): toRpc.ReturnType<envelope>; export declare namespace toRpc { /** Numberish input accepted by {@link ox#SignatureEnvelope.(toRpc:function)}. */ type Input = SignatureEnvelope<Hex.Hex | number>; /** RPC signature envelope inferred from the input type. */ type ReturnType<envelope extends Input = Input> = GetType<envelope> extends 'secp256k1' ? Secp256k1Rpc : GetType<envelope> extends 'p256' ? P256Rpc : GetType<envelope> extends 'webAuthn' ? WebAuthnRpc : GetType<envelope> extends 'keychain' ? KeychainRpc : GetType<envelope> extends 'multisig' ? MultisigRpc : SignatureEnvelopeRpc; type ErrorType = assert.ErrorType | CoercionError | Signature.toRpc.ErrorType | Errors.GlobalErrorType; } /** * Validates a signature envelope. Returns `true` if the envelope is valid, `false` otherwise. * * @example * ```ts twoslash * import { SignatureEnvelope } from 'ox/tempo' * * const valid = SignatureEnvelope.validate({ * signature: { * r: '0x0000000000000000000000000000000000000000000000000000000000000000', * s: '0x0000000000000000000000000000000000000000000000000000000000000000', * yParity: 0 * }, * type: 'secp256k1' * }) * // @log: true * ``` * * @param envelope - The signature envelope to validate. * @returns `true` if valid, `false` otherwise. */ export declare function validate(envelope: PartialBy<SignatureEnvelope, 'type'>): boolean; export declare namespace validate { type ErrorType = Errors.GlobalErrorType; } /** * Verifies a signature envelope against a digest/payload. * * Supports `secp256k1`, `p256`, and `webAuthn` signature types. * * :::warning * `keychain` signatures are not supported and will throw an error. * ::: * * @example * ### Secp256k1 * * ```ts twoslash * import { SignatureEnvelope } from 'ox/tempo' * import { Secp256k1 } from 'ox' * * const privateKey = Secp256k1.randomPrivateKey() * const publicKey = Secp256k1.getPublicKey({ privateKey }) * const payload = '0xdeadbeef' * * const signature = Secp256k1.sign({ payload, privateKey }) * const envelope = SignatureEnvelope.from(signature) * * const valid = SignatureEnvelope.verify(envelope, { * payload, * publicKey * }) * // @log: true * ``` * * @example * ### P256 * * For P256 signatures, the `address` or `publicKey` must match the embedded * public key in the signature envelope. * * ```ts twoslash * import { SignatureEnvelope } from 'ox/tempo' * import { P256 } from 'ox' * * const privateKey = P256.randomPrivateKey() * const publicKey = P256.getPublicKey({ privateKey }) * const payload = '0xdeadbeef' * * const signature = P256.sign({ payload, privateKey }) * const envelope = SignatureEnvelope.from({ * prehash: false, * publicKey, * signature * }) * * const valid = SignatureEnvelope.verify(envelope, { * payload, * publicKey * }) * // @log: true * ``` * * @example * ### WebCryptoP256 * * ```ts twoslash * import { SignatureEnvelope } from 'ox/tempo' * import { WebCryptoP256 } from 'ox' * * const { privateKey, publicKey } = * await WebCryptoP256.createKeyPair() * const payload = '0xdeadbeef' * * const signature = await WebCryptoP256.sign({ * payload, * privateKey * }) * const envelope = SignatureEnvelope.from({ * prehash: true, * publicKey, * signature * }) * * const valid = SignatureEnvelope.verify(envelope, { * payload, * publicKey * }) * // @log: true * ``` * * @example * ### WebAuthnP256 * * ```ts twoslash * import { SignatureEnvelope } from 'ox/tempo' * import { WebAuthnP256 } from 'ox' * * const credential = await WebAuthnP256.createCredential({ * name: 'Example' * }) * const payload = '0xdeadbeef' * * const { metadata, signature } = await WebAuthnP256.sign({ * challenge: payload, * credentialId: credential.id * }) * const envelope = SignatureEnvelope.from({ * metadata, * signature, * publicKey: credential.publicKey * }) * * const valid = SignatureEnvelope.verify(envelope, { * payload, * publicKey: credential.publicKey * }) * // @log: true * ``` * * @param parameters - Verification parameters. * @returns `true` if the signature is valid, `false` otherwise. */ export declare function verify(signature: SignatureEnvelope, parameters: verify.Parameters): boolean; export declare namespace verify { type Parameters = { /** Payload that was signed. */ payload: Hex.Hex | Bytes.Bytes; } & OneOf<{ /** Public key that signed the payload. */ publicKey: PublicKey.PublicKey; } | { /** Address that signed the payload. */ address: Address.Address; }>; } /** * Error thrown when a signature envelope cannot be coerced to a valid type. */ export declare class CoercionError extends Errors.BaseError { readonly name = "SignatureEnvelope.CoercionError"; constructor({ envelope }: { envelope: unknown; }); } /** * Error thrown when a signature envelope is missing required properties. */ export declare class MissingPropertiesError extends Errors.BaseError { readonly name = "SignatureEnvelope.MissingPropertiesError"; constructor({ envelope, missing, type, }: { envelope: unknown; missing: string[]; type: Type | 'keychain' | 'multisig'; }); } /** * Error thrown when a serialized signature envelope cannot be deserialized. */ export declare class InvalidSerializedError extends Errors.BaseError { readonly name = "SignatureEnvelope.InvalidSerializedError"; constructor({ reason, serialized }: { reason: string; serialized: Hex.Hex; }); } /** * Error thrown when a native multisig owner approval is invalid. */ export declare class InvalidMultisigApprovalError extends Errors.BaseError { readonly name = "SignatureEnvelope.InvalidMultisigApprovalError"; constructor({ reason }: { reason: string; }); } /** * Error thrown when a signature envelope fails to verify. */ export declare class VerificationError extends Errors.BaseError { readonly name = "SignatureEnvelope.VerificationError"; } //# sourceMappingURL=SignatureEnvelope.d.ts.map