THE EXECUTION LAYER
Encrypted solutions
An encrypted implementation answers the same specification as a plain one — same signature, same points, same generator, same verifier — but its measured perimeter is longer: data must be encoded, encrypted, computed on, decrypted and decoded, and keys must exist before any of that. The contract below makes every stage explicit, clocks each one, and scores exactly one.
Four functions
The author writes four functions instead of three:
init (p, cc) -> State public setup: plaintexts,
plans, precomputed material
encoding(cc, inp) -> [Plaintext] packing cleartext into slots
run (state, cc, cts, publics) -> [Ciphertext] the answer ← MEASURED
decoding(p, cc, pts, publics) -> Outputs unpacking the result
cc is the cryptographic context. Arguments declared secret<…> in the
signature arrive in run as ciphertexts; public arguments arrive as plain
values. Only run is inside the timing window.
The envelope
Everything cryptographic that is not the author's algorithm — context construction, key generation, encryption of the encoded inputs, decryption of the results — is generated code, called the envelope. The author never touches a secret key; the envelope makes them, uses them, and they exist only inside the measured process.
envelope: keygen → encrypt(encoding(inputs)) → [ run ] → decoding(decrypt(outputs))
↑ the only scored call
Every stage is clocked and reported: keygen (as envelope_s), init, and
per case encoding, encrypt, the measured call, decrypt, decoding.
The pages show them apart — an encrypted answer costs more than its measured
call, and the platform says so instead of hiding it — but none of them enter
the score.
The declared parameters
The envelope is built from config.jsonc, committed beside the solution.
It declares the scheme and everything the context needs — ring dimension,
multiplicative depth or torus budget, scale, batch size, rotation key
indexes, bootstrapping. The runner reads it from the measured commit and the
run records it, so a page can always hold the parameters against what the
circuit actually spent — spare levels included.
Security, with its provenance
The config names a security floor (128-bit classic and up). How much that claim is worth depends on who enforces it, and the pages say which:
- enforced — the library itself refuses smaller parameters at context
creation (OpenFHE's
HEStd_128_classic); - estimated — the toolchain checks the declared parameters against a published table before anything runs, but the library does not attest a level itself (Poulpy).
A number without its provenance reads like a certificate, which is why the distinction is printed everywhere the number is.
Libraries
The toolchain scaffolds the whole wire — harness, envelope, config, build — per library, from the same signature:
| library | scheme(s) | language of the skeleton |
|---|---|---|
| OpenFHE | ckks, bgv, bfv | C++ or Python |
| Poulpy | ckks | Rust |
fherma implementation init kernel/spec@1.0.0 --fhe openfhe --scheme ckks fherma implementation init kernel/spec@1.0.0 --fhe poulpy --scheme ckks
Two implementations of one specification on two libraries are directly comparable — same points, same data, same verifier — and the compare page has a view that holds libraries side by side.
What a run reports, beyond the times
result_level— the level the answer came back at: the depth the circuit actually spent, held against the depth the config paid for;- ciphertext counts in and out of the measured call;
- the memory profile, sampled by the runner five times a second — key material shows up as the step right after keygen, and the pages read it off the curve rather than estimating it.
What is judged
Exactly what is judged for a plain solution: the decoded cleartext outputs, by the specification's verifier, case by case — and the point under the bundle's bar. Encryption is between the oracle and the run, and the oracle never knows it happened.