Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions agent/flow-trace/04_DKG_AND_COMPUTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -608,8 +608,15 @@ ThresholdKeyshare receives AllThresholdSharesCollected
│ │ 2. require(publicKeyHashes[e3Id] == 0) │
│ │ → Can only publish once │
│ │ 3. require(nodes.length == committee.length) │
│ │ 4. publicKeyHashes[e3Id] = pkHash │
│ │ 5. enclave.onCommitteePublished(e3Id, pkHash) │
│ │ 4. When proofAggregationEnabled: │
│ │ e3.pkVerifier.verify(pkCommitment, proof) │
│ │ → BFV: `BfvPkVerifier` (DkgAggregator Honk) │
│ │ • pins `publicInputs[0]` = nodes_fold VK hash │
│ │ • pins `publicInputs[1]` = C5 VK hash │
│ │ • checks last PI = pkCommitment │
│ │ Redeploy verifier when sub-circuit VKs change. │
│ │ 5. publicKeyHashes[e3Id] = pkHash │
│ │ 6. enclave.onCommitteePublished(e3Id, pkHash) │
│ │ │ │
│ │ │ ┌─ Enclave.sol ────────────────────────┐ │
│ │ │ │ onCommitteePublished(e3Id, pkHash) {│ │
Expand All @@ -620,7 +627,7 @@ ThresholdKeyshare receives AllThresholdSharesCollected
│ │ │ │ Emit E3StageChanged(KeyPublished) │ │
│ │ │ │ } │ │
│ │ │ └──────────────────────────────────────┘ │
│ │ 6. Emit CommitteePublished(e3Id, nodes, pk, C5 proof) │
│ │ 7. Emit CommitteePublished(e3Id, nodes, pk, C5 proof) │
│ │ → Note: emits full pk bytes, NOT just pkHash │
│ │ } │
│ └─────────────────────────────────────────────────────┘
Expand Down Expand Up @@ -837,7 +844,11 @@ EnclaveSolReader decodes CiphertextOutputPublished event
│ │ 4. decryptionVerifier.verify( │
│ │ e3Id, keccak256(output), proof │
│ │ ) │
│ │ → Verifies decryption was done correctly │
│ │ → BFV: `BfvDecryptionVerifier` │
│ │ • pins `publicInputs[0]` = c6_fold VK hash │
│ │ • pins `publicInputs[1]` = C7 VK hash │
│ │ • checks trailing 100 coeffs vs output hash │
│ │ Redeploy verifier when sub-circuit VKs change. │
│ │ 5. stage = Complete │
│ │ 6. _distributeRewards(e3Id) │
│ │ │ │
Expand Down
58 changes: 6 additions & 52 deletions circuits/benchmarks/results_insecure/crisp_verify_gas.json

Large diffs are not rendered by default.

102 changes: 51 additions & 51 deletions circuits/benchmarks/results_insecure/integration_summary.json

Large diffs are not rendered by default.

92 changes: 46 additions & 46 deletions circuits/benchmarks/results_insecure/report.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Enclave ZK Circuit Benchmarks

**Generated:** 2026-04-29 10:02:54 UTC
**Generated:** 2026-05-18 13:44:31 UTC

**Git Branch:** `feat/benches`
**Git Commit:** `36c01c62b86e2527279842280337f2f4724d2487`
**Git Branch:** `feat/1524`
**Git Commit:** `7df3cad298ea4d0194af1dcea8afc397a7c0540e`

**Committee Size:** `H=3`, `N=3`, `T=1`

Expand All @@ -15,36 +15,36 @@

