React Native Quick Crypto
API Reference

Post-Quantum Cryptography

Quantum-resistant algorithms (ML-DSA, ML-KEM, SLH-DSA)

Post-Quantum Cryptography (PQC) provides cryptographic algorithms that are secure against both classical and quantum computers. RNQC implements the NIST standardized lattice-based algorithms via OpenSSL 3.6+.

Why Post-Quantum?

Quantum computers threaten RSA, ECDSA, and ECDH. The PQC algorithms below are NIST-standardized replacements designed to resist quantum attacks while running efficiently on classical hardware.

Table of Contents

Algorithms

ML-DSA (FIPS 204)

Module Lattice Digital Signature Algorithm. Replacement for RSA and ECDSA signatures.

Parameter SetSecurity LevelPublic KeySignatureUse Case
ML-DSA-44NIST Level 21,312 B2,420 BGeneral purpose
ML-DSA-65NIST Level 31,952 B3,309 BRecommended
ML-DSA-87NIST Level 52,592 B4,627 BMaximum security

ML-KEM (FIPS 203)

Module Lattice Key Encapsulation Mechanism. Replacement for ECDH key exchange.

Parameter SetSecurity LevelPublic KeyCiphertextShared Secret
ML-KEM-512NIST Level 1800 B768 B32 B
ML-KEM-768NIST Level 31,184 B1,088 B32 B
ML-KEM-1024NIST Level 51,568 B1,568 B32 B

SLH-DSA (FIPS 205)

Stateless Hash-Based Digital Signature Algorithm (formerly SPHINCS+). A hash-based alternative to ML-DSA — security relies only on the underlying hash function, making it a conservative choice when lattice assumptions are a concern. Each parameter set comes in s (small signature, slow) and f (fast, larger signature) variants.

Parameter SetSecurity LevelPublic KeySignatureNotes
SLH-DSA-SHA2-128s / SLH-DSA-SHAKE-128sNIST Level 132 B7,856 BSmall sig
SLH-DSA-SHA2-128f / SLH-DSA-SHAKE-128fNIST Level 132 B17,088 BFast sign
SLH-DSA-SHA2-192s / SLH-DSA-SHAKE-192sNIST Level 348 B16,224 BSmall sig
SLH-DSA-SHA2-192f / SLH-DSA-SHAKE-192fNIST Level 348 B35,664 BFast sign
SLH-DSA-SHA2-256s / SLH-DSA-SHAKE-256sNIST Level 564 B29,792 BSmall sig
SLH-DSA-SHA2-256f / SLH-DSA-SHAKE-256fNIST Level 564 B49,856 BFast sign

Performance Tradeoff

The s variants produce smaller signatures but signing is markedly slower than ML-DSA. The f variants sign faster but emit signatures 4–6× larger. For most applications ML-DSA is preferable; reach for SLH-DSA when a hash-only security assumption is required.


ML-DSA (Digital Signatures)

Node.js API

Generate ML-DSA key pairs and sign/verify using the standard crypto API:

import { generateKeyPairSync, sign, verify } from 'react-native-quick-crypto';

// Generate ML-DSA-65 key pair
const { publicKey, privateKey } = generateKeyPairSync('ml-dsa-65');

// Sign
const message = Buffer.from('quantum-safe message');
const signature = sign(null, message, privateKey);

// Verify
const isValid = verify(null, message, publicKey, signature);
console.log('Valid:', isValid); // true

Key Export/Import

ML-DSA keys support multiple export formats:

// Export as PEM
const pubPem = publicKey.export({ type: 'spki', format: 'pem' });
const privPem = privateKey.export({ type: 'pkcs8', format: 'pem' });

// Export as DER
const pubDer = publicKey.export({ type: 'spki', format: 'der' });

// Re-import
import { createPublicKey, createPrivateKey } from 'react-native-quick-crypto';

const imported = createPublicKey({
  key: pubDer,
  format: 'der',
  type: 'spki',
});

ML-KEM (Key Encapsulation)

ML-KEM uses encapsulation rather than key exchange. One party encapsulates a shared secret using the other's public key, producing a ciphertext. The other party decapsulates the ciphertext with their private key to recover the same shared secret.

Node.js API

import {
  generateKeyPairSync,
  encapsulate,
  decapsulate,
} from 'react-native-quick-crypto';

// Generate ML-KEM-768 key pair
const { publicKey, privateKey } = generateKeyPairSync('ml-kem-768');

// Encapsulate: produces shared secret + ciphertext
const { sharedSecret, ciphertext } = encapsulate(publicKey);

// Decapsulate: recovers the same shared secret
const recovered = decapsulate(privateKey, ciphertext);

console.log(sharedSecret.equals(recovered)); // true

SLH-DSA (Hash-Based Digital Signatures)

Node.js API

Generate SLH-DSA key pairs and sign/verify using the standard crypto API. Twelve parameter sets are available: slh-dsa-{sha2,shake}-{128,192,256}{s,f}.

import { generateKeyPairSync, sign, verify } from 'react-native-quick-crypto';

// Generate SLH-DSA-SHA2-128f key pair (fast variant)
const { publicKey, privateKey } = generateKeyPairSync('slh-dsa-sha2-128f');

// Sign
const message = Buffer.from('hash-based, quantum-safe message');
const signature = sign(null, message, privateKey);

// Verify
const isValid = verify(null, message, publicKey, signature);
console.log('Valid:', isValid); // true

WebCrypto API

PQC algorithms are fully supported through the SubtleCrypto interface.

ML-DSA via SubtleCrypto

import { subtle } from 'react-native-quick-crypto';

