ECDSA & Signers
Signers
Ox exports utilities for the following ECDSA signers:
Secp256k1
: Utilities for the secp256k1 elliptic curve – the primary curve used on the Ethereum protocol.P256
: Utilities for NIST P256 cryptography. Commonly used in Ethereum Account Abstraction.WebAuthnP256
: P256 utilities using the Web Authentication API. Commonly used in Ethereum Account Abstraction.WebCryptoP256
: P256 utilities using the Web Crypto API. Commonly used in Ethereum Account Abstraction.
Private Keys
We can generate private keys using one of the Signer modules with their respective generation function:
import { P256, Secp256k1, WebCryptoP256 } from 'ox'
// Generate a private key on the secp256k1 curve.
const const privateKey: `0x${string}`privateKey = Secp256k1.randomPrivateKey()
// Generate a private key on the P256 curve.
const const privateKey_2: `0x${string}`privateKey_2 = P256.randomPrivateKey()
// Generate a private key on the P256 curve using the Web Crypto API.
const const keypair: {
privateKey: CryptoKey;
publicKey: PublicKey;
}keypair = await WebCryptoP256.createKeyPair()
Public Keys
We can extract Public Keys from Private Keys using one of the respective Signer functions:
import { Secp256k1, P256 } from 'ox'
{
const privateKey = Secp256k1.randomPrivateKey()
const const publicKey: {
prefix: number;
x: bigint;
y: bigint;
}publicKey = Secp256k1.getPublicKey({ privateKey })
}
{
const privateKey = P256.randomPrivateKey()
const publicKey = P256.getPublicKey({ privateKey })
}
We can also extract an Ethereum Address from a Public Key using Address.fromPublicKey
:
import { Address, Secp256k1 } from 'ox'
const privateKey = Secp256k1.randomPrivateKey()
const publicKey = Secp256k1.getPublicKey({ privateKey })
const const address: `0x${string}`address = Address.fromPublicKey(publicKey)
Signing
Payloads are signed using the respective Signer's sign
function:
import { Secp256k1, P256, WebCryptoP256, WebAuthnP256 } from 'ox'
const payload = '0xdeadbeef'
// secp256k1
{
const privateKey = Secp256k1.randomPrivateKey()
const const signature: {
r: bigint;
s: bigint;
yParity: number;
}signature = Secp256k1.sign({ payload, privateKey })
}
// P256
{
const privateKey = P256.randomPrivateKey()
const signature = P256.sign({ payload, privateKey })
}
// WebCrypto-P256
{
const { privateKey } = await WebCryptoP256.createKeyPair()
const signature = WebCryptoP256.sign({ payload, privateKey })
}
Verification
Signatures can be verified against the signing payload and respective public key using the respective Signer's verify
function:
import { Secp256k1, P256, WebCryptoP256 } from 'ox'
const payload = '0xdeadbeef'
// secp256k1
{
const privateKey = Secp256k1.randomPrivateKey()
const publicKey = Secp256k1.getPublicKey({ privateKey })
const signature = Secp256k1.sign({ payload, privateKey })
const verified = Secp256k1.verify({ payload, publicKey, signature })
}
// P256
{
const privateKey = P256.randomPrivateKey()
const publicKey = P256.getPublicKey({ privateKey })
const signature = P256.sign({ payload, privateKey })
const verified = P256.verify({ payload, publicKey, signature })
}
// WebCrypto-P256
{
const { privateKey, publicKey } = await WebCryptoP256.createKeyPair()
const signature = await WebCryptoP256.sign({ payload, privateKey })
const verified = await WebCryptoP256.verify({ payload, publicKey, signature })
}
Recovery
Public Keys can be recovered from a signature and payload using the Signer's respective function:
import { Secp256k1, P256, WebCryptoP256 } from 'ox'
const payload = '0xdeadbeef'
// secp256k1
{
const privateKey = Secp256k1.randomPrivateKey()
const signature = Secp256k1.sign({ payload, privateKey })
const publicKey = Secp256k1.recoverPublicKey({ payload, signature })
}
// P256
{
const privateKey = P256.randomPrivateKey()
const signature = P256.sign({ payload, privateKey })
const publicKey = P256.recoverPublicKey({ payload, signature })
}
Signatures
Signatures in Ox are represented via the Signature.Signature
type – an object containing the standard ECDSA signature components of:
r
: abigint
representing ther
component of the signature.s
: abigint
representing thes
component of the signature.yParity
(or "recovery bit"): an optionalnumber
representing the recovery bit of the signature – typically utilized for recovery operations.
Examples:
import { Signature } from 'ox'
// Signature with a recovery bit (yParity)
const signature = Signature.from({
r: 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
yParity: 0,
})
// Signature without a recovery bit (yParity)
const signature_2 = Signature.from({
r: 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
})
Serializing
You may need to serialize a Signature into Hex or Bytes format for specific use cases. You can do this using the Signature.toHex
or Signature.toBytes
functions:
import { Signature } from 'ox'
const signature = Signature.from({
r: 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
yParity: 0,
})
const const serialized: `0x${string}`serialized = Signature.toHex(signature)
const const serialized_bytes: Uint8Arrayserialized_bytes = Signature.toBytes(signature)
Public Keys
Public Keys in Ox can come in two forms: a compressed and uncompressed format. Generally, you will interact with uncompressed Public Keys, but it is important to be aware of the format.
Public Keys are represented via the PublicKey.PublicKey
type – an object containing the standard ECDSA public key components of:
prefix
: anumber
representing the prefix of the public key (4
for uncompressed,2
or3
for compressed).x
: abigint
representing thex
coordinate of the public key.y
: (if uncompressed) abigint
representing they
coordinate of the public key.
An example Public Key:
import { PublicKey } from 'ox'
// Uncompressed
const publicKey = PublicKey.from({
prefix: 4,
x: 59295962801117472859457908919941473389380284132224861839820747729565200149877n,
y: 24099691209996290925259367678540227198235484593389470330605641003500238088869n,
})
// Compressed
const publicKey_2 = PublicKey.from({
prefix: 2,
x: 59295962801117472859457908919941473389380284132224861839820747729565200149877n,
})
Serializing
You may need to serialize a Public Key into Hex or Bytes format for specific use cases. You can do this using the PublicKey.toHex
or PublicKey.toBytes
functions:
import { PublicKey } from 'ox'
const publicKey = PublicKey.from({
x: 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
y: 24099691209996290925259367678540227198235484593389470330605641003500238088869n,
})
const const serialized: `0x${string}`serialized = PublicKey.toHex(publicKey)
const const serialized_bytes: Uint8Arrayserialized_bytes = PublicKey.toBytes(publicKey)
Related Modules
Module | Description |
---|---|
P256 | Utility functions for NIST P256 ECDSA cryptography. |
PublicKey | Utility functions for working with ECDSA public keys. |
Secp256k1 | Utility functions for secp256k1 ECDSA cryptography. |
Signature | Utility functions for working with ECDSA signatures. |
WebAuthnP256 | Utility functions for NIST P256 ECDSA cryptography using the Web Authentication API |
WebCryptoP256 | Utility functions for NIST P256 ECDSA cryptography using the Web Crypto API |