| Circuit | Constraints | Prove time (s) | Verify time (ms) | Proof size (KB) |
| -------------------- | ----------- | -------------- | ---------------- | --------------- |
| C0 | 6847 | 0.12 | 24.97 | 15.88 |
| C1 | 57818 | 0.34 | 25.84 | 15.88 |
| C2a | 142625 | 0.78 | 25.50 | 15.88 |
| C2b | 198355 | 0.85 | 26.06 | 15.88 |
| C3a | 132633 | 0.78 | 25.14 | 15.88 |
| C3b | 132633 | 0.78 | 25.14 | 15.88 |
| C4a | 92515 | 0.50 | 25.00 | 15.88 |
| C4b | 92515 | 0.50 | 25.00 | 15.88 |
| C5 | 151717 | 0.79 | 26.28 | 15.88 |
| user_data_encryption | 53732 | 0.33 | 24.58 | 15.88 |
| C6 | 86927 | 0.52 | 25.34 | 15.88 |
| C7 | 104273 | 0.49 | 25.42 | 15.88 |
| C0 | 6847 | 0.12 | 26.98 | 15.88 |
| C1 | 57818 | 0.33 | 25.28 | 15.88 |
| C2a | 142625 | 0.77 | 25.29 | 15.88 |
| C2b | 198355 | 0.83 | 25.44 | 15.88 |
| C3a | 132633 | 0.79 | 26.15 | 15.88 |
| C3b | 132633 | 0.79 | 26.15 | 15.88 |
| C4a | 92515 | 0.49 | 25.59 | 15.88 |
| C4b | 92515 | 0.49 | 25.59 | 15.88 |
| C5 | 151717 | 0.79 | 25.38 | 15.88 |
| user_data_encryption | 53732 | 0.32 | 24.95 | 15.88 |
| C6 | 86927 | 0.50 | 24.76 | 15.88 |
| C7 | 104273 | 0.48 | 26.30 | 15.88 |

### Artifacts

| Artifact | Proof size | Public input size | Verify gas | Calldata gas | Total gas |
| -------- | ---------- | ----------------- | ---------- | ------------ | --------- |
| Π_DKG | 10.69 KB | 0.41 KB | 3037922 | 175616 | 3213538 |
| Π_user | 15.88 KB | 0.12 KB | 2973073 | 170272 | 3143345 |
| Π_dec | 10.69 KB | 3.41 KB | 3549077 | 186764 | 3735841 |
| Π_DKG | 10.69 KB | 0.41 KB | 3037910 | 175424 | 3213334 |
| Π_user | 15.88 KB | 0.12 KB | 2972965 | 170200 | 3143165 |
| Π_dec | 10.69 KB | 3.41 KB | 3549222 | 186764 | 3735986 |

### Role / Phase / Activity

| Role | Phase | Activity | Prove time | Proof size | Bandwidth |
| --------------- | ----- | -------------------------------- | ---------- | ---------- | --------- |
| Each ciphernode | P1 | one-time DKG participation | 379.38 s | 127.00 KB | 128.19 KB |
| Each ciphernode | P1 | one-time DKG participation | 304.50 s | 127.00 KB | 128.19 KB |
| Aggregator | P2 | combine folds + C5 | 0.79 s | 10.69 KB | 11.09 KB |
| User | P3 | per user input | 0.65 s | 15.88 KB | 16.00 KB |
| Each ciphernode | P4 | per computation output (C6) | 0.52 s | 15.88 KB | 16.00 KB |
| Aggregator | P4 | per computation output (C7+fold) | 80.31 s | 10.69 KB | 14.09 KB |
| User | P3 | per user input | 0.64 s | 15.88 KB | 16.00 KB |
| Each ciphernode | P4 | per computation output (C6) | 0.50 s | 15.88 KB | 16.00 KB |
| Aggregator | P4 | per computation output (C7+fold) | 79.27 s | 10.69 KB | 14.09 KB |

## Integration test (`test_trbfv_actor`)

