Service Info

Status--
Endpointhttp://docker:8085
PQC AlgorithmECDSA secp256r1 + ML-DSA-65
FIPS StandardFIPS 186-5 (ECDSA) + FIPS 204 (ML-DSA)

Where PQC is Used

📜
Contract Deployment

Deploy smart contracts with ML-DSA-65 signature over the code hash. Quantum-safe provenance from day one.

ML-DSA-65 (FIPS 204)
🔗
Dual Signature

Every transaction signed with both ECDSA (secp256r1) and ML-DSA-65. Legacy clients verify ECDSA; PQC clients verify ML-DSA-65.

ECDSA + ML-DSA-65
✅
Dual Verification

Verify both signatures. Network enforces bothValid during transition; phases out ECDSA once all clients are PQC-capable.

ECDSA + ML-DSA-65

Description

This service demonstrates the dual-signature pattern for smart contracts — the migration bridge between classical and post-quantum blockchains.

Sign once, verify anywhere: Every transaction gets both an ECDSA signature (for legacy verifiers) and an ML-DSA-65 signature (for PQC-aware verifiers). Verifiers check whichever signature they support.

Classical (ECDSA secp256r1): Java's Signature.getInstance("SHA256withECDSA")
PQC (ML-DSA-65): provider.sign(data, privKey, "ML-DSA-65") via Qudo JNI

Contracts are deployed with an ML-DSA-65 signature over the SHA-256 code hash, establishing quantum-safe provenance.

POST /api/dapp/deploy-contract Deploy a smart contract with PQC signature
🔒 Qudo provider: provider.sign(sha256(code), privKey, "ML-DSA-65"). Contract hash + ML-DSA-65 signature establishes quantum-safe provenance.
POST /api/dapp/dual-sign Dual-sign transaction (ECDSA + ML-DSA-65)
🔒 Classical: Signature.getInstance("SHA256withECDSA"). PQC: provider.sign(data, privKey, "ML-DSA-65"). Returns both signatures + public keys.
POST /api/dapp/dual-verify Verify both ECDSA and ML-DSA-65 signatures
🔒 Verifies both signatures. Returns {ecdsaValid, mldsaValid, bothValid}. Production: enforce bothValid during migration, then phase out ECDSA.
GET /api/dapp/contracts List all deployed contracts
🔒 Returns all contracts with codeHash, ML-DSA-65 signature, and deployment timestamp.
GET /api/dapp/health Service health + supported algorithms
🔒 Returns service status with ECDSA + ML-DSA-65 algorithm availability.

dApp Migration Reference

Migrate your smart contracts to quantum-safe signatures using the dual-signature pattern: keep ECDSA for legacy verifiers while adding ML-DSA-65 for PQC-aware verifiers. Use this playground to try dual signing, then use the Qudo JNI provider in your own dApp.

1. How It Works 2. Migrate Your System 3. Performance 4. Pitfalls 5. FAQ

1. How Dual-Signature Works

dApp Client                                          Verifier Network
   |                                                      |
   |  1. Sign the SAME txData bytes with BOTH keys         |
   |     ecSig  = Signature.getInstance("SHA256withECDSA") |
   |              .sign(txData)  // secp256r1              |
   |     mlSig  = provider.sign(txData, mldsaPrivKey,      |
   |                             "ML-DSA-65")              |
   |                                                      |
   |---- txData + ecSig + mlSig + both public keys ------>|
   |                                                      |
   |     2. Legacy verifier checks ecSig  (ECDSA)          |
   |        PQC verifier checks mlSig  (ML-DSA-65)         |
   |        Strict verifier checks BOTH                    |
   |                                                      |
   |     3. Migration phases:                              |
   |        Phase 1 (bootstrap):  accept if ecValid        |
   |        Phase 2 (transition): require bothValid        |
   |        Phase 3 (PQC only):   accept if mlValid        
🔗
Backward Compatibility

Legacy clients that only know ECDSA continue to work. They verify ecdsaSignature and ignore the ML-DSA field. No hard fork required.

🛡
Forward Security

Once a majority of verifiers are PQC-capable, switch to bothValid enforcement. Attackers breaking ECDSA with a quantum computer still can't forge ML-DSA-65.

2. Migrate Your System

Add the Qudo JNI provider alongside your existing ECDSA code. Keep both signatures on every transaction until the network fully migrates.

Complete Java Implementation (Dual-Sign)

import com.qudo.crypto.QudoCrypto;
import com.qudo.crypto.QudoKeyPair;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Signature;
import java.security.spec.ECGenParameterSpec;

// ============================================================
// Initialize once at startup
// ============================================================
QudoCrypto provider = QudoCrypto.create();

// Classical ECDSA keypair (existing code, unchanged)
KeyPairGenerator ecKpg = KeyPairGenerator.getInstance("EC");
ecKpg.initialize(new ECGenParameterSpec("secp256r1"));
KeyPair ecKeys = ecKpg.generateKeyPair();

// PQC ML-DSA-65 keypair (new)
QudoKeyPair mldsaKeys = provider.generateKeyPair("ML-DSA-65");

// ============================================================
// Sign a transaction with BOTH algorithms
// ============================================================
byte[] txData = "transfer 100 PQC to 0xabc123".getBytes();

