Skip to main content

Post-Quantum Cryptography

Shamwari is built PQC-native from day one. Post-quantum cryptographic operations are integrated directly into key generation, account addressing, transaction signing, block forging, and encrypted messaging via the nxt.crypto package.

Key Primitives Summary

PrimitiveStandardFunctionPublic Key SizeSecret Key SizeOutput / Sig Size
ML-KEM-512NIST FIPS 203Key Encapsulation (KEM)800 bytes1632 bytes768 bytes (Ciphertext)
ML-DSA-2NIST FIPS 204Digital Signatures1312 bytes2528 bytes2420 bytes (Signature)
ShamwariQKPCompositeHybrid QKP Container2112 bytes4160 bytesN/A

Key Generation & PBKDF2 Key Derivation

Key pair generation derives deterministic master seeds from user passphrases using PBKDF2-HMAC-SHA512 (100,000 iterations) paired with SHA3-256 domain separation:

// Derive composite ShamwariQKP from secret phrase
String secretPhrase = "your secret high-entropy passphrase";
ShamwariQKP keyPair = Crypto.getShamwariQKP(secretPhrase);

ShamwariPublicKey publicKey = keyPair.getPublicKey();
ShamwariPrivateKey privateKey = keyPair.getPrivateKey();

Domain Separation Mechanism

Under the hood, Crypto.generateShamwariQKP(byte[] seed) splits the derived 32-byte seed into distinct domain-separated inputs:

  • 0x01 || seed hashed with SHA3-256 produces kyberSeed.
  • 0x02 || seed hashed with SHA3-256 produces dilithiumSeed.

Digital Signatures (ML-DSA-2 / Dilithium Level 2)

All protocol transactions, block headers, digital certificates, and administrative actions are authenticated using ML-DSA-2 signatures via nxt.crypto.Crypto.

// Transaction signing
byte[] transactionBytes = "Transaction Payload".getBytes(StandardCharsets.UTF_8);
byte[] signature = Crypto.sign(transactionBytes, privateKey.getDilithiumPrivateKey()); // 2420 bytes

// Signature verification
boolean isValid = Crypto.verify(signature, transactionBytes, publicKey.getDilithiumPublicKey());

Signing Security

ML-DSA uses rejection sampling during signature generation to guarantee that signature instances leak zero information regarding the signer's secret key.

Key Encapsulation & Authenticated Payload Encryption

For confidential payloads and encrypted messaging, Shamwari pairs ML-KEM-512 key encapsulation with AES-256-GCM symmetric encryption using nxt.crypto.EncryptedData. HKDF-SHA256 derives the 32-byte AES key bound to the Kyber ciphertext bytes as salt:

// Encrypt plaintext payload for recipient
byte[] plaintext = "Confidential Payload Data".getBytes(StandardCharsets.UTF_8);

EncryptedData encryptedData = EncryptedData.encrypt(
plaintext,
senderPrivateKey.getKyberPrivateKey(),
recipientPublicKey.getKyberPublicKey()
);

// Decrypt payload as recipient
byte[] decryptedBytes = encryptedData.decrypt(
recipientPrivateKey.getKyberPrivateKey(),
senderPublicKey.getKyberPublicKey()
);

Encrypted Payload Wire Format

The serialized representation of an EncryptedData object combines the AES-GCM ciphertext and 768-byte Kyber ciphertext:

┌──────────────────────────────────────────────────────────────┐
│ AES-256-GCM Payload │
│ [ 12 B Nonce | Ciphertext | 16 B GCM Tag ] │
├──────────────────────────────────────────────────────────────┤
│ Kyber-512 Ciphertext │
│ [ 768 Bytes ] │
└──────────────────────────────────────────────────────────────┘

Security Controls & ShamwariQKP Memory Protection

To prevent inadvertent leakage of private key material in application logs or network traffic, ShamwariQKP enforces strict access separation and memory sanitation:

  1. Public-Only Default JSON: ShamwariQKP.getJSON() and getPublicJSON() return public key material only. Private keys require an explicit, opt-in call to getPrivateJSON().
  2. In-Memory Sanitization: Calling qkp.destroy() or privateKey.destroy() zeroize secret key byte arrays in memory (Arrays.fill(arr, (byte) 0)).
  3. Side-Channel Mitigation: Key equality evaluations use constant-time byte comparisons (constantTimeCompare) to eliminate timing side-channels.
// Export public JSON (safe for logging, caching, API responses)
JSONObject publicJson = keyPair.getJSON();

// Opt-in export containing private key (for encrypted wallet backup)
JSONObject privateJson = keyPair.getPrivateJSON();

// Wipe secret key material from memory when finished
keyPair.destroy();

Account Identity & Serialized Key Encodings

Accounts in Shamwari derive their identity directly from a composite ShamwariPublicKey:

  1. Master Seed Derivation: PBKDF2-HMAC-SHA512 derives a high-entropy seed from the passphrase.
  2. Domain Separation: SHA3-256 generates independent seeds for ML-KEM-512 and ML-DSA-2.
  3. ASN.1 / DER Encodings:
    • Public keys use ASN.1 X.509 SubjectPublicKeyInfo format.
    • Private keys use ASN.1 PKCS#8 PrivateKeyInfo format.
  4. Account ID Conversion: The account numeric ID is derived from the SHA-256 digest of the ASN.1/DER encoded ShamwariPublicKey.

Protocol-Enforced Account Controls & AI Agents

To support automated finance and autonomous AI software agents, Shamwari introduces AutonomousAccountControl:

  • AI Agent Accounts (AUTONOMOUS): Software-driven accounts operating under hard operational limits established on-chain by a controlling human account.
  • Protocol Limits: Enforces per-transaction caps, daily transfer caps, transaction-type restrictions, and counterparty account whitelists.
  • Security Guarantee: Controlled accounts cannot alter or remove their own operational limits; modifications require an explicit SET_AUTONOMOUS_ACCOUNT_CONTROL transaction signed by the controlling account's ML-DSA-2 key.