# Accumulated ML-DSA tests

This file provides [accumulated](https://words.filippo.io/accumulated/) random
ML-DSA key generation and signature tests at various iteration counts, and
accumulated exhaustive tests for various field operations.

## Key generation and signature tests

The vectors are generated by reading seeds from one instance of SHAKE128, and
writing the derived public key and the deterministic signature of an empty
message to another instance of SHAKE128.

```
s = SHAKE128()
a = SHAKE128()
for i in range(N):
    seed = read(s, 32)
    public_key = keygen(seed)
    write(a, public_key)
    signature = sign_deterministic(seed, message="", context="")
    write(a, signature)
    if not verify(public_key, signature): error
result = read(a, 32)
```

This allows running a number of known-answer tests that would be impractical if
the results had to be stored in full.

In particular, the 60 million iteration test has a 99.9% chance of hitting any
value in [0, q). Storing that many vectors would require between 225 GB
(ML-DSA-44) and 435 GB (ML-DSA-87).

100 iterations is suitable for rapid interactive tests. 10 000 iterations are
suitable for CI. 60 000 000 iterations are suitable for development.

Using fixed message, context, and signature randomness leads to the same μ for
every test, but doesn't reduce coverage because μ is only hashed with either
the secret key's random K, or w1 which is derived from the random matrix A.

### ML-DSA-44

- 100 iterations: `d51148e1f9f4fa1a723a6cf42e25f2a99eb5c1b378b3d2dbbd561b1203beeae4`
- 10 000 iterations: `e7fd21f6a59bcba60d65adc44404bb29a7c00e5d8d3ec06a732c00a306a7d143`
- 60 000 000 iterations: `080b48049257f5cd30dee17d6aa393d6c42fe52a29099df84a460ebaf4b02330`

### ML-DSA-65

- 100 iterations: `8358a1843220194417cadbc2651295cd8fc65125b5a5c1a239a16dc8b57ca199`
- 10 000 iterations: `5ff5e196f0b830c3b10a9eb5358e7c98a3a20136cb677f3ae3b90175c3ace329`
- 60 000 000 iterations: `0af0165db2b180f7a83dbecad1ccb758b9c2d834b7f801fc49dd572a9d4b1e83`

### ML-DSA-87

- 100 iterations: `8c3ad714777622b8f21ce31bb35f71394f23bc0fcf3c78ace5d608990f3b061b`
- 10 000 iterations: `80a8cf39317f7d0be0e24972c51ac152bd2a3e09bc0c32ce29dd82c4e7385e60`
- 60 000 000 iterations: `011166e9d5032c9bdc5c9bbb5dbb6c86df1c3d9bf3570b65ebae942dd9830057`

## Field operation tests

The vector is generated by writing to a SHAKE128 instance the following
12 values, as ASCII decimals with an optional leading `-` sign (if negative),
one per line, for each element r in ℤq from 0 to q - 1:

  - r mod± q
  - ‖r‖∞ = |r mod± q|
  - r1, r0 = Power2Round(r)
      - r1
      - r0 mod q

For ML-DSA-44 (γ₂ = (q - 1) / 88):
  - HighBits(r) = UseHint(0, r)
  - UseHint(1, r)
  - LowBits(r)
  - ‖LowBits(r)‖∞ = |LowBits(r)|

For ML-DSA-65 and ML-DSA-87 (γ₂ = (q - 1) / 32):
  - HighBits(r) = UseHint(0, r)
  - UseHint(1, r)
  - LowBits(r)
  - ‖LowBits(r)‖∞ = |LowBits(r)|

Note that HighBits(r), LowBits(r) = Decompose(r), so Decompose(r) can be tested
by checking its otuputs match those of HighBits(r) and LowBits(r). Similarly,
UseHint(0, r) can be tested by checking it matches HighBits(r).

```
f930663417278156ab05d940294a77210a809c924d8ab63ec72f4526247602c7
```

See [mldsa-py@4c650a4][mldsa-py-test] and [CL 762940][go-cl-762940] for examples of how to use this vector.

[mldsa-py-test]: https://github.com/FiloSottile/mldsa-py/commit/4c650a4a9db751a179cf2ec57d5fe01f2bee191c
[go-cl-762940]: https://go.dev/cl/762940

For r = 6 010 000, the 12 lines to be hashed are:

```
-2370417
2370417
734
8377489
32
31
-84848
84848
11
12
248464
248464
```
