Zero Knowledge Proof circuit for RSA-4096 signature verification using SHA-512 hashing, built with Circom. This generic circuit verifies any RSA-4096 signature with SHA-512 hashing and PKCS1v15 padding using Groth16 zk-SNARKs. Includes Random.org integration as an example use case.
- ✅ 4096-bit RSA signature verification with PKCS1v15 padding
- ✅ SHA-512 hashing (512-bit output)
- ✅ Generic circuit - works with any RSA-4096 + SHA-512 signature
- ✅ Random.org API integration (example use case)
- ✅ Full zero-knowledge proof generation and verification workflow
- ✅ Supports exponent 65537
- Constraints: 1,071,212 (over 1 million)
- Wires: 1,060,273
- Public Inputs: 200
- Key Size: 4096-bit RSA
npm install-
Install Circom (required for circuit compilation):
npm install -g circom
-
Set up Random.org API key (optional, for testing with real data):
# Create .env file echo "RANDOM_ORG_API_KEY=your-api-key-here" > .env
-
Download Powers of Tau (required for proof generation, ~2.3GB):
npm run download-ptau
-
Generate proving keys (one-time setup, takes ~10-30 minutes):
npm run setup-proof
Test that the circuit correctly verifies RSA signatures:
# Run all tests
npm test
# Run general RSA test (generates its own keys - proves generic functionality)
npm run test:general
# Run Random.org integration test (optional - requires API key)
npm run test:randomRecommended: Start with npm run test:general - this test generates its own RSA-4096 keys and signatures, proving the circuit works with any RSA-4096 + SHA-512 signature.
Generate and verify actual zk-SNARK proofs:
npm run test:proofThis test will:
- Compile the circuit (if not already compiled)
- Check for Powers of Tau file
- Generate or reuse proving/verification keys
- Generate a witness for a test RSA signature
- Generate a zero-knowledge proof (~10-30 minutes)
- Verify the proof (instant)
circom-rsa-4096-sha512-verify/
├── circuits/
│ ├── sha512/ # SHA512 circuit implementation
│ ├── bigint/ # Big integer arithmetic (for RSA operations)
│ ├── pow_mod.circom # Modular exponentiation
│ └── rsa_verify.circom # RSA verification with SHA512
├── src/
│ ├── randomOrgClient.ts # Random.org API client
│ ├── signatureParser.ts # Parse signatures for circuit input
│ └── generateRsaSignature.ts # RSA key generation utilities
├── test/
│ ├── test_general_rsa_4096.ts # General RSA signature tests
│ ├── test_rsa_pkcs1v15_sha512.ts # Random.org integration tests
│ └── test_proof_generation.ts # Full ZK proof workflow
├── scripts/
│ ├── download-powers-of-tau.sh # Download trusted setup file
│ ├── generate-zkey.js # Generate proving key
│ └── setup-proof-generation.sh # Full proof setup
└── package.json
component main = RsaVerifyPkcs1v15(64, 64, 17, 8);
// Parameters: (word_size, num_words, exp_bits, hash_len)
// 64-bit words, 64 words = 4096 bits, 17-bit exponent (65537), 8 words for SHA512exp[64]: RSA public exponent (65537, represented as 64 words)sign[64]: RSA signature (4096 bits)modulus[64]: RSA public key modulus (4096 bits)hashed[8]: SHA512 hash of the message (512 bits = 8 words)
The circuit works with any RSA-4096 signature using SHA-512. Test it with your own signatures:
import { generateRsaKeyPair, signRsaPkcs1v15Sha512, prepareRsaSignatureForCircuit } from './src/generateRsaSignature';
// Generate your own RSA-4096 key pair
const keyPair = generateRsaKeyPair();
// Sign your data
const message = "Your message here";
const signature = signRsaPkcs1v15Sha512(message, keyPair.privateKey);
// Prepare circuit input
const circuitInput = prepareRsaSignatureForCircuit(
signature,
message,
keyPair.publicKey
);
// Use with circuit
const input = {
exp: circuitInput.exp.map(x => x.toString()),
sign: circuitInput.sign.map(x => x.toString()),
modulus: circuitInput.modulus.map(x => x.toString()),
hashed: circuitInput.hashed.map(x => x.toString())
};
// Run: npm run test:generalimport { RandomOrgClient } from './src/randomOrgClient';
import { loadPublicKeyFromCert } from './src/loadPublicKeyFromCert';
import { parseSignatureForCircuit } from './src/signatureParser';
// Get signed random data
const client = new RandomOrgClient(apiKey);
const signedData = await client.generateSignedIntegers(10, 1, 100, true);
// Load public key
const publicKeyPem = loadPublicKeyFromCert('server.crt');
// Prepare circuit input
const dataString = RandomOrgClient.getSignedDataString(signedData);
const circuitInput = parseSignatureForCircuit(
signedData.signature,
dataString,
publicKeyPem
);
// Use with circuit
const input = {
exp: circuitInput.exp.map(x => x.toString()),
sign: circuitInput.sign.map(x => x.toString()),
modulus: circuitInput.modulus.map(x => x.toString()),
hashed: circuitInput.hashed.map(x => x.toString())
};Download Powers of Tau:
npm run download-ptau
# Downloads ~2.3GB file (power 21, supports up to 2M constraints)Generate Proving Key:
npm run setup-proof
# Or manually:
node scripts/generate-zkey.jsThis generates:
rsa_verify_pkcs1v15.zkey- Proving key (~730MB)vkey.json- Verification key (small)
npm run test:proofOr programmatically:
import snarkjs from 'snarkjs';
// Generate witness
const { calculateWitness } = require('./build/proof_test/rsa_verify_pkcs1v15_js/witness_calculator');
const witness = await calculateWitness(input);
// Generate proof
const { proof, publicSignals } = await snarkjs.groth16.prove(
'build/proof_test/rsa_verify_pkcs1v15.zkey',
witness
);
// Verify proof
const vkey = JSON.parse(fs.readFileSync('build/proof_test/vkey.json'));
const verified = await snarkjs.groth16.verify(vkey, publicSignals, proof);
console.log('Proof verified:', verified);| Step | Time | Frequency |
|---|---|---|
| Download ptau | 10-30 min | Once (lifetime) |
| Compile circuit | 2-5 min | Once per circuit design |
| Generate proving key | 10-30 min | Once per circuit |
| Generate witness | 30-60 sec | Every proof |
| Generate proof | 10-30 min | Every proof |
| Verify proof | Milliseconds | Every verification |
Note: Actual times may vary significantly based on hardware. Modern machines with snarkjs 0.7.5 have been observed to complete zkey generation in ~12 minutes and proof generation in 10-30 minutes.
- Efficient cryptographic operations in snarkjs 0.7.5
- Modern hardware with multiple CPU cores
- Optimized circuit structure for 4096-bit operations
This project includes Random.org integration as a real-world example. The circuit itself is generic and works with any RSA-4096 + SHA-512 signature.
Random.org signs data in the following format:
{completionTime}\n{data[0]}\n{data[1]}\n...\n{data[n-1]}
The signature is a base64-encoded PKCS1v15 RSA signature using SHA-512. Random.org uses a 4096-bit RSA key.
generateSignedIntegers(n, min, max, replacement)- Generate signed random integersgenerateSignedStrings(n, length, characters)- Generate signed random strings
The Random.org public key is available in server.crt (included in this repository). You can also fetch it from:
The circuit verifies PKCS1v15 padding with SHA512 ASN.1 prefix:
0x00 0x01 [padding FF bytes] 0x00 [ASN.1 prefix] [SHA512 hash]
ASN.1 prefix for SHA512:
0x30 0x51 0x30 0x0d 0x06 0x09 0x60 0x86 0x48 0x01 0x65 0x03 0x04 0x02 0x03 0x05 0x00 0x04 0x40
w = 64: Word size in bitsnb = 64: Number of words for RSA modulus (64 × 64 = 4096 bits)e_bits = 17: Number of bits in exponent (65537 = 2^16 + 1)hashLen = 8: Hash length in words (512 bits = 8 × 64 bits)
- Ensure you're using power 21 or higher ptau file
- Check that the downloaded file is ~2.3GB
- Increase Node.js memory:
NODE_OPTIONS=--max_old_space_size=32000 - Close other applications
- Use a machine with more RAM (16GB+ recommended)
- Install circom:
npm install -g circom - Verify:
circom --version
The circuit generates harmless typing warnings about mismatched array dimensions. These are safe to ignore - Circom pads arrays with zeros automatically.
This project was built using code and concepts from the following open-source projects:
-
circom-rsa-verify - RSA signature verification circuit implementation
- Used as reference for RSA verification logic and PKCS1v15 padding verification
- Adapted for 4096-bit keys and SHA-512 hashing
-
sha512 - SHA-512 hashing circuit implementation
- Used as reference for SHA-512 hash function implementation in Circom
- Integrated into the RSA verification workflow
We extend our gratitude to the developers and contributors of these projects for their valuable work.
GPL-3.0