RSA-2048 PKCS#1 v1.5 Verification
Verify RSA-2048 PKCS#1 v1.5 signatures with SHA-256 in zero knowledge: the modulus is public, the signature and the signed message stay private.
On this page
The RSA chiplet proves that a signature verifies under RSA-2048 PKCS#1 v1.5 with SHA-256 and the public exponent 65537, with the modulus public and the signature and the message in the witness.
§ What the proof states
Pkcs1Statement proves s^65537 mod N = EM, where EM is the EMSA-PKCS1-v1_5 encoding of RFC 8017 §9.2 applied to the
SHA-256 digest of the message. N is a public 2048-bit input; the signature s and the message are witness, and the
digest is chained over committed block words.
§ How the tables split the work
The host table chains SHA-256 one block per row and requests two chiplets over the LogUp bus: modular exponentiation
from hekate-gadgets and compression from the SHA-256 chiplet. On the last block row it compares
the modexp output with the encoding, limbs 0 to 7 against the digest words and limbs 8 to 63 against the encoding
constants. All 56 constant limbs are pinned.
§ Outside the proof
- Message padding. FIPS 180-4 §5.1.1 padding is left to the caller.
- RSASSA-PSS.
- Other moduli and exponents. The statement fixes a 2048-bit modulus and e = 65537.
- Signing.
§ Examples
hekate/examples/rsa_pkcs1.rs runs RSA-2048 PKCS#1 v1.5 with SHA-256 end to end on a fixed RSA-2048 key
and its signature over the 200-byte message 0, 1, …, 199, both generated with CPython. From a hekate checkout:
public builds the variable-time table-math prover that the README's measurements use. Without it the recipe builds
the constant-time prover, the one to use when the witness is private.
The program below drives the crate the same way, at two rounds per row and 512-row tables, in two files: src/key.rs
holds the example's modulus N and signature S as 64 limbs of 32 bits each, and src/main.rs builds the statement with
Pkcs1Statement, proves and verifies. Start from the crates in Installation
and add hekate-rsa, hekate-sha2 and rand.
1pub const N: = ;
11
12pub const S: = ;
1
2
3use Config;
4use DefaultHasher;
5use Transcript;
6use Block128;
7use program_id;
8use prove;
9use Pkcs1Statement;
10use preflight;
11use pad_message;
12use HekateVerifier;
13use ;
14use ;
15use Error;
16
17const LABEL: & = b"rsa-pkcs1";
18const ROUNDS_PER_ROW: usize = 2;
19const SHA_ROWS: usize = 512;
20const CPU_ROWS: usize = 512;
21
22type F = Block128;
23
24
N is the only public input; the message, its digest and the signature stay in the witness. The statement pins no SHA-256 padding: the proof shows that the prover holds a four-block message with a valid signature under N, and the message length is not fixed.
§ Performance
Zero-knowledge proofs, measured on Apple M3 Max, 16 cores. Build: --release, std parallel blake3 table-math public. Best of three on an otherwise idle machine. The Benchmarks page has the base-protocol figures and the command for each run.
| Workload | Input | Proving | Verify | Proof size | Peak memory |
|---|---|---|---|---|---|
| RSA-2048 PKCS#1 v1.5 | RFC 8017 | 209 ms | 8.0 ms | 1,813 KiB | 401 MiB |
§ Security
The crate has not been audited and may contain bugs and security flaws, as its README states. Hekate proves 100 bits of soundness.
§ License
hekate-rsa is AGPL-3.0-only. Commercial licenses are available from Oumuamua Labs at
info@oumuamua.dev. The README's Usage section builds the statement for one
RSA-2048 signature, and the API reference is on docs.rs.