Crypto

Random bytes, BLAKE2b, secret boxes, public-key boxes, Ed25519, and Argon2id.

std.crypto exposes Zynx-owned cryptography modules backed by the runtime's pinned libsodium snapshot. Callers import Zynx modules and do not link -lsodium separately.

Warning

Zynx is 0.0.0-dev and unreleased. Treat this page as the current API inventory, not a production security endorsement, cryptographic audit, or ABI stability promise. Review the pinned runtime dependency and threat model before using these APIs for real secrets.

The current public modules are std.crypto.random, std.crypto.hash.blake2b, std.crypto.secretbox, std.crypto.box, std.crypto.sign.ed25519, and std.crypto.password.argon2id.

All byte inputs use bytes.Bytes, so callers can pass string literals, String, existing Bytes, and [u8] slices directly as call arguments. Typed wrappers expose wrapper.bytes() when their raw bytes must be borrowed. Secret-key wrappers zero their owned storage in drop.

Random

crypto.random provides OS-backed random bytes and integers.

import std.crypto.random;
import std.mem;

fn main() {
    let out = [0 as u8, 0 as u8, 0 as u8, 0 as u8];

    try random.fill(mem.slice_of<u8>(out.ptr, out.length));

    let value = try random.uint32();
    let below_ten = try random.uniform(10 as u32);

    assert below_ten < 10 as u32;
    _ = value;
}

The integer helper is named uint32() because u32 is a reserved type token.

BLAKE2b

crypto.hash.blake2b provides typed Digest and Key wrappers, one-shot hashing, keyed hashing, and caller-owned output variants.

import std.crypto.hash.blake2b;

fn main() {
    let digest = try blake2b.sum("abc");
    let view = digest.bytes();

    assert view.length == blake2b.bytes;
}

Use blake2b.Key.random() or blake2b.Key(data) for keyed hashing:

let key = try blake2b.Key.random();
let digest = try blake2b.sum_keyed("message", &key);

sum_into(data, out) and sum_keyed_into(data, key, out) write into caller-owned output buffers and return the byte count written.

Secretbox

crypto.secretbox provides symmetric authenticated encryption with typed Key and Nonce wrappers. The high-level seal(message, key) helper creates a fresh nonce and returns nonce || mac || ciphertext.

import std.bytes;
import std.crypto.secretbox;

fn main() {
    let key = try secretbox.Key.random();
    let sealed = try secretbox.seal("hidden", &key);
    let opened = try secretbox.open(bytes.Bytes(sealed.slice()), &key);

    assert opened.length == 6;
}

Use seal_into(message, key, nonce, out) and open_into(ciphertext, key, nonce, out) when the nonce and destination storage are managed by the caller. These _into forms do not prepend the nonce; keep the nonce beside the ciphertext.

Public-Key Box

crypto.box provides public-key authenticated encryption. KeyPair.random() creates a public/secret keypair, and KeyPair(seed) creates a deterministic pair from a typed seed.

The high-level seal(message, recipient_public, sender_secret) helper creates a fresh nonce and returns nonce || mac || ciphertext.

import std.bytes;
import std.crypto.box;

fn main() {
    let alice = try box.KeyPair.random();
    let bob = try box.KeyPair.random();

    let sealed = try box.seal("hello", &bob.public, &alice.secret);
    let opened = try box.open(bytes.Bytes(sealed.slice()), &alice.public, &bob.secret);

    assert opened.length == 5;
}

Use box.seal_into(message, recipient, sender, nonce, out) and box.open_into(ciphertext, sender, recipient, nonce, out) when the nonce and buffers are explicit.

Ed25519

crypto.sign.ed25519 exposes detached signatures. Combined signed-message helpers are not part of the current API.

import std.crypto.sign.ed25519;

fn main() {
    let keys = try ed25519.KeyPair.random();
    let signature = try ed25519.sign("message", &keys.secret);

    assert ed25519.verify("message", &signature, &keys.public);
    assert !ed25519.verify("changed", &signature, &keys.public);
}

