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-devand 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.
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.
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.
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.
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.
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).
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;
}
std.crypto re-exports CryptoError, box, errors, hash, password,
random, secretbox, sign, and secure_zero(out).
| Module | Item | Purpose |
|---|---|---|
crypto | secure_zero(out) | Wipe caller-owned byte storage. |
random | fill(out) | Fill caller-owned bytes with OS-backed randomness. |
random | uint32() | Return a random u32 throws(CryptoError). |
random | uniform(upper_bound) | Return a random u32 throws(CryptoError) below upper_bound. |
hash.blake2b | Digest, Key | Typed digest and keyed-hash key wrappers. |
hash.blake2b | sum(data) | Return a default-size Digest throws(CryptoError). |
hash.blake2b | sum_keyed(data, key) | Return a keyed Digest throws(CryptoError). |
hash.blake2b | sum_into(data, out) | Write a digest into caller storage. |
hash.blake2b | sum_keyed_into(data, key, out) | Write a keyed digest into caller storage. |
secretbox | Key, Nonce | Symmetric key and nonce wrappers. |
secretbox | seal(message, key) | Return `nonce |
secretbox | open(sealed, key) | Authenticate and decrypt sealed data. |
secretbox | seal_into, open_into | Explicit-nonce caller-owned buffer APIs. |
box | PublicKey, SecretKey, Seed, Nonce, KeyPair | Public-key box wrappers. |
box | seal(message, recipient, sender) | Return `nonce |
box | open(sealed, sender, recipient) | Authenticate and decrypt sealed data. |
box | seal_into, open_into | Explicit-nonce caller-owned buffer APIs. |
sign.ed25519 | PublicKey, SecretKey, Seed, Signature, KeyPair | Detached-signature wrappers. |
sign.ed25519 | sign(message, secret_key) | Return a detached Signature throws(CryptoError). |
sign.ed25519 | verify(message, signature, public_key) | Return whether a detached signature verifies. |
sign.ed25519 | sign_into(message, secret_key, out) | Write a detached signature into caller storage. |
password.argon2id | Profile, Salt | Password hashing profile and salt wrappers. |
password.argon2id | hash_password(password) | Return an Argon2id storage String throws(CryptoError | AllocError). |
password.argon2id | hash_password(password, profile) | Hash with an explicit profile. |
password.argon2id | verify(encoded, password) | Verify a storage string. |
password.argon2id | needs_rehash(encoded, profile) | Check whether a storage string should be upgraded. |
password.argon2id | derive_key_into(password, salt, profile, out) | Derive bytes into caller-owned storage. |
Crypto APIs report CryptoError.Init, CryptoError.Invalid,
CryptoError.Buffer, CryptoError.Auth, CryptoError.Random,
CryptoError.Resource, or allocation errors from owned-result helpers.