mooncry

    Pure-MoonBit crypto primitives: SHA-1/2 (incl. SHA-512/224/256), SHA-3, Keccak-256, SHAKE/cSHAKE, BLAKE2b/BLAKE2s/BLAKE3 (+keyed), RIPEMD-160, HMAC/Poly1305/CMAC/KMAC/GMAC, AES-CBC/GCM/CTR/CCM/KW/SIV, ChaCha20/XChaCha20 + Salsa20, HKDF/PBKDF2/scrypt/Argon2, RSA (PKCS1-v1.5/OAEP/PSS), ECDSA P-256, Ed25519/Ed25519ctx/Ed25519ph, X25519, HOTP/TOTP (SHA-1/256/512), SipHash, CRC32/CRC32C/CRC-64/Adler-32, Base64/Hex, sealed-box envelope

    crypto
    hash
    md5
    sha256
    sha512
    sha3
    shake
    blake2
    blake3
    hmac
    poly1305
    aes
    chacha20
    aead
    kdf
    base64
    hex
    crc32
    siphash
    cmac
    sealed-box
    scrypt
    rsa
    oaep
    pss
    ed25519
    x25519
    hkdf-sha3
    salsa20
    sha1
    hotp
    totp
    aes-kw
    ecdsa
    argon2
    aes-siv
    keccak256
    cshake
    kmac
    crc64
    blake2s
    xchacha20
    sha512-224
    sha512-256
    hchacha20
    ripemd160
    aes-ccm
    hkdf-sha512
    totp-sha256
    ed25519ctx
    ed25519ph
    gmac
    adler32
    blake2-keyed
    pbkdf2-sha1
    Download zip
    Author
    Version
    0.39.0
    License
    Apache-2.0
    Last updated
    1 hour ago
    Downloads
    237

    #mooncry

    A pure-MoonBit, zero-dependency native cryptographic library for the MoonBit ecosystem. No FFI, no C — every primitive is implemented in plain MoonBit and verified against official standard vectors.

    #Highlights

    • Correct — every algorithm is checked against FIPS / NIST / RFC test vectors, and cross-validated against reference implementations (pycryptodome, cryptography, hashlib, libsodium, zlib) plus randomized differential testing. 555 tests, run with moon test --deny-warn.
    • Broad — MD5, SHA-1, the SHA-2 and SHA-3 families (incl. SHA-512/224 and SHA-512/256), Keccak-256, SHAKE/cSHAKE XOFs, KMAC128/256, BLAKE2b, BLAKE2s, BLAKE3, RIPEMD-160, HMAC (incl. HMAC-SHA3), Poly1305, CMAC-AES, keyed BLAKE2b/2s, GMAC, AES-CBC/GCM/CTR/CCM/KW/SIV, ChaCha20, Salsa20, ChaCha20-Poly1305 AEAD, XChaCha20 / XChaCha20-Poly1305 (24-byte nonce), HKDF, PBKDF2, scrypt, Argon2, RSA (PKCS1-v1.5/OAEP/PSS, incl. multi-hash _with variants**)**, ECDSA P-256 / secp256k1, Ed25519 (incl. Ed25519ctx / Ed25519ph), Ed448 (incl. contexts), X25519 / X448, ML-KEM-512/768/1024 (FIPS 203 post-quantum KEM), HOTP/TOTP (incl. SHA-256/SHA-512 variants), SipHash-2-4, CRC32/CRC32C/CRC-64/Adler-32, a sealed-box AEAD envelope, Base64, Hex.
    • Fast where it matters — hex / Base64 encoding are O(n); AES MixColumns uses precomputed GF(2^8) tables (~5x over bit-sliced math); throughput is measured by moon bench.
    • Fail-fast input validation — AES / ChaCha20 / SHAKE / hex functions abort with a clear message on wrong key / IV / nonce / tag lengths instead of producing garbage. Graceful Result-returning variants (hex_to_bytes_or, base64_decode_or) are provided for callers that prefer to branch on error.
    • Single source of truth — one-shot hash entry points delegate to the streaming hashers, so the incremental and one-shot paths share one implementation.

    The implementations are correct and tested but have not been formally audited. See Security & performance boundaries.

    #Repositories

    Both are kept in sync. To add the mirror locally:

    git remote add gitlink https://www.gitlink.org.cn/CC01/mooncry_mirror.git git push gitlink master

    #Algorithms

    #Hash functions

    • MD5 (RFC 1321) — 128-bit digest
    • SHA-224 / SHA-256 (FIPS 180-4) — 224 / 256-bit digest
    • SHA-384 / SHA-512 (FIPS 180-4) — 384 / 512-bit digest
    • SHA-512/224 / SHA-512/256 (FIPS 180-4 §5.3.6) — truncated SHA-512 variants
    • SHA-3 (FIPS 202) — SHA3-224 / 256 / 384 / 512 (Keccak-f[1600] sponge)
    • Keccak-256 (original Keccak submission, domain 0x01) — the Ethereum hash
    • BLAKE2b (RFC 7693) — 1..64-byte digest; keyed variant (MAC, 1..64-byte key)
    • BLAKE2s (RFC 7693) — 1..32-byte digest (32-bit words, 64-byte blocks); keyed variant (MAC, 1..32-byte key)
    • RIPEMD-160 (Dobbertin et al. 1996) — 160-bit digest (Bitcoin legacy)
    • BLAKE3 (BLAKE3 spec) — 32-byte default digest, XOF (arbitrary-length via tree-Merkle)

    #Extendable-output functions (XOF)

    • SHAKE128 / SHAKE256 (FIPS 202) — variable-length output
    • cSHAKE128 / cSHAKE256 (NIST SP 800-185) — customizable XOFs (function name N + customization string S; degenerate to SHAKE when both empty)

    #Message authentication

    • HMAC-SHA256 / HMAC-SHA512 (RFC 2104)
    • HMAC-SHA3-256 / HMAC-SHA3-512 (RFC 2104 over FIPS 202)
    • HMAC-SHA3-224 / HMAC-SHA3-384 (RFC 2104 over FIPS 202)
    • Poly1305 (RFC 8439) — one-time MAC
    • AES-CMAC (NIST SP 800-38B) — 128-bit tag, 128/192/256-bit keys
    • KMAC128 / KMAC256 (NIST SP 800-185) — Keccak-based MAC with customization string; KMACXOF128 / KMACXOF256 variable-length variants
    • GMAC (NIST SP 800-38D) — AES-GCM authentication-only mode (16-byte tag); one-shot and incremental (gmac_new / gmac_update / gmac_finalize)

    #Symmetric ciphers / AEAD

    • AES-CBC (NIST SP 800-38A) — PKCS#7 padding, 128/192/256-bit keys, IV prepended
    • AES-GCM (NIST SP 800-38D) — authenticated encryption with AAD, 96-bit nonce
    • AES-CCM (NIST SP 800-38C / RFC 3610) — CBC-MAC + CTR AEAD, 7..13-byte nonce, 4..16-byte tag
    • Adler-32 (RFC 1950) — zlib rolling checksum
    • AES-CTR (NIST SP 800-38A) — 128-bit big-endian counter, stream cipher
    • ChaCha20 (RFC 8439) — 256-bit key, 96-bit nonce, stream cipher
    • Salsa20 (eSTREAM, 20-round) — 16/32-byte key, 8-byte nonce, stream cipher
    • ChaCha20-Poly1305 (RFC 8439) — AEAD (ciphertext || 16-byte tag)
    • XChaCha20 (draft-irtf-cfrg-xchacha) — ChaCha20 with a 24-byte nonce via HChaCha20 subkey derivation
    • XChaCha20-Poly1305 (draft-irtf-cfrg-xchacha / libsodium IETF) — AEAD with a 24-byte nonce (ciphertext || 16-byte tag)

    #Key derivation

    • HKDF-SHA256 (RFC 5869) — extract + expand
    • HKDF-SHA512 (RFC 5869) — extract + expand over SHA-512
    • HKDF-SHA3-256 (RFC 5869 over FIPS 202)
    • PBKDF2-HMAC-SHA256 (RFC 8018) — password-based key derivation
    • PBKDF2-HMAC-SHA1 (RFC 8018 / RFC 6070 vectors) — legacy KDF (WPA2)
    • PBKDF2-HMAC-SHA512 (RFC 8018) — password-based key derivation
    • PBKDF2-HMAC-SHA3-256 (RFC 8018 over FIPS 202)
    • scrypt (RFC 7914) — memory-hard password-based KDF (Salsa20/8 + BlockMix + ROMix)

    #Checksums / PRFs

    • CRC32 (IEEE 802.3, poly 0xEDB88320 reflected)
    • CRC32C (Castagnoli, poly 0x82F63B78 reflected) — iSCSI / ext4
    • CRC-64/XZ (poly 0x42F0E1EBA9EA3693 reflected) — xz / lzma
    • CRC-64/GO-ISO (poly 0x000000000000001B reflected) — Go hash/crc64 ISO
    • SipHash-2-4 (Aumasson & Bernstein 2012) — 64-bit short-input PRF

    #Composite envelope

    • Sealed box — versioned AEAD envelope: HKDF-SHA256 (key derivation) + AES-256-GCM (AEAD). Wire format: version(1) ‖ nonce(12) ‖ ciphertext ‖ tag(16).

    #Asymmetric (RSA)

    • RSAES-PKCS1-v1.5 (RFC 8017 §7.2) — public-key encryption (decrypt is deterministic; encrypt takes caller-supplied padding randomness — no RNG)
    • RSAES-OAEP (RFC 8017 §7.1) — SHA-256 + MGF1-SHA256 (decrypt deterministic; encrypt takes a caller-supplied 32-byte seed)
    • RSASSA-PKCS1-v1.5 (RFC 8017 §8.2) — sign/verify over SHA-256 (deterministic)
    • RSASSA-PSS (RFC 8017 §8.1) — SHA-256 + MGF1-SHA256, caller-supplied salt

    #Asymmetric signatures (Ed25519)

    • Ed25519 (RFC 8032, ed25519-sha-512) — deterministic sign/verify.
    • Ed25519ctx / Ed25519ph (RFC 8032 §7.2/§7.3) — context-bound and pre-hashed variants (dom2 domain separation) Field arithmetic over GF(2^255-19) uses @bigint; the twisted-Edwards base point is recovered from y = 4/5. Signing is deterministic (no RNG).

    #Key agreement (X25519)

    • X25519 (RFC 7748) — Diffie-Hellman over Curve25519 via the x-coordinate-only Montgomery ladder. Reuses the GF(2^255-19) field ops.

    #Encoding

    • Base64 (RFC 4648) — standard alphabet with padding
    • Hex — bytes ↔ lowercase hex

    #Streaming API

    MD5, SHA-224/256/384/512, SHA3-224/256/384/512, and SHAKE128/256 support incremental new / update / finalize for streaming or large inputs. For byte-at-a-time streams prefer sha256_update_byte / sha224_update_byte over update(hasher, Bytes::make(1, b)): no Bytes allocation and a minimal hot path (~1.3x one-shot cost vs ~3.7x for 1-byte update chunks).

    #Installation

    moon add cc06b/mooncry

    #Quick start

    Create a new project, add the dependency, then import the lib package and call its functions through the @lib alias. Dependencies are declared in moon.pkg (per-package), not as a top-level import statement, and assert_true is only available inside test blocks — so use println in main.

    moon new myapp cd myapp moon add cc06b/mooncry

    Edit cmd/main/moon.pkg to import the library:

    import { "cc06b/mooncry/lib", } pkgtype(kind: "executable")

    Edit cmd/main/main.mbt:

    fn main {
    // SHA-256 one-shot
    let digest = @lib.sha256(b"Hello, world!")
    println("SHA-256: " + @lib.bytes_to_hex(digest))

    // AES-GCM round-trip (256-bit key, 96-bit nonce, with AAD)
    let key = Bytes::make(32, b'\x00')
    let iv = Bytes::make(12, b'\x00')
    let (ciphertext, tag) = @lib.aes_gcm_encrypt(b"secret data", key, iv, b"aad")
    let (plaintext, ok) = @lib.aes_gcm_decrypt(ciphertext, key, iv, b"aad", tag)
    let status = if ok { "OK" } else { "FAIL" }
    println("AES-GCM round-trip: " + status)
    println("Recovered: " + @lib.bytes_to_hex(plaintext))

    // Sealed-box envelope: HKDF-SHA256 derives the AES-256-GCM key from a
    // master key + context, then encrypts into a versioned envelope.
    let master = Bytes::make(32, b'\x07')
    let nonce = Bytes::make(12, b'\x01')
    let envelope = @lib.sealed_box_seal(master, nonce, b"plaintext", b"aad", b"tenant-1")
    match @lib.sealed_box_open(master, envelope, b"aad", b"tenant-1") {
    Ok(pt) => println("Sealed box: " + @lib.bytes_to_hex(pt))
    Err(msg) => println("Sealed box failed: " + msg)
    }
    }

    Run it:

    moon run cmd/main

    SHA-256: 315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3 AES-GCM round-trip: OK Recovered: 7365637265742064617461

    A larger runnable example that validates the implementation against NIST/RFC standard vectors lives in cmd/main of the repository itself. Run it with moon run cmd/main.

    #Public API

    All functions live in the lib package (cc06b/mooncry/lib), called as @lib.<fn> after declaring the import in your moon.pkg.

    FunctionDescription
    md5(data : Bytes) -> BytesMD5 one-shot, 16-byte digest
    sha224 / sha256 / sha384 / sha512(data : Bytes) -> BytesSHA-2 family (FIPS 180-4)
    sha512_224 / sha512_256(data : Bytes) -> BytesSHA-512/224 / SHA-512/256 (FIPS 180-4 §5.3.6)
    ripemd160(data : Bytes) -> BytesRIPEMD-160, 20-byte digest
    sha3_224 / sha3_256 / sha3_384 / sha3_512(data : Bytes) -> BytesSHA-3 (FIPS 202)
    keccak_256(data : Bytes) -> BytesKeccak-256 (legacy 0x01 padding, Ethereum), 32 bytes
    shake_128 / shake_256(data : Bytes, out_len : Int) -> BytesSHAKE XOF, out_len bytes
    cshake_128 / cshake_256(data, n, s : Bytes, out_len : Int) -> BytescSHAKE (SP 800-185); N=S="" ⇒ SHAKE
    kmac_128 / kmac_256(key, data, s : Bytes, out_len : Int) -> BytesKMAC fixed-length MAC (SP 800-185)
    kmac_xof_128 / kmac_xof_256(key, data, s : Bytes, out_len : Int) -> BytesKMACXOF variable-length variant
    blake2b(data : Bytes, out_len : Int) -> BytesBLAKE2b (RFC 7693), out_len 1..64
    blake2b_keyed(data, key : Bytes, out_len : Int) -> Byteskeyed BLAKE2b (MAC), key 1..64
    blake2s(data : Bytes, out_len : Int) -> BytesBLAKE2s (RFC 7693), out_len 1..32
    blake2s_keyed(data, key : Bytes, out_len : Int) -> Byteskeyed BLAKE2s (MAC), key 1..32
    blake3(data : Bytes) -> BytesBLAKE3, 32-byte digest
    blake3_xof(data : Bytes, out_len : Int) -> BytesBLAKE3 XOF (arbitrary-length)
    hmac_sha256 / hmac_sha512(key, msg : Bytes) -> BytesHMAC (RFC 2104)
    hmac_sha3_256 / hmac_sha3_512(key, msg : Bytes) -> BytesHMAC over SHA-3 (RFC 2104 + FIPS 202)
    hmac_sha3_224 / hmac_sha3_384(key, msg : Bytes) -> BytesHMAC over SHA3-224/384 (RFC 2104 + FIPS 202)
    poly1305(key, msg : Bytes) -> BytesPoly1305 MAC (RFC 8439), 16-byte tag
    cmac_aes(data, key : Bytes) -> BytesAES-CMAC (NIST SP 800-38B), 16-byte tag
    aes_encrypt_cbc / aes_decrypt_cbc(data, key, iv) -> BytesAES-CBC (IV prepended, PKCS#7)
    aes_gcm_encrypt(pt, key, iv, aad) -> (Bytes, Bytes)AES-GCM encrypt → (ct, 16-byte tag)
    aes_gcm_decrypt(ct, key, iv, aad, tag) -> (Bytes, Bool)AES-GCM decrypt, constant-time tag verify
    aes_ccm_encrypt(pt, key, nonce, aad, mac_len) -> BytesAES-CCM AEAD (SP 800-38C) → ct ‖ tag
    aes_ccm_decrypt(input, key, nonce, aad, mac_len) -> BytesAES-CCM decrypt, aborts on tag mismatch
    gmac(key, iv, aad) -> BytesGMAC (SP 800-38D), 16-byte tag
    gmac_verify(key, iv, aad, tag) -> BoolGMAC constant-time tag verify
    gmac_new(key, iv) -> GmacStateIncremental GMAC (chunked AAD, 12-byte IV)
    gmac_new_iv(key, iv) -> GmacStateIncremental GMAC, any IV length (SP 800-38D)
    gmac_update(st, aad_chunk)Feed an AAD chunk
    gmac_finalize(st) -> BytesIncremental GMAC 16-byte tag
    gmac_iv(key, iv, aad) -> BytesGMAC with any IV length (SP 800-38D)
    gmac_iv_verify(key, iv, aad, tag) -> BoolGMAC any-IV constant-time verify
    aes_ctr(data, key, iv) -> BytesAES-CTR encrypt/decrypt (symmetric)
    chacha20_xor(input, key, nonce, counter) -> BytesChaCha20 encrypt/decrypt (symmetric)
    salsa20_keystream_block(key, nonce, counter) -> BytesSalsa20 keystream block (64 bytes)
    salsa20_xor(key, nonce, counter, data) -> BytesSalsa20 stream cipher encrypt/decrypt (symmetric)
    chacha20_poly1305_encrypt(key, nonce, aad, pt) -> BytesChaCha20-Poly1305 AEAD → ct ‖ tag
    chacha20_poly1305_decrypt(key, nonce, aad, input) -> BytesAEAD decrypt, aborts on tag mismatch
    hchacha20(key, in16 : Bytes) -> BytesHChaCha20 subkey derivation (draft-irtf-cfrg-xchacha §2.2)
    xchacha20_xor(input, key, nonce24, counter) -> BytesXChaCha20 stream cipher, 24-byte nonce (symmetric)
    xchacha20_poly1305_encrypt(key, nonce24, aad, pt) -> BytesXChaCha20-Poly1305 AEAD → ct ‖ tag
    xchacha20_poly1305_decrypt(key, nonce24, aad, input) -> BytesXChaCha20-Poly1305 AEAD decrypt, aborts on tag mismatch
    hotp_sha256 / hotp_sha512(key, counter, digits) -> StringHOTP (RFC 4226) with HMAC-SHA256/512
    totp_sha256 / totp_sha512(key, unix_time, step, digits) -> StringTOTP (RFC 6238) with HMAC-SHA256/512
    ed25519ctx_sign(seed, msg, ctx) / ed25519ctx_verify(pk, msg, sig, ctx)Ed25519ctx (RFC 8032), ctx 1..255 bytes
    ed25519ph_sign(seed, msg, ctx) / ed25519ph_verify(pk, msg, sig, ctx)Ed25519ph (RFC 8032), SHA-512 prehash
    adler32(data : Bytes) -> BytesAdler-32 (RFC 1950), 4-byte big-endian
    hkdf_sha256(salt, ikm, info, len) -> BytesHKDF-SHA256 (RFC 5869)
    hkdf_sha512(salt, ikm, info, len) -> BytesHKDF-SHA512 (RFC 5869)
    pbkdf2_hmac_sha256(password, salt, iterations, len) -> BytesPBKDF2-HMAC-SHA256 (RFC 8018)
    pbkdf2_hmac_sha512(password, salt, iterations, len) -> BytesPBKDF2-HMAC-SHA512 (RFC 8018)
    pbkdf2_hmac_sha1(password, salt, iterations, len) -> BytesPBKDF2-HMAC-SHA1 (RFC 8018)
    hkdf_sha3_256(salt, ikm, info, len) -> BytesHKDF-SHA3-256 (RFC 5869 over FIPS 202)
    pbkdf2_hmac_sha3_256(password, salt, iterations, len) -> BytesPBKDF2-HMAC-SHA3-256 (RFC 8018 over FIPS 202)
    scrypt(password, salt, n, r, p, dklen) -> Bytesscrypt memory-hard KDF (RFC 7914), n power of two
    rsa_pkcs1_v15_encrypt(msg, n, e, rand_ps) -> BytesRSAES-PKCS1-v1.5 encrypt (RFC 8017 §7.2)
    rsa_pkcs1_v15_decrypt(ct, n, d) -> BytesRSAES-PKCS1-v1.5 decrypt
    rsa_pkcs1_v15_sign(msg, n, d) -> BytesRSASSA-PKCS1-v1.5 sign (SHA-256)
    rsa_pkcs1_v15_verify(msg, sig, n, e) -> BoolRSASSA-PKCS1-v1.5 verify
    rsa_oaep_encrypt(msg, n, e, seed, label) -> BytesRSAES-OAEP encrypt (SHA-256)
    rsa_oaep_decrypt(ct, n, d, label) -> BytesRSAES-OAEP decrypt
    rsa_oaep_encrypt_with(msg, n, e, seed, label, hash) -> BytesOAEP encrypt, chosen hash + MGF1
    rsa_oaep_decrypt_with(ct, n, d, label, hash) -> BytesOAEP decrypt, chosen hash
    rsa_pss_sign(msg, n, d, salt) -> BytesRSASSA-PSS sign (SHA-256)
    rsa_pss_verify(msg, sig, n, e, salt_len) -> BoolRSASSA-PSS verify
    rsa_pkcs1_v15_sign_crt(msg, p, q, dp, dq, qinv) -> BytesPKCS1-v1.5 sign via CRT (~2.6x, byte-identical)
    rsa_pkcs1_v15_decrypt_crt(ct, p, q, dp, dq, qinv) -> BytesPKCS1-v1.5 decrypt via CRT
    rsa_oaep_decrypt_crt(ct, p, q, dp, dq, qinv, label) -> BytesOAEP decrypt via CRT
    rsa_pss_sign_crt(msg, p, q, dp, dq, qinv, salt) -> BytesPSS sign via CRT
    rsa_pkcs1_v15_sign_with(msg, n, d, hash) -> BytesPKCS1-v1.5 sign, hash = SHA-1/256/384/512
    rsa_pkcs1_v15_verify_with(msg, sig, n, e, hash) -> BoolPKCS1-v1.5 verify, chosen hash
    rsa_pss_sign_with(msg, n, d, salt, hash) -> BytesPSS sign, chosen hash + MGF1
    rsa_pss_verify_with(msg, sig, n, e, salt_len, hash) -> BoolPSS verify, chosen hash
    rsa_pkcs1_v15_sign_with_crt(msg, p, q, dp, dq, qinv, hash) -> Bytesv1.5 sign, CRT + chosen hash
    rsa_pss_sign_with_crt(msg, p, q, dp, dq, qinv, salt, hash) -> BytesPSS sign, CRT + chosen hash
    ed25519_public_key(seed) -> BytesDerive 32-byte Ed25519 public key
    ed25519_sign(seed, message) -> BytesEd25519 sign (RFC 8032), 64-byte sig
    ed25519_verify(public_key, message, sig) -> BoolEd25519 verify
    ecdsa_p256_public_key(sk) -> BytesECDSA P-256 public key (uncompressed)
    ecdsa_p256_sign(sk, message) -> BytesECDSA P-256 sign (RFC 6979, SHA-256)
    ecdsa_p256_sign_low_s(sk, message) -> BytesP-256 sign, low-S canonical (WebCrypto)
    ecdsa_p256_verify(pk, message, sig) -> BoolECDSA P-256 verify
    ecdsa_secp256k1_public_key(sk) -> BytesECDSA secp256k1 public key (uncompressed)
    ecdsa_secp256k1_sign(sk, message) -> BytesECDSA secp256k1 sign (RFC 6979, SHA-256)
    ecdsa_secp256k1_sign_low_s(sk, message) -> Bytessecp256k1 sign, BIP-62 low-S canonical
    ecdsa_secp256k1_verify(pk, message, sig) -> BoolECDSA secp256k1 verify
    x25519(scalar, u) -> BytesX25519 scalar mult (RFC 7748), DH shared secret
    x25519_public_key(private_key) -> BytesDerive X25519 public key (base u=9)
    ed448_public_key(seed) -> BytesDerive 57-byte Ed448 public key
    ed448_sign(seed, message) -> BytesEd448 sign (RFC 8032), 114-byte sig
    ed448_sign_ctx(seed, message, ctx) -> BytesEd448 sign with context
    ed448_verify(pk, message, sig) -> BoolEd448 verify (cofactor equation)
    ed448_verify_ctx(pk, message, sig, ctx) -> BoolEd448 verify with context
    x448(scalar, u) -> BytesX448 scalar mult (RFC 7748), DH shared secret
    x448_public_key(private_key) -> BytesDerive X448 public key (base u=5)
    ml_kem_512_keygen(d, z) -> (ek, dk)ML-KEM-512 keygen (FIPS 203, deterministic in d,z)
    ml_kem_512_encaps(ek, m) -> (K, c)ML-KEM-512 encapsulation
    ml_kem_512_decaps(dk, c) -> BytesML-KEM-512 decapsulation (implicit rejection)
    ml_kem_768_keygen / encaps / decapsML-KEM-768 (same shapes)
    ml_kem_1024_keygen / encaps / decapsML-KEM-1024 (same shapes)
    ml_kem_768_hybrid_seal(ek, m, aad, msg)ML-KEM-768 hybrid encryption (HKDF + ChaCha20-Poly1305)
    ml_kem_768_hybrid_open(dk, blob, aad) -> Option[Bytes]hybrid decryption; None on any failure
    ml_kem_768_hybrid_seal_init + ml_kem_hybrid_stream_update/finalstreaming hybrid seal
    poly1305_new / poly1305_update / poly1305_finalizeincremental Poly1305
    aes_gcm_siv_encrypt(key, nonce, aad, pt)AES-GCM-SIV (RFC 8452, nonce-misuse-resistant)
    aes_gcm_siv_decrypt(key, nonce, aad, ct) -> Option[Bytes]AES-GCM-SIV decryption
    xwing_keygen(seed) -> (pk, sk)X-Wing hybrid KEM keygen (ML-KEM-768 + X25519)
    xwing_encaps(pk, eseed) -> (ss, ct)X-Wing encapsulation (derandomized)
    xwing_decaps(ct, sk) -> BytesX-Wing decapsulation
    turbo_shake_128(data, d, out_len)TurboSHAKE128 (RFC 9861, Keccak-p[1600,12])
    kangaroo_twelve_128(m, c, out_len)KangarooTwelve KT128 (tree hash + customization)
    turbo_shake_256 / kangaroo_twelve_256256-bit capacity variants
    hpke_setup_s(suite, mode, pk_r, ikm_e, info, psk, psk_id, sk_s)HPKE sender setup (RFC 9180, all 4 modes)
    hpke_seal(ctx, aad, pt) / hpke_open(ctx, aad, ct)HPKE authenticated encryption (auto sequence numbers)
    hpke_export(ctx, exporter_context, len)HPKE exporter
    hpke_x25519_* / hpke_p256_* / hpke_x448_*HPKE cipher-suite selectors (all RFC-vectored suites)
    ml_dsa_44_keygen(seed) -> (pk, sk)ML-DSA-44 keygen (FIPS 204, deterministic in seed)
    ml_dsa_44_sign(sk, msg, rnd, ctx) -> BytesML-DSA-44 sign (pure; rnd = 0^32 = deterministic)
    ml_dsa_44_verify(pk, msg, sig, ctx) -> BoolML-DSA-44 verify
    ml_dsa_65_keygen / sign / verifyML-DSA-65 (same shapes)
    ml_dsa_87_keygen / sign / verifyML-DSA-87 (same shapes)
    ml_dsa_44_sign_prehash(sk, msg, rnd, ctx, ph)HashML-DSA-44 sign (FIPS 204 Alg 4, OID-tagged pre-hash)
    ml_dsa_44_verify_prehash(pk, msg, sig, ctx, ph)HashML-DSA-44 verify (FIPS 204 Alg 5)
    ml_dsa_44_sign_mu(sk, mu, rnd) / verify_mu(pk, mu, sig)ML-DSA-44 external-mu interface (Alg 7/8)
    dsa_prehash_variants / dsa_prehash_sha2_256 / ...12 pre-hash selectors (SHA2/SHA3 family + SHAKE-128/256)
    slh_keygen(slh_sha2_128s, sk_seed, sk_prf, pk_seed)SLH-DSA keygen (FIPS 205, deterministic in the three seeds)
    slh_sign(params, sk, msg, ctx) / slh_sign_hedged(...)SLH-DSA pure signing (deterministic / hedged)
    slh_verify(params, pk, msg, sig, ctx)SLH-DSA verification
    slh_sign_prehash / slh_verify_prehashHashSLH-DSA (OID-tagged pre-hash, 12 hash functions)
    slh_sign_raw / slh_verify_rawraw-M' internal interface
    slh_sha2_128s ... slh_shake_256fall 12 SLH-DSA parameter sets
    crc32 / crc32c(data : Bytes) -> BytesCRC-32 (IEEE) / CRC-32C, 4-byte big-endian
    crc64_xz / crc64_go_iso(data : Bytes) -> BytesCRC-64/XZ / CRC-64/GO-ISO, 8-byte big-endian
    siphash_2_4(key, data : Bytes) -> BytesSipHash-2-4 (64-bit), key 16 bytes → 8 bytes
    sealed_box_seal(master_key, nonce, pt, aad, ctx) -> BytesAEAD envelope (HKDF + AES-256-GCM)
    sealed_box_open(master_key, envelope, aad, ctx) -> Result[Bytes, String]Open envelope, Err on auth failure
    base64_encode(data : Bytes) -> StringBase64 encode (RFC 4648)
    base64_decode(encoded : String) -> BytesBase64 decode
    base64_decode_or(encoded : String) -> Result[Bytes, String]Base64 decode, Err on malformed input
    bytes_to_hex(data : Bytes) -> StringBytes → lowercase hex
    hex_to_bytes(hex : String) -> Byteshex → Bytes (aborts on bad input)
    hex_to_bytes_or(hex : String) -> Result[Bytes, String]hex → Bytes, Err on bad input
    bytes_equal(a, b : Bytes) -> BoolConstant-time comparison

    Streaming hashers (<algo>_new / sha3_update / sha3_finalize / shake_finalize) are available for MD5, SHA-224/256/384/512, SHA3-224/256/384/512, and SHAKE128/256, plus SHA-512/224 / SHA-512/256 (sha512_224_new / sha512_256_new with sha512_update). For SHA-3/SHAKE, sha3_update is shared and the finalize method depends on the variant (sha3_finalize for fixed-length, shake_finalize(h, out_len) for XOF).

    AES-CBC/GCM/CTR keys may be 128, 192, or 256 bits; the nonce for GCM and ChaCha20 is 96 bits (12 bytes), the recommended length per spec. Wrong lengths cause an abort with a descriptive message.

    #Security & performance boundaries

    • Not audited. The code is correct against known vectors but has had no formal security review. Do not use it to protect high-value assets without an independent audit.
    • AES is not constant-time. MixColumns uses precomputed GF(2^8) lookup tables (mul2/3/9/11/13/14) for ~5x throughput. This leaks key-dependent table indices through the CPU cache — acceptable for many use cases but not side-channel-safe against a local attacker. Since v0.19.0 GHASH also uses precomputed 4-bit tables (keyed by the GCM hash subkey), so it is no longer bit-sliced and is likewise not side-channel-safe; the GCM tag comparison and CBC PKCS#7 verification remain constant-time (no early exit on mismatch).
    • Nonce reuse is catastrophic for AES-GCM and ChaCha20(-Poly1305). Never reuse a (key, nonce) pair. The library does not track nonces — generate a fresh one per message (e.g. a counter or CSPRNG).
    • PBKDF2 is a KDF, not a password hasher. For interactive password storage prefer Argon2 / bcrypt / scrypt elsewhere; PBKDF2 is included for compatibility with existing protocols.
    • MD5 is collision-broken. It is included for legacy compatibility only — do not sign or authenticate with it.
    • BLAKE3 supports arbitrary-length input via the tree-Merkle mode (verified vs the reference blake3 Python package up to 5000 bytes).
    • Inputs are validated, not silently padded. Wrong key / IV / nonce / tag lengths abort immediately rather than producing wrong output.
    • No RNG. The library provides deterministic primitives; obtain keys, IVs, and nonces from a secure source.

    #Performance

    Throughput is measured by the lib benchmark suite (moon bench) on 1 KiB inputs. Figures below are from the development sandbox; absolute numbers vary by host — run moon bench locally for comparable figures.

    moon bench

    Algorithm1 KiB (approx.)
    MD5~8.5 µs
    SHA-256~16 µs
    SHA-512~14 µs
    SHA3-256~140 µs
    SHAKE128 1KiB (out=32)~80 µs
    SHAKE256 1KiB (out=64)~92 µs
    BLAKE2b~27 µs
    BLAKE3~46 µs
    HMAC-SHA256~23 µs
    HMAC-SHA3-256~213 µs
    HMAC-SHA3-512~338 µs
    AES-128-CMAC~347 µs
    SipHash-2-4~4.2 µs
    CRC32 / CRC32C~4.7 µs
    sealed_box_seal~588 µs (HKDF + AES-256-GCM)
    scrypt (N=1024,r=8,p=1,dk32)~84 ms (memory-hard KDF)
    Argon2id (t=1,m=64,p=1,dk16)~1 ms (memory-hard KDF)
    ECDSA P-256 sign~13 ms (Jacobian, was ~270 ms affine)
    ECDSA P-256 verify~24 ms (Jacobian, was ~540 ms affine)
    AES-256-SIV encrypt 1KiB~950 µs (S2V + AES-CTR)
    AES-128-KW wrap 32B~146 µs
    ChaCha20~48 µs
    ChaCha20-Poly1305 encrypt~73 µs (was ~456 µs)
    Poly1305 MAC~7 µs (was ~387 µs, BigInt)
    AES-256-CBC~315 µs (table-based GF mul)
    AES-256-GCM~487 µs (GHASH 4-bit tables)
    Base64 encode~10 µs
    Hex encode~6.7 µs

    v0.18.0 perf pass. The Keccak-f[1600] state was flattened from a nested 5×5 Array[Array[UInt64]] to a flat 25-lane array (removing the inner-array indirection from the hot permutation loop), and ChaCha20 now expands the key/nonce words once per call instead of per block. Measured on 1 KiB inputs: SHAKE128 ~123 → ~80 µs (-35%), SHAKE256 ~136 → ~92 µs (-32%), ChaCha20 ~54 → ~48 µs (-11%).

    v0.19.0 perf pass. GHASH (the GF(2^128) multiply inside AES-GCM) was rewritten from a 128-iteration bit-serial loop to a precomputed 4-bit table (32 nibble lookups + XORs per multiply), cutting AES-256-GCM from ~507 to ~487 µs/KiB. Poly1305 was rewritten from per-block @bigint arithmetic to 5-limb radix-2^26 arithmetic with UInt64 partial products ("donna" style): Poly1305 drops from ~387 to ~7 µs/KiB (-98%), which takes ChaCha20-Poly1305 AEAD from ~456 to ~73 µs/KiB (-84%) and also speeds up XChaCha20-Poly1305 and the sealed-box envelope.

    v0.20.0 perf pass. ECDSA P-256 point arithmetic moved from affine to Jacobian projective coordinates. Affine double/add each need one Fermat-exponentiation modular inverse (~256 field muls), so a 256-bit scalar multiplication cost ~384 inverses; Jacobian double/add need none, inverting only once when converting back to affine. All field subtractions stay non-negative (the X25519 BigInt lesson). Measured on one host: sign ~270 → ~13 ms and verify ~540 → ~24 ms (~21-23x). Signatures are byte-identical to before (RFC 6979 deterministic k is unchanged), so no compatibility break.

    v0.21.0 perf pass. Two fronts. (1) SHA-256 streaming: the hasher now reuses one 64-word message schedule instead of allocating 16- and 64-word arrays per block, reads buffer words without an intermediate Bytes, and finalizes with in-place padding (no padded-array allocation); one-shot SHA-256 1KiB drops ~26.9 → ~20.7 µs (-23%). New sha256_update_byte / sha224_update_byte give byte-at-a-time streams a zero-allocation hot path: ~26.3 µs/KiB, only ~1.3x one-shot (the old 1-byte update pattern is ~3.7x). (2) RSA: all four private-key operations (PKCS1-v1.5 sign/decrypt, OAEP decrypt, PSS sign) gain _crt variants taking the CRT key (p, q, dP, dQ, qInv) and doing two half-width exponentiations instead of one full-width (RFC 8017 §5.1.2) — ~17.6-18.5 ms → ~6.8-7.0 ms on RSA-1024 (~2.5-2.6x). CRT output is byte-identical to the single-exponentiation path (deterministic padding), verified in-tree. The PSS/OAEP emBits computation no longer allocates a ~k-char binary string per call.

    v0.22.0 features. Three additions. (1) ECDSA secp256k1 (Bitcoin curve, y² = x³ + 7): sign/verify/public-key with the same RFC 6979 + SHA-256 deterministic construction as P-256. The point/RFC-6979 code is now curve-parameterized (P-256 keeps its fast a = −3 doubling; secp256k1 uses the a = 0 specialization), and P-256 signatures stay byte-identical. Verified against the Python ecdsa library (sign_digest_deterministic) plus cryptography cross-verification; signatures are not low-S-normalized (verify accepts any s in [1, n−1]); use ecdsa_secp256k1_sign_low_s for BIP-62 canonical output (v0.23.0). (2) Multi-hash RSA signatures: rsa_pkcs1_v15_sign_with / rsa_pkcs1_v15_verify_with / rsa_pss_sign_with / rsa_pss_verify_with take an RsaHash (SHA-1/256/384/512) for the message hash, DigestInfo (v1.5) and MGF1 (PSS). The plain functions stay fixed to SHA-256. Verified byte-for-byte against pycryptodome. (3) Incremental GMAC (gmac_new / gmac_update / gmac_finalize): chunked AAD over the same table-accelerated GHASH, equal to the one-shot gmac tag (verified in-tree and against pycryptodome GCM-empty tags).

    v0.23.0 features. Two additions. (1) secp256k1 low-S signatures (ecdsa_secp256k1_sign_low_s): BIP-62 canonical form — if s > n/2 it is replaced by n − s (r unchanged, still valid and deterministic). Verified against the Python ecdsa library's sigencode_string_canonize plus cryptography. (2) Multi-hash RSA-OAEP: rsa_oaep_encrypt_with / rsa_oaep_decrypt_with take an RsaHash for lHash and MGF1 (the plain functions stay fixed to SHA-256). Exact ciphertexts verified against pycryptodome (fixed seed via its randfunc hook) plus random-seed interop; SHA-512 vectors use a dedicated 2048-bit key since OAEP-SHA512 needs k ≥ 2·hLen + 2 + |M| (impossible on 1024 bits).

    v0.24.0 features. Two additions. (1) P-256 low-S signatures (ecdsa_p256_sign_low_s): the WebCrypto / widely-mandated canonical form — if s > n/2 it is replaced by n − s (r unchanged, still valid and deterministic); ecdsa_p256_verify accepts both forms. Verified against the Python ecdsa library's sigencode_string_canonize plus cryptography, with a property test asserting s ≤ n/2 byte-wise. (2) GMAC with any IV length (gmac_iv / gmac_iv_verify one-shot and gmac_new_iv incremental): SP 800-38D §8.2.1 — 96-bit IVs keep the fast J0 = IV || 0³¹ || 1 path; other lengths derive J0 via GHASH over IV || 0^(s+64) || [len(IV)]₆₄. Verified against pycryptodome GCM-empty tags for IV lengths 1/8/16/20/32 plus 12-byte fast-path equality and streaming-vs-one-shot properties.

    v0.25.0 features. CRT × multi-hash combinations: the CRT speed of v0.21.0 and the hash choice of v0.22.0 are now combinable — rsa_pkcs1_v15_sign_with_crt and rsa_pss_sign_with_crt take both the CRT key (p, q, dP, dQ, qInv) and an RsaHash. Deterministic padding makes them byte-identical to the pycryptodome-verified _with paths (transitive verification across all four hashes, plus a salt_len=0 deterministic case).

    v0.26.0 features. The 448-bit suite. (1) Ed448 (RFC 8032 §5.2): pure EdDSA over edwards448 (Goldilocks field p = 2⁴⁴⁸ − 2²²⁴ − 1), SHAKE256-based hashing with dom4 domain separation, context support (ed448_sign_ctx / ed448_verify_ctx), cofactor verification equation [4][S]B = [4]R + [4][k]A. Verified against all nine official RFC 8032 §7.4 vectors incl. the 1023-octet message and the context-carrying one, plus tamper/context-mismatch/S≥L negative tests. (2) X448 (RFC 7748): Montgomery-ladder Diffie-Hellman over curve448 with RFC §5 clamping. Verified against the official RFC 7748 §5.2 vectors, the §6.1 DH triple, and the single-iteration K=u=5 vector, plus an ECDH commutativity property.

    v0.27.0 features. Post-quantum: ML-KEM (FIPS 203) — the NIST standard module-lattice KEM, all three parameter sets (ML-KEM-512/768/1024). Pure MoonBit on UInt (q = 3329), NTT-domain arithmetic with the standard zeta/gamma tables, rejection sampling from a true incremental SHAKE128 stream, CBD noise sampling, Compress/ByteEncode for d = 1/4/5/10/11/12, and the full K-PKE + ML-KEM algorithm set (KeyGen/Encaps/Decaps_internal, implicit rejection included). The API is the deterministic internal form: callers supply CSPRNG randomness (d, z for keygen; m for encaps). Lesson learned during this work: the FIPS 203 final text instantiates G = SHA3-512 and H = SHA3-256 (not SHAKE256 as in earlier drafts) — only J and PRF remain SHAKE256. Verified against the official NIST ACVP vectors (keyGen + encapsulation + decapsulation, incl. implicit-rejection cases) for all three parameter sets, plus round-trip and tamper properties.

    v0.28.0 features. Post-quantum: ML-DSA (FIPS 204) — the NIST module-lattice signature standard, all three parameter sets (ML-DSA-44/65/87). Pure-MoonBit port: NTT over q = 8380417 (Int64-widening multiplies — Int is 32-bit on wasm-gc), rejection sampling (SampleNTT/SamplePolyCBD/ExpandMask), Power2Round/Decompose/HighBits/ LowBits/MakeHint/UseHint, hint bit-pack/unpack, and the full K-PKE + ML-DSA KeyGen/Sign/Verify internal algorithms (pure message interface, hedged or deterministic via the rnd input). Verified against the official NIST ACVP vectors: keyGen (all sets), sigGen pure deterministic, and the full sigVer external-pure suite including every rejection category. HashML-DSA and external-mu followed in v0.29.0/v0.30.0.

    v0.29.0 features. ML-DSA HashML-DSA + external-mu interfaces completes the FIPS 204 algorithm surface. HashML-DSA (Algorithms 4/5): M' = 0x01 || octet(|ctx|) || ctx || OID(PH) || PH(M) with the DER OID tag of the pre-hash function (all 12 NIST digests/XOFs; SHAKE-128 pre-hash output 32 B, SHAKE-256 64 B). External-mu (Algorithms 7/8): sign/verify with the 64-byte message digest mu supplied externally. Verified against the official NIST ACVP vector sets (FIPS204-tr1 sigGen pre-hash, deterministic, byte-exact; full sigVer pre-hash suite; all rejection categories).

    v0.30.0 features. ML-DSA external-mu ACVP coverage — the external-mu entry points shipped in v0.29.0 (*_sign_mu / *_verify_mu) are now pinned against the official NIST ACVP external-mu vector groups: sigGen deterministic (byte-exact, mu supplied) and the full sigVer external-mu suite including all rejection categories. ML-DSA's complete FIPS 204 surface — pure, pre-hash and external-mu interfaces — is now vector-verified (789 tests).

    v0.31.0 features. SLH-DSA (SPHINCS+, FIPS 205) — the NIST stateless hash-based signature standard, all 12 approved parameter sets (SLH-DSA-{SHA2,SHAKE}-{128,192,256}{s,f}). Pure-MoonBit port: WOTS+ chains, XMSS Merkle trees, the hypertree, FORS few-time signatures, the SHA2 instance (MGF1-SHA-256/512 based H_msg, compressed 22-byte addresses, category-dependent hash selection) and the SHAKE instance (SHAKE256 based). Verified against the official NIST ACVP vectors: keyGen (all sets), sigGen deterministic (pure, pre-hash with OID tagging, and internal/raw-M' semantics) and sigVer. Note: SLH-DSA is deliberately expensive — signing runs thousands of hash calls; the full 849-test suite takes ~17 minutes.

    v0.32.0 features. SLH-DSA speed-up (~16%) + hasher cloning. SLH signing now runs through a per-key hash suite: the SHA2/SHAKE PK.seed prefix is absorbed once and reused via zero-allocation working hashers (state reset per call, prefix bytes restored). New public utilities sha256_clone / sha512_clone / sha3_clone deep-copy streaming hashers for hashing many messages that share a prefix. Note a subtle trap now documented in the test history: when a buffered prefix is shorter than one block, multi-block absorptions overwrite the prefix region of the buffer, so a reused hasher must restore it.

    v0.33.0 features. ML-KEM hybrid encryption (KEM + DEM) ml_kem_{512,768,1024}_hybrid_seal / hybrid_open plus streaming hybrid_seal_init + ml_kem_hybrid_stream_update / stream_final. Composition: (K, c) = Encaps(ek, m); (key, nonce) = HKDF-SHA256(salt = c, ikm = K, info = "mooncry/ml-kem-hybrid/v1", 44); blob = c || ChaCha20-Poly1305(key, nonce, aad, msg). open returns None on any failure (KEM implicit rejection surfaces as a tag mismatch). New incremental Poly1305 (poly1305_new / update / finalize; the one-shot is now built on it). Also fixes a latent HMAC bug: keys longer than one block were not zero-padded after hashing (ipad/opad truncated); RFC 4231 TC6 regression vectors added. Verification: KEM I/O from the official NIST ACVP vectors (FIPS 203); the composition layer is cross-checked against pycryptodome.

    v0.34.0 features. SLH-DSA ~25% faster (suite 17 min → 13 min). Two allocation-removal passes on the per-node hash hot path: sha256_finalize_n / sha512_finalize_n write truncated digests directly (one allocation instead of finalize + slice), and T_l over WOTS+/FORS public values now feeds the pre-split blocks into the hasher without concatenating. Regression-tested against truncated one-shot digests. (A moonc 0827 compiler ICE forced the finalize_n internals to be factored into a shared padding helper — noted for future toolchains.)

    v0.35.0 features. X-Wing hybrid KEM (draft-connolly-cfrg-xwing-kem) — the ML-KEM-768 + X25519 composite KEM: xwing_keygen (32-byte seed → 1216-byte pk), xwing_encaps (derandomized in a 64-byte eseed) and xwing_decaps (implicit rejection inherited from ML-KEM). Verified against the official draft test vectors (keygen, encapsulation and decapsulation for all three published vectors).

    v0.36.0 features. TurboSHAKE + KangarooTwelve (RFC 9861) turbo_shake_128 / turbo_shake_256 (Keccak-p[1600,12] sponge with a domain byte; 12-round permutation factored out of the SHA-3 core) and kangaroo_twelve_128 / kangaroo_twelve_256 (Sakura tree hash over 8192-byte chunks with a customization string). Verified against every applicable RFC 9861 test vector, including the 8191/8192-byte tree boundary and customization-string cases.

    v0.37.0 features. HPKE — Hybrid Public Key Encryption (RFC 9180). DHKEM(X25519, HKDF-SHA256) and DHKEM(X448, HKDF-SHA512); KDFs HKDF-SHA256/SHA512; AEADs AES-128-GCM, AES-256-GCM and ChaCha20Poly1305; all four modes (base / psk / auth / auth+psk). hpke_setup_s / hpke_setup_r (derandomized via explicit ephemeral IKM), hpke_seal / hpke_open with automatic sequence numbers (None on authentication failure), and hpke_export. Verified against the official RFC 9180 Appendix A vectors (every mode of the X25519 suites, including the sequence-number carry at 255/256); X448 covered by round-trip tests.

    v0.38.0 features. HPKE completes: DHKEM(P-256, HKDF-SHA256) with rejection-sampling key derivation and uncompressed-point encoding, covering the remaining official RFC 9180 Appendix A suites (A.3-A.5, all four modes each), including the mixed DHKEM(P-256)+HKDF-SHA512 ciphersuite where the KEM-internal KDF differs from the suite KDF. All three DHKEMs the RFC defines vectors for are now vector-verified.

    v0.39.0 features. AES-GCM-SIV (RFC 8452) — the nonce-misuse-resistant AEAD: aes_gcm_siv_encrypt /aes_gcm_siv_decrypt for AEAD_AES_128_GCM_SIV and AEAD_AES_256_GCM_SIV. POLYVAL is implemented via the RFC Appendix A equivalence with GHASH (ByteReverse + mulX), reusing the library's table-accelerated GF(2^128) multiplier. Verified against all 48 official RFC 8452 Appendix C vectors (encrypt byte-exact + decrypt round-trip).

    Hashes, ChaCha20, and hex/Base64 are throughput-bound by the algorithm; AES trades constant-time property for ~5x speed via lookup tables (see Security & performance boundaries).

    #Testing

    Every algorithm is verified against official standard vectors:

    moon test

    Coverage: MD5 (RFC 1321), SHA-2 family (FIPS 180-4 + million-a), SHA-3 (NIST KAT), SHAKE (FIPS 202), BLAKE2b (RFC 7693 + hashlib), BLAKE3 (python blake3), HMAC (RFC 4231), HMAC-SHA3 (hashlib), Poly1305 (RFC 8439), AES-CMAC (NIST SP 800-38B + pycryptodome), ChaCha20-Poly1305 (RFC 8439 + pycryptodome), HKDF (RFC 5869), PBKDF2 (RFC 6070), scrypt (RFC 7914 + hashlib.scrypt), AES-CBC/GCM/CTR (NIST SP 800-38A/D), ChaCha20 (RFC 8439), RSA (RFC 8017 PKCS1-v1.5/OAEP/PSS + pycryptodome), Ed25519 (RFC 8032 + cryptography lib), X25519 (RFC 7748 + cryptography lib), CRC32/CRC32C (zlib + manual ref), SipHash-2-4 (Python reference), Salsa20 (eSTREAM + pycryptodome), SHA-1 (hashlib) + HOTP/TOTP (RFC 4226/6238), Base64 (RFC 4648), hex round-trip, Keccak-256 / cSHAKE128/256 / KMAC128/256/XOF (NIST SP 800-185 official samples + pycryptodome, differential-tested), CRC-64/XZ + CRC-64/GO-ISO (CRC RevEng check values), SHA-512/224 / SHA-512/256 (FIPS 180-4 + hashlib), BLAKE2s (RFC 7693 + hashlib), HMAC-SHA3-224/384 (stdlib hmac), XChaCha20 / XChaCha20-Poly1305 (draft-irtf-cfrg-xchacha official vectors + libsodium, differential-tested), TOTP-SHA256/512 (RFC 6238 Table 1, all 12 rows), HKDF-SHA512 / PBKDF2-HMAC-SHA512 (RFC 5869 construction anchored on TC1 + hashlib), RIPEMD-160 (official paper suite incl. million-a, + hashlib), AES-CCM (RFC 3610 Packet Vector #1 + pycryptodome), Ed25519ctx / Ed25519ph (RFC 8032 §7.2/§7.3 official vectors), GMAC (pycryptodome GCM) + incremental-vs-one-shot, keyed BLAKE2b/2s (hashlib keyed), Adler-32 (zlib), PBKDF2-HMAC-SHA1 (RFC 6070 official suite), ECDSA secp256k1 (Python ecdsa RFC 6979 + cryptography cross-verify, sk = 1 ⇒ pubkey = G anchor; low-S BIP-62 via sigencode_string_canonize), multi-hash RSA PKCS1-v1.5/PSS/OAEP (pycryptodome, SHA-1/384/512 exact + random-salt/seed interop; OAEP-SHA512 on a 2048-bit key), sealed-box round-trip + tamper, and property-based round-trip checks (deterministic PRNG) for every cipher + streaming-vs-one-shot consistency. 555 tests.

    #Development

    The CI (.github/workflows/moonbit-ci.yml) installs the latest MoonBit toolchain and runs the four required checks — moon check --deny-warn, moon fmt --check, moon info, moon test --deny-warn — and verifies that no build artifacts are tracked. Run them locally:

    moon check --deny-warn moon fmt --check moon info moon test --deny-warn moon bench # run the benchmark suite

    The module manifest is moon.mod (TOML); per-package manifests are moon.pkg (TOML). Build outputs (_build/, generated .mbti) are gitignored and must not be committed.

    #Publishing (maintainers)

    moon.mod declares name = "cc06b/mooncry", license Apache-2.0. Publishing requires the owner of the cc06b namespace to be logged in:

    moon login # one time, with the account that owns cc06b moon publish # publishes the current version

    Before publishing, ensure all four checks above pass and the tree is clean.

    #License

    Apache-2.0