Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Signers & Authentication

What this teaches: the Signer interface, the two built-in implementations, and how session keys delegate authority.

The interface

A signer implements three methods:

type Signer = {
  getKeyHash(): Promise<KeyHash>
  signTx(signDoc: SignDoc): Promise<SignatureOutcome>
  signArbitrary<T>(payload: ArbitraryDoc<T>): Promise<ArbitrarySignatureOutcome>
}

signTx signs an EIP-712-typed transaction document. signArbitrary signs an arbitrary message, used for session creation and off-chain proofs. getKeyHash identifies which on-chain key the signer represents.

PrivateKeySigner

Backed by a local secp256k1 key. Three construction paths:

import { PrivateKeySigner } from "@left-curve/sdk"
 
const a = PrivateKeySigner.fromMnemonic("your twelve word mnemonic here ...")
const b = PrivateKeySigner.fromPrivateKey(new Uint8Array(32))
const c = PrivateKeySigner.fromRandomKey()

fromMnemonic uses BIP-39 + BIP-32 to derive the key. fromRandomKey generates an ephemeral keypair — useful for one-shot scripts.

For signArbitrary, this signer signs payload.message (SHA-256 over the canonical-serialized message). The returned signed: field is the raw signature.

Session signer

A session signer signs with an ephemeral session key plus a stored authorization from the user's primary key. The user authorizes the session once; the session signs many transactions until it expires.

import { createSessionSigner } from "@left-curve/sdk"
import type { SigningSession } from "@left-curve/sdk"
 
const session: SigningSession = await loadSessionFromStorage()
const signer = createSessionSigner(session)

Both signers hash payload.message the same way. The divergence is in what gets returned: createSessionSigner returns a SessionCredential (the session + the signed-message envelope) as signed:, so the verifier can re-derive the message from chain state.

Use createSession on a signer client to mint a SigningSession. Persist it to storage and rehydrate on next load.

Passkeys (WebAuthn)

For browser wallets, the SDK exposes WebAuthn helpers via @left-curve/crypto:

import {
  createWebAuthnCredential,
  requestWebAuthnSignature,
  verifyWebAuthnSignature,
} from "@left-curve/crypto"

These return raw P-256 signatures. Wire them into a custom Signer implementation that wraps the user's passkey for signTx. The SDK does not ship a built-in passkey signer — the wallet layer owns that.

Next