npm package: @kirkelliott/kdfts
Description: Quantum-seeded KDF — Argon2id with salt from ANU vacuum fluctuations
Latest version: 2.0.1

# kdfts

[![CI](https://github.com/dmvjs/kdfts/actions/workflows/ci.yml/badge.svg)](https://github.com/dmvjs/kdfts/actions/workflows/ci.yml)
[![license](https://img.shields.io/github/license/dmvjs/kdfts)](LICENSE)

Argon2id KDF with optional quantum-backed salt provenance. Salt is sourced from the [ANU Quantum Random Number Generator](https://quantumnumbers.anu.edu.au) (photon shot noise at a beam splitter) when available, with `strict` mode for deployments where that provenance is required. Falls back to `crypto.getRandomValues()` otherwise.

Standard CSPRNGs already satisfy OWASP's salt requirements. The ANU source adds auditable entropy provenance — useful for compliance workflows or systems that need to document their randomness chain, not a substitute for strong KDF parameters.

## Install

```bash
npm install @kirkelliott/kdfts
```

Get a free ANU API key at [quantumnumbers.anu.edu.au](https://quantumnumbers.anu.edu.au):

```bash
export ANU_API_KEY=your-key-here
```

## Usage

**Derive and persist:**

```ts
import { derive, formatCert } from '@kirkelliott/kdfts'

const { hash, certificate } = await derive('my-password', {
  context: 'myapp:user42:session',  // domain separation — optional but recommended
})

// Persist this single string — it contains everything needed to verify later
await db.users.update({ passwordHash: hash })

console.log(formatCert(certificate))
// ════════════════════════════════════════════════════
//   kdfts Key Certificate
// ════════════════════════════════════════════════════
//   Source:        ANU Quantum Vacuum (photon shot noise)
//   Timestamp:     2026-03-07T04:00:00.000Z
//   KDF:           argon2id
//   t / m / p:     3 / 65536 / 4
//   Key length:    32 bytes (256 bits)
//   Salt bytes:    32 bytes (256 bits)
//   Context:       myapp:user42:session
//
//   Salt hash:     7bcaf7d45ef1191f9d72556b5f7f6e17...
//   Key hash:      f0d6b878bb864d5261d5ccd05353bfc1...
// ════════════════════════════════════════════════════
```

**Verify later:**

```ts
import { verify } from '@kirkelliott/kdfts'

const valid = await verify('my-password', storedHash)
// Parameters, salt, and context are all read from the hash string.
```

**Reuse a source across multiple derivations** (saves one ANU round-trip):

```ts
import { QuantumSource, derive } from '@kirkelliott/kdfts'

const source = await QuantumSource.create()
console.log(source.source)  // 'anu' | 'crypto'

const [keyA, keyB] = await Promise.all([
  derive(passwordA, { source }),
  derive(passwordB, { source }),
])
```

## Options

| Option | Type | Default | Description |
|---|---|---|---|
| `context` | `string` | — | Domain separation string, passed as Argon2id `associatedData`. Embedded in the hash — no need to pass to `verify()`. |
| `saltBytes` | `number` | `32` | Bytes of quantum entropy to fetch. |
| `keyLength` | `number` | `32` | Output key length in bytes. |
| `cost` | `{ timeCost, memoryCost, parallelism }` | `{ timeCost: 3, memoryCost: 65536, parallelism: 4 }` | Argon2id parameters. `memoryCost` is in KiB. Embedded in the hash — no need to track separately. |
| `strict` | `boolean` | `false` | Throw if the ANU source is unavailable instead of falling back to `crypto.getRandomValues()`. |
| `source` | `QuantumSource` | — | Pre-created source for reuse or testing. |

## Security notes

- Salt is fetched fresh for every `derive` call — never reused
- Context is passed as Argon2id `associatedData` and embedded in the hash — `verify()` reads it automatically
- Verification uses `crypto.timingSafeEqual` — no timing oracle on key comparison
- Argon2id defaults (`timeCost=3, memoryCost=65536, parallelism=4`) exceed [OWASP minimum recommendations](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html)
- The certificate records only SHA-256 hashes of the salt and key, never the raw values
- Every claim in this README is validated by the [test suite](https://github.com/dmvjs/kdfts/actions/workflows/ci.yml)

## License

MIT © Kirk Elliott