Developers
Build quantum-resistant applications on Po8 using the Quantum Abstraction Layer, native precompiles, and ERC-4337 smart accounts.
Quantum Abstraction Layer
The QAL enables full EVM compatibility while using post-quantum cryptography under the hood. Existing Solidity contracts deploy without modification.
Native PQC Operations
Heavy lattice operations are exposed via precompiled contracts for gas-efficient execution.
0x20
ML_KEM_DECAPS
Performs ML-KEM-768 decapsulation for on-chain key exchange.
Parameters
bytes ciphertext1,088 bytes ML-KEM ciphertextbytes secretKey2,400 bytes secret key (or key ID)Returns
bytes32 sharedSecret32-byte shared secretGas Cost
Base: 3,000 gas + 10 gas per input byte
// Solidity usage bytes32 secret = ML_KEM_DECAPS.decaps(ciphertext, keyId);
0x21
ML_DSA_VERIFY
Verifies ML-DSA-65 signatures for smart account validation.
Parameters
bytes messageMessage hash (32 bytes typical)bytes signature3,309 bytes ML-DSA signaturebytes publicKey1,952 bytes public keyReturns
bool validTrue if signature is validGas Cost
Base: 5,000 gas + 2 gas per signature byte
// Solidity usage bool valid = ML_DSA_VERIFY.verify(msgHash, sig, pubKey);
0x22
NTT_MUL
Accelerates Number Theoretic Transform polynomial multiplication for ZK circuits.
Parameters
bytes polyAFirst polynomial coefficientsbytes polyBSecond polynomial coefficientsReturns
bytes resultProduct polynomialGas Cost
Base: 1,000 gas + 5 gas per coefficient
// Useful for Halo2/Plonkish circuits bytes memory product = NTT_MUL.multiply(polyA, polyB);
ERC-4337 Integration
All Po8 accounts are smart contracts following the ERC-4337 standard, enabling ML-DSA signature verification.
Address Derivation
Addresses are derived from ML-DSA public keys:
// Address = truncate(SHA3-256(mlDsaPublicKey), 20)
address userAddress = address(uint160(uint256(
keccak256(mlDsaPublicKey)
)));
QAL_Account Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@account-abstraction/contracts/core/BaseAccount.sol";
contract QAL_Account is BaseAccount {
bytes public mlDsaPublicKey;
constructor(bytes memory _publicKey) {
mlDsaPublicKey = _publicKey;
}
function validateUserOp(
UserOperation calldata userOp,
bytes32 userOpHash,
uint256 missingAccountFunds
) external override returns (uint256 validationData) {
// Extract ML-DSA signature from userOp.signature
bytes memory signature = userOp.signature;
// Call ML_DSA_VERIFY precompile at 0x21
(bool success, bytes memory result) = address(0x21).staticcall(
abi.encode(userOpHash, signature, mlDsaPublicKey)
);
require(success && abi.decode(result, (bool)), "Invalid signature");
// Pay for gas if needed
if (missingAccountFunds > 0) {
payable(msg.sender).transfer(missingAccountFunds);
}
return 0; // Valid
}
}
UserOperation Structure
struct UserOperation {
address sender; // QAL_Account address
uint256 nonce;
bytes initCode; // For account creation
bytes callData; // Contract call data
uint256 callGasLimit;
uint256 verificationGasLimit;
uint256 preVerificationGas;
uint256 maxFeePerGas;
uint256 maxPriorityFeePerGas;
bytes paymasterAndData;
bytes signature; // 3,309 byte ML-DSA signature
}
Contract Examples
QuantumBridge Contract
Lock assets and mint quantum-safe equivalents.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract QuantumBridge {
mapping(address => mapping(address => uint256)) public deposits;
event Deposit(address indexed user, address indexed token, uint256 amount);
event Withdraw(address indexed user, address indexed token, uint256 amount);
function deposit(address token, uint256 amount) external {
// msg.sender is QAL_Account - already PQC verified
IERC20(token).transferFrom(msg.sender, address(this), amount);
deposits[msg.sender][token] += amount;
emit Deposit(msg.sender, token, amount);
}
function withdraw(address token, uint256 amount) external {
require(deposits[msg.sender][token] >= amount, "Insufficient balance");
deposits[msg.sender][token] -= amount;
IERC20(token).transfer(msg.sender, amount);
emit Withdraw(msg.sender, token, amount);
}
}
Encrypted Messaging
Use ML-KEM for on-chain key exchange.
contract EncryptedMessaging {
struct Message {
bytes kemCiphertext; // 1,088 bytes
bytes encryptedData; // AES-GCM encrypted
}
mapping(address => Message[]) public inbox;
mapping(address => bytes) public kemPublicKeys;
function registerKey(bytes calldata kemPubKey) external {
require(kemPubKey.length == 1184, "Invalid key size");
kemPublicKeys[msg.sender] = kemPubKey;
}
function sendMessage(
address recipient,
bytes calldata kemCiphertext,
bytes calldata encryptedData
) external {
inbox[recipient].push(Message(kemCiphertext, encryptedData));
}
}
JavaScript SDK
Installation
npm install @po8/sdk
Basic Usage
import { Po8Provider, QALWallet } from '@po8/sdk';
// Connect to Po8 network
const provider = new Po8Provider('https://rpc.po8.network');
// Create wallet from seed
const wallet = QALWallet.fromMnemonic(
'your twenty four word mnemonic phrase here ...'
);
// Get address (derived from ML-DSA public key)
console.log('Address:', wallet.address);
console.log('ML-DSA Public Key:', wallet.mlDsaPublicKey.length, 'bytes');
// Sign a message
const signature = await wallet.signMessage('Hello Po8!');
console.log('Signature:', signature.length, 'bytes'); // 3,309
// Send transaction via bundler
const tx = await wallet.sendTransaction({
to: '0x...',
value: ethers.parseEther('1.0'),
data: '0x'
});
await tx.wait();
Precompile Helpers
import { MlKem, MlDsa, Ntt } from '@po8/sdk/crypto';
// ML-KEM key exchange
const { publicKey, secretKey } = MlKem.generateKeypair();
const { ciphertext, sharedSecret } = MlKem.encapsulate(publicKey);
const decrypted = MlKem.decapsulate(ciphertext, secretKey);
// ML-DSA signing
const { publicKey: sigPk, secretKey: sigSk } = MlDsa.generateKeypair();
const signature = MlDsa.sign(message, sigSk);
const valid = MlDsa.verify(message, signature, sigPk);