// Classical ECDSA (unchanged)
Signature ecSigner = Signature.getInstance("SHA256withECDSA");
ecSigner.initSign(ecKeys.getPrivate());
ecSigner.update(txData);
byte[] ecSig = ecSigner.sign();  // 64-72 bytes

// PQC ML-DSA-65 via Qudo JNI (MUST sign the SAME txData bytes)
byte[] mlSig = provider.sign(txData, mldsaKeys.getPrivateKeyPem(), "ML-DSA-65");  // 3,309 bytes

// Broadcast: txData + ecSig + mlSig + both public keys (ecKeys.getPublic(), mldsaKeys.getPublicKeyPem())
// The verifier is a separate system — it receives the public keys over the wire.

// ============================================================
// Verify both signatures (on the verifier side)
// ============================================================
// ECDSA verification (unchanged)
Signature ecVerifier = Signature.getInstance("SHA256withECDSA");
ecVerifier.initVerify(ecKeys.getPublic());
ecVerifier.update(txData);
boolean ecValid = ecVerifier.verify(ecSig);

// ML-DSA-65 verification via Qudo JNI
boolean mlValid = provider.verify(txData, mlSig, mldsaKeys.getPublicKeyPem(), "ML-DSA-65");

// Migration policy
boolean bothValid = ecValid && mlValid;
// Phase 1 (now):       accept if ecValid
// Phase 2 (transition): require bothValid
// Phase 3 (PQC only):  accept if mlValid

provider.close();
This is what runs in your dApp. Keep your existing ECDSA code — just add the Qudo JNI calls alongside. Both signatures go into the same transaction envelope. The verifier chooses which to enforce based on your migration phase.

What Changes vs What Stays

ComponentChanges?What to do
Transaction schemaYes — add fieldsAdd mldsaSignature and mldsaPublicKey alongside existing ECDSA fields
Signing logicYes — add callAdd provider.sign(data, privKey, "ML-DSA-65") after your ECDSA sign
Verification logicYes — add checkAdd provider.verify(). Enforce bothValid during transition.
ECDSA codeNoKeep as-is — legacy verifiers depend on it
Smart contract bytecodeNoDual signatures are at the transaction layer, not contract layer
Wallet addressesNoAddresses stay the same. New ML-DSA public keys published alongside existing ECDSA keys.

3. Performance

Numbers assume keypairs are cached at startup (generated once, reused for all transactions).

OperationECDSA secp256r1ML-DSA-65Dual (both)
Keypair generation (once at startup)~3ms~55ms~58ms startup
Sign (per transaction)<1ms~10ms~11ms total
Verify (per transaction)<1ms~5ms~6ms total
Signature size64-72 bytes3,309 bytes~3.4KB per tx
Public key size33 bytes (compressed)~2,726 bytes (PEM)~2.8KB per wallet
Impact: Dual signing adds ~10ms and ~3.3KB per transaction. For most dApps this is acceptable. For high-throughput L2s, consider aggregating ML-DSA signatures off-chain or using ML-DSA-44 (2,420 bytes).

4. Pitfalls

Pitfall: Block size grows significantly with dual signatures

Cause: Adding ML-DSA-65 to every transaction adds ~3.3KB per tx. A block with 1,000 txs grows by ~3.3MB.
Mitigation: Use ML-DSA-44 (2,420 bytes) for higher throughput, or aggregate PQC signatures off-chain with a commitment on-chain.

Pitfall: Signing different bytes with each algorithm

Cause: If ECDSA signs txDataV1 and ML-DSA signs txDataV2, an attacker who breaks one algorithm can swap in a different transaction under the other signature.
Fix: Sign the exact same bytes with both algorithms. Serialize the transaction (including nonce, chain ID, timestamp) into one canonical txData array, then sign that array twice.

Pitfall: Downgrade attacks during transition

Cause: An attacker strips the ML-DSA signature from a transaction, forges an ECDSA signature (using a quantum computer against the weaker algorithm), and submits it. A permissive verifier that accepts either signature would let this through.
Fix: Enforce bothValid (Phase 2) as soon as most wallets support ML-DSA. Never accept transactions with only one signature once PQC keys are registered.

5. FAQ

Q: Why dual-sign instead of just switching to ML-DSA?

A: A hard fork to PQC-only signatures breaks all existing wallets. Dual signatures let the network migrate gradually: old wallets still work (ECDSA), new wallets add PQC protection, and the network enforces stricter policies over time.

Q: Do smart contracts themselves need to change?

A: No. Dual signatures are at the transaction envelope layer, not the contract bytecode. Your Solidity/Vyper contracts stay identical. Only the transaction signing and verification layers change.

Q: What algorithm should I use for ECDSA? secp256k1 or secp256r1?

A: Match your chain's native curve. Ethereum/Bitcoin use secp256k1; enterprise chains and this simulator use secp256r1 (NIST P-256). The Qudo JNI provider adds ML-DSA-65 alongside either curve.

Q: When should I switch from Phase 1 to Phase 2?

A: When >80% of active wallets on your network have ML-DSA keys. Until then, enforcing bothValid would break legacy users. After 80%, require both; after 95%, consider PQC-only.

Crypto Inventory Scanner

Analyze any endpoint's cryptographic configuration. Enter a host:port to scan its TLS setup and identify what's quantum-safe vs what needs migration.

Scan Endpoint