npm package: @maatara/core-pqc
Description: Ma'atara Post-Quantum Cryptography Toolkit for Browser and Node.js
Author: Ma'atara
Latest version: 0.5.1

# Ma'atara Core PQC Toolkit
A portable, audited Post-Quantum Cryptography toolkit for browser and Node.js environments.

## Features
# Ma'atara Core PQC Toolkit

A portable, audited Post-Quantum Cryptography toolkit for browser and Node.js. Includes deterministic helpers for governance multisig and NFT/art token flows.

## Features

- Kyber ML-KEM-768 (key encapsulation)
- Dilithium2 (sign/verify)
- HKDF-SHA256 (key derivation)
- AES-256-GCM (AEAD)
- Base64url helpers and constant‑time compare
- Deterministic preimage builders (JCS) for governance, mint, transfer, and anchor
- Royalty validation and multisig attestation verification

## Install

```bash
npm install @maatara/core-pqc
```

Initialize WASM once on startup:

```ts
import { initWasm } from '@maatara/core-pqc';
await initWasm();
```

## Core PQC usage

```ts
import {
	kyberKeygen, kyberEncaps, kyberDecaps,
	dilithiumKeygen, dilithiumSign, dilithiumVerify,
	hkdfSha256, aesGcmWrap, aesGcmUnwrap, b64uEncode
} from '@maatara/core-pqc';

await initWasm();

// Kyber
const { public_b64u, secret_b64u } = await kyberKeygen();
const { kem_ct_b64u, shared_b64u } = await kyberEncaps(public_b64u);
const { shared_b64u: shared2 } = await kyberDecaps(secret_b64u, kem_ct_b64u);

// Dilithium
const signKeys = await dilithiumKeygen();
const msg = b64uEncode(new TextEncoder().encode('hello pqc'));
const sig = await dilithiumSign(msg, signKeys.secret_b64u);
const ok = await dilithiumVerify(msg, sig.signature_b64u, signKeys.public_b64u);
```

## Deterministic helpers (multisig and NFT)

All helpers return canonical JSON and a base64url message suitable for signing with Dilithium2.

```ts
import {
	jcsCanonicalize,
	buildPolicyPreimage,
	buildMintPreimage,
	buildTransferPreimage,
	buildAnchorPreimage,
	validateRoyalty,
	verifyAttestations,
	dilithiumSign
} from '@maatara/core-pqc';

// 1) Governance policy (multisig)
const policy = { version: 'v1', threshold: 2, signers: [{ id: 'a', publicKeyB64u: '...' }, { id: 'b', publicKeyB64u: '...' }] };
const { canonical: govCanon, msg_b64u: govMsg } = await buildPolicyPreimage(policy);
const att = await dilithiumSign(govMsg!, signerSecret);

// 2) Mint preimage (royalty optional)
const header = { createdAt: Date.now(), royalty: { receiver: '0xabc...', bps: 500 } };
const asset = { id: 'uuid', sha256: '...', mediaType: 'image/png' };
if (!await validateRoyalty(header.royalty.receiver, header.royalty.bps)) throw new Error('Bad royalty');
const { msg_b64u: mintMsg } = await buildMintPreimage(header, asset);
const mintSig = await dilithiumSign(mintMsg!, signerSecret);

// 3) Transfer preimage
const { msg_b64u: xferMsg } = await buildTransferPreimage({ assetId: 'uuid', to: 'did:key:...' });
const xferSig = await dilithiumSign(xferMsg!, signerSecret);

// 4) Anchor preimage (Merkle root + chains)
const { msg_b64u: anchorMsg } = await buildAnchorPreimage('user-123', 'deadbeef...', '2025-01', { apf: ['root1','root2'] });

// Verify a set of governance attestations for a canonical message
const validCount = await verifyAttestations(govMsg!, [
	{ alg: 'dilithium2', publicKeyB64u: signerPub1, signatureB64u: sig1.signature_b64u },
	{ alg: 'dilithium2', publicKeyB64u: signerPub2, signatureB64u: sig2.signature_b64u }
], [signerPub1, signerPub2]);
```

