Security

No independent audit. This library has not been reviewed by anyone outside the project, and it is not a FIPS-validated or NIST-validated cryptographic module. It passes 4,228 official known-answer vectors, which is evidence that it computes the right function — and nothing more than that. Conformance is not review.

What is and is not claimed

The honest summary
PropertyStatus
Conformance to final SP 800-232Tested against the complete official vector corpus.
Compatibility with Ascon v1.2None, deliberately. Different algorithms.
Independent cryptographic auditNot done.
FIPS or NIST validationNot a validated module.
Constant-time tag comparisonFull-scan comparison in the source; no guarantee about generated code.
Constant-time overallNot claimed. See below.
Zeroization of key materialNot possible to guarantee under the OCaml GC.
Nonce misuse resistanceNone. Ascon-AEAD128 has none by design.

Nonce discipline is the caller's job

Reusing a nonce with the same Ascon-AEAD128 key breaks the scheme. It is not a weakening that costs you some security margin; it is a failure of the construction's stated requirement. The library validates that a nonce is 16 bytes and can do nothing else about it: it has no state across calls and cannot detect reuse.

A counter that is persisted before use, or a random nonce from a cryptographic source with a documented rekey bound, are the usual answers. Whichever you pick, that choice is a property of your protocol, not of this code.

Timing behaviour

Authentication tags are compared with a dedicated routine that scans every byte and has no content-dependent early exit. Bytes.equal is never used on a tag. The permutation itself is written with bitwise and shift operations on fixed-width Int64 values, with no secret-dependent branches or table lookups.

That is the source-level story, and it is where the claim stops. No formal constant-time guarantee is made for the generated code, for the OCaml compiler that produced it, or for the runtime it executes on. Establishing one would require inspecting native output on every target compiler, which has not been done. If your threat model includes a local timing adversary, this library has not been shown to be adequate for it.

Secrets in the OCaml heap

OCaml heap data cannot be reliably zeroized. The garbage collector is free to copy a value during a minor collection or a compaction, and the original bytes stay wherever they were until something else overwrites them. Keys, plaintext, and intermediate sponge state are all ordinary heap values and all subject to this.

What the library does do: a rejected candidate plaintext is overwritten with zeros before it is dropped. Treat that as tidiness rather than a guarantee — the collector may already have copied it elsewhere. Keys and nonces are copied into abstract, length-validated values on construction, so a caller mutating the original buffer afterwards cannot change what a cipher operation uses.

Failures are values

Ordinary authentication failure returns Error `Authentication_failure. It is never raised as an exception, so a forgery cannot travel up a call stack disguised as a programming error, and a handler cannot swallow it by accident along with unrelated failures. Decryption computes the whole candidate plaintext, verifies the full 128-bit tag, and only then returns anything.

Do not report to a peer which error occurred. The distinction between a malformed record and a failed tag is useful in your logs and useless to an attacker only as long as it stays there.

What the implementation self-review covered

SECURITY_REVIEW.md records a focused self-review against the standard. It is not an audit; it is a checklist of the things that most often go wrong in a from-scratch implementation, with the answer recorded for each.

Representation
Every external word is loaded and stored byte by byte in explicit little-endian order. There are no host-endian casts and no big-endian compatibility path, which is what keeps the v1.2 confusion from being possible at all.
Permutation constants
The round-constant schedule is f0 e1 d2 c3 b4 a5 96 87 78 69 5a 4b, XORed into the low byte of S2, with p[8] starting at b4. Diffusion rotations are (19, 28), (61, 39), (1, 6), (10, 17) and (7, 41). Zero-state p[8] and p[12] outputs were taken from the official C reference, and NIST Appendix B's three precomputed initialization states are checked too.
Padding and domain separation
Byte-aligned padding XORs 0x01 at the first unused byte, and a message ending exactly on a rate boundary gets its own empty padded block. AEAD applies the domain-separation bit after the associated-data phase including when that data is empty.
The AEAD tail
Encryption emits only the occupied rate bytes before padding. Decryption replaces only the received low bytes in the state and preserves the rest — the place a from-scratch implementation is most likely to be subtly wrong.
Lengths
One-shot XOF and CXOF lengths are validated before allocation. Combined AEAD allocation checks for addition overflow. Key, nonce and tag lengths are exact.

What still needs human attention

The same document is explicit about what a reviewer should not take on trust:

  1. Compare the bitsliced S-box and rotations directly against Section 3 of the final standard, and inspect native code on each intended compiler.
  2. Re-check the AEAD last-block state replacement for every tail length from 0 to 15.
  3. Review compiler output and runtime behaviour before making any stronger timing statement than the one above.
  4. Assess allocation volume, GC behaviour, and secret lifetime for each target deployment.
  5. Re-run the vectors and the differential harness from a clean checkout against a separately obtained official reference.
  6. Add a real 32-bit runtime CI job. The code is written for one; the current hosted matrix does not exercise it.

Reporting a vulnerability

Please do not open a public issue for a suspected vulnerability. Use the repository's private advisory form.

Include the affected version or commit, a minimal reproducer where possible, the expected impact, and whether disclosure is time-sensitive. Receipt should be acknowledged within seven days.

Until the first stable release, security fixes are made on main. After it, the latest minor release line receives them. The full policy is in SECURITY.md.