-
-
Notifications
You must be signed in to change notification settings - Fork 1
ed25519
Classical digital signatures via Ed25519 (RFC 8032), the Edwards-curve EdDSA instance over edwards25519, with both pure (RFC 8032 §5.1.6, signature generation) and prehash (RFC 8032 §5.1.7, signature verification, Ed25519ph) modes and strict verification per FIPS 186-5 (Digital Signature Standard) §7.6.4, Verification.
Ed25519 is the EdDSA instance defined by RFC 8032 (Edwards-Curve Digital Signature Algorithm) §5.1, Ed25519, over the twisted Edwards curve edwards25519 birationally equivalent to Curve25519. Signatures are 64 bytes, verifying keys are 32 bytes, and a secret key is the 32-byte seed the signer holds. This module covers the two RFC 8032 §5.1 modes:
- Pure Ed25519 (RFC 8032 §5.1.6, signature generation) signs the message bytes directly with no context binding.
- Ed25519ph (RFC 8032 §5.1.7, signature verification) signs a SHA-512 prehash of the message, with an optional context bound through the dom2(F=1, C) prefix.
The module does NOT implement Ed25519ctx (RFC 8032 §5.1, the
pure-with-context variant); applications that need context-bound
signing over arbitrary-length messages should use the prehash
mode through signPrehashed and verifyPrehashed, or
Ed25519PreHashSuite at the envelope layer.
Verification is strict per FIPS 186-5 §7.6.4: signature
malleability vectors that the permissive cofactor-eight equation
would accept get rejected. Specifically, s outside [0, L),
non-canonical R or pk encodings, and small-order public keys all
return false. The implementation rejects the same malleated
records ACVP's testPassed=false EDDSA-sigVer corpus uses to
exercise the strict gate.
The test corpus pairs RFC 8032 §7, Test Vectors for Ed25519, with
the NIST ACVP EDDSA records: keyGen vectors prove the §5.1.5,
Key Generation, derivation; sigGen vectors prove signing
byte-equivalence to a third-party implementation; sigVer
including the testPassed=false records prove that the strict
checks fire on every spec-defined failure mode. Verifier
coverage lives in vector_audit.md.
import { init } from 'leviathan-crypto'
import { ed25519Wasm } from 'leviathan-crypto/ed25519/embedded'
await init({ ed25519: ed25519Wasm })The leviathan-crypto/ed25519/embedded subpath exports the WASM
blob under three names that all resolve to the same string:
ed25519Wasm (reads most naturally in this context),
curve25519Wasm (the canonical name shared with the
leviathan-crypto/x25519/embedded subpath), and x25519Wasm
(the alias preferred under the matching subpath). Pick whichever
matches the surrounding code; tree-shaking is unaffected.
Ed25519 and X25519 share a single WASM binary, curve25519.wasm,
which hosts the GF(2^255-19) field arithmetic, the edwards25519
substrate, the Montgomery ladder, the scalar arithmetic mod L,
point compression and decompression, plus an embedded SHA-512 for
the Ed25519 hash chain. The top-level init() accepts ed25519
and x25519 as aliases that resolve to the underlying
curve25519 module; calling either alias enables both classes,
and passing both aliases with the same source is de-duped at the
init layer. Passing different sources for the two aliases throws.
For tree-shakeable imports the leviathan-crypto/ed25519 subpath
exports its own init function:
import { ed25519Init } from 'leviathan-crypto/ed25519'
import { ed25519Wasm } from 'leviathan-crypto/ed25519/embedded'
await ed25519Init(ed25519Wasm)ed25519Init(source) and x25519Init(source) both load the same
WASM module under the curve25519 slot. Calling x25519Init
also enables the Ed25519 class and vice versa. Ed25519
ships scalar (no WebAssembly SIMD); init({ ed25519: ... })
works on every WASM-capable runtime regardless of SIMD support.
Construction is parameter-less. Every public method runs against
the singleton curve25519 instance, stages inputs at fixed
offsets above the WASM mutable region, calls the underlying
export, copies outputs to fresh Uint8Arrays, then wipes the
staged buffers.
new Ed25519()Throws if init({ ed25519: ... }) (or init({ x25519: ... }),
or the subpath init) has not been called. Cheap, runs a layout
assertion and returns.
Generate a new key pair using a fresh 32-byte seed from
crypto.getRandomValues. Equivalent to calling keygenDerand
with a random seed; the local seed buffer is wiped on return.
const ed = new Ed25519()
const { publicKey, secretKey } = ed.keygen()
// publicKey: 32-byte encoded A (RFC 8032 §5.1.2, encoding)
// secretKey: 32-byte seed (RFC 8032 §5.1.5, key generation)
ed.dispose()Deterministic key generation, RFC 8032 §5.1.5, key generation.
Use this when you must derive a key from a known seed (testing,
ACVP records, key escrow, deterministic deployments). Throws
RangeError if seed.length !== 32.
const seed = new Uint8Array(32)
crypto.getRandomValues(seed)
const ed = new Ed25519()
const { publicKey, secretKey } = ed.keygenDerand(seed)
ed.dispose()
seed.fill(0)secretKey is a fresh copy of seed; the RFC 8032 §5.1.5
"sk = seed" identity holds. Treat the seed with the same care
as the secret key.
Pure Ed25519 sign, RFC 8032 §5.1.6, signature generation. Returns a 64-byte signature R || s.
const ed = new Ed25519()
const { publicKey, secretKey } = ed.keygen()
const sig = ed.sign(secretKey, publicKey, message)
const ok = ed.verify(publicKey, message, sig) // true
ed.dispose()The caller passes pk alongside sk; the WASM re-derives pk from sk
internally and compares it against the caller-supplied value.
A mismatch traps via unreachable and the TypeScript wrapper
rethrows as SigningError('sig-malformed-input'). See
Fault-Injection Defense for the
rationale.
Pure Ed25519 has no native context parameter. Applications that
need context-bound signing should use signPrehashed (or
Ed25519PreHashSuite at the envelope layer).
Important
Pure-mode signing has a per-call message ceiling of approximately
248 KB; messages above the ceiling throw RangeError. Pure Ed25519
signatures are non-streamable by design. For larger payloads use
the prehash mode (signPrehashed directly, or Ed25519PreHashSuite
wrapped in SignStream / VerifyStream); the digest is computed at
the TypeScript layer and only the 64-byte SHA-512 output crosses the
WASM boundary.
Ed25519ph sign, RFC 8032 §5.1.7, signature verification (the spec defines pure and prehash together; the prehash variant adds the dom2 prefix). Returns a 64-byte signature.
import { SHA512 } from 'leviathan-crypto'
const digest = new SHA512().hash(message) // 64 bytes
const sig = ed.signPrehashed(secretKey, publicKey, digest, new Uint8Array(0))The caller supplies the 64-byte SHA-512 digest; the library does
not compute it. Wrong-length digest throws RangeError. ctx
is required and must be a Uint8Array; pass an empty
Uint8Array(0) explicitly when no context binding is needed.
Per RFC 8032 §5.1, Ed25519, |C| is encoded in a single octet,
so 255 is the spec ceiling; longer ctx values throw RangeError.
The dom2(F=1, ctx) prefix binds ctx into both SHA-512 inputs
that produce r and k.
Strict pure Ed25519 verify, RFC 8032 §5.1.7, signature
verification, with FIPS 186-5 §7.6.4, Verification, strict gates.
Returns true on success, false on every signature failure
mode. Throws only on caller-side contract violations
(non-Uint8Array inputs, wrong-length pk or sig).
const ok = ed.verify(publicKey, message, sig) // booleanThe cryptographic checks live inside the WASM and run in this
order: pk decompresses canonically, R decompresses canonically,
s lies in [0, L), [8]A is not the identity, and the
signature equation [s]B = R + [k]A holds. The first four
guard against signature malleability and small-order forgery;
the last is the §5.1.7 strict verification equation. A failure
in any returns false.
Strict Ed25519ph verify, RFC 8032 §5.1.7. Same rejection
conditions as verify, plus the dom2(F=1, ctx) prefix on the
SHA-512 input that produces k. Returns boolean for every
signature outcome.
const ok = ed.verifyPrehashed(publicKey, digest, ctx, sig)Wrong-length digest throws RangeError. Oversize ctx
(ctx.length > 255) returns false inside the WASM rather than
throwing; verify maps every invalid input shape to "not
verified" so a malformed signature never produces a runtime
exception.
Wipe all curve25519 WASM scratch memory. Idempotent. Safe to
call multiple times. Every public method already wipes the
WASM mutable region and the TS-side staging region on its own
success and throw paths; dispose() is defence-in-depth at
instance teardown.
The two RFC 8032 §5.1 modes bind different inputs into the
signing equation. Pure Ed25519 hashes prefix || M to derive
the per-signature nonce r and hashes R || pk || M to derive
the challenge scalar k. Ed25519ph wraps both hash inputs in the
dom2(F=1, ctx) prefix and substitutes digest = SHA-512(M) for
M. Signatures from the two modes are not interchangeable on the
same key because the bytes hashed into k differ; a §5.1.6
signature does not verify under verifyPrehashed and vice versa.
Pick pure when:
- The message bytes fit in a single
Uint8Arrayat sign time. - The protocol does not require a context label.
- Byte-for-byte interop with classical RFC 8032 §7, Test Vectors for Ed25519, signers is required (test corpus, third-party signers, FIDO U2F).
Pick prehash when:
- The message is too large to buffer (a streaming signer
computes SHA-512 incrementally and hands the digest to
signPrehashed). - The protocol binds a context string into the signature for domain separation, key purpose, or version pinning.
- A FIPS 140 boundary computes SHA-512 in a different module from Ed25519 and supplies the digest at the boundary.
Per RFC 8032 §5.1, Ed25519, ctx must be 255 bytes or fewer; pure mode rejects every non-empty ctx (no spec-defined home for it), prehash mode binds ctx via dom2.
Ed25519 distinguishes two failure classes: verification failures
(binary, return false) versus caller-contract violations (throw
TypeError or RangeError). The split follows FIPS 186-5
§7.6.4, Verification.
| Condition |
sign / variants |
verify / variants |
|---|---|---|
Input not a Uint8Array
|
throw TypeError
|
throw TypeError
|
seed.length !== 32 |
throw RangeError
|
n/a |
sk.length !== 32 |
throw RangeError
|
n/a |
pk.length !== 32 |
throw RangeError
|
throw RangeError
|
sig.length !== 64 |
n/a | throw RangeError
|
digest.length !== 64 (prehash) |
throw RangeError
|
throw RangeError
|
ctx.length > 255 (prehash sign) |
trap (rethrown) | return false
|
M.length exceeds per-call WASM scratch |
throw RangeError
|
throw RangeError
|
| Caller pk does not match pk derived from sk | SigningError |
n/a |
| Off-curve / non-canonical pk encoding | n/a | return false
|
| Off-curve / non-canonical R encoding | n/a | return false
|
s >= L (strict-S, ACVP "modify s" path) |
n/a | return false
|
Small-order pk ([8]A == identity) |
n/a | return false
|
Signature equation [s]B != R + [k]A
|
n/a | return false
|
Wrong-shape inputs are caller mistakes and throw so the bug
surfaces immediately. Cryptographic failures map to false
because they are indistinguishable from a wrong-key attempt and
should not raise as exceptions. The asymmetry on
ctx.length > 255 between sign and verify matches the underlying
WASM posture: sign aborts unreachably so the TypeScript wrapper
rethrows; verify returns 0 so the wrapper passes that through
as boolean false.
The strict-verification checks are SUF-CMA-critical. RFC 8032
§5.1.7, signature verification, leaves room for the permissive
cofactor-eight equation [8s]G = [8](R + [k]A), which would
accept malleated s values and small-order R. FIPS 186-5 §7.6.4
locks down the strict form; this implementation follows FIPS
186-5 and rejects every spec-defined malleation.
Verifying key pk, RFC 8032 §5.1.2, encoding:
pk = enc(A) = (sign_bit_of_x << 255) | y_le
32 bytes total. Bytes 0..30 plus the low 7 bits of byte 31 carry the y-coordinate in little-endian; bit 7 of byte 31 carries the sign of x. Non-canonical encodings (y >= p) are rejected on decompress.
Secret key sk, RFC 8032 §5.1.5, key generation:
sk = seed (32 random bytes)
The RFC 8032 spec defines sk to be the seed itself, not the
clamped scalar a. The signer expands h = SHA-512(seed), clamps
a = clamp(h[0..32]) per RFC 7748 (Elliptic Curves for Security)
§5, The X25519 and X448 Functions, derives prefix = h[32..64],
and computes pk = encode([a]B). The library stores sk as the
seed and re-derives a / prefix on every sign call. Treat the
seed with the same care as the full key: compromise of the seed
reveals everything.
Signature sig, RFC 8032 §5.1.6, signature generation:
sig = encode(R) || encode(s)
64 bytes total. Bytes 0..32 carry the compressed Edwards point
R per §5.1.2; bytes 32..64 carry the scalar s as a little-endian
32-byte integer in [0, L).
The curve order L is
L = 2^252 + 27742317777372353535851937790883648493
RFC 8032 §5.1, Ed25519, parameters. The strict-S check rejects
any s >= L.
Every Ed25519 public method ends with a two-phase wipe:
- The WASM-side
wipeBuffersexport zeroes the mutable region fromMUTABLE_STARTtoBUFFER_END. That covers the SHA-512 state, the clamped scalar a, the signing prefix, the per-signature r and k, the Edwards points A and R, the pk-check buffer, and the ladder scratch. - The TypeScript wrapper zeroes the I/O staging region above
BUFFER_END(the seed slot, pk slot, sig slot, digest slot, ctx slot, and the variable-length message slot). The WASM does not own that region; the wrapper owns it and is responsible for the wipe.
Both phases run inside a try / finally so the wipe fires on
the success path and on every throw path. Caller-supplied
buffers (sk, pk, M, digest, sig, ctx) are NEVER mutated; the
library copies them into the staging region, never aliases them.
dispose() re-runs both phases as defence-in-depth at instance
teardown. Calling it multiple times is safe.
Ed25519.sign and Ed25519.signPrehashed accept the public
key alongside the secret key. The WASM ignores the
caller-supplied pk during signing and re-derives pk from sk; it
then compares the derived value against the caller-supplied
buffer and aborts via unreachable if they differ.
This is defence against a narrow but documented attack class.
RFC 8032 §5.1.6, signature generation, derives r as
SHA-512(prefix || M) where prefix = h[32..64]. A
fault-injection attacker who can flip bits in the sk-derived
intermediates (the clamped scalar a, or the prefix bytes) can
bias r in ways that leak the long-term scalar through standard
ECC fault analysis. Forcing the signer to also know the
encoded pk means the attacker must know both the seed and the
derived public key, which removes any advantage from a
sk-only fault.
The TypeScript wrapper catches the WebAssembly.RuntimeError
that an unreachable trap raises and rethrows it as
SigningError('sig-malformed-input', ...) so callers can
branch on the failure. The cost is one extra Edwards scalar
multiplication per sign, roughly 5ms at parameter-set sizes;
verifies are unaffected (verify operates on public inputs).
Ed25519Suite and Ed25519PreHashSuite route through the
unexported _signInternalPk / _signPrehashedInternalPk
helpers on the Ed25519 class, which derive pk inside the same
WASM call and skip the cross-check. At the suite call site the
comparison would be between two outputs of the same
potentially-faulted module on the same call, so the defence
collapses to no defence; skipping it saves one basepoint scalar
multiplication per sign on the hot path that every Sign and
SignStream invocation traverses.
Direct-class callers who hold a stored, known-good pk should
keep using Ed25519.sign(sk, pk, M) and Ed25519.signPrehashed(sk, pk, digest, ctx)
to retain the fault-injection defence. See
architecture.md §Where defense ends
for the canonical posture.
| Error | Cause |
|---|---|
Error: leviathan-crypto: call init({ ed25519: ... }) before using Ed25519 |
Class constructor invoked before init. |
TypeError: leviathan-crypto: ed25519 seed must be a Uint8Array |
keygenDerand passed a non-Uint8Array seed. |
RangeError: leviathan-crypto: ed25519 seed must be 32 bytes (got N) |
keygenDerand passed a wrong-length seed. |
TypeError: leviathan-crypto: ed25519 secret key must be a Uint8Array |
sign or signPrehashed passed a non-Uint8Array sk. |
RangeError: leviathan-crypto: ed25519 secret key must be 32 bytes (got N) |
sign or signPrehashed passed a wrong-length sk. |
TypeError: leviathan-crypto: ed25519 public key must be a Uint8Array |
Any method passed a non-Uint8Array pk. |
RangeError: leviathan-crypto: ed25519 public key must be 32 bytes (got N) |
Any method passed a wrong-length pk. |
TypeError: leviathan-crypto: ed25519 message must be a Uint8Array |
sign or verify passed a non-Uint8Array message. |
RangeError: leviathan-crypto: ed25519 pure-mode message length N exceeds the per-call ... |
Message larger than the WASM input scratch (~248 KB cap). Use Ed25519PreHashSuite + SignStream for larger payloads. |
TypeError: leviathan-crypto: ed25519 signature must be a Uint8Array |
verify or verifyPrehashed passed a non-Uint8Array sig. |
RangeError: leviathan-crypto: ed25519 signature must be 64 bytes (got N) |
verify or verifyPrehashed passed a wrong-length sig. |
TypeError: leviathan-crypto: ed25519 prehash digest must be a Uint8Array |
signPrehashed or verifyPrehashed passed a non-Uint8Array. |
RangeError: leviathan-crypto: ed25519 prehash digest must be 64 bytes (got N) |
Prehash digest is not exactly 64 bytes. |
TypeError: leviathan-crypto: ed25519 context must be a Uint8Array |
signPrehashed or verifyPrehashed passed a non-Uint8Array. |
RangeError: leviathan-crypto: ed25519 context must be <= 255 bytes (got N) |
ctx longer than the RFC 8032 §5.1 ceiling. |
SigningError('sig-malformed-input', 'leviathan-crypto: ed25519 sign aborted ...') |
Caller-supplied pk does not match pk derived from sk. |
verify and verifyPrehashed return false on every signature
failure (wrong sig, off-curve pk or R, non-canonical encodings,
s >= L, small-order pk). They throw only on the contract
violations above.
The Ed25519 suites wrap the primitive into the SignatureSuite
interface for use with Sign, SignStream, and VerifyStream.
Two suite consts ship:
-
Ed25519Suite(format byte0x01), pure Ed25519, satisfiesSignatureSuiteonly. -
Ed25519PreHashSuite(format byte0x11), Ed25519ph with fixed SHA-512 prehash, satisfiesStreamableSignatureSuiteand plugs intoSignStream/VerifyStream.
Pure mode does NOT bind user context. Pure Ed25519 has no
spec-defined home for ctx, so Ed25519Suite.sign(sk, msg, ctx)
throws SigningError('sig-ctx-unsupported') on any non-empty
ctx and routes callers to Ed25519PreHashSuite for
context-bound signatures.
Prehash mode binds the suite-level ctxDomain plus the caller's
user_ctx through buildEffectiveCtx before passing the result
into the WASM's dom2(F=1, effective_ctx) prefix. Each method
instantiates a fresh Ed25519 instance inside a try / finally { dispose() } block, so WASM key material is wiped on every
path. The Ed25519PreHashSuite.wasmModules array lists
['curve25519', 'sha2']: curve25519 hosts the signing
substrate, sha2 drives the running SHA-512 in the streaming
prehash path.
See signaturesuite.md for
the full wire format, format-byte allocation, and worked
examples through Sign, SignStream, and VerifyStream.
The integration tier exercises the v3 sign layer against the real Ed25519 primitive. It asserts:
-
Sign.sign/Sign.verifyround-trip for bothEd25519SuiteandEd25519PreHashSuite. -
SignStream+VerifyStreamround-trip via the prehash suite, proving the SHA-512 running-hash wiring insign/hasher.tslines up with the suite'ssignPrehashed/verifyPrehashedpath. - RFC 8032 §7.1 cross-check: the pure suite's envelope sig bytes for §7.1 records match the RFC reference signature verbatim (the envelope's 2-byte preamble prefixes them without changing the sig).
- ACVP §7.3 spot-check: ACVP sigGen records with empty context flow through the suite layer cleanly.
- Cross-mode tamper: flipping
suite_byte0x01↔0x11yieldsSigningError('sig-suite-mismatch')fromSign.verify(the verifier checks the wire byte against the suite'sformatEnum).
Ed25519PreHashSuite (0x11) is deterministic per RFC 8032 §5.1.7,
so Sign.sign and SignStream produce byte-identical signatures
over the same (sk, msg, ctx). The stream-equivalence test asserts
that byte-equality across every chunk shape.
| Document | Description |
|---|---|
| architecture | Repository structure, build and CI, WASM modules, public API, test suite, and security posture |
| init.md |
init() API and module-loader contract |
| signing.md |
Sign, SignStream, VerifyStream, envelope wire format, SigningError
|
| signaturesuite.md |
SignatureSuite interface plus the Ed25519Suite and Ed25519PreHashSuite consts |
| asm_curve25519.md | Low-level WASM module reference |
| ed25519_audit.md | Ed25519 audit checklist |
| x25519.md | Companion key-agreement primitive sharing the same WASM module |
| exports.md | Full export catalog |
- Sign Tools
-
SignatureSuite
- format-byte catalog, hybrid composite encodings, custom suite contract
- Serpent-256 TypeScript | WASM
-
Serpent,SerpentCtr,SerpentCbc,SerpentGenerator
-
- ChaCha20 TypeScript | WASM
-
ChaCha20,Poly1305,ChaCha20Poly1305,XChaCha20Poly1305,ChaCha20Generator
-
- AES TypeScript | WASM
-
AES,AESCbc,AESCtr,AESGCM,AESGCMSIV,AESGenerator
-
- ML-DSA TypeScript | WASM
- pure (FIPS 204):
MlDsa44,MlDsa65,MlDsa87 - pure-mode suites:
MlDsa44Suite,MlDsa65Suite,MlDsa87Suite - prehash suites:
MlDsa44PreHashSuite,MlDsa65PreHashSuite,MlDsa87PreHashSuite
- pure (FIPS 204):
- SLH-DSA TypeScript | WASM
- pure (FIPS 205):
SlhDsa128f,SlhDsa192f,SlhDsa256f - pure-mode suites:
SlhDsa128fSuite,SlhDsa192fSuite,SlhDsa256fSuite - prehash suites:
SlhDsa128fPreHashSuite,SlhDsa192fPreHashSuite,SlhDsa256fPreHashSuite
- pure (FIPS 205):
- Ed25519 TypeScript | WASM
-
Ed25519(pure + Ed25519ph),Ed25519Suite,Ed25519PreHashSuite
-
- ECDSA-P256 TypeScript | WASM
-
EcdsaP256(hedged + RFC 6979),EcdsaP256Suite - DER codec:
ecdsaSignatureToDer,ecdsaSignatureFromDer,encodeEcPrivateKey,decodeEcPrivateKey,pointDecompress
-
- Hybrid composites PQ-only | Classical+PQ
- PQ-only:
MlDsa44SlhDsa128fSuite,MlDsa65SlhDsa192fSuite,MlDsa87SlhDsa256fSuite - Classical+PQ:
MlDsa44Ed25519Suite,MlDsa65Ed25519Suite,MlDsa44EcdsaP256Suite,MlDsa65EcdsaP256Suite
- PQ-only:
- X25519 TypeScript | WASM
-
X25519,KeyAgreementError(RFC 7748)
-
- ML-KEM TypeScript | WASM
-
MlKem512,MlKem768,MlKem1024
-
-
Ratchet (SPQR)
-
KDFChain,ratchetInit,kemRatchetEncap,kemRatchetDecap,RatchetKeypair,SkippedKeyStore
-
- Hashing overview
- SHA-2 TypeScript | WASM
-
SHA256,SHA384,SHA512,SHA224,SHA512_224,SHA512_256 -
HMAC_SHA256,HMAC_SHA384,HMAC_SHA512,HKDF_SHA256,HKDF_SHA512
-
- SHA-3 TypeScript | WASM
-
SHA3_224,SHA3_256,SHA3_384,SHA3_512,SHAKE128,SHAKE256
-
- BLAKE3 TypeScript | WASM
-
BLAKE3,BLAKE3Stream,BLAKE3KeyedHash,BLAKE3KeyedHashStream -
BLAKE3DeriveKey,BLAKE3DeriveKeyStream,BLAKE3OutputReader,BLAKE3Hash
-
-
KMAC
-
CSHAKE128,CSHAKE256,KMAC128,KMAC256,KMACXOF128,KMACXOF256
-
-
Merkle
-
MerkleVerifier,MerkleLog -
SignedLog,Sha256Tree,Blake3Tree,MemoryStorage
-
-
Fortuna CSPRNG
-
Fortuna,SerpentGenerator,ChaCha20Generator,AESGenerator,SHA256Hash,SHA3_256Hash,BLAKE3Hash
-
- Utils TypeScript | WASM
-
constantTimeEqual,randomBytes,wipe, encoding helpers
-
-
TypeScript interfaces
-
Hash,KeyedHash,Blockcipher,Streamcipher,AEAD,Generator,HashFn
-