- Salsa20: round-reduced variants can now be used.
- The POLYVAL universal hash function was added.
- AEGIS: support for 256-bit tags was added.
- A MAC API was added to AEGIS (
std.crypto.auth.aegis
) - AEGIS can be used as a high-performance MAC on systems with hardware AES support. Note that this is not a hash function; a secret key is absolutely required in order to authenticate untrusted messages. - Edwards25519: a
rejectLowOrder()
function was added to quickly reject low-order points. - HKDF: with
extractInit()
, a PRK can now be initialized with only a salt, the keying material being added later, possibly as multiple chunks. - Hash functions that returns a fixed-length digest now include a
finalResult()
function that returns the digest as an array, as well as apeek()
function that returns it without changing the state. - AES-CMAC has been implemented, and is availble in
crypto.auth.cmac
. std.crypto.ecc
: theisOdd()
function was added to return the parity of a field element.bcrypt
: bcrypt has a slightly annoying limitation: passwords are limited to 72 bytes, and additional bytes are silently ignored. A new option,silently_truncate_password
, can be set totrue
to transparently pre-hash the passwords and overcome this limitation.
- A HMAC key size can have any length, and
crypto.Hmac*.key_size
was previously set to 256 bits for general guidance. This has been changed to match the actual security level of each function. secp256k1
: themulPublic()
andverify()
functions can now return aNonCanonicalError
in addition to existing errors.Ed25519
: the top-levelEd25519.sign()
,Ed25519.verify()
,key_blinding.sign()
andkey_blinding.unblindPublicKey()
functions, that were already deprecated in version 0.10.0, have been removed. For consistency with other signature schemes, these functions have been moved to theKeyPair
,PublicKey
,BlindKeyPair
andBlindPublicKey
structures.
The Keccak permutation was only used internally for sha3
. It was completely revamped and has now its dedicated public interface in crypto.core.keccak
.
keccak.KeccakF
is the permutation itself, which now supports sizes between 200 and 1600 bits, as well as a configurable number of rounds. And keccak.State
offers an API for standard sponge-based constructions.
Taking advantage of this, the SHAKE extendable output function (XOF) has been added, and can be found in std.crypto.hash.sha3.Shake128
and std.crypto.hash.sha3.Sha256
. SHAKE is based on SHA-3, NIST-approved, and the output of can be of any length, which has many applications and is something we were missing in the standard library.
The more recent TurboSHAKE variant is also available, as crypto.hash.sha3.TurboShake128
and crypto.hash.sha3.TurboShake256
. TurboSHAKE benefits from the extensive analysis of SHA-3, its output can also be of any length, and it has good performance across all platforms. In fact, on CPUs without SHA-256 acceleration, and when using WebAssembly, TurboSHAKE is the fastest function we have in the standard library. If you need a modern, portable, secure, overall fast hash function / XOF, that is not vulnerable to length-extension attacks (unlike SHA-256), TurboSHAKE should be your go-to choice.
Kyber is a post-quantum public key encryption and key exchange machanism. It was selected by NIST for the first post-quantum cryptography standard.
It is available in the standard library, in the std.crypto.kem
namespace, making Zig the first language with post-quantum cryptography available right in the standard library.
Kyber512
, Kyber768
and Kyber1024
, as specified in the current draft, are supported.
The TLS client (std.crypto.tls.Client
) also supports the hybrid X25519Kyber768
post-quantum key agreement mechanism by default.
Thanks a lot to Bas Westerbaan for contributing this!
Cryptography frequently requires computations over arbitrary finite fields.
This is why a new namespace made its appearance: std.crypto.ff
.
Functions from this namespace never require dynamic allocations, are designed to run in constant time, and transparently perform conversions from/to the Montgomery domain.
This allowed us to implement RSA verification without using any allocators.
Side channels in cryptographic code can be exploited to leak secrets.
And mitigations are useful but also come with a performance hit.
For some applications, performance is critical, and side channels may not be part of the threat model. For other applications, hardware-based attacks is a concern, and mitigations should go beyond constant-time code.
Zig 0.11 introduces the std_options.side_channels_mitigations
global setting to accomodate the different use cases.
It can have 4 different values:
-
none
: which doesn't enable additional mitigations. "Additional", because it only disables mitigations that don't have a big performance cost. For example, checking authentication tags will still be done in constant time. -
basic
: which enables mitigations protecting against attacks in a common scenario, where an attacker doesn't have physical access to the device, cannot run arbitrary code on the same thread, and cannot conduct brute-force attacks without being throttled. -
medium
: which enables additional mitigations, targeting protection against practictal attacks even in a shared environement. -
full
: which enables all the available mitigations, going beyond ensuring that the code runs in constant time.
The more mitigations are enabled, the bigger the performance hit will be. But this let applications choose what's best for their use case.
medium
is the default.
Gimli and Xoodoo have been removed from the standard library, in favor of Ascon.
These are great permutations, and there's nothing wrong with them from a practical security perspective.
However, both were competing in the NIST lightweight crypto competition.
Gimli didn't pass the 3rd selection round, and was not used much in the wild besides Zig and libhydrogen. It will never be standardized and is unlikely to get more traction in the future.
The Xoodyak mode, that Xoodoo is the permutation of, brought some really nice ideas. There are discusisons to standardize a Xoodyak-like mode, but without Xoodoo.
So, the Zig implementations of these permutations are better maintained outside the standard library.
For lightweight crypto, Ascon is the one that we know NIST will standardize and that we can safely rely on from a usage perspective.
So, Ascon was added instead (in crypto.core.Ascon
). We support the 128
and 128a
variants, both with Little-Endian or Big-Endian encoding.
Note that we currently only ship the permutation itself, as the actual constructions are very likely to change a lot during the ongoing standardization process.
The default CSPRNG (std.rand.DefaultCsprng
) used to be based on Xoodoo. It was replaced by a traditional ChaCha-based random number generator, that also improves performance on most platforms.
For constrained environments, std.rand.Ascon
is also available as an alternative. As the name suggest, it's based on Ascon, and has very low memory requirements.
- HKDF: expansion to
<hash size> * 255
bytes not an error any more. - Curve25519: when compiled to WebAssembly, scalar multiplication emitted too many local variables for some runtimes. This has been fixed. The code is also significantly smaller in
ReleaseSmall
mode. - Prime-order curves: points whose X coordinate was
0
used to be rejected with anIdentityElement
error. These points were also not properly serialized. That has been fixed. - Argon2: outputs larger than 64 bytes are now correctly handled.
- GHASH was reimplemented and is now ~3x faster.
- AES encryption now takes advantage of the
EOR3
instruction on Apple Silicon for a slight performance boost. - The ChaCha20 implementation can now take advantage of CPUs with 256 and 512 bit vector registers for a significant speedup.
- Poly1305 got a little bit faster, too.
- SHA256 can take advantage of hardware acceleration on x86_64 and aarch64.