High-Level Crypto

The high-level crypto layer is intended to cover the most common application tasks with APIs that already make the important design choices for you.

Instead of asking you to pick from a menu of primitives, it tries to answer workflow-level questions directly:

What "High-Level" Means Here

In Eryx, "high-level" does not mean "toy" or "less capable". It means the API owns more of the security-sensitive decisions:

That is the part most applications benefit from. The more of that an API can do for you, the fewer opportunities there are to make a subtle mistake.

Password Hashing

Use @eryx/crypto/password for stored passwords.

This module currently uses Argon2id under the hood and returns a tagged string format suitable for storing in a database.

local password = require("@eryx/crypto/password")

local stored = password.hash("hunter2")

if password.verify("hunter2", stored) then
	print("accepted")
end

Why use this instead of Argon2 directly:

If you are authenticating humans, this is the right default.

Secretbox-Style Encryption

Use @eryx/crypto/secretbox when you want to encrypt data with a symmetric shared secret and you want authentication as well as confidentiality.

This module currently uses ChaCha20-Poly1305 underneath and serializes a self-contained ciphertext format:

local secretbox = require("@eryx/crypto/secretbox")

local ciphertext, key = secretbox.seal(buffer.fromstring("top secret"))
local opened = secretbox.open(ciphertext, key)

assert(buffer.tostring(opened) == "top secret")

Why use this instead of calling the AEAD primitive directly:

This is the right API when your application simply needs to seal and later open data using a shared key.

Hashing

The high-level crypto surface also includes digest helpers for ordinary application use via @eryx/crypto/hash.

These are intended for cases like:

local hash = require("@eryx/crypto/hash")

local digest = hash.digest(buffer.fromstring("hello"))

assert(hash.verify(buffer.fromstring("hello"), digest))

The specific underlying algorithm is intentionally hidden behind the API. The digest value is tagged so stored values can remain self-describing if the implementation choice changes later.

Important caveat: plain hashing does not authenticate who produced the data. If an attacker can modify the message, use HMAC or authenticated encryption instead.

HMAC

The high-level crypto surface also includes keyed message authentication via @eryx/crypto/hmac.

Use HMAC when:

local hmac = require("@eryx/crypto/hmac")

local mac = hmac.digest(
	buffer.fromstring("shared-secret"),
	buffer.fromstring("message")
)

assert(hmac.verify(
	buffer.fromstring("shared-secret"),
	buffer.fromstring("message"),
	mac
))

The concrete HMAC algorithm is intentionally hidden from callers. Like the digest API, the returned value is tagged for forward compatibility.

When To Drop Down To Hazmat

Use the high-level layer unless you specifically need one of these:

That is when the hazmat layer becomes the right tool.