Signature unstable
Digital signatures: Ed25519, ECDSA on P-256, P-384 and P-521, RSA-PSS, and RSASSA-PKCS1-v1_5.
The Signature service generates key pairs, signs, verifies, and computes a private key's public key. The top-level privateKey, publicKey, privateKeyFromCryptoKey, publicKeyFromCryptoKey, and toBytes functions build and export keys without a service.
The hash is part of the algorithm. ECDSA P-256, P-384 and P-521 sign with SHA-256, SHA-384 and SHA-512, as JOSE ES256, ES384 and ES512 do. RSA algorithms come from rsaPss and rsaPkcs1v15, with pre-made values such as rsaPssSha256.
Keys are opaque. They hold either bytes or a CryptoKey, display only their
algorithm, and compare by reference. The bytes are:
- Ed25519: the 32-byte seed and the 32-byte public key;
- ECDSA: PKCS#8 for private keys, and the uncompressed SEC1 point for public keys;
- RSA: PKCS#8 and SPKI DER.
Only Ed25519 private keys and Ed25519 and ECDSA public keys have a raw
constructor. Other keys come from Signature.generateKeyPair,
CryptoKeys, or key formats.
Gotchas
- Ed25519 needs Chrome 137, Firefox 129, or Safari 17. There is no fallback for older browsers.
- Ed25519 keys are generated from
SecureRandombytes, so a seededSecureRandomreproduces them. ECDSA and RSA key generation, and ECDSA and RSA-PSS signatures, use WebCrypto's own randomness and cannot be seeded. Test them with round trips such asverify(sign(data)).
Algorithms
ECDSA on P-256 with SHA-256 (JOSE ES256), with 64-byte signatures.
Signature
declare const ecdsaP256: Ecdsa<"P-256">ECDSA on P-384 with SHA-384 (JOSE ES384), with 96-byte signatures.
Signature
declare const ecdsaP384: Ecdsa<"P-384">ECDSA on P-521 with SHA-512 (JOSE ES512), with 132-byte signatures.
Signature
declare const ecdsaP521: Ecdsa<"P-521">Ed25519 (RFC 8032).
Signature
declare const ed25519: Ed25519rsaPkcs1v15
unstableBuilds an RSASSA-PKCS1-v1_5 algorithm for a hash and a modulus length in bits.
Signature
declare function rsaPkcs1v15(options: { readonly hash: Algorithm; readonly modulusLength: number;}): RsaPkcs1v15rsaPkcs1v15Sha256
unstableRSASSA-PKCS1-v1_5 with SHA-256 (JOSE RS256), generating 3072-bit keys.
Signature
declare const rsaPkcs1v15Sha256: RsaPkcs1v15rsaPkcs1v15Sha384
unstableRSASSA-PKCS1-v1_5 with SHA-384 (JOSE RS384), generating 3072-bit keys.
Signature
declare const rsaPkcs1v15Sha384: RsaPkcs1v15rsaPkcs1v15Sha512
unstableRSASSA-PKCS1-v1_5 with SHA-512 (JOSE RS512), generating 3072-bit keys.
Signature
declare const rsaPkcs1v15Sha512: RsaPkcs1v15Builds an RSA-PSS algorithm for a hash and a modulus length in bits.
Details
MGF1 uses the same hash. The salt length defaults to the hash's output length.
Signature
declare function rsaPss(options: { readonly hash: Algorithm; readonly modulusLength: number; readonly saltLength?: number;}): RsaPssrsaPssSha256
unstableRSA-PSS with SHA-256 (JOSE PS256), generating 3072-bit keys.
Signature
declare const rsaPssSha256: RsaPssrsaPssSha384
unstableRSA-PSS with SHA-384 (JOSE PS384), generating 3072-bit keys.
Signature
declare const rsaPssSha384: RsaPssrsaPssSha512
unstableRSA-PSS with SHA-512 (JOSE PS512), generating 3072-bit keys.
Signature
declare const rsaPssSha512: RsaPssConstructors
privateKey
unstableBuilds an Ed25519 private key from its 32-byte seed.
Details
The bytes are copied. Another length fails with an InvalidKey reason,
including the 64-byte seedโpublic key form libsodium and TweetNaCl use:
pass its first 32 bytes. ECDSA and RSA private keys have no raw form, so
passing them is a type error.
Signature
declare function privateKey<A extends Ed25519>(algorithm: A, bytes: Uint8Array): Effect<PrivateKey<A>, CryptoError>privateKeyFromCryptoKey
unstableBuilds a private key from an existing CryptoKey, such as a
non-extractable one.
Details
The CryptoKey must be a private key of the algorithm's WebCrypto name,
curve or hash, with the sign usage. Otherwise the constructor fails with
an InvalidKey reason. The modulus length of an RSA algorithm is not
checked. The key must come from the Crypto object of the WebCrypto
reference.
Signature
declare function privateKeyFromCryptoKey<A extends Algorithm>(algorithm: A, cryptoKey: CryptoKey): Effect<PrivateKey<A>, CryptoError>Builds a public key from its raw form: 32 bytes for Ed25519, or an uncompressed SEC1 point for ECDSA.
Details
The bytes are copied. A wrong length, or a compressed point, fails with an
InvalidKey reason. Only uncompressed points are taken because Safari and
Firefox before 146 reject compressed ones in raw import, though they accept
them inside SPKI: decode a compressed point with KeyFormat.spki. Whether a
point is on the curve is checked when the key is first used. RSA public keys have
no raw form, so passing them is a type error.
Signature
declare function publicKey<A extends Ed25519 | Ecdsa<Curve>>(algorithm: A, bytes: Uint8Array): Effect<PublicKey<A>, CryptoError>publicKeyFromCryptoKey
unstableBuilds a public key from an existing CryptoKey.
Details
The CryptoKey must be a public key of the algorithm's WebCrypto name,
curve or hash, with the verify usage. Otherwise the constructor fails
with an InvalidKey reason. The key must come from the Crypto object of
the WebCrypto reference.
Signature
declare function publicKeyFromCryptoKey<A extends Algorithm>(algorithm: A, cryptoKey: CryptoKey): Effect<PublicKey<A>, CryptoError>Converting
Exports a key's stored bytes.
Details
Returns a fresh Uint8Array: the seed or raw public key for Ed25519,
PKCS#8 or the uncompressed point for ECDSA, and PKCS#8 or SPKI DER for
RSA. A CryptoKey-backed key is exported on the WebCrypto reference, and
fails with a NotExtractable reason when the CryptoKey is not
extractable.
Signature
declare function toBytes(key: PrivateKey<Algorithm> | PublicKey<Algorithm>): Effect<Uint8Array<ArrayBufferLike>, CryptoError>Guards
isPrivateKey
unstableChecks whether a value is a PrivateKey.
Signature
declare function isPrivateKey(u: unknown): u is PrivateKey<Algorithm>isPublicKey
unstableChecks whether a value is a PublicKey.
Signature
declare function isPublicKey(u: unknown): u is PublicKey<Algorithm>Layers
layerWebCrypto
unstableLayer that provides Signature on the WebCrypto reference.
Details
Every algorithm runs on crypto.subtle. The layer imports a byte-backed
key on first use and caches the CryptoKey. Ed25519 private keys come from
SecureRandom, so a seeded SecureRandom reproduces them.
Signature
declare const layerWebCrypto: Layer.Layer<Signature, never, SecureRandom.SecureRandom>Models
Signature
type Algorithm = Ed25519 | Ecdsa | RsaPss | RsaPkcs1v15An elliptic curve for ECDSA.
Signature
type Curve = "P-256" | "P-384" | "P-521"ECDSA on a NIST curve, with the curve's hash and raw rโs signatures.
Signature
interface Ecdsa<C extends Curve = Curve> { readonly _tag: "Ecdsa"; readonly hash: Algorithm; readonly name: { readonly "P-256": "ecdsaP256"; readonly "P-384": "ecdsaP384"; readonly "P-521": "ecdsaP521"; }[C]; readonly namedCurve: C;}Ed25519 (RFC 8032), with 64-byte signatures.
Signature
interface Ed25519 { readonly _tag: "Ed25519"; readonly name: "ed25519";}A private key and its public key.
Signature
interface KeyPair<out A extends Algorithm = Algorithm> { readonly privateKey: PrivateKey<A>; readonly publicKey: PublicKey<A>;}An opaque signing key for the algorithm A.
Details
The key holds either bytes or a CryptoKey from
privateKeyFromCryptoKey. toString, toJSON, and inspect show
only the algorithm. Keys compare by reference and do not implement Equal.
Signature
interface PrivateKey<out A extends Algorithm = Algorithm> extends Inspectable { readonly "~effect/crypto/Signature/PrivateKey": "~effect/crypto/Signature/PrivateKey"; readonly algorithm: A;}An opaque verification key for the algorithm A.
Details
The key holds either bytes or a CryptoKey from
publicKeyFromCryptoKey. Keys compare by reference and do not
implement Equal.
Signature
interface PublicKey<out A extends Algorithm = Algorithm> extends Inspectable { readonly "~effect/crypto/Signature/PublicKey": "~effect/crypto/Signature/PublicKey"; readonly algorithm: A;}RSASSA-PKCS1-v1_5 (RFC 8017), from rsaPkcs1v15.
Details
modulusLength is in bits and is only read by key generation: an imported
key's algorithm.modulusLength is its real size.
Signature
interface RsaPkcs1v15 { readonly _tag: "RsaPkcs1v15"; readonly hash: Algorithm; readonly modulusLength: number; readonly name: string;}RSA-PSS (RFC 8017), from rsaPss.
Details
modulusLength is in bits and is only read by key generation: an imported
key's algorithm.modulusLength is its real size. saltLength is in bytes.
Signature
interface RsaPss { readonly _tag: "RsaPss"; readonly hash: Algorithm; readonly modulusLength: number; readonly name: string; readonly saltLength: number;}Services
Service that generates key pairs, signs, verifies, and computes public keys.
Signature
declare class Signature extends Shape<"effect/crypto/Signature", { readonly generateKeyPair: <A extends Algorithm>(algorithm: A) => Effect<KeyPair<A>, CryptoError>; readonly publicKeyOf: <A extends Algorithm>(privateKey: PrivateKey<A>) => Effect<PublicKey<A>, CryptoError>; readonly sign: (privateKey: PrivateKey, data: Uint8Array) => Effect<Uint8Array<ArrayBufferLike>, CryptoError>; readonly verify: (publicKey: PublicKey, signature: Uint8Array, data: Uint8Array) => Effect<boolean, CryptoError>;}, this> { constructor(_: never);}Example Signing and verifying with Ed25519
import { Effect, Layer } from "effect"import { SecureRandom, Signature } from "effect/crypto"
const program = Effect.gen(function*() { const signature = yield* Signature.Signature const { privateKey, publicKey } = yield* signature.generateKeyPair(Signature.ed25519) const data = new TextEncoder().encode("message") const signed = yield* signature.sign(privateKey, data) return [signed.length, yield* signature.verify(publicKey, signed, data)]})
const layer = Signature.layerWebCrypto.pipe(Layer.provide(SecureRandom.layerWebCrypto))await Effect.runPromise(program.pipe(Effect.provide(layer))) // => [64, true]