// Generate key pair
const keyPair = await subtle.generateKey({ name: 'ML-DSA-65' }, true, [
  'sign',
  'verify',
]);

// Sign
const data = new TextEncoder().encode('quantum-safe data');
const signature = await subtle.sign(
  { name: 'ML-DSA-65' },
  keyPair.privateKey,
  data,
);

// Verify
const isValid = await subtle.verify(
  { name: 'ML-DSA-65' },
  keyPair.publicKey,
  signature,
  data,
);

ML-KEM via SubtleCrypto

import { subtle } from 'react-native-quick-crypto';

// Generate encapsulation key pair
const keyPair = await subtle.generateKey({ name: 'ML-KEM-768' }, true, [
  'deriveBits',
  'deriveKey',
]);

// Encapsulate: get shared secret bits + ciphertext
const { sharedSecret, ciphertext } = await subtle.encapsulateBits(
  { name: 'ML-KEM-768' },
  keyPair.publicKey,
);

// Decapsulate: recover shared secret
const recovered = await subtle.decapsulateBits(
  { name: 'ML-KEM-768' },
  keyPair.privateKey,
  ciphertext,
);

// Or derive a key directly from encapsulation
const { key: aesKey, ciphertext: ct } = await subtle.encapsulateKey(
  { name: 'ML-KEM-768' },
  keyPair.publicKey,
  { name: 'AES-GCM', length: 256 },
  true,
  ['encrypt', 'decrypt'],
);

// Decapsulate to get the same AES key
const recoveredKey = await subtle.decapsulateKey(
  { name: 'ML-KEM-768' },
  keyPair.privateKey,
  ct,
  { name: 'AES-GCM', length: 256 },
  true,
  ['encrypt', 'decrypt'],
);

SLH-DSA via SubtleCrypto

import { subtle } from 'react-native-quick-crypto';

// Generate key pair (use the canonical FIPS 205 name)
const keyPair = await subtle.generateKey({ name: 'SLH-DSA-SHA2-128f' }, true, [
  'sign',
  'verify',
]);

const data = new TextEncoder().encode('signed with hash-based PQC');
const signature = await subtle.sign(
  { name: 'SLH-DSA-SHA2-128f' },
  keyPair.privateKey,
  data,
);

const isValid = await subtle.verify(
  { name: 'SLH-DSA-SHA2-128f' },
  keyPair.publicKey,
  signature,
  data,
);

Key Export Formats

Algorithmspkipkcs8jwkraw-publicraw-seed
ML-DSA-44/65/87
ML-KEM-512/768/1024
SLH-DSA-{SHA2,SHAKE}-{128,192,256}{s,f}
// Export ML-DSA public key as JWK
const jwk = await subtle.exportKey('jwk', keyPair.publicKey);

// Export raw public key bytes
const rawPub = await subtle.exportKey('raw-public', keyPair.publicKey);

// Export seed (deterministic private key material)
const seed = await subtle.exportKey('raw-seed', keyPair.privateKey);

// Import from raw-public
const imported = await subtle.importKey(
  'raw-public',
  rawPub,
  { name: 'ML-DSA-65' },
  true,
  ['verify'],
);

Real-World Examples

Hybrid Signature (Classical + PQC)

Combine Ed25519 with ML-DSA for defense-in-depth during the quantum transition:

import { generateKeyPairSync, sign, verify } from 'react-native-quick-crypto';

function hybridSign(message: Buffer) {
  const ed = generateKeyPairSync('ed25519');
  const pqc = generateKeyPairSync('ml-dsa-65');

  const edSig = sign(null, message, ed.privateKey);
  const pqcSig = sign(null, message, pqc.privateKey);

  return {
    message,
    signatures: { ed25519: edSig, mlDsa65: pqcSig },
    publicKeys: { ed25519: ed.publicKey, mlDsa65: pqc.publicKey },
  };
}

function hybridVerify(signed: ReturnType<typeof hybridSign>): boolean {
  const edValid = verify(
    null,
    signed.message,
    signed.publicKeys.ed25519,
    signed.signatures.ed25519,
  );
  const pqcValid = verify(
    null,
    signed.message,
    signed.publicKeys.mlDsa65,
    signed.signatures.mlDsa65,
  );

  // Both must pass
  return edValid && pqcValid;
}

Quantum-Safe Key Exchange

Use ML-KEM to establish a shared secret for symmetric encryption:

import {
  generateKeyPairSync,
  encapsulate,
  decapsulate,
  createCipheriv,
  createDecipheriv,
  createHash,
  randomBytes,
} from 'react-native-quick-crypto';

// Server publishes its ML-KEM public key
const server = generateKeyPairSync('ml-kem-768');

// Client encapsulates a shared secret
const { sharedSecret, ciphertext } = encapsulate(server.publicKey);

// Derive AES key from shared secret
const aesKey = createHash('sha256').update(sharedSecret).digest();
const iv = randomBytes(12);

// Encrypt with AES-GCM
const cipher = createCipheriv('aes-256-gcm', aesKey, iv);
let encrypted = cipher.update('secret message', 'utf8', 'base64');
encrypted += cipher.final('base64');
const tag = cipher.getAuthTag();

// Server decapsulates to get the same shared secret
const serverSecret = decapsulate(server.privateKey, ciphertext);
const serverKey = createHash('sha256').update(serverSecret).digest();

// Server decrypts
const decipher = createDecipheriv('aes-256-gcm', serverKey, iv);
decipher.setAuthTag(tag);
let decrypted = decipher.update(encrypted, 'base64', 'utf8');
decrypted += decipher.final('utf8');
console.log(decrypted); // "secret message"

On this page