NoNoncense - generate globally unique nonces in distributed Elixir

Generate globally unique nonces (number-only-used-once) in distributed Elixir. These nonces are used to form the basis of an upcoming GUID generation package unique ID package Once, or in crypto operations that require nonces.

The nonces come in multiple types:

  • counter nonces that are unique but predictable and can be generated incredibly quickly
  • sortable nonces (Snowflake IDs) that have an accurate creation timestamp in their first bits
  • encrypted nonces that are not just unique but also unpredictable

The nonces are guaranteed to be unique if:

  • machine IDs are unique for each node
  • individual machines maintain a somewhat accurate clock (specifically, the UTC clock has to have progressed between node restarts)

To aid with the unique machine IDs, NoNoncense.MachineId and its subsidiary conflict-detecting genserver NoNoncense.MachineId.ConflictGuard can be used. ConflictGuard requires connected nodes to function, but is an optional extra and the entire thing can also work without it.

It’s possible to use the nonces for cryptographic purposes like cipher IVs and generating Poly1305 one-time-keys. For usecases where a nonce is required that is not just unique but unpredictable, there is a uniqueness-preserving encrypted-nonce option. However, caveats apply, with 96-bits nonces in particular, you should read the NoNoncense module docs.

Last but not least, performance is great thanks to the use of Erlang primitives :persistent_term and :atomics. Plaintext nonces can be generated at rates of tens of millions of nonces per second :slight_smile:

Package: no_noncense | Hex
Docs: NoNoncense v1.0.1 — Documentation

7 Likes

The related Ecto type has arrived!

1 Like

v0.0.3 is out!

  • sortable nonces (Snowflake IDs) added
  • improves 96-bits encrypted nonces so that they don’t leak message counter info
  • shorter, clearer docs

After NoNoncense 0.x took the Elixir world by storm, ushering in a new generation of ID generation, one can barely imagine the feverish excitement of the wider ecosystem in the buildup to its 1.0 release. On this fine Christmas Day morning, the long wait is finally over.

NoNoncense 1.0 features:

  • Redesigned encrypted nonce API, the key is now passed to init/1
  • Derives keys appropriate for each supported cipher from one base key
  • Huge performance improvement for encrypted nonces because key expansion is moved to init/1, for example 128 bits nonces improved from 2.8M ops/s to 9M on one core
  • Fully encrypted 96-bits nonces are now possible thanks to the optional Speck cipher support using optional dep SpeckEx, because it has a variant with a block size of 96 bits
  • Blowfish replaces 3DES as the default cipher for 64/96 bits nonces (AES is still the default for 128 bits)
  • Backwards compatible using the migration guide (in the following sense: although code changes are required, 0.0.x encrypted nonces keep their uniqueness guarantee)

The performance increase with the OTP ciphers is realized by caching the key expansion result, a.k.a. crypto_init reference. That also allows Blowfish to (vastly) outperform 3DES, which is why it is the new default cipher. More details on nonce encryption, including why Speck is a nice upgrade for 96 bits nonces, can be found in the Hex docs.

2 Likes