20. PQC-Guard: Multi-VM Smart Account
PQC-Guard is an experimental cross-chain smart-account design in the repository. It uses hash-based WOTS-style attestations and chain-specific verification code to explore post-quantum authorization without requiring lattice arithmetic on every destination VM. Deployment security depends on the validator registry, attestation root, guardian/recovery policy, key custody and the target-chain contract.
20.1 Cryptographic Primitives
The on-chain verification relies entirely on hash operations available on all VMs:
- WOTS (w=16, LEN=67): 64 message digits + 3 checksum digits in base-16. Each digit chain applied
W-1-dtimes; the compressed public key iskeccak256(concat(chain_i)). - Attestor Merkle tree:
attestor_leaf = keccak256("PQCG_ATTESTOR_LEAF" ‖ id ‖ wots_root). A binary Merkle tree of attestor leaves; the root is anchored on-chain by the L0 oracle. - WOTS leaf:
wots_leaf = keccak256("PQCG_WOTS_LEAF" ‖ wots_pub)— domain-separated to prevent second-preimage across tree levels. - Authorization digest:
keccak256(account ‖ to ‖ value ‖ data_hash ‖ nonce ‖ chain_id)— canonical across all VMs.
20.2 Canonical Binary Serialization
Cross-VM attestation blobs use a chain-agnostic binary format:
blob := uint32(N) ‖ proof_0 ‖ … ‖ proof_{N-1}
proof_i :=
id [32 bytes] attestor identifier
wots_root [32 bytes] WOTS tree root
uint64(li) [8 bytes] leaf index in WOTS tree
uint32(|sig|) [4 bytes] number of WOTS chains (LEN=67)
sig [67×32 bytes]
uint32(|path|)[4 bytes] Merkle proof depth
path [depth×32 bytes]
uint64(si) [8 bytes] attestor index in set tree
uint32(|sp|) [4 bytes] set Merkle proof depth
sp [depth×32 bytes]
The TypeScript SDK (pqc-guard/sdk/src/canonical.ts) implements serialization and per-chain digest computation for the runtime families covered by the repository. The supported set and test status must be checked against the exact commit and deployment matrix.
20.3 VM Ports and Test Status
| Chain | Runtime | Language | Tests | Framework |
|---|---|---|---|---|
| Ethereum, Base, Arbitrum, Optimism, Polygon, Avalanche, BSC | EVM | Solidity | Foundry | ✅ |
| Tron | TVM (EVM) | Solidity | Foundry | ✅ |
| Solana | SVM | Rust (Anchor) | cargo test | ✅ 5/5 |
| Sui | Move 2024 | Move | sui move test | ✅ 5/5 |
| Aptos | Move | Move | aptos move test | ✅ 3/3 |
| NEAR | WASM | Rust (near-sdk 5.x) | cargo test | ✅ 4/4 |
| Stellar | Soroban | Rust (soroban-sdk) | cargo test | ✅ 4/4 |
| Canton Network | Canton (DAML) | DAML | daml test | ✅ |
| Internet Computer (ICP) | WASM (Canister) | Rust (ic-cdk) | cargo test | ✅ |
The ports aim to expose a common migration, execution and recovery interface, but runtime-specific behavior differs. Non-EVM divergences, test coverage and deployment assumptions are documented in the repository and must be reviewed per target chain.
20.4 Guardian Escape Hatch
If the Quantos network becomes unavailable, funds are never frozen:
- After
RECOVERY_TIMEOUT(30 days of inactivity), the guardian threshold is unlocked. - M-of-N guardians can collectively sweep funds to a recovery address.
- The escape hatch is enforced by a block/time oracle on each VM, independently of Quantos uptime.
20.5 Runtime-Specific Implementation Constraints
Each non-EVM runtime imposes constraints that shaped the canonical design:
Stellar / Soroban (Rust): The soroban_sdk::Bytes type does not expose a to_array() method or a generic extend_from_slice(). All binary encoding is done via sequential push_back(byte) calls with explicit bit-shifting. The Hash<32> return type of soroban_sdk::env::keccak256 is wrapped in a helper keccak_bytes(env, &Bytes) -> BytesN<32> that converts via .into(), centralizing the type normalization. Because Soroban does not support multiple #[contract] exports from a single binary (symbol collision), the oracle's initialization function is exported as init_oracle rather than init.
NEAR (near-sdk 5.x / Rust): The near-sdk 5.x API uses the combined #[near] macro applied to both the struct and its implementation block; gas is expressed as Gas::from_tgas(u64) and token amounts as NearToken::from_yoctonear(u128). Running cargo test against NEAR contract crates requires the unit-testing feature flag declared in [dev-dependencies] of Cargo.toml. The contract's keccak256 is provided by the near_sdk::env::keccak256_array host function, which returns [u8; 32] directly.
Aptos (Move): Aptos Move uses the aptos_framework::event::emit<T>(event: T) function, which requires the type parameter T to have has drop, store abilities. All four event structs declare these abilities explicitly.
Sui (Move 2024.beta): The Sui Move.toml declares edition = "2024.beta", which mandates that all struct types accessible outside their defining module carry the public keyword. Event types are emitted via sui::event::emit<T>() and require has copy, drop abilities — no store is needed (unlike Aptos).
Solana (Anchor / SVM): Anchor's #[account] macro derives AnchorSerialize and AnchorDeserialize for all state structs. PDA seeds are defined in the #[derive(Accounts)] context struct using seeds = [b"...", ...] and bump fields. The Solana keccak::hash() function operates on &[u8] and returns a keccak::Hash with a .0: [u8; 32] field.
EVM / Tron (Solidity): Tron's TVM is byte-compatible with the EVM; the same PQCGuard.sol bytecode deploys on Tron without modification. The only runtime distinction is the chain ID in the authorization digest.