## Notes app integration (independent repo)

Use the deterministic helpers to prepare messages client‑side, sign, and POST to the Core Worker endpoints.

```ts
import {
	initWasm,
	buildMintPreimage,
	dilithiumSign,
	verifyAttestations
} from '@maatara/core-pqc';

await initWasm();

// Build preimage and sign
const { msg_b64u } = await buildMintPreimage(header, asset);
const sig = await dilithiumSign(msg_b64u!, userSecret_b64u);
const attestation = { alg: 'dilithium2', publicKeyB64u: userPublic_b64u, signatureB64u: sig.signature_b64u };

// Optionally validate locally before submit
const valid = await verifyAttestations(msg_b64u!, [attestation], [userPublic_b64u]);
if (!valid) throw new Error('Attestation failed');

// Submit to Core
await fetch(`${CORE_URL}/api/assets/mint`, {
	method: 'POST',
	headers: { 'content-type': 'application/json' },
	body: JSON.stringify({ header, asset, attestations: [attestation] })
});
```

## Build from source

```bash
# Build npm wrapper
cd packages/core-pqc
npm run build
```

WASM bindings live in `@maatara/core-pqc-wasm` (Rust + wasm-bindgen). This package consumes those exports and provides a browser/Node‑friendly API.

## Security notes

- Zero‑knowledge: server never receives user secrets/DEKs
- Post‑quantum primitives (Kyber, Dilithium)
- Constant‑time operations where applicable
- Deterministic JSON canonicalization (JCS‑like) for signature stability

## License

Apache‑2.0

## Veritas Block Preimage (v2 JCS)

Blocks (Veritas chain) now use a canonical JCS JSON preimage for signatures (version 2). Legacy version 1 used a plain JSON.stringify of an object with insertion ordering. The new helper ensures deterministic ordering consistent with governance/asset preimages.

Helper:
```ts
import { buildBlockPreimage } from '@maatara/core-pqc';

const { canonical, msg_b64u } = await buildBlockPreimage({
  index: block.index.toString(),      // string (bigint safe)
  timestamp: block.timestamp.toString(),
  previousHash: block.previousHash,
  dataHash: block.dataHash,
  metadataHash: block.metadataHash,
  signatureAlg: 'dilithium2',
  ownerPublicKey: dilithiumPublicKeyB64u,
  contentType: block.contentType || 'application/json',
  version: 2,
});
// Sign msg_b64u with Dilithium secret
```

Canonical object fields included (lexicographically ordered by JCS):
- contentType
- dataHash
- index (string)
- metadataHash
- ownerPublicKey (Dilithium public key, base64url)
- previousHash
- signatureAlg
- timestamp (string)
- version

Excluded: signature, encryptionKeyHash, any transient fields.

Message to sign: `base64url( UTF-8(canonical JSON) )`. No hashing layer (if you need prehash use Dilithium pre-hash mode externally before signature—current flow signs raw canonical bytes).

### Migration Notes (v1 -> v2)
- Existing blocks signed under legacy scheme still verify: server falls back to legacy ordering if JCS verification fails.
- New blocks should set `version: 2` and use Dilithium key for `ownerPublicKey` (not the userId hash) to assert authorship.
- Enable server debug logging of preimage by setting env `DEBUG_PREIMAGE=1`.
- Future breaking change removal: once all clients migrate, legacy fallback can be removed.

### Client Checklist
1. Always stringify bigint counters to decimal strings before building the preimage.
2. Provide the true Dilithium public key as `ownerPublicKey`.
3. Do not inject extra fields; they will be ignored (and change canonical ordering if you wrongly sign them locally).
4. Ensure base64url is unpadded (`-` / `_` substitutions). The helper already does this.