Expand All @@ -53,15 +53,15 @@
| Phase | Duration (s) |
| ------------------------------------------- | ------------ |
| Starting trbfv actor test | 0.00 |
| Setup completed | 2.98 |
| Committee Setup Completed | 20.25 |
| Setup completed | 3.04 |
| Committee Setup Completed | 20.24 |
| Committee Finalization Complete | 0.01 |
| ThresholdShares -> PublicKeyAggregated | 379.38 |
| E3Request -> PublicKeyAggregated | 381.92 |
| Application CT Gen | 0.31 |
| ThresholdShares -> PublicKeyAggregated | 304.50 |
| E3Request -> PublicKeyAggregated | 307.02 |
| Application CT Gen | 0.32 |
| Running FHE Application | 0.00 |
| Ciphertext published -> PlaintextAggregated | 80.31 |
| Entire Test | 485.79 |
| Ciphertext published -> PlaintextAggregated | 79.27 |
| Entire Test | 409.92 |

### Thread pool (same process as integration test)

Expand All @@ -75,26 +75,26 @@

| Name | Avg (s) | Runs | Total (s) |
| ----------------------------- | ------- | ---- | --------- |
| CalculateDecryptionKey | 0.11 | 3 | 0.33 |
| CalculateDecryptionShare | 0.61 | 3 | 1.84 |
| CalculateThresholdDecryption | 0.57 | 1 | 0.57 |
| CalculateDecryptionKey | 0.12 | 3 | 0.35 |
| CalculateDecryptionShare | 0.61 | 3 | 1.83 |
| CalculateThresholdDecryption | 0.58 | 1 | 0.58 |
| GenEsiSss | 0.12 | 3 | 0.37 |
| GenPkShareAndSkSss | 0.22 | 3 | 0.67 |
| ZkDecryptedSharesAggregation | 8.54 | 1 | 8.54 |
| ZkDecryptionAggregation | 49.65 | 1 | 49.65 |
| ZkDkgAggregation | 20.66 | 1 | 20.66 |
| ZkDkgShareDecryption | 1.45 | 6 | 8.68 |
| ZkNodeDkgFold | 78.08 | 3 | 234.23 |
| ZkPkAggregation | 2.19 | 1 | 2.19 |
| ZkDecryptedSharesAggregation | 8.57 | 1 | 8.57 |
| ZkDecryptionAggregation | 49.05 | 1 | 49.05 |
| ZkDkgAggregation | 20.15 | 1 | 20.15 |
| ZkDkgShareDecryption | 1.50 | 6 | 9.03 |
| ZkNodeDkgFold | 62.89 | 3 | 188.67 |
| ZkPkAggregation | 2.16 | 1 | 2.16 |
| ZkPkBfv | 0.33 | 3 | 0.99 |
| ZkPkGeneration | 1.34 | 3 | 4.01 |
| ZkShareComputation | 2.65 | 6 | 15.91 |
| ZkShareEncryption | 2.47 | 36 | 89.00 |
| ZkThresholdShareDecryption | 6.20 | 3 | 18.59 |
| ZkVerifyShareDecryptionProofs | 0.10 | 3 | 0.30 |
| ZkVerifyShareProofs | 0.22 | 5 | 1.08 |