sign_into(message, secret_key, out) writes a detached signature into caller-owned storage. Public keys, secret keys, seeds, and signatures can also be reconstructed from exact-length byte inputs with their constructors, such as ed25519.Seed(data) or ed25519.Signature(data).

Argon2id

crypto.password.argon2id provides Argon2id13 password storage strings, verification, rehash checks, and deterministic key derivation. Password inputs are bytes.Bytes, so embedded NUL bytes are valid.

import std.crypto.password.argon2id;

fn main() {
    let encoded = try argon2id.hash_password("password");

    assert try argon2id.verify(encoded.str(), "password");
    assert !(try argon2id.verify(encoded.str(), "wrong"));
    assert !(try argon2id.needs_rehash(encoded.str(),
                                       argon2id.Profile.Interactive));
}

Profiles are Interactive, Moderate, and Sensitive. Pass a profile to hash_password(password, profile) or needs_rehash(encoded, profile).

Use derive_key_into(password, salt, profile, out) for deterministic key derivation:

import std.crypto.password.argon2id;
import std.mem;

fn main() {
    let salt = try argon2id.Salt.random();
    let key = [0 as u8, 0 as u8, 0 as u8, 0 as u8,
               0 as u8, 0 as u8, 0 as u8, 0 as u8,
               0 as u8, 0 as u8, 0 as u8, 0 as u8,
               0 as u8, 0 as u8, 0 as u8, 0 as u8];

    let n = try argon2id.derive_key_into(
        "password",
        &salt,
        argon2id.Profile.Interactive,
        mem.slice_of<u8>(key.ptr, key.length));

    assert n == key.length;
}

API Reference

std.crypto re-exports CryptoError, box, errors, hash, password, random, secretbox, sign, and secure_zero(out).

ModuleItemPurpose
cryptosecure_zero(out)Wipe caller-owned byte storage.
randomfill(out)Fill caller-owned bytes with OS-backed randomness.
randomuint32()Return a random u32 throws(CryptoError).
randomuniform(upper_bound)Return a random u32 throws(CryptoError) below upper_bound.
hash.blake2bDigest, KeyTyped digest and keyed-hash key wrappers.
hash.blake2bsum(data)Return a default-size Digest throws(CryptoError).
hash.blake2bsum_keyed(data, key)Return a keyed Digest throws(CryptoError).
hash.blake2bsum_into(data, out)Write a digest into caller storage.
hash.blake2bsum_keyed_into(data, key, out)Write a keyed digest into caller storage.
secretboxKey, NonceSymmetric key and nonce wrappers.
secretboxseal(message, key)Return `nonce
secretboxopen(sealed, key)Authenticate and decrypt sealed data.
secretboxseal_into, open_intoExplicit-nonce caller-owned buffer APIs.
boxPublicKey, SecretKey, Seed, Nonce, KeyPairPublic-key box wrappers.
boxseal(message, recipient, sender)Return `nonce
boxopen(sealed, sender, recipient)Authenticate and decrypt sealed data.
boxseal_into, open_intoExplicit-nonce caller-owned buffer APIs.
sign.ed25519PublicKey, SecretKey, Seed, Signature, KeyPairDetached-signature wrappers.
sign.ed25519sign(message, secret_key)Return a detached Signature throws(CryptoError).
sign.ed25519verify(message, signature, public_key)Return whether a detached signature verifies.
sign.ed25519sign_into(message, secret_key, out)Write a detached signature into caller storage.
password.argon2idProfile, SaltPassword hashing profile and salt wrappers.
password.argon2idhash_password(password)Return an Argon2id storage String throws(CryptoError | AllocError).
password.argon2idhash_password(password, profile)Hash with an explicit profile.
password.argon2idverify(encoded, password)Verify a storage string.
password.argon2idneeds_rehash(encoded, profile)Check whether a storage string should be upgraded.
password.argon2idderive_key_into(password, salt, profile, out)Derive bytes into caller-owned storage.

Errors

Crypto APIs report CryptoError.Init, CryptoError.Invalid, CryptoError.Buffer, CryptoError.Auth, CryptoError.Random, CryptoError.Resource, or allocation errors from owned-result helpers.