Skip to content

vercingetorx/dilithium-nim

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

56 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

dilithium-nim — Pure Nim CRYSTALS-Dilithium (signatures)

A pure Nim port of the CRYSTALS-Dilithium digital signature scheme (post-quantum). Uses SHAKE (Keccak) and constant-time helpers implemented in Nim.

Dilithium lets you create a public key, sign messages with a secret key, and anyone can verify those signatures with the public key. It’s NIST-standardized.

Status

  • Implements the full signature API (keygen, sign, verify) for Dilithium2/3/5.
  • Passes the official NIST KAT (.rsp) vectors.
  • Supports both deterministic and randomized signing (compile-time toggle).
  • Optional context label (up to 255 bytes).

Sizes (by parameter set)

Set Public Key Secret Key Signature
Dilithium2 1312 B 2528 B 2420 B
Dilithium3 1952 B 4000 B 3293 B
Dilithium5 2592 B 4864 B 4595 B

Message size is unchanged by signing; only the signature is added.

Quick API

Simple, human-readable API (see dilithium.nim).

import dilithium  # exports: generateKeypair, signDetached, verifyDetached, signMessage, openSignedMessage

# 1) Make a key pair (uses OS randomness).
let (publicKey, secretKey) = generateKeypair()

# 2) Sign a message (detached signature).
let message = "Meet at 12:30 near the cafe."
let signature = signDetached(message, secretKey)   # optional label: signDetached(message, secretKey, "orders")

# 3) Verify the detached signature.
let ok = verifyDetached(signature, message, publicKey)
doAssert ok

# 4) Sign a message as a single blob (attached: signature stored before the message).
let signedBlob = signMessage(message, secretKey)   # optional label: signMessage(message, secretKey, "chat")

# 5) Verify and recover the original message from a signed blob.
let (valid, recovered) = openSignedMessage(signedBlob, publicKey)
doAssert valid

With a context label (optional)

Use a short label to keep signatures scoped to a feature in your app (e.g., "login", "invoice"). You must pass the same label to both sign and verify.

let label = "orders"
let sig = signDetached("Order #4821: ship today", secretKey, label)
let ok  = verifyDetached(sig, "Order #4821: ship today", publicKey, label)  # true
let no  = verifyDetached(sig, "Order #4821: ship today", publicKey, "WRONG")# false

Deterministic vs randomized signing

By default we follow the reference: randomized signing adds fresh randomness to each signature.

disable randomized signing at compile time:

# Deterministic signing (rnd = all zero bytes):
-d:nors or -d:norandsig

Enable it (default, can be omitted):

# Randomized signing (fresh randomness per signature):
-d:rs or -d:randsig

Selecting the parameter set

Default is Dilithium2. Choose at compile time:

-d:mode=2   # Dilithium2
-d:mode=3   # Dilithium3
-d:mode=5   # Dilithium5

Testing (KAT)

A lightweight KAT harness is included (parses NIST .rsp and checks pk/sk/sm):

# Example: point to the Dilithium2 vectors
KAT_RSP=/nistkat/PQCsignKAT_Dilithium2.rsp \
nim c -r -d:kat nistkat/test_kat_runner.nim

Tips:

  • Use KAT_LIMIT=N to run only the first N vectors while debugging.

RNG

  • Public API uses the OS RNG (e.g., /dev/urandom) for keygen and (if enabled) for randomized signing.
  • The KAT harness uses the same deterministic DRBG as the reference so results match the .rsp files.

Security notes

  • Constant-time primitives are used where required, but this code has not been audited.
  • Nim is GC’d; secret zeroization is not guaranteed. Be careful with long-lived secrets.

Layout

src/
  ntt.nim           # Number-theoretic transform and tables
  packing.nim       # (Un)packing of keys/signatures
  params.nim        # Parameter set & sizes; selected by DILITHIUM_MODE (2/3/5)
  poly.nim          # Polynomial ops
  polyvec.nim       # Vectors of polynomials
  randombytes.nim   # OS RNG for public API (e.g., /dev/urandom)
  reduce.nim        # Modular reduction helpers
  rounding.nim      # power2round, decompose, hints (make_hint/use_hint)
  sign.nim          # Keygen, sign, verify (public API)
  symmetric.nim     # SHAKE256 wrappers (XOF/PRF)
dilithium.nim       # high-level, friendly API
test/               # basic tests
nistkat/            # KAT tests
private/            # crypto backends

Note

This project is for reference/education. Do not use in production without an independent security review.

Releases

No releases published

Packages

No packages published

Languages