Sum of tracked operation wall time: **457.62 s** (often much larger than end-to-end wall clock
| ZkPkGeneration | 1.33 | 3 | 3.99 |
| ZkShareComputation | 2.69 | 6 | 16.16 |
| ZkShareEncryption | 2.49 | 24 | 59.76 |
| ZkThresholdShareDecryption | 6.05 | 3 | 18.14 |
| ZkVerifyShareDecryptionProofs | 0.10 | 3 | 0.29 |
| ZkVerifyShareProofs | 0.23 | 5 | 1.13 |

Sum of tracked operation wall time: **381.88 s** (often much larger than end-to-end wall clock
because work runs in parallel).

## Raw circuit benchmark JSON (Nargo)
Expand Down
5 changes: 3 additions & 2 deletions examples/CRISP/enclave.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ chains:
rpc_url: ws://localhost:8545
contracts:
e3_program:
address: "0x809d550fca64d94Bd9F66E60752A544199cfAC3D"
deploy_block: 31
address: "0x0E801D84Fa97b50751Dbf25036d067dCf18858bF"
deploy_block: 37
enclave:
address: "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e"
deploy_block: 14
Expand All @@ -21,6 +21,7 @@ chains:
address: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512"
deploy_block: 4
- name: "sepolia"
enabled: false
# Public Sepolia WebSocket endpoint (see repo docs for the recommended default).
rpc_url: "wss://ethereum-sepolia-rpc.publicnode.com"
contracts:
Expand Down
7 changes: 5 additions & 2 deletions examples/CRISP/packages/crisp-contracts/deploy/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ export const deploy = async () => {
const shouldDeployEnclave = Boolean(process.env.DEPLOY_ENCLAVE)
const shouldPrintEnv = Boolean(process.env.PRINT_ENV_VARS)

// Mock BFV verifiers only: CRISP E2E uses E3_PROOF_AGGREGATION_ENABLED=false and does not
// ship compiled `*.vk_recursive_hash` artifacts required by BfvPkVerifier / BfvDecryptionVerifier.
if (shouldDeployEnclave) {
await deployEnclave(true, true)
await deployEnclave(true, false)
}
await deployCRISPContracts()

Expand All @@ -60,5 +62,6 @@ export const deploy = async () => {
}

deploy().catch((err) => {
console.log(err)
console.error(err)
process.exit(1)
})
2 changes: 1 addition & 1 deletion examples/CRISP/server/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ CRON_API_KEY=1234567890
# Based on Default Anvil Deployments (Only for testing)
ENCLAVE_ADDRESS=0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e
FEE_TOKEN_ADDRESS=0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
E3_PROGRAM_ADDRESS=0x809d550fca64d94Bd9F66E60752A544199cfAC3D
E3_PROGRAM_ADDRESS=0x0E801D84Fa97b50751Dbf25036d067dCf18858bF
CIPHERNODE_REGISTRY_ADDRESS=0xa513E6E4b8f2a923D98304ec87F64353C4D5C853

# E3 Config
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: LGPL-3.0-only
//
// This file is provided WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.
pragma solidity 0.8.28;

import { ICircuitVerifier } from "../interfaces/ICircuitVerifier.sol";

/// @notice Test helper: reverts if `verify` is invoked (proves early return in wrappers).
contract RevertOnVerifyCircuitVerifier is ICircuitVerifier {
function verify(
bytes calldata,
bytes32[] calldata
) external pure returns (bool) {
revert("verify called");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,20 @@ contract BfvDecryptionVerifier is IDecryptionVerifier {
/// @notice Underlying Honk verifier for the DecryptionAggregator circuit.
ICircuitVerifier public immutable circuitVerifier;

constructor(address _circuitVerifier) {
/// @notice Expected recursive VK hash for the c6_fold sub-circuit (`publicInputs[0]`).
bytes32 public immutable expectedC6FoldKeyHash;

/// @notice Expected recursive VK hash for the C7/decrypted_shares_aggregation sub-circuit (`publicInputs[1]`).
bytes32 public immutable expectedC7KeyHash;

constructor(
address _circuitVerifier,
bytes32 _expectedC6FoldKeyHash,
bytes32 _expectedC7KeyHash
) {
circuitVerifier = ICircuitVerifier(_circuitVerifier);
expectedC6FoldKeyHash = _expectedC6FoldKeyHash;
expectedC7KeyHash = _expectedC7KeyHash;
}

/// @inheritdoc IDecryptionVerifier
Expand All @@ -40,7 +52,13 @@ contract BfvDecryptionVerifier is IDecryptionVerifier {
(bytes, bytes32[])
);

if (publicInputs.length < MESSAGE_COEFFS_COUNT) {
if (publicInputs.length < MESSAGE_COEFFS_COUNT + 2) {
return false;
}
if (publicInputs[0] != expectedC6FoldKeyHash) {
return false;
}
if (publicInputs[1] != expectedC7KeyHash) {
return false;
}
if (!_verifyPlaintextHash(publicInputs, plaintextOutputHash)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,20 @@ contract BfvPkVerifier is IPkVerifier {
/// @notice Underlying Honk verifier for the DkgAggregator circuit.
ICircuitVerifier public immutable circuitVerifier;

constructor(address _circuitVerifier) {
/// @notice Expected recursive VK hash for the nodes_fold sub-circuit (`publicInputs[0]`).
bytes32 public immutable expectedNodesFoldKeyHash;

/// @notice Expected recursive VK hash for the C5/pk_aggregation sub-circuit (`publicInputs[1]`).
bytes32 public immutable expectedC5KeyHash;

constructor(
address _circuitVerifier,
bytes32 _expectedNodesFoldKeyHash,
bytes32 _expectedC5KeyHash
) {
circuitVerifier = ICircuitVerifier(_circuitVerifier);
expectedNodesFoldKeyHash = _expectedNodesFoldKeyHash;
expectedC5KeyHash = _expectedC5KeyHash;
}

/// @inheritdoc IPkVerifier
Expand All @@ -35,7 +47,13 @@ contract BfvPkVerifier is IPkVerifier {
(bytes, bytes32[])
);

if (publicInputs.length == 0) {
if (publicInputs.length < 3) {
return false;
}
if (publicInputs[0] != expectedNodesFoldKeyHash) {
return false;
}
if (publicInputs[1] != expectedC5KeyHash) {
return false;
}
if (publicInputs[publicInputs.length - 1] != pkCommitment) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,28 @@
// or FITNESS FOR A PARTICULAR PURPOSE.
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";

import {
BFV_DECRYPTION_SUB_CIRCUIT_VK_HASH_PATHS,
readVkRecursiveHash,
} from "../../scripts/utils";
import decryptionAggregatorVerifierModule from "./decryptionAggregatorVerifier";

export default buildModule("BfvDecryptionVerifier", (m) => {
const { decryptionAggregatorVerifier } = m.useModule(
decryptionAggregatorVerifierModule,
);

const expectedC6FoldKeyHash = readVkRecursiveHash(
BFV_DECRYPTION_SUB_CIRCUIT_VK_HASH_PATHS.c6Fold,
);
const expectedC7KeyHash = readVkRecursiveHash(
BFV_DECRYPTION_SUB_CIRCUIT_VK_HASH_PATHS.c7,
);

const bfvDecryptionVerifier = m.contract("BfvDecryptionVerifier", [
decryptionAggregatorVerifier,
expectedC6FoldKeyHash,
expectedC7KeyHash,
]);

return { bfvDecryptionVerifier };
Expand Down
17 changes: 16 additions & 1 deletion packages/enclave-contracts/ignition/modules/bfvPkVerifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,27 @@
// or FITNESS FOR A PARTICULAR PURPOSE.
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";

import {
BFV_PK_SUB_CIRCUIT_VK_HASH_PATHS,
readVkRecursiveHash,
} from "../../scripts/utils";
import dkgAggregatorVerifierModule from "./dkgAggregatorVerifier";

export default buildModule("BfvPkVerifier", (m) => {
const { dkgAggregatorVerifier } = m.useModule(dkgAggregatorVerifierModule);

const bfvPkVerifier = m.contract("BfvPkVerifier", [dkgAggregatorVerifier]);
const expectedNodesFoldKeyHash = readVkRecursiveHash(
BFV_PK_SUB_CIRCUIT_VK_HASH_PATHS.nodesFold,
);
const expectedC5KeyHash = readVkRecursiveHash(
BFV_PK_SUB_CIRCUIT_VK_HASH_PATHS.c5,
);

const bfvPkVerifier = m.contract("BfvPkVerifier", [
dkgAggregatorVerifier,
expectedNodesFoldKeyHash,
expectedC5KeyHash,
]);

return { bfvPkVerifier };
}) as any;
Loading
Loading