siwx verifies wallet-claimed identities for CAIP-122 Sign-In with X. This
document describes what the library does and does not promise.
- Message syntax (eip4361 / SIWS), field validation,
Expectbinding + time policy, signature verification foreip155andsolananamespaces. - The library is byte-in/byte-out: it never performs I/O, builds transports, or applies timeouts.
- Server:
createMessage/Message::newwith a freshnonce,issuedAt, shortexpirationTime; store domain+nonce (+ chainId/requestId) per challenge. - Wallet signs the formatted text (or SIWS envelope).
- Server:
authenticate(ns, signed, signature, expect)—Expectbinds domain and nonce (required) plus any of scheme/uri/chainId/requestId; then expiry/not-before/max-age, then the signature. Treat a valid-but- unbound signature as hostile.
- RPC providers are injected (
with_provider/rpcmap). Provider trust, URL selection and transport timeouts belong to the caller — never accept provider URLs from untrusted input (SSRF). - On-chain verification (
rpcfeature) bindseth_chainIdto the message chain before anyeth_calland caches it per chain-id key; smart-account verdicts are only as strong as the account contract'sisValidSignature. - Error
reasonstrings are fixed and never contain URLs, hosts or provider error text.
- Reliance-party profile requires
uri,version,chainId,nonce,issuedAt— the spec grammar marks them optional. - Only lowercase/uppercase-hex or valid EIP-55 EVM addresses; mixed-case
checksum failures are
InvalidField { address }. - Ed25519: A and R must be canonical encodings of prime-order-subgroup
(torsion-free, non-identity) points,
S < L, strict verification. - SIWS
versionmust be1; off-chain envelopes are version 1 with exactly one signer.
| Risk | Owner |
|---|---|
| Nonce reuse / missing domain binding | Caller (Expect is required) |
| Smart-account logic changes post-deploy | Inherent to on-chain state |
| Wallet signing UI clarity | Wallet/app; statement text is opaque bytes to us |
| RPC provider compromise | Caller transport policy |