Crypto primitives
Elide ships a shared cryptographic primitives layer in
dev.elide.lang.javascript.crypto.primitives. It is host-internal —
guest JavaScript does not see it directly. The Node crypto module and
the WHATWG crypto.subtle global consume it.
Coverage
| Family | Algorithms | Backend |
|---|---|---|
| Hash | SHA-1, SHA-2 (224 / 256 / 384 / 512 / 512-224 / 512-256), SHA-3 (224 / 256 / 384 / 512), MD5 | JCE |
| Hash | BLAKE2b, BLAKE2s, BLAKE3 | Native |
| HMAC | MD5, SHA-1, SHA-2 (224 / 256 / 384 / 512), SHA-3 (224 / 256 / 384 / 512) — not 512-224, 512-256, or BLAKE; no MD5 PRF for KDFs | JCE |
| KDF | PBKDF2 (any HMAC PRF), HKDF (any HMAC PRF) | JCE |
| KDF | scrypt (RFC 7914), Argon2 (Argon2d / 2i / 2id) | Native |
| Symmetric | AES-{128, 192, 256}-{CBC, CTR, GCM, KW} | JCE |
| AEAD | AES-{128, 192, 256}-GCM (already covered above) | JCE |
| AEAD | ChaCha20-Poly1305, XChaCha20-Poly1305, AES-{128, 256}-GCM-SIV | Native |
| Signature | RSA PKCS#1 v1.5 over SHA-{1, 256, 384, 512}; RSA-PSS over SHA-{256, 384, 512} | JCE |
| Signature | ECDSA on P-256 / P-384 / P-521 | JCE |
| Signature | Ed25519 | Native |
| Key agreement | ECDH on P-256 / P-384 / P-521 | JCE |
| Key agreement | X25519 | Native |
| Random | randomBytes, fill, randomInt (rejection sampling, no modulo bias) | JCE |
| Constant-time eq | TimingSafeEqual.equals(...) | JCE |
| Key import/export | PKCS#8 (private), SubjectPublicKeyInfo (public) for RSA / EC | JCE |
Public types
CryptoException // RuntimeException for malformed input / auth failure
HashAlgorithm // SHA*, SHA3*, MD5, BLAKE2b/2s, BLAKE3
HmacAlgorithm // HMAC over MD5, SHA-1, SHA-2 (224-512), SHA-3
SymmetricAlgorithm // AES variants + ChaCha20-Poly1305 + AES-GCM-SIV
SignatureAlgorithm // RSA-PKCS1, RSA-PSS, ECDSA-P{256,384,521}, Ed25519
KeyAgreementAlgorithm // ECDH-P{256,384,521}, X25519
Argon2Type // ARGON2D, ARGON2I, ARGON2ID
Hash, Hmac // streaming digester / MAC, AutoCloseable
Pbkdf2, Hkdf // one-shot KDFs (JCE-served)
Scrypt, Argon2 // one-shot KDFs (native-served)
SymmetricCipher // seal / open
Signer // sign / verify, plus signEd25519 / verifyEd25519 / generateEd25519KeyPair
KeyExchange // agree (ECDH), agreeX25519, generateX25519KeyPair, x25519PublicFromSecret
KeyMaterial // PKCS#8 / SPKI parse + encode, RSA / EC keypair generation
SecureRandomSource // randomBytes, fill, randomInt
TimingSafeEqual // constant-time compare
CryptoBackends // registry holding the optional native backend
NativeCryptoBackend // SPI for the FFM-backed engine
NativeCrypto // FFM bridge + tryInstall()Backend model
JCE-served algorithms call into the JDK directly — no provider hook is
needed because JCE itself is pluggable at the JVM level. Native-served
algorithms route through the optional [NativeCryptoBackend] installed
on [CryptoBackends]. The runtime calls
[NativeCrypto.tryInstall()][NativeCrypto] during startup; before that
runs (and on systems where libelideruntime is missing), every
native-only operation surfaces a clear UnsupportedOperationException
explaining what is missing.
The native side is a Rust shim around RustCrypto crates: blake2,
blake3, chacha20poly1305, aes-gcm-siv, ed25519-dalek,
x25519-dalek, scrypt, argon2. The Java-Rust ABI is the same
dual-path Panama / @CFunction pattern as the URL and compression
layers; output buffers are caller-allocated at known sizes.
Streaming vs one-shot
Hash and Hmac are streaming (update / digest / doFinal); both
also expose static one-shot helpers when the entire input is already in
hand.
KDFs (Pbkdf2, Hkdf, Scrypt, Argon2) are intentionally one-shot —
they take their input all at once and have no reason to stream.
Symmetric ciphers and AEADs are exposed only one-shot via
SymmetricCipher.seal / open. Streaming AEAD is not surfaced at this
layer: cutting AEAD payloads at arbitrary boundaries is incompatible
with the engines' tag computation, and the public modules
(node:crypto.createCipheriv for non-AEAD modes, WHATWG crypto.subtle
which is one-shot anyway) do not need it.
Threading
Stateless one-shot operations (everything but Hash / Hmac
authenticator instances) are safe from any thread. Hash and Hmac
instances are not safe for concurrent use — same model as the rest of
the runtime, matching the graal-js single-thread-per-realm contract.
[NativeCryptoBackend]: NativeCryptoBackend.java
[CryptoBackends]: CryptoBackends.java
[NativeCrypto]: NativeCrypto.java