diff --git a/.husky/pre-push b/.husky/pre-push index a316c7f6a8..c50453b68b 100644 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -1,3 +1,4 @@ pnpm lint pnpm check:pnpm -pnpm check:license \ No newline at end of file +pnpm check:license +pnpm check:committee \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 09d0d9c5d1..b20013f402 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3841,6 +3841,7 @@ dependencies = [ "num-bigint", "rand 0.8.5", "rand_chacha 0.3.1", + "serde_json", "serial_test", "tempfile", "tokio", diff --git a/agent/RULES.md b/agent/RULES.md index 11cf5b2466..df4f3dc992 100644 --- a/agent/RULES.md +++ b/agent/RULES.md @@ -12,6 +12,27 @@ content. - `tests/` — Integration tests - `agent/` — LLM context documentation +## Build configuration: preset and committee + +Two orthogonal axes pick what gets compiled into `circuits/bin/`: + +- **Preset** (`--preset insecure-512` [default] | `secure-8192`): the BFV parameter set. +- **Committee** (`--committee micro` [default] | `small` | `medium`): `(N, T, H)` for the + secret-sharing committee. Mirrors `e3_zk_helpers::CiphernodesCommitteeSize`. + +The current selection is the single source of truth at three places that **must** stay in sync: + +| File | Owner | +| ----------------------------------------------------------- | ------------------------------------------ | +| `circuits/lib/src/configs/committee/active.nr` | regenerated by `scripts/build-circuits.ts` | +| `packages/enclave-contracts/scripts/utils.ts` (`BFV_DKG_H`) | regenerated by `scripts/build-circuits.ts` | +| `circuits/bin/.active-preset.json` | written by `scripts/build-circuits.ts` | + +`scripts/check-committee.sh` (pre-push hook: `pnpm check:committee`) enforces consistency. Always +switch with `pnpm build:circuits --committee `; never hand-edit the three files above. +Supported `(preset, committee)` pairs live in `scripts/circuit-constants.ts`. See +`scripts/README.md#circuit-builder` and `circuits/benchmarks/README.md` for the full recipe. + ## Flow-Trace Documentation (`agent/flow-trace/`) The `agent/flow-trace/` directory contains detailed protocol documentation that traces the complete diff --git a/agent/flow-trace/04_DKG_AND_COMPUTATION.md b/agent/flow-trace/04_DKG_AND_COMPUTATION.md index e1bc60c69f..583d116035 100644 --- a/agent/flow-trace/04_DKG_AND_COMPUTATION.md +++ b/agent/flow-trace/04_DKG_AND_COMPUTATION.md @@ -473,6 +473,13 @@ ThresholdKeyshare receives AllThresholdSharesCollected │ │ │ → Stored encrypted locally for later decryption │ │ │ └─────────────────────────────────────────────────────┘ │ +├─ 2b. CANONICAL H ROSTER (when H < N): +│ Before C4 witness layout, merge external honest party_ids with own_party_id, +│ sort ascending, and keep the lowest H — same rule as PublicKeyAggregator C5 cap +│ (`e3_zk_helpers::canonical_honest_party_ids_with_own`). Persisted as `honest_parties`. +│ Parties outside the lowest H still complete KeyshareCreated but are not in the +│ aggregator's NodeFold / `honest_committee_addresses` roster. +│ ├─ 3. PUBLISH C4 PROOF REQUESTS: │ DecryptionShareProofsPending { │ sk_request: DkgShareDecryptionProofRequest (C4a), @@ -548,31 +555,43 @@ ThresholdKeyshare receives AllThresholdSharesCollected │ ├─ Only the active aggregator's buffer flushes into PublicKeyAggregator │ - ├─ When threshold_n keyshares collected: + ├─ When N distinct keyshares collected (committee size from on-chain `threshold_n`): +│ │ +│ ├─ C1 verification runs over all N submitters; parties failing C1 are marked dishonest +│ │ +│ ├─ Honest-set selection (compile-time H from `committee::active`, may be < N): +│ │ • Require at least H parties with valid C1 proofs; otherwise E3Failed +│ │ • If more than H parties pass C1, keep the H lowest `party_id`s as the canonical +│ │ honest set (extras remain in the full committee roster for `committee_hash` +│ │ binding but do not receive NodeFold / C5 inputs) │ │ -│ ├─ 1. Aggregate public key shares: +│ ├─ 1. Aggregate public key shares (H honest keyshares): │ │ aggregate_pk = Fhe::get_aggregate_public_key( -│ │ [pk_share_1, pk_share_2, ..., pk_share_N] +│ │ [pk_share for each of the H canonical honest parties] │ │ ) │ │ → Uses PublicKeyShare::aggregate() │ │ → Produces the COLLECTIVE public key │ │ → Anyone can encrypt with this key │ │ → Only M+1 committee members can decrypt together │ │ -│ ├─ 2. Compute commitment: -│ │ pk_hash = compute_pk_commitment(aggregate_pk) +│ ├─ 2. Build C5 proof request (H canonical honest keyshares): +│ │ proof_request.keyshare_bytes = [pk_share for each H party] +│ │ proof_request.aggregated_pk_bytes = aggregate_pk +│ │ proof_request.committee_n = committee_h = H // C5 circuit sized for H, not N +│ │ (per-share compute_pk_commitment already checked against C1; aggregate +│ │ commitment is proved as a C5 public output, not pre-published here) │ │ │ ├─ 3. REQUEST C5 PROOF: │ │ Publish PkAggregationProofPending { -│ │ proof_request: PkAggregationProofRequest, +│ │ proof_request, // H keyshares + aggregate_pk (see step 2) │ │ public_key: aggregate_pk, -│ │ public_key_hash: pk_hash +│ │ nodes: honest_nodes // H canonical subset │ │ } │ │ │ ├─ 4. C5 PROOF GENERATION (ProofRequestActor): │ │ ├─ Dispatches ComputeRequest::zk(ZkRequest::PkAggregation {...}) │ │ │ → Circuit: PkAggregation (C5) -│ │ │ → Proves aggregate PK was correctly computed from all pk_shares +│ │ │ → Proves aggregate PK was correctly computed from the H canonical honest keyshares │ │ ├─ ZkActor generates proof via bb binary │ │ ├─ Signs proof │ │ └─ Publishes PkAggregationProofSigned { @@ -593,6 +612,8 @@ ThresholdKeyshare receives AllThresholdSharesCollected │ │ │ └─ 6. Publish PublicKeyAggregated { │ e3_id, pubkey: aggregate_pk, pk_commitment, nodes, +│ committee_addresses, // length N — full on-chain topNodes binding +│ honest_committee_addresses, // length H — canonical honest subset │ dkg_aggregator_proof │ } │ @@ -947,7 +968,8 @@ EnclaveSolReader decodes CiphertextOutputPublished event │ │ │ │ by C6 │ ├──────┼────────────────────────────┼───────────────────┼──────────────────────────────┤ │ C5 │ PK Aggregation │ Aggregation │ Aggregate PK correctly │ -│ │ │ │ computed from all pk_shares │ +│ │ │ │ computed from H canonical │ +│ │ │ │ honest keyshares (not all N) │ ├──────┼────────────────────────────┼───────────────────┼──────────────────────────────┤ │ C6 │ Threshold Share Decryption │ Decryption │ Decryption share correctly │ │ │ (T5) │ │ derived from sk + ciphertext;│ diff --git a/circuits/benchmarks/README.md b/circuits/benchmarks/README.md index 5fe45048e7..d6376335c8 100644 --- a/circuits/benchmarks/README.md +++ b/circuits/benchmarks/README.md @@ -19,6 +19,43 @@ From this directory: Options and secure-only **config** circuit behavior are documented in the script and `config.json`. +### Selecting committee size (micro / small / medium) + +Benchmarks compile and run against whichever committee is **active** in the Noir tree. Default is +`micro` (N=3, T=1, H=3). To benchmark with a different committee, switch it once at the build step +and the Rust integration test, gas-extraction script, and report will all pick it up automatically. + +**Step-by-step** (from repository root): + +```bash +# 1. Pick the committee. This regenerates committee/active.nr, default/mod.nr, +# and patches BFV_DKG_H / BFV_THRESHOLD_T in utils.ts atomically. It also writes +# the committee into circuits/bin/.active-preset.json. +pnpm build:circuits --preset insecure-512 --committee medium + +# 2. (Optional) Verify the four files agree. +pnpm check:committee +# → ✓ check:committee: medium (H=8, T=4) consistent across active.nr, utils.ts, .active-preset.json + +# 3. Run the benchmark. ENCLAVE_COMMITTEE_SIZE makes the Rust test pick the same committee +# and panic up-front if it disagrees with the stamp. +ENCLAVE_COMMITTEE_SIZE=medium ./circuits/benchmarks/run_benchmarks.sh --mode insecure + +# 4. To go back to micro, run step 1 again with --committee micro. +pnpm build:circuits --preset insecure-512 --committee micro +``` + +**All `(preset, committee)` pairs are supported.** The parity matrices in +`circuits/lib/src/configs/committee//parity_{insecure,secure}.nr` are auto-generated by the +`generate_parity_matrices` Rust binary, invoked from `scripts/build-circuits.ts` whenever the +committee changes. The values are deterministic functions of the committee's `(N, T)` and the +preset's threshold `QIS`, so any pair compiles and proves correctly. + +**Skipping the build step:** `pnpm check:committee` runs in the pre-push hook and fails the push if +`active.nr`, `utils.ts`, `.active-preset.json`, or any committed `parity_*.nr` disagree with what +`build:circuits --committee ` would produce. Always use `pnpm build:circuits --committee` to +switch; manual edits to those files will trip the check. + ### Proof aggregation and folding (integration) The gas / integration stage runs `cargo test -p e3-tests test_trbfv_actor` with **proof aggregation diff --git a/circuits/benchmarks/results_insecure_agg/crisp_verify_gas.json b/circuits/benchmarks/results_insecure_agg/crisp_verify_gas.json deleted file mode 100644 index 7187133662..0000000000 --- a/circuits/benchmarks/results_insecure_agg/crisp_verify_gas.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "verify_gas": { - "dkg": 3125294, - "user": 2972881, - "dec": 3640985 - }, - "source": "folded_proof_export_plus_crisp_verify_test", - "artifact_sizes_bytes": { - "dkg": { - "proof": 10944, - "public_inputs": 480 - }, - "dec": { - "proof": 10944, - "public_inputs": 3552 - } - }, - "calldata_gas": { - "dkg": { - "proof": 169980, - "public_inputs": 6168, - "total": 176148 - }, - "dec": { - "proof": 169956, - "public_inputs": 17304, - "total": 187260 - } - }, - "integration_summary": { - "integration_test": "test_trbfv_actor", - "benchmark_config": { - "mode": "insecure", - "bfv_preset_subdir": "insecure-512", - "bfv_preset": "InsecureThreshold512", - "lambda": 2, - "proof_aggregation_enabled": true, - "multithread_concurrent_jobs": 13, - "committee_h": 3, - "committee_n": 3, - "committee_t": 1, - "nodes_spawned": 20, - "network_model": "in_process_bus", - "testmode_harness": true - }, - "proof_aggregation_enabled": true, - "dkg_fold_attestation_verifier": "0x7969c5eD335650692Bc04293B07F5BF2e7A673C0", - "multithread": { "rayon_threads": 13, "max_simultaneous_rayon_tasks": 13, "cores_available": 14 }, - "operation_timings": [ - { "name": "CalculateDecryptionKey", "avg_seconds": 0.004296347, "runs": 3, "total_seconds": 0.012889042 }, - { "name": "CalculateDecryptionShare", "avg_seconds": 0.020525153, "runs": 3, "total_seconds": 0.061575459 }, - { "name": "CalculateThresholdDecryption", "avg_seconds": 0.019100917, "runs": 1, "total_seconds": 0.019100917 }, - { "name": "GenEsiSss", "avg_seconds": 0.006925194, "runs": 3, "total_seconds": 0.020775584 }, - { "name": "GenPkShareAndSkSss", "avg_seconds": 0.010452847, "runs": 3, "total_seconds": 0.031358542 }, - { "name": "NodeDkgFold/c2ab_fold", "avg_seconds": 8.270900388, "runs": 3, "total_seconds": 24.812701166 }, - { "name": "NodeDkgFold/c3a_fold", "avg_seconds": 34.927441903, "runs": 3, "total_seconds": 104.782325709 }, - { "name": "NodeDkgFold/c3ab_fold", "avg_seconds": 7.542320708, "runs": 3, "total_seconds": 22.626962125 }, - { "name": "NodeDkgFold/c3b_fold", "avg_seconds": 34.922820125, "runs": 3, "total_seconds": 104.768460375 }, - { "name": "NodeDkgFold/c4ab_fold", "avg_seconds": 7.895315874, "runs": 3, "total_seconds": 23.685947624 }, - { "name": "NodeDkgFold/node_fold", "avg_seconds": 18.310982819, "runs": 3, "total_seconds": 54.932948458 }, - { "name": "ZkDecryptedSharesAggregation", "avg_seconds": 1.566955375, "runs": 1, "total_seconds": 1.566955375 }, - { "name": "ZkDecryptionAggregation", "avg_seconds": 47.874825458, "runs": 1, "total_seconds": 47.874825458 }, - { "name": "ZkDkgAggregation", "avg_seconds": 19.861393583, "runs": 1, "total_seconds": 19.861393583 }, - { "name": "ZkDkgShareDecryption", "avg_seconds": 1.358248069, "runs": 6, "total_seconds": 8.149488419 }, - { "name": "ZkNodeDkgFold", "avg_seconds": 111.87172225, "runs": 3, "total_seconds": 335.61516675 }, - { "name": "ZkPkAggregation", "avg_seconds": 0.925223417, "runs": 1, "total_seconds": 0.925223417 }, - { "name": "ZkPkBfv", "avg_seconds": 0.218732388, "runs": 3, "total_seconds": 0.656197166 }, - { "name": "ZkPkGeneration", "avg_seconds": 3.515460263, "runs": 3, "total_seconds": 10.54638079 }, - { "name": "ZkShareComputation", "avg_seconds": 2.332301763, "runs": 6, "total_seconds": 13.993810582 }, - { "name": "ZkShareEncryption", "avg_seconds": 3.965180039, "runs": 24, "total_seconds": 95.164320958 }, - { "name": "ZkThresholdShareDecryption", "avg_seconds": 3.440710889, "runs": 3, "total_seconds": 10.322132667 }, - { "name": "ZkVerifyShareDecryptionProofs", "avg_seconds": 0.103301764, "runs": 3, "total_seconds": 0.309905292 }, - { "name": "ZkVerifyShareProofs", "avg_seconds": 0.285312216, "runs": 5, "total_seconds": 1.426561084 } - ], - "operation_timings_total_seconds": 882.167406542, - "operation_timings_metric": "tracked_job_wall", - "phase_timings": [ - { "label": "Starting trbfv actor test", "seconds": 0e-9, "metric": "wall_clock" }, - { "label": "Setup completed", "seconds": 2.7038335, "metric": "wall_clock" }, - { "label": "Committee Setup Completed", "seconds": 20.174264042, "metric": "wall_clock" }, - { "label": "Committee Finalization Complete", "seconds": 0.003923875, "metric": "wall_clock" }, - { "label": "Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall)", "seconds": 131.619168, "metric": "wall_clock" }, - { "label": "ThresholdShares -> PublicKeyAggregated", "seconds": 144.272573833, "metric": "wall_clock" }, - { "label": "E3Request -> PublicKeyAggregated", "seconds": 144.78216475, "metric": "wall_clock" }, - { "label": "Application CT Gen", "seconds": 0.009741125, "metric": "wall_clock" }, - { "label": "Running FHE Application", "seconds": 0.000051333, "metric": "wall_clock" }, - { "label": "Aggregator P4: Aggregation pending -> PlaintextAggregated (wall)", "seconds": 49.457601, "metric": "wall_clock" }, - { "label": "Ciphertext published -> PlaintextAggregated", "seconds": 53.35583, "metric": "wall_clock" }, - { "label": "Entire Test", "seconds": 221.027911708, "metric": "wall_clock" } - ], - "folded_artifacts": { - "dkg_aggregator": { - "proof_hex": "0x000000000000000000000000000000000000000000000002b30b0403aeee459600000000000000000000000000000000000000000000000db8eebcfc671fdeea00000000000000000000000000000000000000000000000af8f618d2adad1ebe0000000000000000000000000000000000000000000000000002c5040e9c20dc00000000000000000000000000000000000000000000000a2de63e4ca6eb0e210000000000000000000000000000000000000000000000021ae69d4a65c7a8e900000000000000000000000000000000000000000000000a005bc241e7d733b30000000000000000000000000000000000000000000000000002aa8c45dd85d4000000000000000000000000000000000000000000000008ff1dbd0f4b9b41c900000000000000000000000000000000000000000000000a46e1fc8b19f097560000000000000000000000000000000000000000000000075006eb06b9214632000000000000000000000000000000000000000000000000000093433350ca3600000000000000000000000000000000000000000000000c8e6e0c4281f705a50000000000000000000000000000000000000000000000043c924cc53c6b0e6b000000000000000000000000000000000000000000000009a11c5c7358610a3300000000000000000000000000000000000000000000000000001c36379475c900f5f028b1ca9b05f4fd64f348afe95c048291c2608303e91a5c888446ce265e275b7caf50609f9aed4ce3fdda4988dff1b9cfa755d22a06ac9bd70fe011311d3021f96a67be4ae494bd7f310637090a697383e48e1cfe83d199fea464581f5b26f5d27b00505d5850189be9bf43d8b14ee58b28a16c87b3bf9d5bd3dae341de20a977a63187eb07fb817d6f32bd7e353ea5f2e4563e05af30e41de8d76caf2a05fb7411e0736765ea872b88f93642e1a0a122c2beda192429812e49797d0d2b0b2d57c7f9a3d89feb36de6e8925068d4cf01c5631bba6ad66d9dfea89eef42507b82d0cdde68023f51cd886423293963e553af03761d6bdd7e82c5f3f70581726faac8f74102eb6129ddf5940c15a1f473a25099ce9aed7c8502f304535e73f02c89d7edbdc59430a931b60bf65dba6ff6c4568fcf3361abd1e9097cc3446930d256472545bebbdf0cd8202744ebee6b32aded93bbab7c8b07493ffe15d753c2e767d9b71f63f422e0d8397639315c74a3f459246674a141133d6068e91cd04236270fbc4be415c1b3fb0340ab79c0aebf168d36a35a77d26f5507817a381e82997d3d4e6bf47cf282de75db04e846b05a1171e1b27b3378df7f46c8a0d5f452ef0980db9a94784dc6878f8768320b7a5f1327d5a0398b9090cde4a0301320d2c66315a1209ffec932d6318d851ff138899b2fc2f20210b9ba6487e63272dc9292a55757e58a10eaf53bb32db4bd956cb6ea7db2f7d3d376ffde54a0c481c8e2b91e9e7d106a81edff57b8a49e69ba1cbce8d8ad7a768f51040cd0760adda1f1b057d97309b56258908e7d0b72e311d563d0f33a89b025e9b29dbae8430af6c1d5dc9be373e533150316757b50b3d7f39cb3fb983eec9d368f3997f12567c3516a615929225c27f1166fe0b8a910ade60dec004d39048fbb5e348d1d7b8f14e167cf8625eabdff7f7262e220e7cad7c3169f11ed47467b15790ad046ae3ea490d5aef76bcb164504f3b903fdde68d660bf30a4a023c0639d3b0df5986a898291ca9055a779c358e4526204e571e880645cb2634ddb604f97aab892dd8b2c61206a8ad742b79fdd1cf600bb1b100e239a25d525acfe6fb97a5c0a13dccd21c3e1be9395c5f4a8ce11c7c9adf0450a3dc13c753c8b0d37894fdb03746c10c45e92b11c11485fd5cca6eef8495c4fe4a8e89af5ce2321dacfb3de59466cdec2510156f196cfcdf53325e7070710c87d4451690eff29e4d32a8e34518657116d7ac1562534b4b1a9267d5813b831d136f643f2511cdf969567bb8528b3b509274e022485fa86f947eb6caddb7d6aa964114d188ffd141b79fde4bec77997e8de82e1a22e50c704d7e5fa81ad6470e6e610932071304bd9547f446e615d36f44ab582ea1f51c35052fc32ef3fd4004dc82b1bf9a39b670cbd3064b42858de6d62c0e202f260e6c01dc5da58f0f5ca5aadf80c9a9810e700b5342d312a883895208ed277759e4d19186345a6d59fff1e1b2df1b9ed20c49e08dba5d430c5c889d232c0dbec12765d1f90c1243fec4c3d67e1d37e80f7783ef9a1828baaceb6f59bad6211ce93b78dc48f06df07f27a2150b2b744cf2a5a06a0df954aaeec4161a424e2eb3a35a6b9f4e985ee41ca8ff60b38bfce07c646fcb9cd13c438c57afced26e28939f478f3c70bb968c92a82a5be84d9453b1121028cc087d1d072e7e6c7c0205fe83b1a01ceba1e0e90bcce21bc3dd3be897d503f20f49b07d818120c8883900aac83216fa6bf485c26476d03e6cad5643b6c5cf217f866e372b1ad25028ac239027d059b6b09551123523e2a5f42d33c4b330bf9b77e09785e6e48fa657361dc82de67104ad93500c9741939e8ba447f6dc1fc4191770b950772b9f1c82772b810282ebc72e0e003f822c1a213b3ce88f42565589de9c8a22cd5e3fbeda3c210803bc3b27db480707058c2df76c782e29c4ec3ed4258affc6790d85b95c0102af61b154df03951ef522e8c2e2d7c0e65d89bbbac33c8119dd9bf436def3cc2b3767985ed2bbab59f583232694b3a362918f9f72a99af2f0f5af2efcc7697c2d2fcaf7859f1a53585929269d86b3c8973039adcfbbc308fee491644c480a7c27dfa9fa5ef3bd09bffee4577c9bbc3690003ea1e3aad93e92fb3d3049d533190deaec9660872e7fcabfcddd95bc009081df6bff849124e9e9df109416fc751b0d2a98b66c8baa3500d82452f976c890f25ae6399064f155ecdb915f4d008b7a002f0bba3996e8fb749742a4b69120e029e62ad24d4f998cb586da076c916cb321f43d09bf02b75a56631867d73c77cdf9da4de3492a4b650d78b39b367dfa510fe1e9c7137dda94b17f265f6938deee104649c6163212b3f9be3a66234369c113a8e3a54aa3505c8bd668b9bb77dd5eec4e994e0024de8f3203d92f6f301e1223b57e5d4a69b68f6d9c57d3fd2dba27ca0bfb145ab0c29922b9a2b129f0e3f71fc82a5b8a4a881948245a642bc118320f72a2723d6a7a9ebb1bfe185529acce021f5fa2445c3744c8ac48355df7a41a8520486e45fce375c3c6fbd3b33bac3c2e5e29bc45ca7fd84f34893fc756f888c9db6e8d1b33d731af38f622c11c5e180602f9f504ce236d5dd7c1068c9f472f64905dde988f8e4ae7f199def886026f21843689e58f2f3dfe48f8f5a637b4a71284fc5706e649278419b7c8e538926409cfcd311cf3c556de1e275dbabc9e67658d311ba3cb5c17542c186a7da2ffd129684a2f9bdc4f2ebead34aa0cc6f94cbab3aabd66c8fd8bf65350be1ef08abc28a673680e3f8c7e41567d1ded0d1c173be5f3f0c7e080b2f1545630ef9644321ed718522ab1f7584f6a4ad83079823dbe5c55b19701cdf61208e783f6516be01412b7a8746a2c86c2cacdb91aa020b8d1db64dbc78c4889165e11b4aaf173202bc28bc70e00bc24bb8cbe3839f97793b66099528624e7d1c7fca00b911b707b19bc81d8401fa754ba2a05bc955437d15102dd440d1969450617d725d1c0baf51b3d8ba9c5943f28453d574f21fc2f9a08f9752aa61f9188a9cd8574593a82ac1794392b927399e2682bd77ca428316d1a2a77fd52d12be4d3f7fd57b9b33a68065b4112e464cbb09ae6d219c9acc029a295cd67fe60517b04596e84de3cbd1602082cab3609a950d6731f100664632ada637279bec7ead801d854a2b92a322b0f0f6f0554856fed457ba9fc25583f8f1ff8d03d55205a052c67db1a02282cc80559294b448cbc117fe65a32ae25d61584c1993159d4c2329f89293162f89ad02d91f842933045e44515de74b0f6da4625efb734d885a51865862a4c2d8104682c6d83cb7999c411b070ea3a5bc939cd54c26d43025654b66025c683116bdf06294b2eb9482a612e3d67a632d391609406b60edbc28b9c01c5d5b43796bcc3d007d36fb02537fcd6d3baa7bc9c3859846fce0d7b30d65860a5d8d27f6d2718ed15850e16cdfce67e1dc1d63b0fc45f1a17a0d9c7db71f689e3766e12786b8c2a2d60dc28eeadd07ade9fbf8447fdddc4f91d05b10d136058ad481f9b4a7e024a17029bad7d3a24366de116e8077da5b101c14da26867735d2524bcb9864778e02dd5dc33744ca7e50e87806b9d773d44dd60cac69135a5d29dcb4b93fe58551024ca2bae5c4c5f6682cb487546e40abe929304b714f50ea72c453cd38dd5e8692c2ae119ad1d9ef3b605e627d35720d26cde98e914c811cc457ae3cd5252b79e25893e23371561e89a731da3343d9ceeafb13593ccbf355ea34eba49f2e63c47289f58bd3e1fdacbb319183e85582f405592fe19656cd0a23a1cfe79d906f80d1efe414b0a22a209c332036c65cc9d46751c183d8618b839afa04eb21499cde40a98b16c72709e82be7312a6085b0563e940fc80e1cc10ad90615a040be766a204743f7867ec779c8a1d0d5fe3de9462f19bfdb3da14dad8768e04f13148df882eec36da9754f273e15636d808ea116523f0d567b5316bd1ebcf6c4de936d03908774b8f1d132154642b87c20ac9cd2de8088f1d0a55de6db45a75543d1adb2806b5975df484e4db990be106045d32642afbd7a492681e8681c84ec41bcadc6e1527f9ce6a7a670a20f260ae45d21aaaa489855dd747e5340f01a956152504a31ebc51009014c5b28e9e845c3a143d89302c81d5f94bd499250d48ddaf47fcec0afa7a61480263c5273b8acc667e784402be671586cfdb7b4db3f8a0f5e1fecd2aefbcf44e5f04a3617598869909c0aceaf0951635951ed4180a0a9b50cca1bb2b5b775f56a5b46a804330edd52fcbdf477485ad2f90e1aa0e3c6febb4f769eb0a4e62b793e1ac9676a35745509b1b9137cadb86a1fe28b0a00b1ede0523ef0229d5521820274634a635d398df9b85908f4ffd8533407e995995fb6a6f4f8bcf15aeacc9028dd5d83f265d2fe95d44afb3baa593f702b1937c3a27a40b6f02d7058a16f98da0cb85c8c6cc07d602960eb28aed5a6b5a8005363783c4c6ddb2010fd07d26daf701ec005d7765e9701cf8617925e4dc28744355b61d1fc2dffd272b74a06f3520227be984cbf13925584c110fd52798ddecd811ade62f107d939c1379e3ebcb8d71f09dfa48f3f2be201f2cefcc38345ae3ced3286cd06dec45e9115b345f3e78a3ee45db7f9170064864d5c09cb0fc3e8f5b7a763846c9b6a87d11798becb574a394dc37646282a7f7c7db3824cda09f9f8a5741937915979ac90b4f7b5de4d1eb4a3b7d6181a242ce8efe9e99513e83b53a66d91e85ac3412a40f2ed30dc99975a2a8aef2f11dcbb15473e41cbbc7bbb7adcfb89f3a9aa708170af029423d5e3e33e5bcd5bbc040ef8843868fc9243d05539ef570dbe1e10aef20fd382c33955f4bb9721ff64b91dc1ccb64d1c39f422bad3029fd747441ead524ce950b1a581caa7944b372cb78c0f9933a173143d3c99f2ef5203bbd71341e1b580d87c30fdf3e28038e52e088ee5d1729da0d34f16b6485002e49708b2af80a0440fec31f89fc13213af1d473835795cc991ac856248d6947c032bea69585093d3901d6393263c2e887bb58cf5f9e8dc4da7a20bca245b87607de9ea0620f096ccbcd54b6f3921fca613160e8e406d7331807a16d33650e418f91a75a1b49155d96ae9ab1de581aebaebcb2cbda8934bab4be6568e7c921e6ee1e9ce8ac5b280bf12e8b4976159f25c05e85fd4f48faa1e5042455da26784f0378846b00b1019ece0c5443a7276dce936601960c620c0f48dfdce3d7158691ade1f4c89e8e16e33e4c84777d3b261850f67e4cafd59caabfaea137826ce0b785a1efe2a1e308bf9cb95df87413d1bed427d514f8d2f1ed5215cc8cc01b960d2fe3466acb780ec253f4c5b3916132fce27c7d53c269e49e0d5f5cfc302c1815c83a39a842a4196b71ab05ffccdc4453eb6121cad50beebc9506f5e6e7a86325c089c1505a5d1565e4e200c0f947704862ea0bbb30d55ef3b0138243795391ea5660caa47102215bb22876b29def7ec75957f10b4173c7f04355665519b869e5d51c8f7e156b05af22ec3dffc3be18ba8bef4b6112006d557dbc866a984f59a6b4850790c67d09dbdd531ecb6baede53b5f37ec5bf114667e1d26ff037959d61dda4206f612f01df169922373268b1e7e6fad457ceafaf8c9c25e62c37454897d9732b6135712bee728c4eebc919211002d9c6f8735af7b8c0a544391a46f28c3a889d0f2e7a104554aca10104e8de7cff3649c20d0b1f54088096a7532b5019e476647fa05e2080741d0dbe713cbcaaa2afa2303255df9d8e0d391a6532b96bc449d704437222d0edd1fc730ed424ad8d4b5a39369538c7d586ba3e59184dd5f2902ed1146e1a01c7b01250ab358965ae82a0f4528fa5ada19814df0d73e4256eb85c0782e527f1f4d0221ad31b598531d3812ddcc1499f25e1501865e17df02e1b8cbc9909234c2802c41b8f3e59bdcaca7bca354ac8a06eaceca80e576276e089cb5f29e61b0d1e6d85b56c11df39d49c0836c0a3db33fd564f9b81b2dab176127f2020091e84be762866d62955eb34adfb2c036dfdc79652bd5168e1eccebbc106c6e0842a6ad0ccc37f360dc838e8fd4104c57d8d74b677ebea4c070a1d5e7a7fc219ad1169ddb19c6d2d9d077f9a31b480259d7c4dfe8e603ec1953634fc56a67550bf2f4c127151b656bd10e7db9c9b4e19e526d93e483d2beb6d6f95d5dd7dc4ef270edb572eadb4f1e9abd0639860e241ae44ee499db89e92a7971670be22941efb0fffb8af56e85dcb0a48c09ae10131bf2a64b0ecbebfc772259c580506db69ac2156fe9c7240f7f66d4714e18bb20c07f44dc0cd84f0d9b1aa509b66ea5e255e0648ed0a2962ede02665952151a54e8cea60f1ce897f00a3abdcd6fae82e74b6212fb5e7fae591d70df03de924b74918ada838ac568031697a44c273484fdd102cdfa567eeb6b89ef0d9fa657e8943950256b1e7053b0824e4bef3666272ac0314f463083e7bb01bf0a666e722b81cb549429070f0cb17f6cdbd435b5a9beb8a2e4d8baeeb9fc7abcf248cd7dc6a01075c51db5fa579aeeab43a582b47399ced1f5044f92a873e6418ba412cfa0a8a2db3314585b220ed790f35ea358f93a7630fa379be8dfc67d5eb98c3aab5c2f533d6750b19ea957acc6bf9e2796920007f14afd5d25310bf4bd31ffb348452c2d021e55f237a212ae30aee3f52d514f4520a9af18e31091497248753927f99eee28859559b268451ff74aba9de02ee6b4322d7570ff915b07f2cb9c60a3b39cd3b93d33e3e05f149db531e7da3325e7bbc1384880b0aae07a0d00123c89a8dee209bd57008f71bd1a6a5778e3dc257782b1f4eb8695e6c34c7d409d48f8dd796db2afc7267b6c14299be5aa8fc680abb4d14671db1342e867fff13ead25dfd0ec4deae57cb9c3dd91d62eb03725d734f841d9749ba103d39a29deea0e29fae6d44193eb8daeb4b06ceb487292619b51b15221ac506544d7bbbb235a8b1e025e6f95a55d4a9da6e2269cd0fb34f9990ebdb13cb608f09dfd348a611efeb3a20ba7d4911414ef238b948281e71b4aee677131b1bd90b800ded9e14d190e183fc69564ae4f8e218035a2ae98adc09e2dd8911283d549ab1fd630223ac9b69f13ebd7edc52739fa0d86ae7bc7edfa3923fb49f01b6905210ff375d48be2446ec8ad19fd201030784ae30ecda07d819104ee91e060649b3d0c9e9e2b984ff05a62d46c6e9bbdff96c343c82a6512f86de130e771a1a878e6a41a6ac0fc0788e6b068a9acdf76a9e550c760f1a7d2054f006a5c71ac65c82a640ecfdbd3853275aa0ad3206b715cc3ba60919d7a2d307a318d84729e3e17fc47339081b3733d471aa0c4a156a7b54b1b9285d483229a32bc6340e223d87b4069b04d0fbbc22d2a54ac37af4289e9138d2648099c28729bf009c2d28faf64c8a8042fffd8bb899554655cd463010c1dabe9bd2d7310594d704f1e10ece778e01fa0d14bc72a9095f381f288abef48d73e1c8f70323019bd3790cf90609f16cf84220713056f45f8783d40e5baad22fef47a7e37b46ff86b16a7050120dd8a0182fefb468bc5f043da2c84b3c3c1233743dc0d3f812011ae063c60c20907d674016e758411738d08cb7b38ec5cf2675460d6e4979a92f1a6b69a6d80f09ae9f8647a6057406542e4b5cad4d751ce4851fe2043791ccf35977c9694b27ad7a862ed2c107a8ccf062000dc496547dc6b4d6f3b0ed91a689dad868bb70009cf51ecd1b12f4f015bf9b58c6a3473e82736e632d1274d46e8fb9aadc92ab01e0c7c4c9d3ffe24d2a3ea98e88d74bca4b8fc56d7d94fab738c555f2cb4ab724de351101cb87df73b68d48f182811d7bd724087eb2d3bf773a92ae7fb3023d05f7d92e780bc1b98e1bcfb57bbed3078e50104684c04a0297a1f054585de92e285d2c460dd30427ebc79eb4e26c0479727e1884df19ef51e10dc42db993de31190d3d6c988c1c3dfa4e0105fddb7ac35563ecc72a4a196e035f91148ec48a4b119a13ca4a98e0f7a165f6547ee9750bef23cebfb0e79c139d02c6565e92464618471f2483429f5093edaca8b65ec2d966a66317e4fdfa8efb3df367f2511fd514737a1a937a481e7d8cc9a03c3a60841a4bf7f9754bf2fbbe5cb6164ab948c00b2e306a251f23b43d7d25e038afd9bb94e90efa334bea6c0c33b9e527b154f0271d9823269f3414e5b7274cc402fcf960867cc389df326a885484a21a1730d30e0d40999fc462c52b6a00344eb43a6e589008ec5dabc7d3b7eadc04cef996180edb9f5dd33c7c3ec5e30aa494b252658237e1f49445b383aa5221481bf279c824a408a0cba2b07ae7260ac3a8b16e1d481d8bf795611beb58cf4994317e4a8a1f43bc309f0b9a6938bec0f485cd9f959630aa5929c9a94e40f0fa18f3ef52d225323ffaecbab738f0a11859f83e7823fab2368e875eb74f7efdccd9d03906d70bc078f6741689487c98d8823c61dfe17c86e49cff25367cce5f92cbc602a350181120e505a5904a146484af259d3cc7407766ef0f9d0ed2e8c8eefb1455df430b15d7a20b2b8ce47711235c340fbc0f7cd120ab132ce965274b695e8384b0af2f74f1a79885f6871a7fa28a0bc7c26363be0e27b50ec7c8fb14c67e80e2b47118205e0e8472e0dbd61b66277d3439fac17951af5ca2d6b5af0d524ccba21b6b2a6051dd94a1b8d7e7704680ddef09a1b1c4419f2a9ec9820da589e9b20a70ab24d89962987ddadaf53f6605cd3710fa08fd60f3daab58c4ebee1ff8f0c7b88616302942ef09f82722e003f1421f3722d0df287cad3f920171162ba91a98d6032d74219ce8c4fe3c7e33b0ffa14c83434d58870d116e6c36559a0c5276bd3ede2f133f4b9b09ef25e76cc4ec02d3a62df652cd9034f372c30b66891e912e1bef1e17181b25d1ba2eacf2827897b7b2d0c5995ca072785082d059c8644febf9771752e9b58e4c98cfc60c257c9111c8b2bf6734c7ac89d2bf8276d6eb14a2be82084e6fdf8ee543c1a3922df2d173bb2d7a7124e55a2d39ea70742821f08726c31b6c80e32786142546b5c35a2a9a2441745ce704f0e55134024b64036bd28f8d2b8119e8dd0e5cb9245d8c9058a66731ae81cdac1c54debe97ba687b26ff00671d6b69bb7f1dd005c20971d3f86f8949ae90483fc8972830abc6481f17f90547263749df4c5def86d1923157f67fa1738bef66ca4fa004e6fc5b4af721837799245cf824a7f53cd08d243f550311fd4a3d959daac4cfc85f32604bb35af71ca004ed6051ffde6dc1b4fe2eba6d82661319e9cd3b855ae418d73cbb37864fe3c10c42f2fc3567df4971fe7a1774e33b8a72c9ff4a7c9c666df10ab3fc86bdd66d2337af6fe5478206b02c5f1709d87b9df0b8fae401bfcd98b33c30e01e93675f1f355765c7361b84de13e9aef9e4fe7aad73a2117c05f9714a0d361e693470c80506dc72a579afc28392a084af4bb406e51d53782e6ca9ced5f2733ad62194041187cf6819f495e3f36941d42ff64e68b479b4c98047b50d14e9d906b8970b9a1a85df2ebcd9f91bd9f9e23d6a103a4398801cf9fd35ffe19b1d22551a09c77e050ac86b551234e153b9b1f200e5e4d128ada63380f68aaa80df274d0bd10de6129ec811001ddfa3cda1b108abf1a10645def9a8f6089074ff283c624782d8e507e2120f8237004abe881653eb8da68e34bd3aeb10e4a19a8fe7684dcd8fb2160e98913519c62998314bbad28005c4a83290a62f9334bd58031fd66bb0db262019b4cd0c0423184d42dd0524ddca8871512144dcffcd066ff6ebf9298ea84e812ae69c3c6009d6328449e1f9eeea8fecb6b9e5c96a196891777b729dbcd009b11dd6c86933cad747984c5842202dacdb14319ca09f16950b4ffd8e8380fcfa9223d511d82ba615fd3506e86326f1cda9dcc1cfd9e6d5f1ecefe79eec809734300c4b915bd8b2f50d9ed1228836ea07a31376c0e1f4bfd053de47bc04acebc1fe0930c6a3476edb691858be52b6de2b01d9e1e4abfbf3d3c5d2684b4bfb7c657919035941a2aae3ad42a9e63465e499c16d2dfab35f248622e7e58e84bb84b71d01e032044b717cab2d569ebdfe7d5097752cba06245ffc7cad1b18d79eb62ba3118c1524d59d9cefeeac71e447831f83c6f290ca10481e6916ae350b88d60f3e2f0058bdb51489572e95e31fd84ca7260abc39f36938b4f87e6d4835f1ad5fb221a652e8262f018bfa3856a8cbd34144e6976d45a453f3ec06fd6e376dc4cee60c6500c3280e6ab4927048494018c8afd9bc6fbdcecff3018ccf7d03b51a6eae14b7f8520c39787f70776235f01793d7e7f745848413062433200ef7f8cefee602784ed98b2c9d273cdecb02ddfa18a8a661d741f3bf87647e3b8d25eba2360217f3b3108225afa2797868ceaaa866d663881a0008e416c5f2f80af7149f93050203465a7c2fbfb1ae9517fbaca023c9862be40b2c84f30b81d237bd7c3798c30891c8ac7a91dc7b0b69ed9e0982acb177108b867adebdf348d894dd510a0b7e1cd010d9147a550c8f12f60691d111628d9182c83ce9536af7ead503f2d86b1b07c40fabfd7c29d47e4f8720b7806cee007281fecdf927c5a8090fe200db873a0142f5b631901ff537e84ad96b1796bb469b1b11cbe42c2610dd49aa74187a4129a1854db8be04d0079d6f88c31d140eed4d5a1139b6cf42a9b792ae577cfc7a2879bf32ae3070900028e0e30c27d2c5d1e44d731bd3d2e6d6135dfcfb18572d107551dbd61f608dff663d88629c18be0406c8ba65f8ce3422d544efd0e1e9000dcdc683eb0eece6d0ba89d46022e636bc1ca13b2918d04900ec63e29f630e7b09d795652cbd6a6479cde8cdeedcac973f5d240002f8f6df8a75ecb9e1c6d2b609938753bf2c7da02deb6f5f3bccce5e9ca2afebf91feaf1265aabdbe2ad99212954377b6f55c3faa8c03088b93f943eb08faff93d5c958f119889f11fd09ff304933fda02023e503321f3311c3248fc12cfcd7e748e21b1002a39c02c01d09209a0ce90d8026f074000e455d119e776d349ceb3da94cf523de5dbcff0f48b0c1a8048441e7c85fcfbc208ede9faedcd17cc3feecdee4c70aa042c6e441b059a14cf0077b5c8565e3c03b57181839f9f7ec98fb603c272189a6ff3a1d3a4ab621ee17eecc490d3d3fe3b69830871d0f9879d3049ba97804e641d42ee31522ecf1859fd0e2feeff6c4515dec6601e327c6ffebc6958cdf901c0ca743f82214679087d9626e792e9ee6cd489e79bb805d2da252d55a99150fe19bfb245a1fe42170dbbb9e93f584301289b415aa57fa49a31d5a2373d55a75df54190b1e216324d0c11ef5e89f61d21a42d90763ef5a89092a10e1acfb7e523d7f3fe9f8efbeee02c371b165637262eed95245171b22f53990e63e5d7277c2d73a4c391af7f2e4e1c18101c45f8cae2939e17c2a4999e38be4e8683139cdd427060e6f476809b670f35b2c56491d7f825eba12d6626da300fd3c80da328f0ea49b767a41a88ab8321c15d42c0af8fadf6438d42bf60c3a2b3adc5871de99e21556ddba86feeeb79168a27ba4c7f46b716afd29c915ece35e192e47cdff65cea5c35dd963a7b9ba5232bfcd3e8240bf1278b36d6aa6dcf916c22e853761e388d3f1a40a433aa34b506bff60e623daf6dee09ccd69d2781bc4d993565b6370e7684d7aaeeb2b1fca601357cfc35f67331a5714552e9eb3dd6fbf2119bbbca64ea76c836020d19ec9a1f48e6e38d20777c1c4cb8531ba222faec847efc90b465e9c34a7001ae1aae1a1b5e613f47a7d2a35f2fcaeb1539fa3306807755ed92968758d518fb4475f80a0a3ca9d6a6143384cc6083082d311bc387ed1b500266acb41b8126dfd9c93e1b1fbc2e1f174be1d7761604d9964bf196b9ee0a8706f863e1822950769d6662051d0bfd2686444c417b5ceea329e2584442c5bb2f75f8e7c180fedc7a3a6dc21014bdfe5ba28573f6415f77fa9325bba1727fa321aef3c424a762f29b3bf455f51babf7c357a4e5ed8cff49b4eafd2746f73fa06b1d5ed4bd15999b64d6f3a7121d69a9229292044de7007ec9f717fdf09dbf3b367ef4a7a1baa46b10b4e16ea903e4edaa9011039efcee40df9f889a16f1d4f4a9a29abd4c5d587197dc1da1d8130ef6d7f55840a3d60e13734ce26b321d00aaab7088ae1779d826e99d92f54b0b80606aa57ab42c90e751dc5b716baff6a81bf135f4250f00aaa0df2c833761247a34288a2ea47bb0bc836a6fef419c37495bec860fb6529465724011b4e58017dd1415346d52b19101d5eab12b19a0e441575d47307cd7dece7b39f36fa26a012112fcc778b55fbd14f16cdbd3acf9a9169d544f15345cb6173467874f657f11a12cb8d9cd9c39420f84a35791fac6511b78d593d42fc2b8f5d872900954a406331151227f3b4ab61468947e78586055c0c09c0b98362664e5e1c8975eeaf02cbe3fa2404ac419609ca705c7393296997f81a9c8423adfd4de864c57a97922159f4fd88748365f7c0d07563e4d453417656c8833e29d6390b86fe4b794250a151fa247a5e1b9c58149170293ce42a65b9cdd8b38d9ce0ca032a2513a10b9aa13bd582849621d7b26e71960d6ab34544826f40f4772edbf65887cf9c90675a02a24cd768068be5feb2b8020cab1f939df742e78b85890a0ed8735180b8dac5a2cb32325a25e5a55c3dccdd36db1e560cf06d8edaff94c8f8793df454115ab6907e1433a2fb8a9710e410cb4ae29b749c5a56812e5d7f5071e3f281e22439f66040be430da6e3d00d79a926e6d938d9e102c8de762f46132cb877c9cd0719ef3124a78afd322abf925c981c80564d0990d6a8ce664e2e17c87b4a0f4d853162214634684c7c01135a65a96a2dd46dce177320faba9c4559efd833f3dd5086ba8112b30bbf4ac3c13f437f5c875730809567be74cf8a9c816f4fd6716a9b82a1c0305ed2a51e4878eac2537a240468d0bca71bb3db3dc44587370c898536d53d80368b46b639edce91842b66e208b95b7592b85d9d72657432787fe6037eb85211c1c8adab3ff2f751ea8fbe3a00085f306569ec17b74af594427ec4560689fb70b4e6ed89f6eb53a9e4512918249b9551e0ae6c9f36ea559e9e512e2689d090a17415450b584e5c7cca50b33fac3b1787034d0208acdad636fc3d616d98f1dda10eb9991d957f037ea435e3319c366ef658c47fba775755c948610e7a384fdb026d34b79b7c65045b283b693ec39a3a461580d5e888e2bac27ea2c619e06650b23ef7817b83eebcdf4c1046def9755d8aae19209f9ab2556c7c1836228399dbd063a417e004937c4e8f1238d59628623dfef098ace7e0e94d254f75cf60370991373e1aaacd754e553d42045943f1356cd63e1f3db516c660ea72208a93925c913478d2a2d2d9e8f1fadaae136ac42187cbeaf41a1fecca67b1d9f8e45b8a21509b73b3cda6895c83a1346812b5ffe2c1a73db6cbccc95409b09f062caa7414f2a7b9182faddea8857099a424d6bff704d75eeb4793e53fd6c6b392efd365d02217bb0a66eb65c8ea113ee6800c30e14140d1db32a753de462a44320d257b6c021f6b2dd25f7507d6320a391d0b0de1d495960f32f421d11d91c7ea58f1838f225e75d81035ec78aae5007a650551a2130d8380a88a42cc5f00243adb65118f62bae9123494c72cc94cd04a9a48393508a4042ff5d4bc0de75cf5827c32aece92426e6a4df489f63ffd696a5e09c4569596d59d11853d305eb433044f7c58f0208708aff7ec7dfba646904fab95e07c593ad93e76728526f8818fd7aa58402a80feee7eb15a2f0b3c4cdb007544c53de0e1f82c11bd9d37ec0647180f05a657c2933fc48c254c582ab7479a9c83bd7c4f8eb0e29efa3ed8c4095fe08a1b447db0a0b2c4929f11cc7d7829662940098723811cecc8af257c9ca591eff5e55f15c1ea2954f52b5693fe6643d48e9f2f23f2143777b0cd7c33e824b1df67327692829046a46469f24a35f7a4a268c8071d3b08d4de93efe35e71b2ae80a054ae6cd0345a6af2d87b666f3f5babd0cd2158f9f1d0454c258d701393f9c43f96de381042f38b49a73be70882662b7070df771bc438452d607e3b501f82092cacd524912d368f485ca72dcc9607f4b1db83a3bd6b6e02d235791457fb5526e68a78d321645077c96714c920ce0f10bfbe8a0fd9da0b9366ee0db2b686811ff10cb381d13e0536e73e9b49c2341023a2ceb8651403207aba6394c9fe86be75b1f3c92342221fafa5b188657ec49279ea611926609c5a0a8b137d58691968eec74595db30a5eab47f49335e4f7b0e1c82e6cff21317280e2cdc9c35446b64b3c2295b7ec14cda916f25e16626a75feeb120e95eebd9754a395186204d03d9241a401df77194d9938769c163b7eda901948cbeecdf3e841abf27b3b8c92903ee36dcc5d060953aff4f2442313a8191adb4c9b374dd9cc5f08e8ba058b5c03dd111f489e461c1723525286162fc0c4846dbc36eac9cb8d32c1a121ebf3d81ccb322277755a2e55761686f53936d703806a52065735bcf568ac9d9adf605be45a56b980d198260445b04842fa9fd7ff6d367f50ed8553de4d1743d992577279a8d76586f479110cf8e5875e0c4682626f6a1e55d9116fcc4bebe725bf5ff24704153d8d7b94", - "public_inputs_hex": "0x2138b0022ab9af3c96b082bbf307bc9e79f8f1401462e3ac1cb3a9913a5b856c03d33039d45432d4999b9964018d8d6552808849c83503f50a70d594c01b441900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000c6895e67e144556602cbe13943c8169600000000000000000000000000000000808b3aef60f3e74a629e9331d68a14b202c2cf87674c88d6103108c767ab2ac48e35bee25bf5e92c02761b47af09b71a2c17de150116bdca2a3edbbac4f77678c67c35f056f9e969387b99b5c26da55509a23e762ede2ab19d289955f6fc34a289c4196b6f4fed818bca760158098e851aefe0609e27b1f5e4ba46cd640bb7bbcf5d11024b93b2b80830d9827e59538f1b1e385ae72fb3add3fe838e63d0e080c2409bd2fe5f57f926a01a4e31278a1e0fd8fef8ee3dacae5dd4bd8666f29088e7e2c1680f50451cf263d3e53ba2b8b4135a40b6144087f868125f387412d514b5747bfc6d2fe2bf59b31a94cba4d7b722725d5e5594a87fd3ee32e41daddbf89c75efb45a474670af2162a31702ad09" - }, - "decryption_aggregator": { - "proof_hex": "0x00000000000000000000000000000000000000000000000a6a7b38193b9791f900000000000000000000000000000000000000000000000938adfed18caae40000000000000000000000000000000000000000000000000e21f5e071314e88420000000000000000000000000000000000000000000000000001dcc3d8161f47000000000000000000000000000000000000000000000002e46c7ed7ae9e45950000000000000000000000000000000000000000000000006b452c19c9c3a95200000000000000000000000000000000000000000000000f937207f5e9d7f27200000000000000000000000000000000000000000000000000011234ce13989700000000000000000000000000000000000000000000000bc917c80a1df8a9de000000000000000000000000000000000000000000000004158d1dc6c5fe0793000000000000000000000000000000000000000000000004df57309713331b9200000000000000000000000000000000000000000000000000007698a06035d700000000000000000000000000000000000000000000000b5363c615bf3049790000000000000000000000000000000000000000000000084836ce0c2626f54700000000000000000000000000000000000000000000000de7f5f0f37ffeb22c0000000000000000000000000000000000000000000000000001bca3c66a8927213f200493e130f2f241df6f50e717977080ee976b404ea52ce9a1739a6538942186c4ce5d408bc4469b54741acb17f81532bb104e167f13788ca258657e19ad18bdeaeabf611459f9516a80aa25dae22a716359feb8721e6f73ce82c65ed90504097a64060c9b98a318d0db5087034f8fb8be44fa54632799b74281b02fa3201b5874dca01aa6c15157bbcebfe698062bc743018cbf4c1838fd88dbc7725f1e2cc9baf93dc954f7630b60d425d36ef81eb1be7d8436127e0444eeea525630a31058031e3a95f311de89e96eed8d8edd125cde39fe180ff58ece8d79e1d4b19f2d6403f1677a3e0f98f7d8669a44ee9d1c5227bc6dc8f7fab18b5ea38a23a8a909d6b647f178c12bf5765e4f3fd9e9353f1578914f6289ab3626968195e2204a0b75d68cafcb752224084dafa2b4ac94248907a3cf380066780a921c968cac8c1745343af4f66eb1673679b9c00300c26624904c97f542932abd632e9d9c20b613f65677439219bc9826056b26cd285c1f6ad8cf48940c417ae82c3b6dda3ef601d957cb411fdb0e5a236ac0758e0f106e5c2aea4d997e4e082051f36f37a07e193e06fcb0040e75764cfe7d7b19379e865f44cde8c4021fe7a2cecf7276e482125b04ce7829f541ae0f786317799e17a5d19b18c35032546d862d824f01aa2b2ec87c35f2af31bba08cf65076c41c5b2a532fce570414bfc6619bde14f1f90519c766248124f4e391908fe40e4f4c2e47d959872db00ccc6c66104be6e3a4a01509488b91bdae4548075814bb3cda9893c4acada580aa2c29959515a57de7a31cc4f2c4335d29fdf50154c3993f6ae9031d06f0541f0e718afaf53d83631efd232f3df1898a0799134d1f263b0bfd6dccf19c72088d8811c5e361ba2efb54be181628501e2f6edc49dd9c2140408a2fa36d107456bc9ca11d66c1e426b5c3300cd87deaf468a61d8cd99c96247bf074714476fdffb493aaaf976d4dd235e99b154e79b2ff5e50ab7f8c6ed0796649601b9c5b5efbb5fc5f5b4f216469ba83161e04612689209e87667d0a819663d69a261da2a789ec0318543355b471178ee51394b1536f2652a7fd5ae364f01c53350a79a0a2c030636f3c2b0b1a4f11f8f70b7dd2a2ab687739334dfa9d83fc290414ae7a1369b7b416834d3971e6e4d10c1e739ee4f5603547ba8ba72746f349ac646d2ab09e4faa5ab7e68fd55609c6fe055052cb8a99d490c94cdd0e20fda8125a7fc867867440b977632d440bc72ddf2a79774bb4346a8defd31709e0d3be983bce16ec2f1b6eb0d064df61d33fe4eb0c0a9a31f221442947a6eb27a710db271537ecb73fcaa4ddc4435b85207362ff13ebd5a7cea692e2c11170b8f0e19c3996c9d4fe03f579bee10705ba2cb6a64120e3ec3fd8a3623c614a7233e19fd586b3dcddb5ed038a7b87085bc0d01f35ac0a910d04789ce430f092f249b8a95e3f3e9e57d464b7e39b11b0b2ce0511a53f06732a3e7d8ef4a98f1c0197fe86514ff68a832af68a50812a33c5b1b3d7357f2f0fcac439af16b2c3c51ccc318db8bfedef50919ca1df0ecef4cc3a1295d63a16e24b4427e5397d2aadf907e4021dc59573232a6851a4772bd0d7a9511e5e940c45c13faf58cea6eeddbb0a5bab2b269c8d205cd66a41192cb1a02c691451c60cd43ed39782c235f5b7222db00e52277c1bde022d68a3dbef6836899945390002967f653a03db955a5c8ce104f9bded599366c20d9e4e10815d1676c7de75591876c3b768ca0c50d93bbf03fbebd73298b550e6731cc9df74ce6b043d391fe501dcac5bfba80aea4039869994a026ae689f9fd7bbc45b9da35927b07a1400b8050faed5f52a92daf28e2f7a1e113694c5751fa2819d425c7038381219f561d31ab37ed6c11585362715d889de16fa9c110bafe87a89fb3437d64c75602257e3111a8aae71085083c00061af68a50a444442c811ca0702b1ba59efa80707a12e0574243f7c35ad11d0499bf94e73ddb1a0551fd5dc7137b31c2cb4ebc6845b5c11c03ef720b358f0b3417c3073e3d486c03aebb7b020db1ea2ebd23e08aa22bd2657df69bdd20d3023feef2bd7b0efde8763523aae1b31d1bebc86a1577122722af7b9eb04d62bb5d2dd340cb78eaedc412be64449d0314cfaf30771d59b4913156f4b94b14bf9ce19924e16e516ff1bc66e6955224645525d4eb36650422744014aeed42b2f48def893f4b59685a7a00fd42ae1856463b2ee65aa8f09c21def2f6d4a920159b6487b8928519e70a5adaf40e615c04e7b549c276109ed3888e808c5f4a847d257ea6478a544aab60e354c2cd9251e4456ba225db340d3c35b841ab4876ba9361592e0e2f351f1cef7a81e5875c24f4deb7bd8720b702b4d02941825cdc9b2fd2f8aa1e13b760f9e5f6b87dc45dd74defd1cb013a8894bfd211818a2926b858bb7f334bded04473e5c398fe186bbfa744b7c667066c72db7d9a32d8649606e140be47dbd386381b1fbb1a6238a8c38d9346a624d27d057ca8ef71e68e91fdcd8345fca7dfa89faeebce29c454669b769baaaba0fc712dc541ef8280fe2e79458e28de1f0312d7a3dde0572fe68bbf86f046faa8c2e07927b080f28ec7285880a3c089913308ed80d9c983352b34317079dc36f024c88cbe698f1199da4d50f7601e1a92ce7e958b907c3d08ec1c966d10f838864b06cb903a26f183dff4905cb4bd6861c48fc2e538b3fa22385197567809a7167ec25251e71811b35520a843903bea42f31b157ee343aa5335adec9bcd3120a6d1e4edb158539292537016521f1e1719774bc3472bf8cea73aec615aac019b47e7d879642f462263b44a7a876820f0117f968f8b0bcd1478699159b190360eb331181a2c04be40bb9562ccf1693476d7beea398beed58780d39123f31c1c401b3e59502899dcb070a2498fdee2da8d6266a91ed4ff61d016eaac361e643de776750e0b5e0675313820988967945cf62b69b46bb5aa6914de5556c053dd102f5065ef07c881fcc2858d7069c1c6f7915d99118c1d498f3232b2fbe53f19ae68faf49837c761efd1110cb2769cf48c492062503b64b03bb339905c4871ba162089ecb07e88f922b23a72ef676abd989368ca5ca6efaca4a3546caffe57f71aa15550539f41efe8523d17d0a9e67ea0a1f0e79adda4f7729011eeba0d13f56e2e03db3aa4ea0f1b62ac55a22371b0798281faa7e0ebffa3f57ef9db292b0a30d64528ff64c693dda2a3524a0f84f2bb33871e969321e34c0af763e3076e7f460e92e6cc346eb967e087fe895a6acbbca4f7dd6b474ce3421a5c24f07129f17b389059945b911b318113acae2204d6152a672ffe6be7699486fb5feb674a9fa1d63454eb801e0b0071570f519abe7972bf439e8cf28cce87ba571e359329415b61dfd9605d2e5ee440603623c89bda7c629b4a2dba72f964bf3fb0a45d364198059f2bd2b10ffa4bb0a422889998c100754be16415e5a16450ec06bad480226610e78379eb5be4c2f04a91545a58c5916584ce39798d9f1dcf7742481e3fc90226b8a508e45a3179b207ca949a9e68369a4e7a0e259d4706e083f51f4172b24d00940a5e40c5041721c4e2ba1ee11f1bcf9c2ba0876dcd5bc3b74e779fe4fb8318c7406d47ba5b7da0d76ef4979ba783d83ebf8c7d834f6b0e244320263afd46395579b9a73d00a400646144e651a725f8d554dd3612862c70c98fac4a6dc4e7648ae1c99498221430bb83c7a9e1667315b09ff19d292693ca49c81463918d0c8f89e56e7f1cb588f12100b03aae55f7fbf686c6d8fcdfd2ec95fbde59c33ef6e9162c39088034e3427bfb892d72474b03a197db7242e68fce96b631564d2f94eed762c1c722e38040e22909f91577a6ec1e2c330e5a47c8bb5e6ef018f1a83388c73eb754ff32cfb0c4d38ba8b27885ddadf3f520c796d6fc499fcbc2a3c5a83b97cb77a5174d60d2c1234826405656d94521ee61b88a233af7754bd82be24ee44bef1648438d4fe075b2767664640965dd21e2f989bbf4f2f69c5b1d0d1ca61c90f1ccf62a2f766251a5ee4b01447113c913372d0d49d6415b7a479dc7ef064c184b9140d8bee6a0c1089dd993d092a9e654da9b9d13748d9ff552c1d284a9543151223275818ac1bd3d204262544f9b536b40ac64089e0ffe99370db2f5a5303b14f7f1b43feb901c4dbe086dbbdb2f83982b5a415dbd75c8eb212760574f15b9065a39654e17829f0ed29bce220f0eb2ba77754697a8babd74c5dc104896f4bef310d99a77532076a118a429672a66d8dd32e72a259623f4a330291c23a0b39b4376abd57c6b92ef5e2faffdcb6fdf0419185e0528d35366a1b865dc91dc4a1e228379b219eb52a47d3160a98e6bef560957039f8687bff28bbd1654b0e1a2290f335c53f0e0016dcb8f0a0c2e0d7bbccd7415da0fd8725055b26393b87f071918eda8414cbfc13d7d1c5beffe174876dd3ddae96fa6cdf87acad3ba1709dea8c80f4c7d2e4bf0e894e78471fa89f727f99c2073b57ad0ab2b23ab429995f9eb947fdb176e28c2ff432eba5830407d95888ac9843beee5f7c224ecc1a40afaf7534b5c3010aa00d026e74c47892b4c803ccba015b1341b380f9b441eb79f26c0b1c8447d23f912dfb9d2fe28a5cefa496ff3dbde6fc9fa6767339c8035ca97086d6aadb88b0dc1321688e887d98b25cd01819655e9b1432200c665a0a21d40e7e0244f1c373a202aecf5ee088442b4fd2c5313001a02f584d75eb7b6e52776bcfe474f016bd692a2062da16361e2626c90db4aee731753bac3d68a2963f02fab8f43d4fbf52461e1737999975f52f29533837f361e89088c3be55ca975278143f7bc986da19f71c483e99e599ac5ec9c532fbd2c9dab0e088b6978ed7e65dc278a736e5d03792040ddeb18cea5bb841cca78a2f449e0b360ab2ce1f1dd4c8cb39ea12679615111308ccef9632654f64e19d97906c95bebb106b2700a865a5165b9b8ff470a3b72fb6a7f3a91f58d47828e155cc94dcdd10ad68ba207859b696ccd40783fd81f814647a611ec4c8370bf8c01b1ecc618a945f5432f2981b1c4b34c75077d83d252d91e6be4bafe7db360df60b17cdc52871f581610fd0a35442b466230b85830d294f38eee8d3f464f1191bf6f3697840817fab5682593db32bd18c3e35c279a623cd32c6a3098f4ebd0c1b8944809175090b273ca8fcfc6b2381835cfef50ad7135204c539b5ef18e1256f2107d81daa0665d4e3bf06f0ecfc0a1cf514d0aab105a9eb9f695af73b3ba0df3cb2d1c46b7c02bf108567e6d01cf49e6d767d078d0f7eb40d460e34d78692e0114c3f260886fcc7e00c8b3c7008ff429d1a53aa9c2e2a41d1cb34e154057c4686b4ad1d704d5fdca331c9f8168d21ee75a74a465224f3327845653d52575e720a797cda03fef68668ce7623ef7cc9034bee94b8b0181f2b11ce4e8710e7497246d272de79509f4e2fe6c8b42422f866c5c69f6fd41d41c9c326912a2fc919382d4e3d414ef9fc9ddf546ab52c8d93afc585b420390737f26228865603a7ae33fc8e19c944994028eb2a20b57bfe1a2f15f0f372fd14ef2c297e78695908b0d6cedf144040f14908d59b7ffa58b1b1930bd65270942bd8043e38037bb5213ccccb00db3df8a661e6fd31d165ae465810350f8182320df72bd876d111321de34fe704b96862982f670d697336dcd782eee7b90ebac50dd31b62a91af03d377532a157b4262a7d1cba57fa045d75bda66dfc194c0b8d09ef91d887469dafcae262b0ce0c2d8876e189885ee793cc622d42f5719247341ca89e1cdd4026584e5087558fa70f750cb3e58f15f4655cb2aa5c2072ab82f11dd0b47a22d769197a373b5a799afb067f275a5477a2592432165fbe5e5fe93416f0816a98599b5cdb93b09175bb78f688bfa15eef313efb9d49047188736c9f096d86d047d951f18de0d5bb2b435d9cfaa88521fa55553ac1171aa3676e41ef1387921e9df4c7c6e996e54033a9115e1159e9cedc6121ec9e81a1f516dcde852f17605c68e6a41ce312832b731dee504377e669986a4438985af9523357a9f41ab6b9d08bd5e05aa971a009802ce32e31c29228a1f314a2da664067dae295662923d7715c95afb00e860d12d7b168ae050cf29e4bf1ca4fd61b9129794383fc25db22ad3229fe1d00f4761e37e897caa298944185e893a6bceeb54e22b467102f2d8e3e1b2aa2658687b4f52d165f059f4053284f6f3797ed016a1cd51d6ccd1920f19badf516351bb00b5ac3bf3f00da9600778734dfe59ff118b80c46662518e010c4e1220cc9a38032e0cfabd5a5a5da75a1a827179c567443a9f95c14710c03c74cfaf3ba71459a2e6c84aaa0c8dee4d69514795029ea15228a4696961201437035923818557408cdb632f2206a5d9b67d82fb00e9c7c62a3a47c330f5f0875884e7471a7c2cf9b2ed4d9573c90e0ddd52b583e9ef1b23884e89a0c0c801599f00ff79b96f561378e455584cde3a3f5a4c84a86cb62c0998f4f6beba9ff1d9cc5d092a623abf9cd026ca12b2c816c0a63ba7666422d2609f8896501f94116a4ffe86b44b683ba8071cdd9b7db1f7aa2a76e30c1607e8a6aa03a5384ed982b6b6e809ead534b62fd2963a7027800b08e53c94f16a1b00b753322db877ab20fd39eb60b9280409a4e963c6e5ef6f66e7f8713a7690762ad71158a9c3698d42fce32038142ee603c46b0d6510f279e56c2b05d7096c2416cc3dfba58fdc0c50a8b5d89048bef8ad00d7b6fc744234baefdbc29faf5e4694f0d0bc87ea2397a0de33752094611077ec049e3deae0062a3d54d9c55d2986f356ee54d7ec2645c18012c3dfccee4fed0bbf219d4cdd93b94c2f1dcdd964a7ccba4954033a07815248455ea2bc5b096f90cb81d4b534a82a8c55f8df025430884c395c2992128871e87c67a24158e7d9f2e700b685d9450e5084256931384cb517ce80ecbd955671b13c2855124079a3f8a423b00e0512ba3ee812ac85cc596ff81ccfa7c31dea015cfeea3704b8289741c066bf18d60a8f6e453921513d10a7494b7a8ed8bf4430e906fe2dca5b1f2daf50b5151e78872f7f971fde706bfc267af4d6c71c43c461b331c16f81c053dfc33bbe0973f91e979d96622bb2805eca8bd1ca1c86a7e4f2222e04ad38f0cee9892e7f9aec41ea9fa52334b246d476203f7c2d5f6575b7d126f845c8396208049ac014e067a49c7da865ae3e17c4b4630e63630abc4958e1924a21d32c26166f01ae2b8da72d7a56e1afa6621287663eb5d2983187964f81753ae5213daad6800140e34f3af2d7e227cd2c5bd9d4758586f6a4d60cd0cc70034d64e1fb4d2ab6ed9be9b2810571f2189149d9dfd08f1f8abe05475d3f445230413f3c2d8d7a32ff4c27a59f3922a9523e81ceb9a2b0a35482808b08de05f2686e7dd5fd0b5cf19516cb0558a76d4d97770e28404a2e78dcb63f3b96eb19f1bbf291e88a6145eb27e6fa5ed3609e829094f9cf937c58dd2bbeac045e27afa19407b425abe489f434d671692197d5cf72c07c8e2ac447b2db81b8e0e248d621f0521aeedf472184eff3527a64c13f0c601b3ec2048af2672255c14010fb1430fdd8b36f426c6469ce3c6b0be2cac2ae4ceea8baadd17bd0900a75114a14a370e499163de5a0e817ec703ec5b636140892fa8203d20c032cbd574fc34d2385320f8ef889048179132035bf18bc196f5b08bc5e4d0ae4bf18768342d5b48f90d27c5eda7c200bb025a2de774ef9a8dfd0d75fd844969950a13f5b4320a250d4a124fd0beae2313ac372d0583b79543c07fe4a31afc144acf99238c31b3e0b9c6241225467d7ef6a633313309fa84669b737cda0632d2dd36ec901e1ae3e4a68210fa0b0fa02588eff6e72f73f015951e42f85868c622a8be41f3247a2140f3fc0a30d31f2379fd387240e5f306a17b035720f57dba876e1cd0d33bc87d966d620e65736370fc817ac4ff15db12147cc85c230ebef736047408e03ca8f0be6a642030b5627458aa1e65dd56737ab810b2a8b492586c42e193ce28d9aae97a13db0cc36d358f6efdfc379ee394140a6700fd99e86b8f7d3a594cceb4bbefff68ce15866cdfc9894097f08e89b66f8c30bffcc001044b0594922e11b8a055c9f6ee026ae31ac020370a1f3e06daa5a772272941a101c11714fe8d8e37d40c3122c61d8f610d194cf82da8419cfa1680eb14ee96b6686e9f209a00df36e96a9d6f842571b23c753c5577e9ed466bb585e8910722050a93a8463bb655ccac5d9900a31a460738ff88a624304a1e5b37fb9ffb23887000c006db10e2b4b8985770d88102ff55d36e7513f37acb4c5920fbd220fc20c8b9b1a83128b0c64bcf26f761bc01407ff23a9b11942b6034278ae1b4817169180989eef86eba3f781c6ed7c82b279089823170533c0791d57ca17f1beb9bd6fda0242993bf5be154fa2377340d0c0c8fcd0da22a25000793deaaf634421431ac4d940c6ccbe9265f52eafaa6660cffe9ce6f0ae13c38cb7ce5304e697ff3814a992c030ff909d9b33615c8f9be2f199990be4b96c115324f1f53c609d9c70c9a3d643973be4f407aa54cfcb7741124c48570a6a3906b2eaa017d1c4e98b1336932976e7ac4b2cc3ff548a3d5272ca9b66092c0be62c903cc5f6022fe892c37fbaaa5bba75f41e40b410b223b052ed39b580fcc936b9582cf7c479ce148f56a374df66ddb07dd6547ed67da09e72e7820676bd33cc3dcc778b5e5929677908c6f43d3f2e793b768cb2bb6c11cac258438c7630aa10ec88ac11e66c0855e0be63beebbc4a846a4210d3b16a1a45b07144aa8b8587d6d981683640bcdb7390599cc6b806869d01e425cc59f78d26e009412daa789b0872610de5d576f928321c80f83d64dd5cac4562cfbd72b56bd17165c7c60feb78c973289e4afbb58225262f916b2e189f9195aaaaef30f037d1a0b47a5e1ad425f16c581f4317b4a1cce0458eb64e01a2ce88067b6365f20570e7a6ef374c26e7df9d9b86f1a2ed3f3a6f151d108f24245346f7fbacc41e39d1b89bbc83ce93442bd733e4fb70c090135e71518d07f6f7cb5484256d973b5e107cadc46b3caecb4a0c85930d59631ae69c164b9b51d4af12b414da442ca6e2e2e905b3d35c848bc74803d93cdd1a52642f101ecb76adfbb324aab602cda06f4142f88ea187aa2d9bc2770fb55738bf1c22a0172dd3aaaf0756da7919ea8fd480bd1852cd97487ce18b5406f1e208103de94a56189a902b0e677d3ebb09b9b4403e78dbd0aa42f5e177f3c0e44bff9304af9cfc15d61d2b7172aaff7db8e31c401014a1d5637a540050a7c24f8ce92509be63c99f33c3e169be4e48c5c46c0d00536d73fdfaacd543fc05f62e194e64df3916521560c2e7c70651b0c8cd1711e13cf10ed6d7db7642d832dac4b6699b200a8bae01e5c271a7cb1dd55be7593252ec16d138fea76b7ab76eb2597f4847ffa61f1e5560f85d5b1dfb976384bd384137d0d599a996035b696364b2bbd910add9dd520e1d50d4acbaa28865a9eceb70caf6cfd4e46b787fcef171be5316b41061ad0f844d78c571948c0c3b9ca5b581e66da9006818668cb3024873fb6c209e388964e71e4e7481f60e98293614a491c4343db492b43eaf5acc1b24720b645f73a741b8082ec8e7f0940270bd337222e0e5f38ae454a0bbbb97e2684eb4c0f8665e2f5fb567a7fc8f46d42d76a87b9167d5caaa34cac8c6c35e92f339daa280b074923950ca4fbe26d12fc08df611b122b294ee8165d619809c84a8483ac031a91a321ba578cfff08ff1da3638da881a658ee5025ca8cd4c2412bd64fec5acce4a063c903a928a1bbe47a19d6f20ce2a45e48b775e956e7328e2807bdf0699717624dcc4bea3f49696076d6bd1f3b32648c84b627afc98ee7a255a9b6a7688bc2cb1d022b456c914d73c31a61cdf1f0990d46e50809e625fee7f66f13f3fd3d711053420474e2137299fb499c55d280fadb264bfa1c01fb103c85e1025144416fb45c410b1de94ce3b6b39e31dbdd40085c18596d5a4f3aa5d72f5d762f32657466c3d6cfa119e4b15d66c166f9235130b6b5db7bdeb688674c2c9ffe5953f913dc8b70c89ee3a3e9d0b900d3eb11b0c998e9028b8af68a3a123f0a5aa56f987cb287bed1b4ec7ea4d5080f7460191140fbbc521c4b4ca284d2f52ba94d12c57cffdf6b3a1823c8bec3f227f0964d0269567969b2a6952d67b2cf3fe4ed64ad32021de8df302d6fa0e5934dcb0fe0207c4eaf81924185e0ae50fa740e900c098f17483a8c8e9acbd142b0d3b8d7ed31222b7d9d9642133a4d710850b29be1b312f2043e0553468a03a468da16119a0147bc6655daaeeaccef77df33300f0304b229d0a67f2e2686ed0faf697a8c0be02a92c5eecec61f86730c46d3e4060cedea01e6ad69edab787224daf217fc00d25bc51eaadc89bea9ed8b8b064d00a603bba923afd50feeaa28480fe0bf5208e1f6c3c1ab06c7581870abe1d4263967bca1c83e6d829d9967b15b03c71662b051fef32423b6f60529ef22b34e79fd39a03188920fb378c832b94ae04ee9c1e611c19e994f3fa9a123454d8453ff1ab96e3dfaf32adcce9ce3a58d3ab46800283017c41df169d9030faa8635070293a6b4f92c2a03a23f322f9219eea5c13a65e16f8cfbb4c12898a9b5666c005ee1bfaa0d64396e1ffb0c89394ac75ce404e341592c70ec8ef696ac200a491dc290b060b0d8ab0b0d73a785117cb992fd5082920edf8a802617e40021efd904982120cb763677cfbf5fb26e040250ff71a9e8f0a74f8c8c0cbb2d83b70592dcad430759e5e3365da322b45198c34067f1ef09108461a7aff586e522eff5dd06ba39f32adbbb2ac11cb5ed218b080ef6b47ab0a21d7658d2c57a0b782547f8c5acce7c340cbc4e32291a4f4d261d51eb5d19fc313f13da04d155cee22bdda2a05328dfad96d058d2752e41372178a8ac3069d27277f5ad615312c8a0da2d6f5967a6191fdfa66a465ba370e3d8a8b27f31b75cc1d1dfc9e914df09e8044c0d753950f5a662bdec0dc6b50c3fac197df947b2fe927b02824b638eba85cc6b3a3a4633ea595e9e7c01764122a2a188c7f05b86a0901781fe9cf000e194128b474d8334de7204e7cf9ba4c45a82851cc873cb2d851257d3c067a363b22d3ffc4592989e1cdd50333e7d20858eaded8fa02b85209c329cb4ba3f99922719ac16e761fee300db4c4022070de18149af7d30df3be006208f5703c677000acfdbdab00aa099e0c515cdd6c36e4c2fcb14d4a169ac5226206d780418161648be96d949099a7cd18b491d72cb00baf6a36552c49578cb858004493fa5ffabec5316a34f8af4e3e329c28ace755c8329add179dd15a716fc30cae70fd816fb9ae67f0e595a39585efe683dac6569cecd5b4612600ca7e58142774ac04ad50ebf3fd3ffbe32cfdacc60c4942daa5b1dbd52cb4570ce3acffe92365dd10cb6526daa7ba1a0b8635167f7220c97ce29b11fff0e2780c3d43d82700b6511664384bafbc8ace53cb17529a7cbe4fa1e5b8242a149af5120092d5f50af044e091387602eb00690a21ed41b2b6cd2ea58ffd23c273f07932cea2d0e81664d0b1770c1a8726cbf09e109bb62cf0bbd05bd068eeb95e2f120470b4082e0f037bed194d5aaedd71fdb36b71ebabfc29ba3fc10086cf780c1cdc74ebe0250fa517cbde50830063cefcc39e7848ae2f4ca899903296fefa908e8c18e1bb8a1437ac612ce96cf6c0617a6cd6c6e8a631315a1d3e29d803b558c3a4274960d005b212c9c31e65649812c0dc066ae224f5001a4893fdad31cf49271b8df0353c2feb0c6796198d5ddff04951416833ce4200813f0f39d2ce75da2985d4329c1f2b2023d34a62804670f522d449b1edbf12c255673077c821683b1d8d7e5ddf800a4b7b539cba5dcaf1fdb336daec57ba5cc8e484c04b5e70f74ee3a0a2e954e2175117e97ac2c5bdc2dd375946a0355561c2cb8edb457d5185a93189e13a4aea066c51edf64ec0704d127db99b2ce23ca840435bc4ce9d8b533e23bd09c80f5004b23d8666c77a078368ad040c4e1ce3d4fddf9ed1b1863c9ed1d2eea60ed85f24edbcea0b513edb75f6321e428db3b3082154a7923b2776b96f9276f251b155188c9415d7e4f09e37f89fbaddef8410979efa36c6a1efe5565349a96498aea518ac498adad8a301e7d171c35883c89798ca890032253d77b00393525dfc1c992b73dcd9fdf3f304f8b5c1f7a71f4036d4095ffca43ba1c2ed25761063f0ee3925fcb36659ca28e692b6f5e89599405f990c57ec7237311d663bdafde7d2f81d0dcc1c522e2497eb105f9d9bb4f969cb1c89c2c4010dead0a19023f4bf15879c2f13afbd1caf80f6e3b5628c1e36f57189ec2f5a61d03eaa58e379df3027da6f24403ef8d186c62c5176573cdb2e799c65bb6c0da4fcaba21d4b8c02afeb6b8717fe4b74f45e45025aaacd2ee55901d81ab63d04853f222695e0969e3a9f89b9297aa44364a7a2bcd0be5759f3a27bc00d7a99f32b69cce48cbba3cc858a9fc708deb0b9515755e48edb793a598de521bfecb827ca3fe1e58b9875426b76a268137ba4e5fe24a5d7f977fe9d1b50ce573fe98be883ce057ff046e26d999403f52ff08e8a7dfb7f993a389212ea2ed1bf7725f4a265bdbfc208fcda3df33465c90928f1e1bb77db1955ef73583031893947c902eecff3fe24903319d5c2433e0b0546305540bd96a71fda765fcad36af678a4f07cc95fcd02e81ac2760931d40c132c998a8c0b120abd2d3e666518d1ef5ffa130cca13b78e57cad7a151bb594a1e394e73d71aea3c2d6e5cbbff872c98714fb5fb571e1e3743eea704b295666d21ce4e84ca11a1d673a27b169c5f83088e0ed344fd75dd4b741b05226ab93513305f4a7f83ded532c62d697e04ba2a963e30c321f916c0080e9fbc5ab619aa8c220f38de69ea6d5a49d99f904ace4f9c6132a8708e225fa2ab197c4508ff25c42a92d2a7cc3855cd59f6c96407266922cfb6f523d46e47e29d0447f32582e1951a6b0361e26226f8379a50f2d5e3204c6828da40b8e7cdc816f6b166ef4aa723077f7be16b732f1edab20a5668e50844b717dacc74dd94451cb9460cca88ad8a22ff47083c488ffc04e3b9c39ec7b25f41ee2a2a6cae755bc5d1fb9e1633549013968d569bb6c6f0d95547d93eba03a1da40766f3ab3b18f19b30964af1d69db15b13c2024eb855dd70af579f46fad36a77a77c2cf65812e92125f2f9e4011eb2ccf4716ddca655668da9838e29677662101824afbe875bd3490fa1a7a286ae31704b40587eec531af8bf89a26692686387927daec1d6e004fe9105160219a7d23035a362fa532f57b6269292058de35d8cd36c4c6b1143821adbe16379d11e1232646f4d497651f0954ea9a1df894dfc491003980f60b52cc0a1ab26756077227ee3102ea57dce3271965fbc8bd6e66a68a2b9543b577278024cd4536b2741226c3b1d409828f4e0d9874ecd7069da3c9c77f290915adcdf6b456983796b3fc28042c760483b93e07a9ac85a3991713d1c2f85b94556c6d1a273da1ee90265d01a8981245c7f7f8d10b2915126d9f9ac61a2d6a8c055ea87be9bafcb5643c9b119120d465b5ddb005f7ccba998fd30058ffa33d82c9d8e4e301e780bd7f93832604cfea9de23f1d6b2a50f65047ac9f879eff0451f311164941d680b76395aa208016ec3c5dfd1e4e2451ec13fb58f2242b1c26e54bbd88b44e163e4e7c7aad0b3d5897b5f0d8d49522bd7b5c1aeabc1faa5f92051b7c9609bf3dabb085a533130bb3f740556f8e71453758b79613a124d615ab01b2e1de8a4e519947fcd62b059aca90452fd3b086e6f37ec6b9c8c565885d7bc2125f2a6edc128992c986ed1e16fd93e88a03407f497ac742f49836ac0886ff6354b8a0d7096dd464cbbd9e1182fbc13662c46028cf859e93de493b32a8060828596b2fc4245655a4f9589c0c3e6a3130d7703084bca793e15a9e9d6366f1898695e5d47b7da2fe660461450c47a7186e240f9f600739c2fa2038f28aa34075563b42e39189fff917f77b1d169abf6085508100e18e9651f68113f0371c993ba004d5ac582763655c4df79c28668406aa60c8966a70355446b5ef97eca8f9c21cd311efbd65d6701932662d214ba804cb02a5d0c4e936c50435a6d8a2678558c26aedd38694ee726b9fd89a039a0378b17166714bb1379bb173d2e916411278d8285e9e6dc901a616904b1927280ff562b631da5d3cc81ff70e3269a358e8c4dca3696ccdb546ae1147014621b472511388d61cb1e60590ad87f05617f122417a4282d94bbc643f0547a6682008695507d53505be0bd9b78ed3c7adb01360df7cc3b4e8ac5357485facb49c2e0600e9a923c71d12fcaffcddc8de640403018a9a2ff1c2ebcdfd6700facbbb2dbc42db37fa4e0b64fa45559ed421cf9e91bbb8533983393113a75023ebc8090bb50f8d0b75903c3c8e4b51137f3ccf2b5ee42e549fa6c2c57a336718e1867420e656c75e985702a0b1d78e451a4d0e7abfe681ecfd92e1fe5d00c00a22acdd0ff415858ee7fa9d195fbd1071d672106427bcd2c8f5114e6b4e3b8f6fba28c62b38318cbd8088a2b956ddcdebbcfe0e6670d37b63276fa30a16791a3fee1b9d", - "public_inputs_hex": "0x1a207628cc6936816ccb62a7b56fdbbf8e975293b677c988644e018fc402e4411dfdc7cb6265f100524012f038ee1f205bf8789b70b46c57463dedb4998f7ac800000000000000000000000000000000c6895e67e144556602cbe13943c8169600000000000000000000000000000000808b3aef60f3e74a629e9331d68a14b21806572c19ee2f3532e970d617919b3aa8cdc582782dfad0699badc631f75128000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000022c17de150116bdca2a3edbbac4f77678c67c35f056f9e969387b99b5c26da55509a23e762ede2ab19d289955f6fc34a289c4196b6f4fed818bca760158098e851b1e385ae72fb3add3fe838e63d0e080c2409bd2fe5f57f926a01a4e31278a1e0fd8fef8ee3dacae5dd4bd8666f29088e7e2c1680f50451cf263d3e53ba2b8b4000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - } - } - }, - "test_exit_code": { - "crisp": 0, - "folded_export": 0, - "enclave_contracts": 0 - } -} diff --git a/circuits/benchmarks/results_insecure_agg/integration_summary.json b/circuits/benchmarks/results_insecure_agg/integration_summary.json deleted file mode 100644 index 005a4e2c61..0000000000 --- a/circuits/benchmarks/results_insecure_agg/integration_summary.json +++ /dev/null @@ -1,244 +0,0 @@ -{ - "integration_test": "test_trbfv_actor", - "benchmark_config": { - "mode": "insecure", - "bfv_preset_subdir": "insecure-512", - "bfv_preset": "InsecureThreshold512", - "lambda": 2, - "proof_aggregation_enabled": true, - "multithread_concurrent_jobs": 13, - "committee_h": 3, - "committee_n": 3, - "committee_t": 1, - "nodes_spawned": 20, - "network_model": "in_process_bus", - "testmode_harness": true - }, - "proof_aggregation_enabled": true, - "dkg_fold_attestation_verifier": "0x7969c5eD335650692Bc04293B07F5BF2e7A673C0", - "multithread": { - "rayon_threads": 13, - "max_simultaneous_rayon_tasks": 13, - "cores_available": 14 - }, - "operation_timings": [ - { - "name": "CalculateDecryptionKey", - "avg_seconds": 0.004296347, - "runs": 3, - "total_seconds": 0.012889042 - }, - { - "name": "CalculateDecryptionShare", - "avg_seconds": 0.020525153, - "runs": 3, - "total_seconds": 0.061575459 - }, - { - "name": "CalculateThresholdDecryption", - "avg_seconds": 0.019100917, - "runs": 1, - "total_seconds": 0.019100917 - }, - { - "name": "GenEsiSss", - "avg_seconds": 0.006925194, - "runs": 3, - "total_seconds": 0.020775584 - }, - { - "name": "GenPkShareAndSkSss", - "avg_seconds": 0.010452847, - "runs": 3, - "total_seconds": 0.031358542 - }, - { - "name": "NodeDkgFold/c2ab_fold", - "avg_seconds": 8.270900388, - "runs": 3, - "total_seconds": 24.812701166 - }, - { - "name": "NodeDkgFold/c3a_fold", - "avg_seconds": 34.927441903, - "runs": 3, - "total_seconds": 104.782325709 - }, - { - "name": "NodeDkgFold/c3ab_fold", - "avg_seconds": 7.542320708, - "runs": 3, - "total_seconds": 22.626962125 - }, - { - "name": "NodeDkgFold/c3b_fold", - "avg_seconds": 34.922820125, - "runs": 3, - "total_seconds": 104.768460375 - }, - { - "name": "NodeDkgFold/c4ab_fold", - "avg_seconds": 7.895315874, - "runs": 3, - "total_seconds": 23.685947624 - }, - { - "name": "NodeDkgFold/node_fold", - "avg_seconds": 18.310982819, - "runs": 3, - "total_seconds": 54.932948458 - }, - { - "name": "ZkDecryptedSharesAggregation", - "avg_seconds": 1.566955375, - "runs": 1, - "total_seconds": 1.566955375 - }, - { - "name": "ZkDecryptionAggregation", - "avg_seconds": 47.874825458, - "runs": 1, - "total_seconds": 47.874825458 - }, - { - "name": "ZkDkgAggregation", - "avg_seconds": 19.861393583, - "runs": 1, - "total_seconds": 19.861393583 - }, - { - "name": "ZkDkgShareDecryption", - "avg_seconds": 1.358248069, - "runs": 6, - "total_seconds": 8.149488419 - }, - { - "name": "ZkNodeDkgFold", - "avg_seconds": 111.87172225, - "runs": 3, - "total_seconds": 335.61516675 - }, - { - "name": "ZkPkAggregation", - "avg_seconds": 0.925223417, - "runs": 1, - "total_seconds": 0.925223417 - }, - { - "name": "ZkPkBfv", - "avg_seconds": 0.218732388, - "runs": 3, - "total_seconds": 0.656197166 - }, - { - "name": "ZkPkGeneration", - "avg_seconds": 3.515460263, - "runs": 3, - "total_seconds": 10.54638079 - }, - { - "name": "ZkShareComputation", - "avg_seconds": 2.332301763, - "runs": 6, - "total_seconds": 13.993810582 - }, - { - "name": "ZkShareEncryption", - "avg_seconds": 3.965180039, - "runs": 24, - "total_seconds": 95.164320958 - }, - { - "name": "ZkThresholdShareDecryption", - "avg_seconds": 3.440710889, - "runs": 3, - "total_seconds": 10.322132667 - }, - { - "name": "ZkVerifyShareDecryptionProofs", - "avg_seconds": 0.103301764, - "runs": 3, - "total_seconds": 0.309905292 - }, - { - "name": "ZkVerifyShareProofs", - "avg_seconds": 0.285312216, - "runs": 5, - "total_seconds": 1.426561084 - } - ], - "operation_timings_total_seconds": 882.167406542, - "operation_timings_metric": "tracked_job_wall", - "phase_timings": [ - { - "label": "Starting trbfv actor test", - "seconds": 0e-9, - "metric": "wall_clock" - }, - { - "label": "Setup completed", - "seconds": 2.7038335, - "metric": "wall_clock" - }, - { - "label": "Committee Setup Completed", - "seconds": 20.174264042, - "metric": "wall_clock" - }, - { - "label": "Committee Finalization Complete", - "seconds": 0.003923875, - "metric": "wall_clock" - }, - { - "label": "Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall)", - "seconds": 131.619168, - "metric": "wall_clock" - }, - { - "label": "ThresholdShares -> PublicKeyAggregated", - "seconds": 144.272573833, - "metric": "wall_clock" - }, - { - "label": "E3Request -> PublicKeyAggregated", - "seconds": 144.78216475, - "metric": "wall_clock" - }, - { - "label": "Application CT Gen", - "seconds": 0.009741125, - "metric": "wall_clock" - }, - { - "label": "Running FHE Application", - "seconds": 0.000051333, - "metric": "wall_clock" - }, - { - "label": "Aggregator P4: Aggregation pending -> PlaintextAggregated (wall)", - "seconds": 49.457601, - "metric": "wall_clock" - }, - { - "label": "Ciphertext published -> PlaintextAggregated", - "seconds": 53.35583, - "metric": "wall_clock" - }, - { - "label": "Entire Test", - "seconds": 221.027911708, - "metric": "wall_clock" - } - ], - "folded_artifacts": { - "dkg_aggregator": { - "proof_hex": "0x000000000000000000000000000000000000000000000002b30b0403aeee459600000000000000000000000000000000000000000000000db8eebcfc671fdeea00000000000000000000000000000000000000000000000af8f618d2adad1ebe0000000000000000000000000000000000000000000000000002c5040e9c20dc00000000000000000000000000000000000000000000000a2de63e4ca6eb0e210000000000000000000000000000000000000000000000021ae69d4a65c7a8e900000000000000000000000000000000000000000000000a005bc241e7d733b30000000000000000000000000000000000000000000000000002aa8c45dd85d4000000000000000000000000000000000000000000000008ff1dbd0f4b9b41c900000000000000000000000000000000000000000000000a46e1fc8b19f097560000000000000000000000000000000000000000000000075006eb06b9214632000000000000000000000000000000000000000000000000000093433350ca3600000000000000000000000000000000000000000000000c8e6e0c4281f705a50000000000000000000000000000000000000000000000043c924cc53c6b0e6b000000000000000000000000000000000000000000000009a11c5c7358610a3300000000000000000000000000000000000000000000000000001c36379475c900f5f028b1ca9b05f4fd64f348afe95c048291c2608303e91a5c888446ce265e275b7caf50609f9aed4ce3fdda4988dff1b9cfa755d22a06ac9bd70fe011311d3021f96a67be4ae494bd7f310637090a697383e48e1cfe83d199fea464581f5b26f5d27b00505d5850189be9bf43d8b14ee58b28a16c87b3bf9d5bd3dae341de20a977a63187eb07fb817d6f32bd7e353ea5f2e4563e05af30e41de8d76caf2a05fb7411e0736765ea872b88f93642e1a0a122c2beda192429812e49797d0d2b0b2d57c7f9a3d89feb36de6e8925068d4cf01c5631bba6ad66d9dfea89eef42507b82d0cdde68023f51cd886423293963e553af03761d6bdd7e82c5f3f70581726faac8f74102eb6129ddf5940c15a1f473a25099ce9aed7c8502f304535e73f02c89d7edbdc59430a931b60bf65dba6ff6c4568fcf3361abd1e9097cc3446930d256472545bebbdf0cd8202744ebee6b32aded93bbab7c8b07493ffe15d753c2e767d9b71f63f422e0d8397639315c74a3f459246674a141133d6068e91cd04236270fbc4be415c1b3fb0340ab79c0aebf168d36a35a77d26f5507817a381e82997d3d4e6bf47cf282de75db04e846b05a1171e1b27b3378df7f46c8a0d5f452ef0980db9a94784dc6878f8768320b7a5f1327d5a0398b9090cde4a0301320d2c66315a1209ffec932d6318d851ff138899b2fc2f20210b9ba6487e63272dc9292a55757e58a10eaf53bb32db4bd956cb6ea7db2f7d3d376ffde54a0c481c8e2b91e9e7d106a81edff57b8a49e69ba1cbce8d8ad7a768f51040cd0760adda1f1b057d97309b56258908e7d0b72e311d563d0f33a89b025e9b29dbae8430af6c1d5dc9be373e533150316757b50b3d7f39cb3fb983eec9d368f3997f12567c3516a615929225c27f1166fe0b8a910ade60dec004d39048fbb5e348d1d7b8f14e167cf8625eabdff7f7262e220e7cad7c3169f11ed47467b15790ad046ae3ea490d5aef76bcb164504f3b903fdde68d660bf30a4a023c0639d3b0df5986a898291ca9055a779c358e4526204e571e880645cb2634ddb604f97aab892dd8b2c61206a8ad742b79fdd1cf600bb1b100e239a25d525acfe6fb97a5c0a13dccd21c3e1be9395c5f4a8ce11c7c9adf0450a3dc13c753c8b0d37894fdb03746c10c45e92b11c11485fd5cca6eef8495c4fe4a8e89af5ce2321dacfb3de59466cdec2510156f196cfcdf53325e7070710c87d4451690eff29e4d32a8e34518657116d7ac1562534b4b1a9267d5813b831d136f643f2511cdf969567bb8528b3b509274e022485fa86f947eb6caddb7d6aa964114d188ffd141b79fde4bec77997e8de82e1a22e50c704d7e5fa81ad6470e6e610932071304bd9547f446e615d36f44ab582ea1f51c35052fc32ef3fd4004dc82b1bf9a39b670cbd3064b42858de6d62c0e202f260e6c01dc5da58f0f5ca5aadf80c9a9810e700b5342d312a883895208ed277759e4d19186345a6d59fff1e1b2df1b9ed20c49e08dba5d430c5c889d232c0dbec12765d1f90c1243fec4c3d67e1d37e80f7783ef9a1828baaceb6f59bad6211ce93b78dc48f06df07f27a2150b2b744cf2a5a06a0df954aaeec4161a424e2eb3a35a6b9f4e985ee41ca8ff60b38bfce07c646fcb9cd13c438c57afced26e28939f478f3c70bb968c92a82a5be84d9453b1121028cc087d1d072e7e6c7c0205fe83b1a01ceba1e0e90bcce21bc3dd3be897d503f20f49b07d818120c8883900aac83216fa6bf485c26476d03e6cad5643b6c5cf217f866e372b1ad25028ac239027d059b6b09551123523e2a5f42d33c4b330bf9b77e09785e6e48fa657361dc82de67104ad93500c9741939e8ba447f6dc1fc4191770b950772b9f1c82772b810282ebc72e0e003f822c1a213b3ce88f42565589de9c8a22cd5e3fbeda3c210803bc3b27db480707058c2df76c782e29c4ec3ed4258affc6790d85b95c0102af61b154df03951ef522e8c2e2d7c0e65d89bbbac33c8119dd9bf436def3cc2b3767985ed2bbab59f583232694b3a362918f9f72a99af2f0f5af2efcc7697c2d2fcaf7859f1a53585929269d86b3c8973039adcfbbc308fee491644c480a7c27dfa9fa5ef3bd09bffee4577c9bbc3690003ea1e3aad93e92fb3d3049d533190deaec9660872e7fcabfcddd95bc009081df6bff849124e9e9df109416fc751b0d2a98b66c8baa3500d82452f976c890f25ae6399064f155ecdb915f4d008b7a002f0bba3996e8fb749742a4b69120e029e62ad24d4f998cb586da076c916cb321f43d09bf02b75a56631867d73c77cdf9da4de3492a4b650d78b39b367dfa510fe1e9c7137dda94b17f265f6938deee104649c6163212b3f9be3a66234369c113a8e3a54aa3505c8bd668b9bb77dd5eec4e994e0024de8f3203d92f6f301e1223b57e5d4a69b68f6d9c57d3fd2dba27ca0bfb145ab0c29922b9a2b129f0e3f71fc82a5b8a4a881948245a642bc118320f72a2723d6a7a9ebb1bfe185529acce021f5fa2445c3744c8ac48355df7a41a8520486e45fce375c3c6fbd3b33bac3c2e5e29bc45ca7fd84f34893fc756f888c9db6e8d1b33d731af38f622c11c5e180602f9f504ce236d5dd7c1068c9f472f64905dde988f8e4ae7f199def886026f21843689e58f2f3dfe48f8f5a637b4a71284fc5706e649278419b7c8e538926409cfcd311cf3c556de1e275dbabc9e67658d311ba3cb5c17542c186a7da2ffd129684a2f9bdc4f2ebead34aa0cc6f94cbab3aabd66c8fd8bf65350be1ef08abc28a673680e3f8c7e41567d1ded0d1c173be5f3f0c7e080b2f1545630ef9644321ed718522ab1f7584f6a4ad83079823dbe5c55b19701cdf61208e783f6516be01412b7a8746a2c86c2cacdb91aa020b8d1db64dbc78c4889165e11b4aaf173202bc28bc70e00bc24bb8cbe3839f97793b66099528624e7d1c7fca00b911b707b19bc81d8401fa754ba2a05bc955437d15102dd440d1969450617d725d1c0baf51b3d8ba9c5943f28453d574f21fc2f9a08f9752aa61f9188a9cd8574593a82ac1794392b927399e2682bd77ca428316d1a2a77fd52d12be4d3f7fd57b9b33a68065b4112e464cbb09ae6d219c9acc029a295cd67fe60517b04596e84de3cbd1602082cab3609a950d6731f100664632ada637279bec7ead801d854a2b92a322b0f0f6f0554856fed457ba9fc25583f8f1ff8d03d55205a052c67db1a02282cc80559294b448cbc117fe65a32ae25d61584c1993159d4c2329f89293162f89ad02d91f842933045e44515de74b0f6da4625efb734d885a51865862a4c2d8104682c6d83cb7999c411b070ea3a5bc939cd54c26d43025654b66025c683116bdf06294b2eb9482a612e3d67a632d391609406b60edbc28b9c01c5d5b43796bcc3d007d36fb02537fcd6d3baa7bc9c3859846fce0d7b30d65860a5d8d27f6d2718ed15850e16cdfce67e1dc1d63b0fc45f1a17a0d9c7db71f689e3766e12786b8c2a2d60dc28eeadd07ade9fbf8447fdddc4f91d05b10d136058ad481f9b4a7e024a17029bad7d3a24366de116e8077da5b101c14da26867735d2524bcb9864778e02dd5dc33744ca7e50e87806b9d773d44dd60cac69135a5d29dcb4b93fe58551024ca2bae5c4c5f6682cb487546e40abe929304b714f50ea72c453cd38dd5e8692c2ae119ad1d9ef3b605e627d35720d26cde98e914c811cc457ae3cd5252b79e25893e23371561e89a731da3343d9ceeafb13593ccbf355ea34eba49f2e63c47289f58bd3e1fdacbb319183e85582f405592fe19656cd0a23a1cfe79d906f80d1efe414b0a22a209c332036c65cc9d46751c183d8618b839afa04eb21499cde40a98b16c72709e82be7312a6085b0563e940fc80e1cc10ad90615a040be766a204743f7867ec779c8a1d0d5fe3de9462f19bfdb3da14dad8768e04f13148df882eec36da9754f273e15636d808ea116523f0d567b5316bd1ebcf6c4de936d03908774b8f1d132154642b87c20ac9cd2de8088f1d0a55de6db45a75543d1adb2806b5975df484e4db990be106045d32642afbd7a492681e8681c84ec41bcadc6e1527f9ce6a7a670a20f260ae45d21aaaa489855dd747e5340f01a956152504a31ebc51009014c5b28e9e845c3a143d89302c81d5f94bd499250d48ddaf47fcec0afa7a61480263c5273b8acc667e784402be671586cfdb7b4db3f8a0f5e1fecd2aefbcf44e5f04a3617598869909c0aceaf0951635951ed4180a0a9b50cca1bb2b5b775f56a5b46a804330edd52fcbdf477485ad2f90e1aa0e3c6febb4f769eb0a4e62b793e1ac9676a35745509b1b9137cadb86a1fe28b0a00b1ede0523ef0229d5521820274634a635d398df9b85908f4ffd8533407e995995fb6a6f4f8bcf15aeacc9028dd5d83f265d2fe95d44afb3baa593f702b1937c3a27a40b6f02d7058a16f98da0cb85c8c6cc07d602960eb28aed5a6b5a8005363783c4c6ddb2010fd07d26daf701ec005d7765e9701cf8617925e4dc28744355b61d1fc2dffd272b74a06f3520227be984cbf13925584c110fd52798ddecd811ade62f107d939c1379e3ebcb8d71f09dfa48f3f2be201f2cefcc38345ae3ced3286cd06dec45e9115b345f3e78a3ee45db7f9170064864d5c09cb0fc3e8f5b7a763846c9b6a87d11798becb574a394dc37646282a7f7c7db3824cda09f9f8a5741937915979ac90b4f7b5de4d1eb4a3b7d6181a242ce8efe9e99513e83b53a66d91e85ac3412a40f2ed30dc99975a2a8aef2f11dcbb15473e41cbbc7bbb7adcfb89f3a9aa708170af029423d5e3e33e5bcd5bbc040ef8843868fc9243d05539ef570dbe1e10aef20fd382c33955f4bb9721ff64b91dc1ccb64d1c39f422bad3029fd747441ead524ce950b1a581caa7944b372cb78c0f9933a173143d3c99f2ef5203bbd71341e1b580d87c30fdf3e28038e52e088ee5d1729da0d34f16b6485002e49708b2af80a0440fec31f89fc13213af1d473835795cc991ac856248d6947c032bea69585093d3901d6393263c2e887bb58cf5f9e8dc4da7a20bca245b87607de9ea0620f096ccbcd54b6f3921fca613160e8e406d7331807a16d33650e418f91a75a1b49155d96ae9ab1de581aebaebcb2cbda8934bab4be6568e7c921e6ee1e9ce8ac5b280bf12e8b4976159f25c05e85fd4f48faa1e5042455da26784f0378846b00b1019ece0c5443a7276dce936601960c620c0f48dfdce3d7158691ade1f4c89e8e16e33e4c84777d3b261850f67e4cafd59caabfaea137826ce0b785a1efe2a1e308bf9cb95df87413d1bed427d514f8d2f1ed5215cc8cc01b960d2fe3466acb780ec253f4c5b3916132fce27c7d53c269e49e0d5f5cfc302c1815c83a39a842a4196b71ab05ffccdc4453eb6121cad50beebc9506f5e6e7a86325c089c1505a5d1565e4e200c0f947704862ea0bbb30d55ef3b0138243795391ea5660caa47102215bb22876b29def7ec75957f10b4173c7f04355665519b869e5d51c8f7e156b05af22ec3dffc3be18ba8bef4b6112006d557dbc866a984f59a6b4850790c67d09dbdd531ecb6baede53b5f37ec5bf114667e1d26ff037959d61dda4206f612f01df169922373268b1e7e6fad457ceafaf8c9c25e62c37454897d9732b6135712bee728c4eebc919211002d9c6f8735af7b8c0a544391a46f28c3a889d0f2e7a104554aca10104e8de7cff3649c20d0b1f54088096a7532b5019e476647fa05e2080741d0dbe713cbcaaa2afa2303255df9d8e0d391a6532b96bc449d704437222d0edd1fc730ed424ad8d4b5a39369538c7d586ba3e59184dd5f2902ed1146e1a01c7b01250ab358965ae82a0f4528fa5ada19814df0d73e4256eb85c0782e527f1f4d0221ad31b598531d3812ddcc1499f25e1501865e17df02e1b8cbc9909234c2802c41b8f3e59bdcaca7bca354ac8a06eaceca80e576276e089cb5f29e61b0d1e6d85b56c11df39d49c0836c0a3db33fd564f9b81b2dab176127f2020091e84be762866d62955eb34adfb2c036dfdc79652bd5168e1eccebbc106c6e0842a6ad0ccc37f360dc838e8fd4104c57d8d74b677ebea4c070a1d5e7a7fc219ad1169ddb19c6d2d9d077f9a31b480259d7c4dfe8e603ec1953634fc56a67550bf2f4c127151b656bd10e7db9c9b4e19e526d93e483d2beb6d6f95d5dd7dc4ef270edb572eadb4f1e9abd0639860e241ae44ee499db89e92a7971670be22941efb0fffb8af56e85dcb0a48c09ae10131bf2a64b0ecbebfc772259c580506db69ac2156fe9c7240f7f66d4714e18bb20c07f44dc0cd84f0d9b1aa509b66ea5e255e0648ed0a2962ede02665952151a54e8cea60f1ce897f00a3abdcd6fae82e74b6212fb5e7fae591d70df03de924b74918ada838ac568031697a44c273484fdd102cdfa567eeb6b89ef0d9fa657e8943950256b1e7053b0824e4bef3666272ac0314f463083e7bb01bf0a666e722b81cb549429070f0cb17f6cdbd435b5a9beb8a2e4d8baeeb9fc7abcf248cd7dc6a01075c51db5fa579aeeab43a582b47399ced1f5044f92a873e6418ba412cfa0a8a2db3314585b220ed790f35ea358f93a7630fa379be8dfc67d5eb98c3aab5c2f533d6750b19ea957acc6bf9e2796920007f14afd5d25310bf4bd31ffb348452c2d021e55f237a212ae30aee3f52d514f4520a9af18e31091497248753927f99eee28859559b268451ff74aba9de02ee6b4322d7570ff915b07f2cb9c60a3b39cd3b93d33e3e05f149db531e7da3325e7bbc1384880b0aae07a0d00123c89a8dee209bd57008f71bd1a6a5778e3dc257782b1f4eb8695e6c34c7d409d48f8dd796db2afc7267b6c14299be5aa8fc680abb4d14671db1342e867fff13ead25dfd0ec4deae57cb9c3dd91d62eb03725d734f841d9749ba103d39a29deea0e29fae6d44193eb8daeb4b06ceb487292619b51b15221ac506544d7bbbb235a8b1e025e6f95a55d4a9da6e2269cd0fb34f9990ebdb13cb608f09dfd348a611efeb3a20ba7d4911414ef238b948281e71b4aee677131b1bd90b800ded9e14d190e183fc69564ae4f8e218035a2ae98adc09e2dd8911283d549ab1fd630223ac9b69f13ebd7edc52739fa0d86ae7bc7edfa3923fb49f01b6905210ff375d48be2446ec8ad19fd201030784ae30ecda07d819104ee91e060649b3d0c9e9e2b984ff05a62d46c6e9bbdff96c343c82a6512f86de130e771a1a878e6a41a6ac0fc0788e6b068a9acdf76a9e550c760f1a7d2054f006a5c71ac65c82a640ecfdbd3853275aa0ad3206b715cc3ba60919d7a2d307a318d84729e3e17fc47339081b3733d471aa0c4a156a7b54b1b9285d483229a32bc6340e223d87b4069b04d0fbbc22d2a54ac37af4289e9138d2648099c28729bf009c2d28faf64c8a8042fffd8bb899554655cd463010c1dabe9bd2d7310594d704f1e10ece778e01fa0d14bc72a9095f381f288abef48d73e1c8f70323019bd3790cf90609f16cf84220713056f45f8783d40e5baad22fef47a7e37b46ff86b16a7050120dd8a0182fefb468bc5f043da2c84b3c3c1233743dc0d3f812011ae063c60c20907d674016e758411738d08cb7b38ec5cf2675460d6e4979a92f1a6b69a6d80f09ae9f8647a6057406542e4b5cad4d751ce4851fe2043791ccf35977c9694b27ad7a862ed2c107a8ccf062000dc496547dc6b4d6f3b0ed91a689dad868bb70009cf51ecd1b12f4f015bf9b58c6a3473e82736e632d1274d46e8fb9aadc92ab01e0c7c4c9d3ffe24d2a3ea98e88d74bca4b8fc56d7d94fab738c555f2cb4ab724de351101cb87df73b68d48f182811d7bd724087eb2d3bf773a92ae7fb3023d05f7d92e780bc1b98e1bcfb57bbed3078e50104684c04a0297a1f054585de92e285d2c460dd30427ebc79eb4e26c0479727e1884df19ef51e10dc42db993de31190d3d6c988c1c3dfa4e0105fddb7ac35563ecc72a4a196e035f91148ec48a4b119a13ca4a98e0f7a165f6547ee9750bef23cebfb0e79c139d02c6565e92464618471f2483429f5093edaca8b65ec2d966a66317e4fdfa8efb3df367f2511fd514737a1a937a481e7d8cc9a03c3a60841a4bf7f9754bf2fbbe5cb6164ab948c00b2e306a251f23b43d7d25e038afd9bb94e90efa334bea6c0c33b9e527b154f0271d9823269f3414e5b7274cc402fcf960867cc389df326a885484a21a1730d30e0d40999fc462c52b6a00344eb43a6e589008ec5dabc7d3b7eadc04cef996180edb9f5dd33c7c3ec5e30aa494b252658237e1f49445b383aa5221481bf279c824a408a0cba2b07ae7260ac3a8b16e1d481d8bf795611beb58cf4994317e4a8a1f43bc309f0b9a6938bec0f485cd9f959630aa5929c9a94e40f0fa18f3ef52d225323ffaecbab738f0a11859f83e7823fab2368e875eb74f7efdccd9d03906d70bc078f6741689487c98d8823c61dfe17c86e49cff25367cce5f92cbc602a350181120e505a5904a146484af259d3cc7407766ef0f9d0ed2e8c8eefb1455df430b15d7a20b2b8ce47711235c340fbc0f7cd120ab132ce965274b695e8384b0af2f74f1a79885f6871a7fa28a0bc7c26363be0e27b50ec7c8fb14c67e80e2b47118205e0e8472e0dbd61b66277d3439fac17951af5ca2d6b5af0d524ccba21b6b2a6051dd94a1b8d7e7704680ddef09a1b1c4419f2a9ec9820da589e9b20a70ab24d89962987ddadaf53f6605cd3710fa08fd60f3daab58c4ebee1ff8f0c7b88616302942ef09f82722e003f1421f3722d0df287cad3f920171162ba91a98d6032d74219ce8c4fe3c7e33b0ffa14c83434d58870d116e6c36559a0c5276bd3ede2f133f4b9b09ef25e76cc4ec02d3a62df652cd9034f372c30b66891e912e1bef1e17181b25d1ba2eacf2827897b7b2d0c5995ca072785082d059c8644febf9771752e9b58e4c98cfc60c257c9111c8b2bf6734c7ac89d2bf8276d6eb14a2be82084e6fdf8ee543c1a3922df2d173bb2d7a7124e55a2d39ea70742821f08726c31b6c80e32786142546b5c35a2a9a2441745ce704f0e55134024b64036bd28f8d2b8119e8dd0e5cb9245d8c9058a66731ae81cdac1c54debe97ba687b26ff00671d6b69bb7f1dd005c20971d3f86f8949ae90483fc8972830abc6481f17f90547263749df4c5def86d1923157f67fa1738bef66ca4fa004e6fc5b4af721837799245cf824a7f53cd08d243f550311fd4a3d959daac4cfc85f32604bb35af71ca004ed6051ffde6dc1b4fe2eba6d82661319e9cd3b855ae418d73cbb37864fe3c10c42f2fc3567df4971fe7a1774e33b8a72c9ff4a7c9c666df10ab3fc86bdd66d2337af6fe5478206b02c5f1709d87b9df0b8fae401bfcd98b33c30e01e93675f1f355765c7361b84de13e9aef9e4fe7aad73a2117c05f9714a0d361e693470c80506dc72a579afc28392a084af4bb406e51d53782e6ca9ced5f2733ad62194041187cf6819f495e3f36941d42ff64e68b479b4c98047b50d14e9d906b8970b9a1a85df2ebcd9f91bd9f9e23d6a103a4398801cf9fd35ffe19b1d22551a09c77e050ac86b551234e153b9b1f200e5e4d128ada63380f68aaa80df274d0bd10de6129ec811001ddfa3cda1b108abf1a10645def9a8f6089074ff283c624782d8e507e2120f8237004abe881653eb8da68e34bd3aeb10e4a19a8fe7684dcd8fb2160e98913519c62998314bbad28005c4a83290a62f9334bd58031fd66bb0db262019b4cd0c0423184d42dd0524ddca8871512144dcffcd066ff6ebf9298ea84e812ae69c3c6009d6328449e1f9eeea8fecb6b9e5c96a196891777b729dbcd009b11dd6c86933cad747984c5842202dacdb14319ca09f16950b4ffd8e8380fcfa9223d511d82ba615fd3506e86326f1cda9dcc1cfd9e6d5f1ecefe79eec809734300c4b915bd8b2f50d9ed1228836ea07a31376c0e1f4bfd053de47bc04acebc1fe0930c6a3476edb691858be52b6de2b01d9e1e4abfbf3d3c5d2684b4bfb7c657919035941a2aae3ad42a9e63465e499c16d2dfab35f248622e7e58e84bb84b71d01e032044b717cab2d569ebdfe7d5097752cba06245ffc7cad1b18d79eb62ba3118c1524d59d9cefeeac71e447831f83c6f290ca10481e6916ae350b88d60f3e2f0058bdb51489572e95e31fd84ca7260abc39f36938b4f87e6d4835f1ad5fb221a652e8262f018bfa3856a8cbd34144e6976d45a453f3ec06fd6e376dc4cee60c6500c3280e6ab4927048494018c8afd9bc6fbdcecff3018ccf7d03b51a6eae14b7f8520c39787f70776235f01793d7e7f745848413062433200ef7f8cefee602784ed98b2c9d273cdecb02ddfa18a8a661d741f3bf87647e3b8d25eba2360217f3b3108225afa2797868ceaaa866d663881a0008e416c5f2f80af7149f93050203465a7c2fbfb1ae9517fbaca023c9862be40b2c84f30b81d237bd7c3798c30891c8ac7a91dc7b0b69ed9e0982acb177108b867adebdf348d894dd510a0b7e1cd010d9147a550c8f12f60691d111628d9182c83ce9536af7ead503f2d86b1b07c40fabfd7c29d47e4f8720b7806cee007281fecdf927c5a8090fe200db873a0142f5b631901ff537e84ad96b1796bb469b1b11cbe42c2610dd49aa74187a4129a1854db8be04d0079d6f88c31d140eed4d5a1139b6cf42a9b792ae577cfc7a2879bf32ae3070900028e0e30c27d2c5d1e44d731bd3d2e6d6135dfcfb18572d107551dbd61f608dff663d88629c18be0406c8ba65f8ce3422d544efd0e1e9000dcdc683eb0eece6d0ba89d46022e636bc1ca13b2918d04900ec63e29f630e7b09d795652cbd6a6479cde8cdeedcac973f5d240002f8f6df8a75ecb9e1c6d2b609938753bf2c7da02deb6f5f3bccce5e9ca2afebf91feaf1265aabdbe2ad99212954377b6f55c3faa8c03088b93f943eb08faff93d5c958f119889f11fd09ff304933fda02023e503321f3311c3248fc12cfcd7e748e21b1002a39c02c01d09209a0ce90d8026f074000e455d119e776d349ceb3da94cf523de5dbcff0f48b0c1a8048441e7c85fcfbc208ede9faedcd17cc3feecdee4c70aa042c6e441b059a14cf0077b5c8565e3c03b57181839f9f7ec98fb603c272189a6ff3a1d3a4ab621ee17eecc490d3d3fe3b69830871d0f9879d3049ba97804e641d42ee31522ecf1859fd0e2feeff6c4515dec6601e327c6ffebc6958cdf901c0ca743f82214679087d9626e792e9ee6cd489e79bb805d2da252d55a99150fe19bfb245a1fe42170dbbb9e93f584301289b415aa57fa49a31d5a2373d55a75df54190b1e216324d0c11ef5e89f61d21a42d90763ef5a89092a10e1acfb7e523d7f3fe9f8efbeee02c371b165637262eed95245171b22f53990e63e5d7277c2d73a4c391af7f2e4e1c18101c45f8cae2939e17c2a4999e38be4e8683139cdd427060e6f476809b670f35b2c56491d7f825eba12d6626da300fd3c80da328f0ea49b767a41a88ab8321c15d42c0af8fadf6438d42bf60c3a2b3adc5871de99e21556ddba86feeeb79168a27ba4c7f46b716afd29c915ece35e192e47cdff65cea5c35dd963a7b9ba5232bfcd3e8240bf1278b36d6aa6dcf916c22e853761e388d3f1a40a433aa34b506bff60e623daf6dee09ccd69d2781bc4d993565b6370e7684d7aaeeb2b1fca601357cfc35f67331a5714552e9eb3dd6fbf2119bbbca64ea76c836020d19ec9a1f48e6e38d20777c1c4cb8531ba222faec847efc90b465e9c34a7001ae1aae1a1b5e613f47a7d2a35f2fcaeb1539fa3306807755ed92968758d518fb4475f80a0a3ca9d6a6143384cc6083082d311bc387ed1b500266acb41b8126dfd9c93e1b1fbc2e1f174be1d7761604d9964bf196b9ee0a8706f863e1822950769d6662051d0bfd2686444c417b5ceea329e2584442c5bb2f75f8e7c180fedc7a3a6dc21014bdfe5ba28573f6415f77fa9325bba1727fa321aef3c424a762f29b3bf455f51babf7c357a4e5ed8cff49b4eafd2746f73fa06b1d5ed4bd15999b64d6f3a7121d69a9229292044de7007ec9f717fdf09dbf3b367ef4a7a1baa46b10b4e16ea903e4edaa9011039efcee40df9f889a16f1d4f4a9a29abd4c5d587197dc1da1d8130ef6d7f55840a3d60e13734ce26b321d00aaab7088ae1779d826e99d92f54b0b80606aa57ab42c90e751dc5b716baff6a81bf135f4250f00aaa0df2c833761247a34288a2ea47bb0bc836a6fef419c37495bec860fb6529465724011b4e58017dd1415346d52b19101d5eab12b19a0e441575d47307cd7dece7b39f36fa26a012112fcc778b55fbd14f16cdbd3acf9a9169d544f15345cb6173467874f657f11a12cb8d9cd9c39420f84a35791fac6511b78d593d42fc2b8f5d872900954a406331151227f3b4ab61468947e78586055c0c09c0b98362664e5e1c8975eeaf02cbe3fa2404ac419609ca705c7393296997f81a9c8423adfd4de864c57a97922159f4fd88748365f7c0d07563e4d453417656c8833e29d6390b86fe4b794250a151fa247a5e1b9c58149170293ce42a65b9cdd8b38d9ce0ca032a2513a10b9aa13bd582849621d7b26e71960d6ab34544826f40f4772edbf65887cf9c90675a02a24cd768068be5feb2b8020cab1f939df742e78b85890a0ed8735180b8dac5a2cb32325a25e5a55c3dccdd36db1e560cf06d8edaff94c8f8793df454115ab6907e1433a2fb8a9710e410cb4ae29b749c5a56812e5d7f5071e3f281e22439f66040be430da6e3d00d79a926e6d938d9e102c8de762f46132cb877c9cd0719ef3124a78afd322abf925c981c80564d0990d6a8ce664e2e17c87b4a0f4d853162214634684c7c01135a65a96a2dd46dce177320faba9c4559efd833f3dd5086ba8112b30bbf4ac3c13f437f5c875730809567be74cf8a9c816f4fd6716a9b82a1c0305ed2a51e4878eac2537a240468d0bca71bb3db3dc44587370c898536d53d80368b46b639edce91842b66e208b95b7592b85d9d72657432787fe6037eb85211c1c8adab3ff2f751ea8fbe3a00085f306569ec17b74af594427ec4560689fb70b4e6ed89f6eb53a9e4512918249b9551e0ae6c9f36ea559e9e512e2689d090a17415450b584e5c7cca50b33fac3b1787034d0208acdad636fc3d616d98f1dda10eb9991d957f037ea435e3319c366ef658c47fba775755c948610e7a384fdb026d34b79b7c65045b283b693ec39a3a461580d5e888e2bac27ea2c619e06650b23ef7817b83eebcdf4c1046def9755d8aae19209f9ab2556c7c1836228399dbd063a417e004937c4e8f1238d59628623dfef098ace7e0e94d254f75cf60370991373e1aaacd754e553d42045943f1356cd63e1f3db516c660ea72208a93925c913478d2a2d2d9e8f1fadaae136ac42187cbeaf41a1fecca67b1d9f8e45b8a21509b73b3cda6895c83a1346812b5ffe2c1a73db6cbccc95409b09f062caa7414f2a7b9182faddea8857099a424d6bff704d75eeb4793e53fd6c6b392efd365d02217bb0a66eb65c8ea113ee6800c30e14140d1db32a753de462a44320d257b6c021f6b2dd25f7507d6320a391d0b0de1d495960f32f421d11d91c7ea58f1838f225e75d81035ec78aae5007a650551a2130d8380a88a42cc5f00243adb65118f62bae9123494c72cc94cd04a9a48393508a4042ff5d4bc0de75cf5827c32aece92426e6a4df489f63ffd696a5e09c4569596d59d11853d305eb433044f7c58f0208708aff7ec7dfba646904fab95e07c593ad93e76728526f8818fd7aa58402a80feee7eb15a2f0b3c4cdb007544c53de0e1f82c11bd9d37ec0647180f05a657c2933fc48c254c582ab7479a9c83bd7c4f8eb0e29efa3ed8c4095fe08a1b447db0a0b2c4929f11cc7d7829662940098723811cecc8af257c9ca591eff5e55f15c1ea2954f52b5693fe6643d48e9f2f23f2143777b0cd7c33e824b1df67327692829046a46469f24a35f7a4a268c8071d3b08d4de93efe35e71b2ae80a054ae6cd0345a6af2d87b666f3f5babd0cd2158f9f1d0454c258d701393f9c43f96de381042f38b49a73be70882662b7070df771bc438452d607e3b501f82092cacd524912d368f485ca72dcc9607f4b1db83a3bd6b6e02d235791457fb5526e68a78d321645077c96714c920ce0f10bfbe8a0fd9da0b9366ee0db2b686811ff10cb381d13e0536e73e9b49c2341023a2ceb8651403207aba6394c9fe86be75b1f3c92342221fafa5b188657ec49279ea611926609c5a0a8b137d58691968eec74595db30a5eab47f49335e4f7b0e1c82e6cff21317280e2cdc9c35446b64b3c2295b7ec14cda916f25e16626a75feeb120e95eebd9754a395186204d03d9241a401df77194d9938769c163b7eda901948cbeecdf3e841abf27b3b8c92903ee36dcc5d060953aff4f2442313a8191adb4c9b374dd9cc5f08e8ba058b5c03dd111f489e461c1723525286162fc0c4846dbc36eac9cb8d32c1a121ebf3d81ccb322277755a2e55761686f53936d703806a52065735bcf568ac9d9adf605be45a56b980d198260445b04842fa9fd7ff6d367f50ed8553de4d1743d992577279a8d76586f479110cf8e5875e0c4682626f6a1e55d9116fcc4bebe725bf5ff24704153d8d7b94", - "public_inputs_hex": "0x2138b0022ab9af3c96b082bbf307bc9e79f8f1401462e3ac1cb3a9913a5b856c03d33039d45432d4999b9964018d8d6552808849c83503f50a70d594c01b441900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000c6895e67e144556602cbe13943c8169600000000000000000000000000000000808b3aef60f3e74a629e9331d68a14b202c2cf87674c88d6103108c767ab2ac48e35bee25bf5e92c02761b47af09b71a2c17de150116bdca2a3edbbac4f77678c67c35f056f9e969387b99b5c26da55509a23e762ede2ab19d289955f6fc34a289c4196b6f4fed818bca760158098e851aefe0609e27b1f5e4ba46cd640bb7bbcf5d11024b93b2b80830d9827e59538f1b1e385ae72fb3add3fe838e63d0e080c2409bd2fe5f57f926a01a4e31278a1e0fd8fef8ee3dacae5dd4bd8666f29088e7e2c1680f50451cf263d3e53ba2b8b4135a40b6144087f868125f387412d514b5747bfc6d2fe2bf59b31a94cba4d7b722725d5e5594a87fd3ee32e41daddbf89c75efb45a474670af2162a31702ad09" - }, - "decryption_aggregator": { - "proof_hex": "0x00000000000000000000000000000000000000000000000a6a7b38193b9791f900000000000000000000000000000000000000000000000938adfed18caae40000000000000000000000000000000000000000000000000e21f5e071314e88420000000000000000000000000000000000000000000000000001dcc3d8161f47000000000000000000000000000000000000000000000002e46c7ed7ae9e45950000000000000000000000000000000000000000000000006b452c19c9c3a95200000000000000000000000000000000000000000000000f937207f5e9d7f27200000000000000000000000000000000000000000000000000011234ce13989700000000000000000000000000000000000000000000000bc917c80a1df8a9de000000000000000000000000000000000000000000000004158d1dc6c5fe0793000000000000000000000000000000000000000000000004df57309713331b9200000000000000000000000000000000000000000000000000007698a06035d700000000000000000000000000000000000000000000000b5363c615bf3049790000000000000000000000000000000000000000000000084836ce0c2626f54700000000000000000000000000000000000000000000000de7f5f0f37ffeb22c0000000000000000000000000000000000000000000000000001bca3c66a8927213f200493e130f2f241df6f50e717977080ee976b404ea52ce9a1739a6538942186c4ce5d408bc4469b54741acb17f81532bb104e167f13788ca258657e19ad18bdeaeabf611459f9516a80aa25dae22a716359feb8721e6f73ce82c65ed90504097a64060c9b98a318d0db5087034f8fb8be44fa54632799b74281b02fa3201b5874dca01aa6c15157bbcebfe698062bc743018cbf4c1838fd88dbc7725f1e2cc9baf93dc954f7630b60d425d36ef81eb1be7d8436127e0444eeea525630a31058031e3a95f311de89e96eed8d8edd125cde39fe180ff58ece8d79e1d4b19f2d6403f1677a3e0f98f7d8669a44ee9d1c5227bc6dc8f7fab18b5ea38a23a8a909d6b647f178c12bf5765e4f3fd9e9353f1578914f6289ab3626968195e2204a0b75d68cafcb752224084dafa2b4ac94248907a3cf380066780a921c968cac8c1745343af4f66eb1673679b9c00300c26624904c97f542932abd632e9d9c20b613f65677439219bc9826056b26cd285c1f6ad8cf48940c417ae82c3b6dda3ef601d957cb411fdb0e5a236ac0758e0f106e5c2aea4d997e4e082051f36f37a07e193e06fcb0040e75764cfe7d7b19379e865f44cde8c4021fe7a2cecf7276e482125b04ce7829f541ae0f786317799e17a5d19b18c35032546d862d824f01aa2b2ec87c35f2af31bba08cf65076c41c5b2a532fce570414bfc6619bde14f1f90519c766248124f4e391908fe40e4f4c2e47d959872db00ccc6c66104be6e3a4a01509488b91bdae4548075814bb3cda9893c4acada580aa2c29959515a57de7a31cc4f2c4335d29fdf50154c3993f6ae9031d06f0541f0e718afaf53d83631efd232f3df1898a0799134d1f263b0bfd6dccf19c72088d8811c5e361ba2efb54be181628501e2f6edc49dd9c2140408a2fa36d107456bc9ca11d66c1e426b5c3300cd87deaf468a61d8cd99c96247bf074714476fdffb493aaaf976d4dd235e99b154e79b2ff5e50ab7f8c6ed0796649601b9c5b5efbb5fc5f5b4f216469ba83161e04612689209e87667d0a819663d69a261da2a789ec0318543355b471178ee51394b1536f2652a7fd5ae364f01c53350a79a0a2c030636f3c2b0b1a4f11f8f70b7dd2a2ab687739334dfa9d83fc290414ae7a1369b7b416834d3971e6e4d10c1e739ee4f5603547ba8ba72746f349ac646d2ab09e4faa5ab7e68fd55609c6fe055052cb8a99d490c94cdd0e20fda8125a7fc867867440b977632d440bc72ddf2a79774bb4346a8defd31709e0d3be983bce16ec2f1b6eb0d064df61d33fe4eb0c0a9a31f221442947a6eb27a710db271537ecb73fcaa4ddc4435b85207362ff13ebd5a7cea692e2c11170b8f0e19c3996c9d4fe03f579bee10705ba2cb6a64120e3ec3fd8a3623c614a7233e19fd586b3dcddb5ed038a7b87085bc0d01f35ac0a910d04789ce430f092f249b8a95e3f3e9e57d464b7e39b11b0b2ce0511a53f06732a3e7d8ef4a98f1c0197fe86514ff68a832af68a50812a33c5b1b3d7357f2f0fcac439af16b2c3c51ccc318db8bfedef50919ca1df0ecef4cc3a1295d63a16e24b4427e5397d2aadf907e4021dc59573232a6851a4772bd0d7a9511e5e940c45c13faf58cea6eeddbb0a5bab2b269c8d205cd66a41192cb1a02c691451c60cd43ed39782c235f5b7222db00e52277c1bde022d68a3dbef6836899945390002967f653a03db955a5c8ce104f9bded599366c20d9e4e10815d1676c7de75591876c3b768ca0c50d93bbf03fbebd73298b550e6731cc9df74ce6b043d391fe501dcac5bfba80aea4039869994a026ae689f9fd7bbc45b9da35927b07a1400b8050faed5f52a92daf28e2f7a1e113694c5751fa2819d425c7038381219f561d31ab37ed6c11585362715d889de16fa9c110bafe87a89fb3437d64c75602257e3111a8aae71085083c00061af68a50a444442c811ca0702b1ba59efa80707a12e0574243f7c35ad11d0499bf94e73ddb1a0551fd5dc7137b31c2cb4ebc6845b5c11c03ef720b358f0b3417c3073e3d486c03aebb7b020db1ea2ebd23e08aa22bd2657df69bdd20d3023feef2bd7b0efde8763523aae1b31d1bebc86a1577122722af7b9eb04d62bb5d2dd340cb78eaedc412be64449d0314cfaf30771d59b4913156f4b94b14bf9ce19924e16e516ff1bc66e6955224645525d4eb36650422744014aeed42b2f48def893f4b59685a7a00fd42ae1856463b2ee65aa8f09c21def2f6d4a920159b6487b8928519e70a5adaf40e615c04e7b549c276109ed3888e808c5f4a847d257ea6478a544aab60e354c2cd9251e4456ba225db340d3c35b841ab4876ba9361592e0e2f351f1cef7a81e5875c24f4deb7bd8720b702b4d02941825cdc9b2fd2f8aa1e13b760f9e5f6b87dc45dd74defd1cb013a8894bfd211818a2926b858bb7f334bded04473e5c398fe186bbfa744b7c667066c72db7d9a32d8649606e140be47dbd386381b1fbb1a6238a8c38d9346a624d27d057ca8ef71e68e91fdcd8345fca7dfa89faeebce29c454669b769baaaba0fc712dc541ef8280fe2e79458e28de1f0312d7a3dde0572fe68bbf86f046faa8c2e07927b080f28ec7285880a3c089913308ed80d9c983352b34317079dc36f024c88cbe698f1199da4d50f7601e1a92ce7e958b907c3d08ec1c966d10f838864b06cb903a26f183dff4905cb4bd6861c48fc2e538b3fa22385197567809a7167ec25251e71811b35520a843903bea42f31b157ee343aa5335adec9bcd3120a6d1e4edb158539292537016521f1e1719774bc3472bf8cea73aec615aac019b47e7d879642f462263b44a7a876820f0117f968f8b0bcd1478699159b190360eb331181a2c04be40bb9562ccf1693476d7beea398beed58780d39123f31c1c401b3e59502899dcb070a2498fdee2da8d6266a91ed4ff61d016eaac361e643de776750e0b5e0675313820988967945cf62b69b46bb5aa6914de5556c053dd102f5065ef07c881fcc2858d7069c1c6f7915d99118c1d498f3232b2fbe53f19ae68faf49837c761efd1110cb2769cf48c492062503b64b03bb339905c4871ba162089ecb07e88f922b23a72ef676abd989368ca5ca6efaca4a3546caffe57f71aa15550539f41efe8523d17d0a9e67ea0a1f0e79adda4f7729011eeba0d13f56e2e03db3aa4ea0f1b62ac55a22371b0798281faa7e0ebffa3f57ef9db292b0a30d64528ff64c693dda2a3524a0f84f2bb33871e969321e34c0af763e3076e7f460e92e6cc346eb967e087fe895a6acbbca4f7dd6b474ce3421a5c24f07129f17b389059945b911b318113acae2204d6152a672ffe6be7699486fb5feb674a9fa1d63454eb801e0b0071570f519abe7972bf439e8cf28cce87ba571e359329415b61dfd9605d2e5ee440603623c89bda7c629b4a2dba72f964bf3fb0a45d364198059f2bd2b10ffa4bb0a422889998c100754be16415e5a16450ec06bad480226610e78379eb5be4c2f04a91545a58c5916584ce39798d9f1dcf7742481e3fc90226b8a508e45a3179b207ca949a9e68369a4e7a0e259d4706e083f51f4172b24d00940a5e40c5041721c4e2ba1ee11f1bcf9c2ba0876dcd5bc3b74e779fe4fb8318c7406d47ba5b7da0d76ef4979ba783d83ebf8c7d834f6b0e244320263afd46395579b9a73d00a400646144e651a725f8d554dd3612862c70c98fac4a6dc4e7648ae1c99498221430bb83c7a9e1667315b09ff19d292693ca49c81463918d0c8f89e56e7f1cb588f12100b03aae55f7fbf686c6d8fcdfd2ec95fbde59c33ef6e9162c39088034e3427bfb892d72474b03a197db7242e68fce96b631564d2f94eed762c1c722e38040e22909f91577a6ec1e2c330e5a47c8bb5e6ef018f1a83388c73eb754ff32cfb0c4d38ba8b27885ddadf3f520c796d6fc499fcbc2a3c5a83b97cb77a5174d60d2c1234826405656d94521ee61b88a233af7754bd82be24ee44bef1648438d4fe075b2767664640965dd21e2f989bbf4f2f69c5b1d0d1ca61c90f1ccf62a2f766251a5ee4b01447113c913372d0d49d6415b7a479dc7ef064c184b9140d8bee6a0c1089dd993d092a9e654da9b9d13748d9ff552c1d284a9543151223275818ac1bd3d204262544f9b536b40ac64089e0ffe99370db2f5a5303b14f7f1b43feb901c4dbe086dbbdb2f83982b5a415dbd75c8eb212760574f15b9065a39654e17829f0ed29bce220f0eb2ba77754697a8babd74c5dc104896f4bef310d99a77532076a118a429672a66d8dd32e72a259623f4a330291c23a0b39b4376abd57c6b92ef5e2faffdcb6fdf0419185e0528d35366a1b865dc91dc4a1e228379b219eb52a47d3160a98e6bef560957039f8687bff28bbd1654b0e1a2290f335c53f0e0016dcb8f0a0c2e0d7bbccd7415da0fd8725055b26393b87f071918eda8414cbfc13d7d1c5beffe174876dd3ddae96fa6cdf87acad3ba1709dea8c80f4c7d2e4bf0e894e78471fa89f727f99c2073b57ad0ab2b23ab429995f9eb947fdb176e28c2ff432eba5830407d95888ac9843beee5f7c224ecc1a40afaf7534b5c3010aa00d026e74c47892b4c803ccba015b1341b380f9b441eb79f26c0b1c8447d23f912dfb9d2fe28a5cefa496ff3dbde6fc9fa6767339c8035ca97086d6aadb88b0dc1321688e887d98b25cd01819655e9b1432200c665a0a21d40e7e0244f1c373a202aecf5ee088442b4fd2c5313001a02f584d75eb7b6e52776bcfe474f016bd692a2062da16361e2626c90db4aee731753bac3d68a2963f02fab8f43d4fbf52461e1737999975f52f29533837f361e89088c3be55ca975278143f7bc986da19f71c483e99e599ac5ec9c532fbd2c9dab0e088b6978ed7e65dc278a736e5d03792040ddeb18cea5bb841cca78a2f449e0b360ab2ce1f1dd4c8cb39ea12679615111308ccef9632654f64e19d97906c95bebb106b2700a865a5165b9b8ff470a3b72fb6a7f3a91f58d47828e155cc94dcdd10ad68ba207859b696ccd40783fd81f814647a611ec4c8370bf8c01b1ecc618a945f5432f2981b1c4b34c75077d83d252d91e6be4bafe7db360df60b17cdc52871f581610fd0a35442b466230b85830d294f38eee8d3f464f1191bf6f3697840817fab5682593db32bd18c3e35c279a623cd32c6a3098f4ebd0c1b8944809175090b273ca8fcfc6b2381835cfef50ad7135204c539b5ef18e1256f2107d81daa0665d4e3bf06f0ecfc0a1cf514d0aab105a9eb9f695af73b3ba0df3cb2d1c46b7c02bf108567e6d01cf49e6d767d078d0f7eb40d460e34d78692e0114c3f260886fcc7e00c8b3c7008ff429d1a53aa9c2e2a41d1cb34e154057c4686b4ad1d704d5fdca331c9f8168d21ee75a74a465224f3327845653d52575e720a797cda03fef68668ce7623ef7cc9034bee94b8b0181f2b11ce4e8710e7497246d272de79509f4e2fe6c8b42422f866c5c69f6fd41d41c9c326912a2fc919382d4e3d414ef9fc9ddf546ab52c8d93afc585b420390737f26228865603a7ae33fc8e19c944994028eb2a20b57bfe1a2f15f0f372fd14ef2c297e78695908b0d6cedf144040f14908d59b7ffa58b1b1930bd65270942bd8043e38037bb5213ccccb00db3df8a661e6fd31d165ae465810350f8182320df72bd876d111321de34fe704b96862982f670d697336dcd782eee7b90ebac50dd31b62a91af03d377532a157b4262a7d1cba57fa045d75bda66dfc194c0b8d09ef91d887469dafcae262b0ce0c2d8876e189885ee793cc622d42f5719247341ca89e1cdd4026584e5087558fa70f750cb3e58f15f4655cb2aa5c2072ab82f11dd0b47a22d769197a373b5a799afb067f275a5477a2592432165fbe5e5fe93416f0816a98599b5cdb93b09175bb78f688bfa15eef313efb9d49047188736c9f096d86d047d951f18de0d5bb2b435d9cfaa88521fa55553ac1171aa3676e41ef1387921e9df4c7c6e996e54033a9115e1159e9cedc6121ec9e81a1f516dcde852f17605c68e6a41ce312832b731dee504377e669986a4438985af9523357a9f41ab6b9d08bd5e05aa971a009802ce32e31c29228a1f314a2da664067dae295662923d7715c95afb00e860d12d7b168ae050cf29e4bf1ca4fd61b9129794383fc25db22ad3229fe1d00f4761e37e897caa298944185e893a6bceeb54e22b467102f2d8e3e1b2aa2658687b4f52d165f059f4053284f6f3797ed016a1cd51d6ccd1920f19badf516351bb00b5ac3bf3f00da9600778734dfe59ff118b80c46662518e010c4e1220cc9a38032e0cfabd5a5a5da75a1a827179c567443a9f95c14710c03c74cfaf3ba71459a2e6c84aaa0c8dee4d69514795029ea15228a4696961201437035923818557408cdb632f2206a5d9b67d82fb00e9c7c62a3a47c330f5f0875884e7471a7c2cf9b2ed4d9573c90e0ddd52b583e9ef1b23884e89a0c0c801599f00ff79b96f561378e455584cde3a3f5a4c84a86cb62c0998f4f6beba9ff1d9cc5d092a623abf9cd026ca12b2c816c0a63ba7666422d2609f8896501f94116a4ffe86b44b683ba8071cdd9b7db1f7aa2a76e30c1607e8a6aa03a5384ed982b6b6e809ead534b62fd2963a7027800b08e53c94f16a1b00b753322db877ab20fd39eb60b9280409a4e963c6e5ef6f66e7f8713a7690762ad71158a9c3698d42fce32038142ee603c46b0d6510f279e56c2b05d7096c2416cc3dfba58fdc0c50a8b5d89048bef8ad00d7b6fc744234baefdbc29faf5e4694f0d0bc87ea2397a0de33752094611077ec049e3deae0062a3d54d9c55d2986f356ee54d7ec2645c18012c3dfccee4fed0bbf219d4cdd93b94c2f1dcdd964a7ccba4954033a07815248455ea2bc5b096f90cb81d4b534a82a8c55f8df025430884c395c2992128871e87c67a24158e7d9f2e700b685d9450e5084256931384cb517ce80ecbd955671b13c2855124079a3f8a423b00e0512ba3ee812ac85cc596ff81ccfa7c31dea015cfeea3704b8289741c066bf18d60a8f6e453921513d10a7494b7a8ed8bf4430e906fe2dca5b1f2daf50b5151e78872f7f971fde706bfc267af4d6c71c43c461b331c16f81c053dfc33bbe0973f91e979d96622bb2805eca8bd1ca1c86a7e4f2222e04ad38f0cee9892e7f9aec41ea9fa52334b246d476203f7c2d5f6575b7d126f845c8396208049ac014e067a49c7da865ae3e17c4b4630e63630abc4958e1924a21d32c26166f01ae2b8da72d7a56e1afa6621287663eb5d2983187964f81753ae5213daad6800140e34f3af2d7e227cd2c5bd9d4758586f6a4d60cd0cc70034d64e1fb4d2ab6ed9be9b2810571f2189149d9dfd08f1f8abe05475d3f445230413f3c2d8d7a32ff4c27a59f3922a9523e81ceb9a2b0a35482808b08de05f2686e7dd5fd0b5cf19516cb0558a76d4d97770e28404a2e78dcb63f3b96eb19f1bbf291e88a6145eb27e6fa5ed3609e829094f9cf937c58dd2bbeac045e27afa19407b425abe489f434d671692197d5cf72c07c8e2ac447b2db81b8e0e248d621f0521aeedf472184eff3527a64c13f0c601b3ec2048af2672255c14010fb1430fdd8b36f426c6469ce3c6b0be2cac2ae4ceea8baadd17bd0900a75114a14a370e499163de5a0e817ec703ec5b636140892fa8203d20c032cbd574fc34d2385320f8ef889048179132035bf18bc196f5b08bc5e4d0ae4bf18768342d5b48f90d27c5eda7c200bb025a2de774ef9a8dfd0d75fd844969950a13f5b4320a250d4a124fd0beae2313ac372d0583b79543c07fe4a31afc144acf99238c31b3e0b9c6241225467d7ef6a633313309fa84669b737cda0632d2dd36ec901e1ae3e4a68210fa0b0fa02588eff6e72f73f015951e42f85868c622a8be41f3247a2140f3fc0a30d31f2379fd387240e5f306a17b035720f57dba876e1cd0d33bc87d966d620e65736370fc817ac4ff15db12147cc85c230ebef736047408e03ca8f0be6a642030b5627458aa1e65dd56737ab810b2a8b492586c42e193ce28d9aae97a13db0cc36d358f6efdfc379ee394140a6700fd99e86b8f7d3a594cceb4bbefff68ce15866cdfc9894097f08e89b66f8c30bffcc001044b0594922e11b8a055c9f6ee026ae31ac020370a1f3e06daa5a772272941a101c11714fe8d8e37d40c3122c61d8f610d194cf82da8419cfa1680eb14ee96b6686e9f209a00df36e96a9d6f842571b23c753c5577e9ed466bb585e8910722050a93a8463bb655ccac5d9900a31a460738ff88a624304a1e5b37fb9ffb23887000c006db10e2b4b8985770d88102ff55d36e7513f37acb4c5920fbd220fc20c8b9b1a83128b0c64bcf26f761bc01407ff23a9b11942b6034278ae1b4817169180989eef86eba3f781c6ed7c82b279089823170533c0791d57ca17f1beb9bd6fda0242993bf5be154fa2377340d0c0c8fcd0da22a25000793deaaf634421431ac4d940c6ccbe9265f52eafaa6660cffe9ce6f0ae13c38cb7ce5304e697ff3814a992c030ff909d9b33615c8f9be2f199990be4b96c115324f1f53c609d9c70c9a3d643973be4f407aa54cfcb7741124c48570a6a3906b2eaa017d1c4e98b1336932976e7ac4b2cc3ff548a3d5272ca9b66092c0be62c903cc5f6022fe892c37fbaaa5bba75f41e40b410b223b052ed39b580fcc936b9582cf7c479ce148f56a374df66ddb07dd6547ed67da09e72e7820676bd33cc3dcc778b5e5929677908c6f43d3f2e793b768cb2bb6c11cac258438c7630aa10ec88ac11e66c0855e0be63beebbc4a846a4210d3b16a1a45b07144aa8b8587d6d981683640bcdb7390599cc6b806869d01e425cc59f78d26e009412daa789b0872610de5d576f928321c80f83d64dd5cac4562cfbd72b56bd17165c7c60feb78c973289e4afbb58225262f916b2e189f9195aaaaef30f037d1a0b47a5e1ad425f16c581f4317b4a1cce0458eb64e01a2ce88067b6365f20570e7a6ef374c26e7df9d9b86f1a2ed3f3a6f151d108f24245346f7fbacc41e39d1b89bbc83ce93442bd733e4fb70c090135e71518d07f6f7cb5484256d973b5e107cadc46b3caecb4a0c85930d59631ae69c164b9b51d4af12b414da442ca6e2e2e905b3d35c848bc74803d93cdd1a52642f101ecb76adfbb324aab602cda06f4142f88ea187aa2d9bc2770fb55738bf1c22a0172dd3aaaf0756da7919ea8fd480bd1852cd97487ce18b5406f1e208103de94a56189a902b0e677d3ebb09b9b4403e78dbd0aa42f5e177f3c0e44bff9304af9cfc15d61d2b7172aaff7db8e31c401014a1d5637a540050a7c24f8ce92509be63c99f33c3e169be4e48c5c46c0d00536d73fdfaacd543fc05f62e194e64df3916521560c2e7c70651b0c8cd1711e13cf10ed6d7db7642d832dac4b6699b200a8bae01e5c271a7cb1dd55be7593252ec16d138fea76b7ab76eb2597f4847ffa61f1e5560f85d5b1dfb976384bd384137d0d599a996035b696364b2bbd910add9dd520e1d50d4acbaa28865a9eceb70caf6cfd4e46b787fcef171be5316b41061ad0f844d78c571948c0c3b9ca5b581e66da9006818668cb3024873fb6c209e388964e71e4e7481f60e98293614a491c4343db492b43eaf5acc1b24720b645f73a741b8082ec8e7f0940270bd337222e0e5f38ae454a0bbbb97e2684eb4c0f8665e2f5fb567a7fc8f46d42d76a87b9167d5caaa34cac8c6c35e92f339daa280b074923950ca4fbe26d12fc08df611b122b294ee8165d619809c84a8483ac031a91a321ba578cfff08ff1da3638da881a658ee5025ca8cd4c2412bd64fec5acce4a063c903a928a1bbe47a19d6f20ce2a45e48b775e956e7328e2807bdf0699717624dcc4bea3f49696076d6bd1f3b32648c84b627afc98ee7a255a9b6a7688bc2cb1d022b456c914d73c31a61cdf1f0990d46e50809e625fee7f66f13f3fd3d711053420474e2137299fb499c55d280fadb264bfa1c01fb103c85e1025144416fb45c410b1de94ce3b6b39e31dbdd40085c18596d5a4f3aa5d72f5d762f32657466c3d6cfa119e4b15d66c166f9235130b6b5db7bdeb688674c2c9ffe5953f913dc8b70c89ee3a3e9d0b900d3eb11b0c998e9028b8af68a3a123f0a5aa56f987cb287bed1b4ec7ea4d5080f7460191140fbbc521c4b4ca284d2f52ba94d12c57cffdf6b3a1823c8bec3f227f0964d0269567969b2a6952d67b2cf3fe4ed64ad32021de8df302d6fa0e5934dcb0fe0207c4eaf81924185e0ae50fa740e900c098f17483a8c8e9acbd142b0d3b8d7ed31222b7d9d9642133a4d710850b29be1b312f2043e0553468a03a468da16119a0147bc6655daaeeaccef77df33300f0304b229d0a67f2e2686ed0faf697a8c0be02a92c5eecec61f86730c46d3e4060cedea01e6ad69edab787224daf217fc00d25bc51eaadc89bea9ed8b8b064d00a603bba923afd50feeaa28480fe0bf5208e1f6c3c1ab06c7581870abe1d4263967bca1c83e6d829d9967b15b03c71662b051fef32423b6f60529ef22b34e79fd39a03188920fb378c832b94ae04ee9c1e611c19e994f3fa9a123454d8453ff1ab96e3dfaf32adcce9ce3a58d3ab46800283017c41df169d9030faa8635070293a6b4f92c2a03a23f322f9219eea5c13a65e16f8cfbb4c12898a9b5666c005ee1bfaa0d64396e1ffb0c89394ac75ce404e341592c70ec8ef696ac200a491dc290b060b0d8ab0b0d73a785117cb992fd5082920edf8a802617e40021efd904982120cb763677cfbf5fb26e040250ff71a9e8f0a74f8c8c0cbb2d83b70592dcad430759e5e3365da322b45198c34067f1ef09108461a7aff586e522eff5dd06ba39f32adbbb2ac11cb5ed218b080ef6b47ab0a21d7658d2c57a0b782547f8c5acce7c340cbc4e32291a4f4d261d51eb5d19fc313f13da04d155cee22bdda2a05328dfad96d058d2752e41372178a8ac3069d27277f5ad615312c8a0da2d6f5967a6191fdfa66a465ba370e3d8a8b27f31b75cc1d1dfc9e914df09e8044c0d753950f5a662bdec0dc6b50c3fac197df947b2fe927b02824b638eba85cc6b3a3a4633ea595e9e7c01764122a2a188c7f05b86a0901781fe9cf000e194128b474d8334de7204e7cf9ba4c45a82851cc873cb2d851257d3c067a363b22d3ffc4592989e1cdd50333e7d20858eaded8fa02b85209c329cb4ba3f99922719ac16e761fee300db4c4022070de18149af7d30df3be006208f5703c677000acfdbdab00aa099e0c515cdd6c36e4c2fcb14d4a169ac5226206d780418161648be96d949099a7cd18b491d72cb00baf6a36552c49578cb858004493fa5ffabec5316a34f8af4e3e329c28ace755c8329add179dd15a716fc30cae70fd816fb9ae67f0e595a39585efe683dac6569cecd5b4612600ca7e58142774ac04ad50ebf3fd3ffbe32cfdacc60c4942daa5b1dbd52cb4570ce3acffe92365dd10cb6526daa7ba1a0b8635167f7220c97ce29b11fff0e2780c3d43d82700b6511664384bafbc8ace53cb17529a7cbe4fa1e5b8242a149af5120092d5f50af044e091387602eb00690a21ed41b2b6cd2ea58ffd23c273f07932cea2d0e81664d0b1770c1a8726cbf09e109bb62cf0bbd05bd068eeb95e2f120470b4082e0f037bed194d5aaedd71fdb36b71ebabfc29ba3fc10086cf780c1cdc74ebe0250fa517cbde50830063cefcc39e7848ae2f4ca899903296fefa908e8c18e1bb8a1437ac612ce96cf6c0617a6cd6c6e8a631315a1d3e29d803b558c3a4274960d005b212c9c31e65649812c0dc066ae224f5001a4893fdad31cf49271b8df0353c2feb0c6796198d5ddff04951416833ce4200813f0f39d2ce75da2985d4329c1f2b2023d34a62804670f522d449b1edbf12c255673077c821683b1d8d7e5ddf800a4b7b539cba5dcaf1fdb336daec57ba5cc8e484c04b5e70f74ee3a0a2e954e2175117e97ac2c5bdc2dd375946a0355561c2cb8edb457d5185a93189e13a4aea066c51edf64ec0704d127db99b2ce23ca840435bc4ce9d8b533e23bd09c80f5004b23d8666c77a078368ad040c4e1ce3d4fddf9ed1b1863c9ed1d2eea60ed85f24edbcea0b513edb75f6321e428db3b3082154a7923b2776b96f9276f251b155188c9415d7e4f09e37f89fbaddef8410979efa36c6a1efe5565349a96498aea518ac498adad8a301e7d171c35883c89798ca890032253d77b00393525dfc1c992b73dcd9fdf3f304f8b5c1f7a71f4036d4095ffca43ba1c2ed25761063f0ee3925fcb36659ca28e692b6f5e89599405f990c57ec7237311d663bdafde7d2f81d0dcc1c522e2497eb105f9d9bb4f969cb1c89c2c4010dead0a19023f4bf15879c2f13afbd1caf80f6e3b5628c1e36f57189ec2f5a61d03eaa58e379df3027da6f24403ef8d186c62c5176573cdb2e799c65bb6c0da4fcaba21d4b8c02afeb6b8717fe4b74f45e45025aaacd2ee55901d81ab63d04853f222695e0969e3a9f89b9297aa44364a7a2bcd0be5759f3a27bc00d7a99f32b69cce48cbba3cc858a9fc708deb0b9515755e48edb793a598de521bfecb827ca3fe1e58b9875426b76a268137ba4e5fe24a5d7f977fe9d1b50ce573fe98be883ce057ff046e26d999403f52ff08e8a7dfb7f993a389212ea2ed1bf7725f4a265bdbfc208fcda3df33465c90928f1e1bb77db1955ef73583031893947c902eecff3fe24903319d5c2433e0b0546305540bd96a71fda765fcad36af678a4f07cc95fcd02e81ac2760931d40c132c998a8c0b120abd2d3e666518d1ef5ffa130cca13b78e57cad7a151bb594a1e394e73d71aea3c2d6e5cbbff872c98714fb5fb571e1e3743eea704b295666d21ce4e84ca11a1d673a27b169c5f83088e0ed344fd75dd4b741b05226ab93513305f4a7f83ded532c62d697e04ba2a963e30c321f916c0080e9fbc5ab619aa8c220f38de69ea6d5a49d99f904ace4f9c6132a8708e225fa2ab197c4508ff25c42a92d2a7cc3855cd59f6c96407266922cfb6f523d46e47e29d0447f32582e1951a6b0361e26226f8379a50f2d5e3204c6828da40b8e7cdc816f6b166ef4aa723077f7be16b732f1edab20a5668e50844b717dacc74dd94451cb9460cca88ad8a22ff47083c488ffc04e3b9c39ec7b25f41ee2a2a6cae755bc5d1fb9e1633549013968d569bb6c6f0d95547d93eba03a1da40766f3ab3b18f19b30964af1d69db15b13c2024eb855dd70af579f46fad36a77a77c2cf65812e92125f2f9e4011eb2ccf4716ddca655668da9838e29677662101824afbe875bd3490fa1a7a286ae31704b40587eec531af8bf89a26692686387927daec1d6e004fe9105160219a7d23035a362fa532f57b6269292058de35d8cd36c4c6b1143821adbe16379d11e1232646f4d497651f0954ea9a1df894dfc491003980f60b52cc0a1ab26756077227ee3102ea57dce3271965fbc8bd6e66a68a2b9543b577278024cd4536b2741226c3b1d409828f4e0d9874ecd7069da3c9c77f290915adcdf6b456983796b3fc28042c760483b93e07a9ac85a3991713d1c2f85b94556c6d1a273da1ee90265d01a8981245c7f7f8d10b2915126d9f9ac61a2d6a8c055ea87be9bafcb5643c9b119120d465b5ddb005f7ccba998fd30058ffa33d82c9d8e4e301e780bd7f93832604cfea9de23f1d6b2a50f65047ac9f879eff0451f311164941d680b76395aa208016ec3c5dfd1e4e2451ec13fb58f2242b1c26e54bbd88b44e163e4e7c7aad0b3d5897b5f0d8d49522bd7b5c1aeabc1faa5f92051b7c9609bf3dabb085a533130bb3f740556f8e71453758b79613a124d615ab01b2e1de8a4e519947fcd62b059aca90452fd3b086e6f37ec6b9c8c565885d7bc2125f2a6edc128992c986ed1e16fd93e88a03407f497ac742f49836ac0886ff6354b8a0d7096dd464cbbd9e1182fbc13662c46028cf859e93de493b32a8060828596b2fc4245655a4f9589c0c3e6a3130d7703084bca793e15a9e9d6366f1898695e5d47b7da2fe660461450c47a7186e240f9f600739c2fa2038f28aa34075563b42e39189fff917f77b1d169abf6085508100e18e9651f68113f0371c993ba004d5ac582763655c4df79c28668406aa60c8966a70355446b5ef97eca8f9c21cd311efbd65d6701932662d214ba804cb02a5d0c4e936c50435a6d8a2678558c26aedd38694ee726b9fd89a039a0378b17166714bb1379bb173d2e916411278d8285e9e6dc901a616904b1927280ff562b631da5d3cc81ff70e3269a358e8c4dca3696ccdb546ae1147014621b472511388d61cb1e60590ad87f05617f122417a4282d94bbc643f0547a6682008695507d53505be0bd9b78ed3c7adb01360df7cc3b4e8ac5357485facb49c2e0600e9a923c71d12fcaffcddc8de640403018a9a2ff1c2ebcdfd6700facbbb2dbc42db37fa4e0b64fa45559ed421cf9e91bbb8533983393113a75023ebc8090bb50f8d0b75903c3c8e4b51137f3ccf2b5ee42e549fa6c2c57a336718e1867420e656c75e985702a0b1d78e451a4d0e7abfe681ecfd92e1fe5d00c00a22acdd0ff415858ee7fa9d195fbd1071d672106427bcd2c8f5114e6b4e3b8f6fba28c62b38318cbd8088a2b956ddcdebbcfe0e6670d37b63276fa30a16791a3fee1b9d", - "public_inputs_hex": "0x1a207628cc6936816ccb62a7b56fdbbf8e975293b677c988644e018fc402e4411dfdc7cb6265f100524012f038ee1f205bf8789b70b46c57463dedb4998f7ac800000000000000000000000000000000c6895e67e144556602cbe13943c8169600000000000000000000000000000000808b3aef60f3e74a629e9331d68a14b21806572c19ee2f3532e970d617919b3aa8cdc582782dfad0699badc631f75128000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000022c17de150116bdca2a3edbbac4f77678c67c35f056f9e969387b99b5c26da55509a23e762ede2ab19d289955f6fc34a289c4196b6f4fed818bca760158098e851b1e385ae72fb3add3fe838e63d0e080c2409bd2fe5f57f926a01a4e31278a1e0fd8fef8ee3dacae5dd4bd8666f29088e7e2c1680f50451cf263d3e53ba2b8b4000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - } - } -} diff --git a/circuits/benchmarks/results_insecure_agg/benchmark_run_meta.json b/circuits/benchmarks/results_insecure_agg_micro/benchmark_run_meta.json similarity index 100% rename from circuits/benchmarks/results_insecure_agg/benchmark_run_meta.json rename to circuits/benchmarks/results_insecure_agg_micro/benchmark_run_meta.json diff --git a/circuits/benchmarks/results_insecure_agg_micro/crisp_verify_gas.json b/circuits/benchmarks/results_insecure_agg_micro/crisp_verify_gas.json new file mode 100644 index 0000000000..5b0a531f63 --- /dev/null +++ b/circuits/benchmarks/results_insecure_agg_micro/crisp_verify_gas.json @@ -0,0 +1,107 @@ +{ + "verify_gas": { + "dkg": 3125379, + "user": 2972989, + "dec": 3640997 + }, + "source": "folded_proof_export_plus_crisp_verify_test", + "artifact_sizes_bytes": { + "dkg": { + "proof": 10944, + "public_inputs": 480 + }, + "dec": { + "proof": 10944, + "public_inputs": 3552 + } + }, + "calldata_gas": { + "dkg": { + "proof": 170064, + "public_inputs": 6168, + "total": 176232 + }, + "dec": { + "proof": 169968, + "public_inputs": 17304, + "total": 187272 + } + }, + "integration_summary": { + "integration_test": "test_trbfv_actor", + "benchmark_config": { + "mode": "insecure", + "bfv_preset_subdir": "insecure-512", + "bfv_preset": "InsecureThreshold512", + "lambda": 2, + "proof_aggregation_enabled": true, + "multithread_concurrent_jobs": 13, + "committee_h": 3, + "committee_n": 3, + "committee_t": 1, + "nodes_spawned": 20, + "network_model": "in_process_bus", + "testmode_harness": true + }, + "proof_aggregation_enabled": true, + "dkg_fold_attestation_verifier": "0x7969c5eD335650692Bc04293B07F5BF2e7A673C0", + "multithread": { "rayon_threads": 13, "max_simultaneous_rayon_tasks": 13, "cores_available": 14 }, + "operation_timings": [ + { "name": "CalculateDecryptionKey", "avg_seconds": 0.003899597, "runs": 3, "total_seconds": 0.011698792 }, + { "name": "CalculateDecryptionShare", "avg_seconds": 0.020771278, "runs": 3, "total_seconds": 0.062313835 }, + { "name": "CalculateThresholdDecryption", "avg_seconds": 0.019628875, "runs": 1, "total_seconds": 0.019628875 }, + { "name": "GenEsiSss", "avg_seconds": 0.007804847, "runs": 3, "total_seconds": 0.023414541 }, + { "name": "GenPkShareAndSkSss", "avg_seconds": 0.009254708, "runs": 3, "total_seconds": 0.027764126 }, + { "name": "NodeDkgFold/c2ab_fold", "avg_seconds": 8.419060625, "runs": 3, "total_seconds": 25.257181876 }, + { "name": "NodeDkgFold/c3a_fold", "avg_seconds": 36.69000318, "runs": 3, "total_seconds": 110.070009541 }, + { "name": "NodeDkgFold/c3ab_fold", "avg_seconds": 7.678847138, "runs": 3, "total_seconds": 23.036541416 }, + { "name": "NodeDkgFold/c3b_fold", "avg_seconds": 35.819565458, "runs": 3, "total_seconds": 107.458696375 }, + { "name": "NodeDkgFold/c4ab_fold", "avg_seconds": 8.047481542, "runs": 3, "total_seconds": 24.142444626 }, + { "name": "NodeDkgFold/node_fold", "avg_seconds": 19.279656625, "runs": 3, "total_seconds": 57.838969875 }, + { "name": "ZkDecryptedSharesAggregation", "avg_seconds": 1.60953675, "runs": 1, "total_seconds": 1.60953675 }, + { "name": "ZkDecryptionAggregation", "avg_seconds": 49.763333667, "runs": 1, "total_seconds": 49.763333667 }, + { "name": "ZkDkgAggregation", "avg_seconds": 20.434941375, "runs": 1, "total_seconds": 20.434941375 }, + { "name": "ZkDkgShareDecryption", "avg_seconds": 1.318937159, "runs": 6, "total_seconds": 7.913622958 }, + { "name": "ZkNodeDkgFold", "avg_seconds": 115.937274027, "runs": 3, "total_seconds": 347.811822083 }, + { "name": "ZkPkAggregation", "avg_seconds": 0.863779417, "runs": 1, "total_seconds": 0.863779417 }, + { "name": "ZkPkBfv", "avg_seconds": 0.234095361, "runs": 3, "total_seconds": 0.702286084 }, + { "name": "ZkPkGeneration", "avg_seconds": 2.564455153, "runs": 3, "total_seconds": 7.693365459 }, + { "name": "ZkShareComputation", "avg_seconds": 2.554805451, "runs": 6, "total_seconds": 15.328832709 }, + { "name": "ZkShareEncryption", "avg_seconds": 4.018045519, "runs": 24, "total_seconds": 96.433092457 }, + { "name": "ZkThresholdShareDecryption", "avg_seconds": 3.493319013, "runs": 3, "total_seconds": 10.479957041 }, + { "name": "ZkVerifyShareDecryptionProofs", "avg_seconds": 0.103515208, "runs": 3, "total_seconds": 0.310545626 }, + { "name": "ZkVerifyShareProofs", "avg_seconds": 0.269947275, "runs": 5, "total_seconds": 1.349736376 } + ], + "operation_timings_total_seconds": 908.64351588, + "operation_timings_metric": "tracked_job_wall", + "phase_timings": [ + { "label": "Starting trbfv actor test", "seconds": 0e-9, "metric": "wall_clock" }, + { "label": "Setup completed", "seconds": 2.96616925, "metric": "wall_clock" }, + { "label": "Committee Setup Completed", "seconds": 20.093379417, "metric": "wall_clock" }, + { "label": "Committee Finalization Complete", "seconds": 0.005040209, "metric": "wall_clock" }, + { "label": "Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall)", "seconds": 136.237549, "metric": "wall_clock" }, + { "label": "ThresholdShares -> PublicKeyAggregated", "seconds": 148.9261515, "metric": "wall_clock" }, + { "label": "E3Request -> PublicKeyAggregated", "seconds": 149.434793375, "metric": "wall_clock" }, + { "label": "Application CT Gen", "seconds": 0.009646083, "metric": "wall_clock" }, + { "label": "Running FHE Application", "seconds": 0.000103333, "metric": "wall_clock" }, + { "label": "Aggregator P4: Aggregation pending -> PlaintextAggregated (wall)", "seconds": 51.386342, "metric": "wall_clock" }, + { "label": "Ciphertext published -> PlaintextAggregated", "seconds": 55.335645666, "metric": "wall_clock" }, + { "label": "Entire Test", "seconds": 227.841801083, "metric": "wall_clock" } + ], + "folded_artifacts": { + "dkg_aggregator": { + "proof_hex": "0x000000000000000000000000000000000000000000000001fd49ea2995c1805a000000000000000000000000000000000000000000000009e130f8d07cbd35d1000000000000000000000000000000000000000000000002e5ab83f7a0ec41a9000000000000000000000000000000000000000000000000000180f1d364bc1200000000000000000000000000000000000000000000000b30855f54e294c86600000000000000000000000000000000000000000000000e219fb2ae146a494e000000000000000000000000000000000000000000000004d22012f74a7396a9000000000000000000000000000000000000000000000000000215c2c000275000000000000000000000000000000000000000000000000eac34294d15070d38000000000000000000000000000000000000000000000004e87191632119f7f70000000000000000000000000000000000000000000000015038dbe31f6ab0390000000000000000000000000000000000000000000000000000cf331e3e636f00000000000000000000000000000000000000000000000dd9f98878c5b6f7d6000000000000000000000000000000000000000000000007ee2134f16e8d33160000000000000000000000000000000000000000000000077df2fea764d8310f0000000000000000000000000000000000000000000000000001b58f64c88996077edaeb00d787972da96dd0edbb7c2b101fde53e5028931cdfa8158fa8937632cf53d683e41360f6e529b02d216642bc54fc3b5493f89225f4cdc35ec2dd75e008be81ba59678bc2845a0a790af2b8124f8730d49d964132d0a028970ab563a06cca51c91027c577ff402f93bd200243f9d344e8b2a354f1aaa5da3b43a24e11b6fc61db08de25bc5fd4bb73d7df7383cf857691020be5880f05c25bc8d19710d7eb2427e444196714589588ebf61cc54c552518e950b56b9a6fe08b9bbabd52b0db8963a40cc8dcf97ed101f513d60c9f7ce4bdd3fa84c9c7aa8e5706ef3af1cbdb85e131c9695dde95e1d161deca5430a0adec644f6fdf7c962cc0686cebc0e0f4d1d4c431a4ac5c17aa11206f288f79299605006038c506c284084f626822891b514eac670d39ab672fa43f20c0b65b0e10624a2e638ba001a4291f1740b24777273c445fe315e2193fb45060a7010a34afdaa48d5b4e215b66fbb18d3ba21045761d06795541b65751d20790ac3e1d74cfba39a6027cb9ac310ee2aea83024ab126d473d57e2cdcb9b5af0beb957c65d4308f1a4f7294a1b1ba16e047e50e92d2d26422ae9ca51949ebba20c96db2e5c1b6c8ba2898abf038e018d0e5f90d575b2f9b331683b451b53e7effee6c815296c427b181ae57448fa667f3e8d802eaa8611c3b5b5c25e74c64bc7f45e3112c669ef9f4e0d756670e89c34de6db2cdce2ee36eab74073def9ebb3fde8b4aeb2ee658c9acba864d80fb569c75a77022cb90ab0b77907d8103f901c21ff013851f12f8d4b6d24323694b2cdde560e0ad79dfa9ba2a692ea68660f563b9ca963f67786eacb35794db407e839a365a007463b9e1d2f0df8602e1bdf84d818a0395a5242aebdce60bb8bd4258fb126b52b9bb460323411c99fd5c4b42072c524a975df523f28156065e824e35dcb1d9c1f9a105ad7dc6269609922d8cae5d7c6ad37425e957cb25135476748a8beb332262959fdecd94ecff5648621ae55cb4cfeead8f1042dd04593040a8c76108e9a2c17f170d854dfbb9c9493bd58da3029edad3a4a5c2199ba8948515cb54dd87e14dc69acdfa3e5e67c481bc78cedec6e1af6ae498e8884c5482853dc3161a6dc1e301746d84e8d4f07dbb2de4b7789683203870a9ca01147cebc327a1f2a28e4273678b16eec7b05d7f220111d7b89455daea44633e1d1b73a1a5d698e87248a04a7d9705a4b7af209a598156203cb008220c25975ae7bf3c6e8ba9d3f2c678a09d66e4b7bfca0211c9e3a4a3114eadd1105982c019fa2c8520bff6a6a2fcb9e2cafb862a18a64b540895760e4cb1e8e82771188cb43ab3f0f2a81aa98f416c90a9aac4fba1a822c08cafb8ab98475aaace9e064745616e2eb1471cca54a219b0b6a7e7e884e9e938f7dbef5134e11e9a00492bada044d8eac8e1151a74775310af775f458352ce39e593aadfa030f8343b9c9cdb3c0a51eb8996724a40598f02d3b2758c53427318b585617fc8810f08e1aea10a43ac4d7c25fdbec155e32402d2bdec92c262abc30f56e45f1184e3b5b9190a16efbd59d4aeba4af3a9ec98e0c229a521676816c507fd4f92cb86b6aea59e8dd336b9e7fc1d7c1d38e4349b010332e0457598a26c2c4a3e0d02c20af948d75bbbd56465cc016af714c6ed89205b25caab1ef5e5d4753587b2c423911427ee11eafaa007459e515e54a2b068f128e5f87f9b760a72c83d37430c6ddb70270dcc64319d6416c3b30d37f80f4f209a81ea9f1d236a7b9bd55dc6ced0ec4e526908687831f3d95acd61aff8ff2372b0e2d95a1361900a977f9253a6c9d45f681e2f4011ff13db0c7219085bc33b223460a7bc760f25bdc85f1f16eadf15a59acd2cece7ca3eb789e926f49f7c786161f3e86f116612b5a5a429c31a1fa51e8fd9343031442f5c94fa2987182845a2c1ccb716fd77606020045903b109f92cf24f209754bb0f28a364db55c9b43aa2e51b7498f6e68e2abaf0b76b36d851b29a09217cdaf13c7ee7d0cabea08eccf11fa5693c9691c14321ed941fd08d7204931bc6e514b48ec12e985c8b557ee3708f89ec5b313a1f429eceedc627cbc8ac7b7b50086f6cd9afc75997bb3507c120c8bb726570f72529caf1535ee80af24f911081531cf149a92ed499a134b0eba01b8640b24f5cc592f7e79add4472256c4a49bedc5801a22b7ea65f8361e77ab2156b74036d7c9bdeaa69b37fdc5ec0b8dab05587f48e430f701e3163a917047170bbbccf4b84a16ea42894d2e25d01fbde3702619c8c38d7a06c6846f9ba67215ea2a312148e210efc156d4ebc28d6758efbce0d8d41839febeb131f0945fc01c84af60616bde2a2a4fa6d1715314c1ac81490793c91017a88de75fac5e20d3080548014b07a60120d857b6bf9f57967ba843d74a34204504e29671e4195b3b24281c43c58ee0b93d2af3f13e6314ecc938001ab4d296749dddb73ee17273382e2630ac48d1b66eeb3be980576c76ac6e7add3e4878cbee0724917f0ba962ff243a2e4a055851abd682ecf0908821cf3c1eeb788029b1335670075439c398190673bcc78e40c71398b948d57471fc669d174d2740c405199e6584f871b9e3012a0acab2e96a2afe838043a16becd5c3e687cc6bd2efcae982386f32962b7a88245310639393ccaa5331e97b7db1919bc2d50e86f065cae12b76b07d3348b6180fefa11f9b377c565b5b40383a76bd59af2437e9c72a05e49837b5ba60d7b1712fa7b9e47e883d1d4551c92330f85e8e8a3597879115735095c251d0bd3786bd22ee5a0c362112a3cd554387c3973d608c2aa579b5136e0de6e93d354f4c5a1408a644400d96627bd7b10ef88796326dcbfeeec6916e7462a5e90fd6e417bed428b6e56c827fee917c101bd208fba6a6a96b26c8609660036db1aab7fc68b01a0f050acb41424de2746c4680e9f50d6b1902287390809d57c071bda340980ade048787cf4d2dc03c343eca0db49299fb8b7e69303cbf16384971194fb4c68e3c2eba457fcfbae5f78a3ba7bd14147fc79cf5337190691398b6bd459251c131442a5aa476d922a21867112a84ae48ecd5b6fa90280f477bde61f721c68ee2d2f513ee827cedbf43918a4411f6845084504144059b545de93677a73f32296037de049c8166781f6e1424f72a05999f984b97fadc1ba8d10a7ee32be56c80adbf751ca15b8240f73f458e5b7048fa8db1c7a4abcd252e1f5862aaf75d9dc7ee243a1a0a8fc6f86b636a8616ddc653172189accd3bcdbf647c30f91d364c81c206962ff31db29a42d1aa4e88acc875d3eff57728bb3450ef218f7ce61a98e885b5772c08b80788b8e0221b56ffdb2e044a99df3ce955d77c486dc8ad7b19cc3f20eb2fdf6044932d8a24a9b47713da7d64bafdd7e72db9e8e9d1ce17c51ac428fc991f9b8d2ec0c1e7d1cadc63db8032a4246c2d93b41402b11ef34f0b3052e6b6101b1092f7a6d83b1aae323a8d093b0c50965514a1ccdd249ce909260d2e81ba4921c116c4dd85c556af575139c86bdc4b43305b9290fd471de29fc332e88e094c02253af4b0ddcc70e3c853ff8370f241c6a5af7a9124e46fb711d4710c8e0d860c83253e57c909cef046bded3d5ebaff650057ca72ed08a066a9dd3c5206d7f4293e361d99a9b24098ec04a441e46c7b2b8064dae8c70de8bf385ecca60724131d03a978a8f846bf6ed6b464b43514a9585a961de9dd2df10ef0ead69581821a2426aad64c076e2ef8c465ba244a8f3ab53eb4074c4687c2068724dc4dfb7fb40da880fa666b2ff11fee4198e828d0a81a16b67ab497f5fc6f9763c45cc5a3721d3747876e7d1f7597a136b34a7558eb5a2c775c4ea3a7d587ffeb9e363d52681203eb04847206683a5894d351f7ac067b90c6e2857fdcbbb0de3ae1b88c7e7025bb867319c0650dbb7199954bbb3dde0f1848f61f262b85139607a8194c25820b86479d8130ce090230b101052095e37928cd7b35cec64a52bf2f2d9309fa620a96840836aaa24508174d058c59d3243dfbb8dbfa910180139920b5bba0ba612a3137d9139def0d4c2dc96ead633a57f0deb2f385ef106a6b6e1f8552dcb04a1c7e438c02df964ad4cdf994b96bb5145852e4cff61b67e9d2207bd1f98742861128971620fc09258924db77d5849d4b01c133d5eb0ba35bb715676a8f0760b1209dbdeee1b98148722437e311c449871e52f424bf8af6d022cc9a8bf86c381a0ef751ddb94d31062c176215cc10a722cb13a3edc840154b075046e3d73a49511fa65de3f652272d12117f4922c89ebf154622a90cc22d48d852238d0d8f722a120f665f4406f4560fed8ccf003cc551e15a4619cf80218263ba803fd1f4f751188ce7efb3271294fd4e09cf38d5f5e94bcd90c48b69ba9033a907f50b9058f302d8bd87bf079867a8a7e546035a866bccd46a6b7ae786cf3bcb106b0ca4eea90e7a05252c11dbc7b11bc30a304735bde3abe0bebe3964700f93f6464297b8b708d1241352fe66286724eeaa7fe21b2a1b58fd9f125e39e8e30d6c6281e7177710661aee44cde894457f7694b7e7a097f95bc4b343132fb9bb618a26e7952b6d2db56ffb8b361ffe0789871aac4141603a1877b9da3b9cf0719a17683da02a8717c2b38f5d89e3719efa94ac694f52bc00b4a11822e900f54dfac530acaa4b2c28a91d4295d27ded396d129a08cfd2c717fa74161e1b9f7926288a32abce912e079096a999aad3cd00fa09f8caf340e2e49e665d4d008c12015303de4057f9972dd2677eb529ddbf4a050ab90c6c2c2eeaa88d9b13d277cbc7245c65e2ef0c42230b0a5b03a713209c518fb9ed18faf4b266b4f21c9977677bff73fa324431b70f757eda054f648fdf26a5211123ba1d0ea9dfd5d124e377cd0aa11312ffb0c420c23c32f1c3cdd37dd268e2feb48b54b0e6f19c0ee67a2ae7c01472d2623d1e2fbc69c45daa678a391a5504a0ed5a0a5e4cb250f36501072c265af823abb45b1dc5739f9eb5e10a37d356027db2f6faadfadffdb2ce7ac184bc7f997b53deae162a8ae642df97184ae988c8607ba165006f0dc926cde19a62ba777bfee040ad0da536704fe3046961eea59de7f504851c2b42f0948a576d02146d802592bea5296be00ec01d6bacdae3e08981c5d1e75bc6882c1694ddafe5f01450f0a019131667b2a26bf0f497d5e379f9e70b233d24e3d43d7ffa468c5d04a6ed530c07d20548fae6cd942426fbad40b064d09ba495711ff9ecbb7f8fa128841dadb433d9275b8602a28769edfc46311c99d70a33e6244c69d63d5f1f70312907faabe2b424ff92a16a1011d0b94ab5c70e20e3ddfd84ad4ec7a7cb8c7346a164394319ab2c7c716668fc8d1e4a01cacd713815860faa08a649f03d54cae0a85d453496f807d9c9d01d661377cbf497b95050d15852b24c069aefe635bd35329d9baa8f64108ea7e4af7d45bfd70af8aa9abc564b259e813614a906a560ee7a15f46cd3782c4257ad3ee80e97cb60726b65a4f5a2701c277e8edad07984f7c3753f6139b9276d4512a0541ea808942cf25dbf676e996b9f45c576baf6447a12bd93cffb930a398fc4ca770004b59848f3adedc44b1acbd0248ba516c564d1953f177e73eb288458a12f11a83a53ddd929bcff5c28f195b01cf27c1aafb14b1db691ea07882c25272f45280f7222fe7d7bff564dbbe9c1532e79807ca0d8709f610fdb292606b4d4023d10bcae31fa0f6389085e9e291905031f7c7c07f726cee059974210170ff701c030db637dc65b0c4855a7518fd3f6e08745e376cb32e37b932ae0ad0c5e118818c267aa7c8e9603614da1384b8cdf398b5afc98449b5f454f40b16b02625cbec8c5c8f6e191c0b5fbf55c922fcc68258b33a39ddf72c0beb9ac218911081f65e7af22fc123c58adf831317451c202135ac4d35bd4dac00ddd18f5692e7345c12abdc477eb8b415fda1bd3b6ff88009c5b6b6cf9623d6df79213a82c055506730507438bc795dc759a7c4057b3aafcd52e3d58cc90f9d2709add84cc01b3f56a26ced3f69913748de5d3b4c24b50051ade9e9700dfa8d1d0c5f14d5d1ad7644a107beae994ea0ff4532c54b89514c2d06af3d634ac0a53764eca55210b2f46facc611e557559920cf65593b6616db1eb394d0c20b040ee8a4b48537e1198823ed6cd160de66eb43e9022ffa950caf79c4b4e405d325b8e69bbc9454302ec177251fe8cb4c6c57542b2be93f91666a93ae052a355a731f806b16477b82d44c4d0b255663e6b548a9d8f69d6cd9e2d6a14d12768e38847a5bbafd3b94020502aecccde69569270bf06687f6617cf3eb0903c36f0449823d51a3393f9de19dce60cb1aae13a19b50e34b65ffbc680f412012ae0063d362a77c85be265ef2c7443d2dae210dd161a8c217b18620dcad17590cbae456a61d250fdbba547fd29b3c7854a3a36887dd4ec8c4e93e56907c62a4140aabc9da587617f961fca8d24d85a8c59e11cd64c84fea5e13d586d3e88fa439507f58e26d3c317a8bb7d32177abceee45d0b521eba525527ba8d739426e9c7f3e695a68b59414c0265e9752805ea9635e406b084a400034ba3da86ecc6c4b6217ef5fa2dd4f344913e08fe059c5a303964df6df32cd2788e65facb109fefad82dc156fe1c8b06aa84bf0ee033b4f7d9c3773cf9376080223b5c36409f8e94cf3d3f1d8c62e32276b2112a219cf162993c5c1e2e75c8d2167232efd83178a7570c0bf482866f3c0ab3d16dc2cb07d71751a27546ddf0c335b0f31edab3e88e7796d9347733c18786d5a570414c29fced4459d8dc19627c59aee6008f5e140d510490357cd98931a93de019217ea68fe14ac058df3fa9e9cae7727b03d933a66a23e217e97a5be9d14c762ff034f3d0afadfe715e5da693a3140044e0f392e07659b7fdc04c2fdcbded6fbdf2d4a4ceb366ba2ef2abc371969dfc1735ea35bb48f927360d3059877fd3631fc2604d08c98df80b00821a6a7ae5c5244fbd65539e4af2c0e50d6992fd4fa7184076abfd3c49e37a997c8db51c9e0cc01f39c1afcd92f34131292e2700f8a1957198b7ed6cffb3a7c201fd6ca40409bde83950f8de3f35e81d9fedbc3750eba372baf58a23be51087dea664645af910ca2c8e5044971d829aa0832cb8c72c574521740bc1aa918a1109b5bc99e0e1039c6e585e505a9db5531b76a4bd14a8b1442e37c1c4dfa7150fb43733a9b157c7a601526920599572946feabf80137ba1ad2322871b6aac745a9f874b9bb8ef9ee182a3db6d33de228bca5096f018e3e8a9023650fd0a202af87cfcf8c29efca5d3b980149ea855d69489f595554fb2f23c29a9aff0de611a87627cda3c879b542baaa1677827282a960542661baf13045c14836a3abd071e95bb8e0954b7655fba14a5712b67f5c2a8b44c8b2d9928fc6f0e10a87895332d36c58622031ee8d2d6ccf1973c0c77042c42d618a3dd2c9e512473afbf6d4180bac27744f2881457b5c9fb4b3ab84b4cf8416f1a8570899ff228bf7ad3970337fd65fc3e884d8fff552a7824001e73724072ad01b639d82f630229f0c3b29a4844d16a0e66fd9ab50c1a2a4c4f388c36143449e931aae4bcc22bd450a3e3bfaee4a3102afd669ba6f1b9e9e8f3404f8905bfbd2e49f9ed48db03174c95e1e7078a63f676e989df81004ad1c1d818676bc710aec939c791a2170f20a480ef9719f1f4b7e93c951af6c035835d60e312d54c3199a282f5da2ad40bf4385f43eae8609d03334049837d361c4ab902f4bdc2f8060a51888687db0a1b0af92cb490eefd3f631ad0a9002bcc844b686dfd15ee545a2d408d5b88e9f42171fe53d283a88b7188eb944c0cfb22d8e8f8e667944b5c62a1c7f1adb65e520b864b06dbed7fb1a6c446e24a39a476820bd68ff5b1d23584fe190a99a1e64724b1dac25560fdb393debfb31da4470b28448d42a031efa989617232d2a6ee2b1c258020f28d1b98e3c58a6a66fdc9dceef00668e30a409a699babce4913ebfb0dfaad87dfb55c5852970a9e232469b152967bb67d84b6ea2cccb2393a9ad06f06e79ef7e5f2ee98079b5f97b152dadb8e536ffae0af9209b7e97a18a6eb2a322ef63191d9f65612edbc1c6e9d997ed8415faea2a69318114dc55bb2256f7d522d88aab1575bdebbabb5c233d83e80258dadf60a1cadf436b1ef7536a545a50924af2ebeeddd230c21a822f1f1a1462a7f721f84702e55abecdb1d19adc11cbc1a40d54138980ed32bc41efc10e97fd6f73693807938a5dd3d094630acd94db10dd62a2c9d39431ee742dcd012aaf7b9b05606e9763bc56dd4ce73a00055cbbe2b1b95a359abe81c0fba341e408beb4ebf5fcb99d77386ae932f46597e059a652132dca997945d68bc03f4b8e6fdba705a4df8d264f03227a1d2417dc653698506f05f3ed316b551b2308c5cd275e979b84b05b00dbadea8b8c1f07a5dcdb5d4031bf03e7614209d0576cf3767c632dc3da608817b46a002e256ea39efc23c9f0b636c1539a4e8b2e7ead1b0f0922c4226513eae31d34a5c23aaeefa0c1035fd2217a8a1cf0f64f5bc124d8cdb72b7c110eb58e3895f987dc4a9a2f98cd43eca04b9354718910b3db7336377fb91fa15ecda37a5c97f4e0e845fb0b697f883c51ef3cc44eb53eadc94257571d17b8b2d9664ed59069a47d20d7c9f60c2dc2bb72589069de73a880be8c2d3dc8af7b126a1bfcd539ebf499d735976c4f9416dd125cda14c2fd6b9aadc9fa8e8742674406c850640b91434dbed6db5f6f955a45203f22c60fae57f247f5737a7d76d1e8fbb1c500b0a74103cb671b24a11773ad61ffd241db5e210987b5e0f4f684aded901be922f34095dc04db8cf2df743f08a2e344da58c25e72b35ba59db4cf80a8a405f34d801af11c44ea66a7fde80cd780ec70d8c6f21002b9ae5a48c55d4eaab17fc852ededb4fb7612793e41681769323a5ce7f25cc21e052cf512ca46a3e7d88831681aa60bbdea745630e53f0ba2a0b778aafce261c61c2b2735a8831f86673336cde49256abe49da15549eabbc37047e4676f2e6ba738e6b30aa7b42a99b3d446e938ea33223754a9f7fc73f8e892b868e2c6999aa25e43d53fd63bd8f7fe3ef79733fbac819dd9637b0960086a0244a05a8b2b7f32a0b15e666cd1febe8132991cb7b0ff170207b222e4cd62ac826db1dbce473329f0dc729173335506d3caf2b6c2d3a0390c2d7387e92b875850565046bef359a9fcfe33325f12ac75c3c655f4e21de7ff860fa67b6afe0ce390262e1c1c7fa0c9805fba8b8305755f70c1604a914ae41989a70318a63f0535b178ad7aae2288338fd806347b82943448c52c16da16a4c627f69aea4711e1db02ae912e02611df5100590a244bc928798d13fe02c7b549e060e36a271f556a41145aca25895b56b415c9d11281506c5255c43f0a0da9cd112962a4a1ef37f7842cc962938de54f19839eebba286c3d05d87c64b22667e356b168023df18001b70d89289947bc9fcd0132a253beeff9b1098d308094f88e798eb8756304917799135a1cad102a521af6050b358fb030b2ee513e7d19b214a1956050f85fa6f8c5212b8fd410b568adcd7299767779a372332406e5ebeaeb7f91ab37c7a480b51c09bccc0886917c3cc20c864ed96d4be02a4052219f904fc82992cb9c331c569816ef560c14a12c8a4eea11ee769ef46b124dc807b63015ca546098df6e6a16612abc9a2fd6238b510bc4c17a285359ea54583c384ae62ce76853124e43a9154029d7c520e41153b7dd343f0d7abf1c5220bde7bf5acbbf388a8d92c3100dd9271840cbf35b3829e7720df75a541f0f80423cedb23ced4e458c827ac2ff4e5bc204d8f76b69e4af9233c6965fd34486bb6384e35e4fbdfa557e37e859aa9286db27ac09426cac12567646aebc490e23eaecbcee175485dbb0f7473260a683b729096cdb72801ff55dcf60c26aceccad0274b30697220f5794e03320428b31f94c212aec9328b9e7d0e94f04173fa15d5c975b9993be40b68ebc56373f134721521c4a577a9469eb0c82b41ee48bab8feb84921bb8b8817fc2c6922a6656c9bfc7295954bc31ebe7e13058df8c65c765bed2e0f539adfa3fa1155e295b2dd7c9f41610853333dc74f9f586aca7724f1be833fda34ac29248f8e1c2e1f55f35c408005784fe91eaac93552a5583ecfdb07dc455382a4feecad5e0ea3a6037a3bf9f2e5a1168aa423832bc59965a9fb8d3fc3e4d70105170f5e1df8a269a4b960a8302ef2418b6a730095d73fda3d93f0eee8f2f8f4be4e509d6ebd50e5635ba142802125bd0c7afb84d93c47c4b97c17a5fe600d9a0b3dad54aec6cc7b120f4edee087ebac3ad362292ba295da087132bd932e8effce9cfc1ccee32154b81d601d50994b7bd9fd26dfaa7b9dab924162e185db0f748409770ae64782c447f469d5805cc69bc75589155860294f5a034495d3ae3e09ae450822bccf3a102d1c45fd71d395aac77280661e67c53d84b2b54d4f8d5b463b194a6feed38f1410a22bc990301c57a9c377515d508ce17531560f9430e20b6a2b3cc32d83bb6adbfb2de06170c93eb7f359b3e7a43b193d199f960f14c76c9a014bb8ff6943abf635594130789373290ef2c99000271cc417a41091ecb315478c020a26545812048ec1fe82c1420a8f5627d159eecc865ad5508424323165990eed29599b667fe076289d317ecdca2f802326072891f66f220cee8dc73725e2cb3651f85d42c07eb9bd79c261fc099cfabbb7c637d98e8eb3e1ce7d6a32b22a27e12f9d6c53c2d73d509ec2783d739fb5e079f0a7a3e9818e2b3eb0a5356043c05a3bc5a9a977865d9f5542fcc861efcba31be85280ca013d7f18f62ccc24f8018b60057536d7b36950eda19c4fdfbafb64660fe8d5675483ad49b01162a25a492b43cf00c6d7dae14b2cd2472eb6bfc77291b5cb46d852b9e4932c5a2fb92fdffed5ff915fc7f70459b1b18fb25990ca267319b5b37c6fa91d009aee19b3e9262b363b1e9613298edeb0319294bfc2e5978d4fb62e930ee84c478a6dd17acf6d6d14c01b0829180cf3d352822de17e8a508ceae2804b577cf25382714318836f288c434fcba684506ee27240c4821bb1504a26ff7dbf76dc53dddffa2a8fd185d4e74137c093c0926634809023f91f5b1d22d19b7708d0276f1ac904d1df90443a6feed3f0e58de3c57e71a84bea94561f1c51424b32361e96ec955f5797d3144be8c8f229550bc94fa8f1df6afb0d8842227c0cba3199c994e658e6746f9768093c95930862e3a0b56ac0c1c932e4bf356017cb2ca19e29be7a842b152d800ab0aedfa834a3c7d52a8c00f55f6eccfd21e6775f704cf030f8bc93c9b9f3cdacf89cedea1f828ba2a967c2ef571f0d8981360cc509a91c5c2bfc406a7c72906303d8d8e29c6abccae4cd406b0d0da7d2529d7a8cdb4dbbc5142972291b660b547e2afea0030d70045bad015942a73853124febd5be8350b3d83037a6b57ddfb1251faba5e36f34f01614c2cc4ac0a2353e74a9fcb3e1207eff81c29b29a4cd90d839ac0303ca4dc3c100a1309c1dab3e87b68141dc7e282f96d2913b3a11f5101a2dab52b3e4ad02d8db20ffd228dd53135b5f9a2e5f40efd33b2bba6caaa5579ca941e34290a8019ccbb0c05d9492aacfe8444ebba8ea2d51cd95037aaacb110ae0dd86a51ff39a4a7cf1ebaa014bebd420901a2aa991e18795c8bff01cb64436ade5c1720fff5defe252c89a6983fce2e13997238b6c375cd5838163219451cd3d6a95d617a3757e98627baf0249e295fb4a1cc27f404f1395e6cf613177748c35b5fb9dc002f5532a62e7bd8bac7a6e5374a45b2c066b8dfc9a40facce7765aaa525440acad0513cd71e9ba1123a92b3d6da0f6a6e4c29ce5ef71ca704217e6c985ae5c12409c83b2b2ccaeca49db869ce155e16b30675acdfb4e74f236b7abbdc3b25bc6654aeb3cd0bdd2fa5f0e8bde0fb255102c9980d85225b5f1122ac38bdfefb51ceb05d453f1772c63be41b33fde57974f26a4630df3f9b115b032591c02511255cc052375c145bdb795ea0561c0e86e47f2c40745beb4a9244543a8d8ebeba6553979389602296b4f2d074bd2251c2e7a693a2ab3efea312b8517a1186811cb1703d62c60d1e5b4add004cca09a56964444396391ac57d653f33c2cdfc44a6e63bb5bb073927613dcf926775993dffb6ea2c7e2f2f6ddbc7f534b6f023dbb43fb40518741e0c69103cce484b13de07024b6cd9c698e83d0829fc1dbb5f8f1ff8f7b4dca69a0eee9d7777297b8ae2276377c82b930dd6908de907c96815c2127f4446371dfd013a464b7a07c13da0527242c9f3e885f17879c6004d6031c1dc37a5308ed1eb2ab46a965af357c739981f9aea280d8fdeef48dfc08b31cfaf5f085764459bc611ec28126db3fefb6cd2e5877fa445354a4a3fda6568e11050764a9f17a33b770d5692ff0ea347dfde2feacd5f50bffac4b852fb04f3cc7be151bc6176433692219a35ace66f97b9ef140eda3e578da58e12b0c4d0ca5bd24cec0ad9de1f0aae19c2823c4d79be5f747898b6c1612659254ad4980954587145c25bcfc7bcd24513fb7fbd6388193b305c1f34d893636da9e249cab876bc6bee69c68ddb647f5c2570fbd44116ba2c6588b93e791d2804db739151114201602c986f95461869a8230689ed1771845fa544d40f0dcf069039547f671777d8adae4ba0da5ac598760d03b4a0e2e2debfbcb15663d48f629c06bd90495df5a05c07a4aacf80db859c09d245207ba23e0956ef6f43f3016cd3a16916134f0f30e7a9353c7ecb525d6a226a4d7b349c6b2cb215c1333ea2d15d89f46234fcde79a6ae903dc8194549b92bf37fa219e3847fa332380b064dd59f22d5979687959c467a626d72bc67dcdb272daa654f1e5de7bfc1753944c74f252b10d2a4ae5ebe6a5f8394bf074393d902c6efcd5235081ed472513b81daf4b503e9d47c61be4c45703cba89ebe3347a18a0a87208087cbca1983ff1b3e723d251c254ef889b459219b56c9de83451f7094e5686ecab23149bd755480e155babc78e1dfeb981650331250ad50c773c662a80c521d5493b6b56f4200127656346cda7705b9879f7cc66fe32096dc3b29627082dbc564b34ba021af2300fc84ae6f1d967e4c230b6bcd931e90f553dfd6728f4ebbea547f837170d218c2d2e12abbf0e8721ff8678032bf4d4d62027b58b0d26234f32b61b7c2c7d91619375132318e552b6703061f0b914192b04347c04202e8bddae95e7316edda12a71954f1c0704256f60a180bb3945e00ff5edfbd2056f61610e44aa5d9c5c74efc9720ac89a5c3dba37d12ba8e20b6fcd89db55a72069e3eb9892988392f3185035c36a5cd1aa98553e0c6524378377dff4550af1272462c0881513c64b2a36304cbb5f0673f25f1b2c23fe37cf3f61e6b7f610041ac1b1543baefb5c05f8e135161322189fb52dc0f48d205a1b4469d3f47a6768244ff729077a9e0fd3eb881ff244c1c6a1e034518c85a9990aae5080cd3285f91d23bc261f6b2c62274e887a801fb717eb48ffc0394b133bcaedda178d35be6021282281b29500af25729a69d63df92ae7a38ed24326954b0028d91bccc607371bf84f236dfb952bf8c507b41c9e02828eeeeda60fae8e851939145e2f31726f2af3ec7f3dac53b2ab60efd08863f1d8f007bd851f6a4415949fd7877fcc57221151595feadfe852d6a6104cc1ec027efb3a9bb0aea0bf1b6715826bb2d8712117ec6ce953cdb96931186fa1a153382393864e9da9ea6c814d835f9f3f1cfa0a0953d6acdb9a2b0ee74018584e4b68f0e81092b375c04419c008ea6a44f37e221cdeee906342a11f940350bd5cf4d30deb46f036619ee91884fe5b64189899411adcae708b69806db24bd9c4ce984a56a5761faa3befa8009f863b54a1346e333025e5975353f3f9f00372473e4cb843e9c3027367a9f3050f91563f19912a9b08ffc15b607e5786241168cb7d80cba40efe61cce234f567c163db710e5437720dd7a6cd1d1af665c65904142f41910247881e72c2a99af525c79b3944bc526a0c60c553eca5a1ba6f699890601f6bea59f612944687067a49eeff6af4cc194626a76ae13d56d858c1b172cca005ecd2485f74a469226a3d4664f4d4bc8986b11ead53845d95677719c36ed2cda007b01139be8ad9a496eb700a8f25203d091f15cf780427ba6f545e02c59df445463b2af51b6b3f7381276e6acfad2dfe6b0d2abf08e79e7052e6f723908e5c65f5d8fe6cace05eafacda5533ef8f894ac5160fb90825ae09b542780386f8844d77ae94cecb831fe9686c93ad0fc1b0d40ada1cbbcad58aa5834ceb17b57bf4c04a7e365ea6bc52759b30caf849534590eb3f1a5b815544cf5a2ee9d2a9d1c421347892aa0b527caf180f6ebf4c0c0f9d7ba6143e0e69024c0eb1a32b8ca2315d67fbbddf7d77d90250a9e2909cfa7d965bb4184e1975f16650a489901c9d18270414efd99e1557c7bc31aac748da48763aad10bcf3cfd2dff30bfee0d3517c9653e506aff2b776870c108282eca658a306402393c386217d6af987707aadb011bd56c1524f376166df9784f42c36004f36b106c2afa3130f132b708e79ebc8494aae79f21e15f24197fce5790ed32b7d4877", + "public_inputs_hex": "0x2138b0022ab9af3c96b082bbf307bc9e79f8f1401462e3ac1cb3a9913a5b856c03d33039d45432d4999b9964018d8d6552808849c83503f50a70d594c01b441900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000a81b7087e1431ea26777fc20238aa980000000000000000000000000000000001991a803e262c7a38f41ff63f803b3c202c2cf87674c88d6103108c767ab2ac48e35bee25bf5e92c02761b47af09b71a1301f6e7fbbb73aa8fa2046f5a9854e60b7c72f0b56d2cdef4e3cb5e3d1a660b0827372d8ac27abb349e731af617d334968a1a677756357ab1b3eb22654a72341345ab0ed28ab1183dd8d63e3beb4a6335b88bb03a12fdf4bd39c23c8ac80cce0ed445f4ba59e36bb04bedc22d61894e7f47177273eb6efce052396d70477f050dd6ae6474cac3235c0eb911e38027c416320fdca3d180736d3a3359939e922b2811e91f225484bfbc68da2f299388cf367b3de96e1a14934bcfdeec50d9cacd2aeac2bfcecc16e20fe23d8faa581b380bdf19f50db602737bf9076c967d4a63" + }, + "decryption_aggregator": { + "proof_hex": "0x00000000000000000000000000000000000000000000000d6c9a4126c3a603e7000000000000000000000000000000000000000000000008cb1f7bf2a218a271000000000000000000000000000000000000000000000005220283c0e4cf6a610000000000000000000000000000000000000000000000000002591f9a02cd3c000000000000000000000000000000000000000000000006b4d77dbcef69b44200000000000000000000000000000000000000000000000b66320eaf86a9871f00000000000000000000000000000000000000000000000cfa07aed851a7101e00000000000000000000000000000000000000000000000000016c1cb8b2fcc800000000000000000000000000000000000000000000000f6b54c12ff26b41660000000000000000000000000000000000000000000000076495127c7c04d56100000000000000000000000000000000000000000000000e1ec3aad4e5396ed60000000000000000000000000000000000000000000000000000c6ac8a0fbfd90000000000000000000000000000000000000000000000041e7e2af39eb6aefa00000000000000000000000000000000000000000000000130bbb0ec2348df5300000000000000000000000000000000000000000000000251eff1b962479d7c0000000000000000000000000000000000000000000000000002107a5bda7e69199f2a94bd552a20234800516d5c52446581bda405093494e043bdcf1801a76310ba6c8e991f0f1bb10efd9ba15e43b131799be90a874af8846173da178d91200e38f0d23809e4d22a0a3767df9079919265d5776dee38416f9e54d05efa9f21026b6afddc8486b2987c54a70a1fb90ce7b0dd72dda6973dab43142f3b7c62bc2443e268c7406b5b01022182c3afb35673d07f621b0bcc7a747e62360eeea8861a546fa7cb23c3a401f794ed59faacfc55d7765e050998d9ad542712f29da780041ff587976aaf1421ccd4435f03007f6c37e7dafb835f0a37406ceaa510b1fc0437344273d8e01c1a631f6bf40db17dc5e594cc1d8e13419d94db116a6f63ef2b25a3a0f0f43fdeb8df3b943dcb414dbc186b40075f9dd19c440d4f13e2ea4f1261011370f9d84096dfcecea4ac545ec8bd01b2b552c415b27635e12737dea80af400ea25a45b8a026bb811f5f77e6e5e560349bd500475780f3af5ba16dfd30fc3ee3b89fc56bc2b3f2063c45ba5122e78195e3cb250a46c151bbef8bf71231be39c0dcfd76204d23ae6d83df17d8388410dff5064eedecbb755b8d52a598708e5eaaef7ef3968626bb7989ff7b194254d91d19098ef22fd8fc7cd6c97da8f25913e0cd96488d96dd964aea8ee93c7b50a73328f986c6d022218af78d87d921f33d4df8c65a0de3880854b70a6fd3df79f4d46d652ba9cd18c708038152e9b21fe174f0132d48a6be51930c56f8675ff96a7501ee1345d8983e3f2efcf4b3d0635ff07bd1b0feb29b73fc08a8e6d44bc17adc0d7d721057573e78b494863ac113f7174975f5f8cbdc3582841f7a981ee7287554fb5e0904fb2f26d9d059c5802319633bd5657d8f256fac6d8270e2b0e700311c79cbd1ae54bdb995626e4e43057c3beadcfd029e9fc48b0cf9556ac1e2b5bdab07f3382b71da4cf18bd26ff199bddbe6d355810c13d7c8497215aa1553a7bcd65c2419e6c49743a57f9172016cb4480cff30256429a68654722c993e0cf5d1e02273253188f6e0f2fe02b831c8dc40c2c8ae783307fa58ce6b21600dd9d4c3bb32d0a43cdfc51d857632d1603cd9cf7070c6c25cf6376751f793e33661e47138e502bd104041df30e46ed8916e2935294fcf05139704ef7e4dce91000022db750ffbe816d8682c01735553d0fdf8965d9f0b60a0d5942a38cc0c8cdd801df32e6a3c32f715606733db762c1170630083b9750f29e2c81801a47c041e265cc098a9b56fb71c880f9855157a90b5c006ee62f80ae2f4502f3a9836a0f398fd19e33c30b011925034d2279508b2fc478e725d008b82a40c48b2a0e14b6947b85165b0421150a93e5c3b9a90d0312ffe681ca700827dedf57d5e1ea269fc6aa78d7d94dd5569ec8acc6356721951df72cd0b0a898b3e27f9045435a934420c2f822442973bfcfdf3d70512cec520409ba8be9c92513ac863214905b29b828a06f6ebbd8e6fa38e5c741b562348e17bfabce3fc3da4b3c11befccfa4e1ab94ca6ba8e47a7d51670c5d445a695ca90b41b8163c2ca2ae3df50498e4ba161d1cadad55432b1aae3c02b9b5a3ba5ef6051f498e2af0bfa316f0b5b7294aca4a796a3fb96b12ecc2dbd30eee2f8914e9175566fd353df69a6b30d68e43dc4c73da4fe6b118d427601f2a1097416ca37a2ae870a24a6bf7dec462fc575c31b3e3b27afd9d9f487de88512f8568aa7b9af033886004ee63dd5244a2a0a2a244a3c12c276760d5f7b661bd55ab675d0788e0d2010921dd6930d887853fc2825aa1d4f656fdf9d6651ad241b618c67aaff811f67ffdea89b2d84a49eeaa676c46f87bf1486aba21669c58cf79984e1b5ad4e03f2d2a7620cf1dc77efaef972101aefeef67dfa6b173e359a3c8dd588da4dff0145a95fe6ac10646b4f0039fc29404b9624bd376e7aa99775661f66a13658ed14e6e8e9071187e03ff2ec4197a886923a6d63f398143b8722f4b8d7e40621330fab2dbec944dbb294003a13275ed98772a2bc7c0309bbb3f267c62928eb0bb11c2a818c976dae9ea75f1db179da83afd5fab47a9d928b359b8296b3e7c5681e17ef34746579024874cfd4a2e91b0e25923867f0d683e60629588204b3f436a90453e44188d45a90441ee017dcadea9436511978d98e9feec41e6b4b0f64c9280bd57cdadcc695310630a881c2b8c879e50dbbf7af09b160e3af7004a412562b293932c7eb279063afbf7b5e7e29612bd37742ed3e78b96625184b4c2ff16ade00b53c4ab08dda1da933d9cbff8684f0089d20a9844970ebf3847467cd601f170efd71790b8f8f52899d4acb3013fc16a232704cb553bc03c0bf865bbc23e6620666d9e72d6636e942cef862dee9fba615c2c22f1a34c0f8173e63b12696718b19f9622624b218fcb2d87cfb2d1dc92442219873c5b79af021e6f240b1cd847c1aa40e772dd587203f5f419de22222d938236825aed8171228c123b47843a74e0751ee5b40ab328d7a33a98cf24eb02ca51c5f2023f5fd95fa43b5c238c096ac0ba82b1b166abc43e4a1b1e278bb0dc077809363661e34a1c30ef77c602a26fe28e63baff200a767377346995d6ad4892217a4896553be0ac025e1ede41ef53c0c1ab2df79278b24ad61d06ff2cf1e99b92966957817fa789565baebc4a9fef22c02e38b7cf2d338b14dd6bc9e9261c3a84358cc539b268d7e96ca2a560d62912e053dc8801b13a56bfd925be4f10b74a2d33db592593fe15f5b6ae37456a3db1bb592240e3c0e590ba7c7e570df56c52a8503aa726b9cd5084ef22604894be71653cd1372f1dea72ea6bfb27392c770c26eea1c428c34d2582e5b5113389b1327eee91a17d2d318619887eb7a108180798422b4e11839a665595b54dda52df423d6f85f95466bdafbc0b2e538d53a7d4f733a199c2cda89c3dab1bc31df32c50ae7bd187e664d05a964be01278b6f03b6c6da1432a6601a8ca27279f48a83d820de21149942e08fba15ef61f8f3c0260c7fec1e896f45fce5f717e68e6ad2e300f38827fad7d0591c8ecabb0312d20b4ba0d020fedd669cd16a2f249156de381587ff4a99c4c13e53f8186f56ab498d45067270751d5987782280866b8e377e034e8ab6590cb70665fa7966e3d4bd41536809913d45a3cdac73d54ff80d57b92b7935cb1c6243785dbcce5290f25c7cf59d6797fdaa8a2ef5edc5b8cda7ae7c0e04359721793eed6b29d0e1184dc50ead2075cb3569f05088fd68cedd4c38c82a5912260dd73dace2d9730cc8a448f9d40ebf74c49e40386bc6fcc0e1ea13e922cc424204850dda1c80424c5f4e70415783b45deb7a73e5ec46d53eafd10b0d2a4e6a15f72fb98d519fd708580ba6fb60d00cc7bbe849c8e5d574c6363800171605ada29a408f35d469ce8fcd5b63cc85e07643e6e9cfbb9159e74a85dfd3be0a6ce1e71fdef69fce06a5b6727a42a067ca81b7703558c0b1a8633ed66a5d75153bcea20e7baeef5ce7809e9b8c9f45086236128821a9b67b5d6ac74bad8b3c29f163c95c73b6f42f5807f40b55957a876eb2516a2825c8fc72f236778358a10696d52a36de7e93b3cdd1f394d5468ca71509dd2cb1afe0ca81276bd2b6e0681b663a1debc6de673483e96ce68c81b360440963fec2467d817d22c0337418be2e5201dc40241fd68105880e2848a822ab5bead6b956cfe38c37d219d1b181472a0d5868d78fc5d850c491c9532d1f59668b9a56026d3961b0611f3c5104579b265fce9fb13c67f876520e45417c923ac9aca521380e224dada03f9ebeb77c0d10f915f95affba13b231ba5543f85eaaa0ab392a90f3e93e4d252747863c86bb2b3bf82bad04cc91244f5371a7d0d68ab571456e77a3f6ff3e20cdb96161a3a00cfc8472c1c127c63107a7c94d23f8889452efc2ae6169659384855065b6067c2b24571e4896c3f2dcfb11d3897158601a0b5471282ab5891952b06321c532ba1eb386862d8d3b0686a7c99c178b5d3a32c7366ce8b8ad1062b6abc970821e2700469ae25a747acd5c3c6a03af6c7e85ec16627ee42b81cc9cd43aabc2416ab8265f5ca8f478c6760cbe3113c6b93497a0539042a7a3af49921ba8665c65cec32fb368ded3f4d89f8bff985f141b608c2bced985360313e04b7e19550d6df36806c0a29be7c7b37c27266eed5abf57195d855358db574843efe2a391b89ce88a272a33820cf99cf2088d8910e313d0764bdd1ca0e5bb2bb820c10c95b3c00b45250702d02cf0b3ce811e4dc5ac5b66b362325c9b68038cba8aa5232a79f2f45f2725890d9df66abf32181f24ffced0aa242cc221894a4d6817d5020394a9360822f251caf9082777de6b2b15f498232343238d0b6e90cf6921e6c6bf4d195171276bccae75dd0e48d618a01ec2ae7991247be2be45dccac73b20c9b2053c77171c28b2fd03c8d84440375e372e41ff6388f7bc589de81ea6a1d7ff4e8b331edc04d4168c04e70b35a450c4afdad791a4fa3513b19d276a0fffe50cd1869dbaae213a8ed73c39708cc2a4d032ee933f66e1b87e1973ac316a2026597246b14ef418188aab93dc1cc6e59a141eea6e7720bc28ae4c8e2958c129122b2e04399ff41063f60c4decf651d58774db8f5b881b26f22b0f01a672bfea51bed9ea26faab04a2fb96a880434196ca20aaccf4c97788359624aec9211bc108805c85fc3052288af408b04b4fee3556cd03541fbba5d2d5b14e0f6f828e13e2ee735093525800959b3fd7690e499cffcb85593a4daa08b6fcb8efea6777fdc54e28727458c81ade87c5fa2af0051347096a16c332beab21ba626d6e379b103ba7e543f6f5bd17c14cf881bf41ba471b821338b2dc52932f26363119366f49d4128833dba8290bd01fd27ee7340f46e5e7a624ca523c38def233755241c181bf12196588dde9096521920f4da8a2e09564ec78a72d92dd426bcccb070d4584efe10a39a4107d1438277c3f16a7e143ee690e0a852c9f740db2b8b4b41540f846d2aef734ce030a51f13f8d59a70aaf71cc7cc12fd395a4db636b5e74c83432c41fe61dd4cf9d03f7e1a35ca11c2e63e06dc48e7699d855b74d87cc50391eb8add9f75130db9c006f564cfac2a2c9360dd4f4707af7998aba1e49e881f5903b7667645bc81f851f138e589d303fbb9cbdc2f8b5fedb9d26ef8ff61fa38446c82a07d11d9f6d7403aecbb153c040dbf359d766fec4fb69487b910064c9d80dbbc212e040ea14ed0e3382b7e1b8ff62702059bdccd159a537da8c15cc3d934ea057d3f57b1815571b5944be7baf52ee28d3107bdb2dd8089a3b393012278996570a17ac785a010220f67ca35abef4256ac6dbb8acd27271fc42c11655cdacd5092607fe9c7ef105079e12fd6c3dfd3374318c9fc2ce1cb9042fde86344e62ea85205e6cf67184c214e2113b10ba0d246b330b65a2eb0eedbd559f30b76b2219d0299886433161e818cfe2068fe1012d9ab865942ba25fc3f5ed0f0c94bd74a189d6d8d8235c29a300a4a2c70b7eccee907343da09fc48aa03434a327bf4acddbad2e7c90f8e12c72e91d56142ba079d2864270121fa800ce229172d6d15b7edeebb006a61f3d93e2b5fd60cf7cee2787e78b919dddf2c69b16e56dd21f1b893af7a7bb42ebdad71279926d9650b95fa6d48d5f846880d83a759ee476ac90e4ab08ae7e9bb7254f72a1f9abedf335b7f3e5c194aff4aba68ffbc852ca3b2c1f9bee4ef135ceb63f5289dbfe20b413366895ec66b87d4718e9446e20eea8e80b4cac7e1b9a7988f4a25cfe80d31fe157ce96bb88b314e9b41a107335b3b433ff463e3aaa6cdb786c82fba795d5e57ea0b79f497a5f6bed28a25cad31f1fec901e10e19df77e7d2c380dcff49f691f6f96120c180db4f6f7e6a59c6e49b9974ab4aed86fc6715af5b70dd6e5cf3bef9e6ed6e8ea8f5657a296e0f30627533f24d73ff70c7a183cae5f00b844d94926af4e01bcd9a890f34c26c8e52f7b43c4d92d060abcfaa444dee2216ac436e277931eda67d179f8aa67c06714344452c5774ac784c30c441b638220ad1975ba226f13a81410750450ed3f4a6a02064578f28b111bf86f26e0b8250d256e1372e7e3b5dfa47445803a509501f547d05fb3a24e74a34af1e7d45df704c57a824adcff7851b4d7d67cdbbade3114f492fb634ec2e088f2783b978e5121515a83b8b4a6950d28c922efd67283140ce93baffb5d15eb72ef544c5c2e531a051ea8ae08f1f87f55fc446f7fe8e4fb25093dbb38bf03a2e399137d541b2504cd4288543c7b1c51cd9f54551d339149340ebae8a52401d0e26ee5341d89a31fa179ce5dfd2a4a9428cd64be345723b717dcd64b2929ad87b243fb7bcb3bb52339cd359dc854082703b9fbc15e87e87f39589a2054bc9828d92ee0b9cd165c13f35b457b0b7f484e3025192770ff1e333014cff16a594775ef17440e92212227553ce62d0ed4fc5417fa3d4863a6ac133aaa1ef8a238493863330d26841be91b6d417967ecd5590fe852fa8c692b2da8a96d836aeb6483c921a5e73bc19366199a1b5c847d7bf11b1c85f29c33fbc6f57aae6d2b799c31b2cf855e0c221ac623b42500d0e4995dc9729189c53e4ad9a8918244d5770d1846b14e13b64826b918f632917e0cf629542ba751f9ce57df94911db2e9d57c43a90a6b0d0b325d3f0be9c1625d2ac88f9915da498f34a6613cba927f2ab56416083992a378bc72aa09af520fcc520a1a8e5991b2a7271249afb3c848d6057ab4950d92579f62f7b5119ac63e6782976db8e9977e3fd5289a9296b70f899070308c729839490b27581ff7d90a4fe1578d2f895108b2c28c1c1b8ec174a37146ff4397c87b0cdf51261b88c198f4bec0b60838a72080f25236b6f6db072b3a4effd09d378c84d82bc703beb7ebf047d1b3f2bf4ece8b5e36284a1cfc0e0b57b862d781cbe696e77e650ebe5eadc8e3bfff1a4daf73bb4dc7ac9d88f49208d4e454f8d52018fb4c69570a3b0972fcb7a44ba524e43d779bcecc8f0f91d2ed80882db28686113fd6cbea26cea97ab08e431c705da6558f9c003d48fb2f9ac5f288c186cd189909aa9b7f0b25cf05b0bd940479d99dbceca591f5e2bdec7636476cf3ca59e3c4f912594200f45c0bd06867a9e8a24df50920f4d827a373be6582fefc1c9d179525908261032ae4d0bc4e51053b9e551927c993e92036b1a23f32832fe5040b9d0765235b03fd56870bdd2ccc031334058a9ecbd853d70df1f1840b45b98848285447b4a413ba58b32a3d3eeec6af4ce9ab146afc6551817d059f8e5612dd6d31ebbe415c23d9ba4b98e0ec420542b8fb7693cde2a6461a996e9b3b4d203bf66515a1af0116671f9de44bfffad700fce97fb29d638d0adf936f689b8c806fb26b26d89fa30c7d6149448ca434faf792c3e6a2a986a3ee36cc881ffb75f14c78d8245084a703beddd3684696503f46572e92f37ed233472a287f601d3751206d83bb17173c22b471f3255ea19fcac979fc8cf5a1c4acdb637b9d06352c8181bcbeef1e8d7c1222ed4147920c465875fbf43993b7673e938add0abca2c077afd4146d36d7890232c17223a3a6dbee9eb4b9c926a9f7972d06a8f4eda222b6a53f055be94f3116380494ecd15f4e289b533c34bb469e60a891e400696090772f3c29c3f4df121d2e1303f08114842b9c87903a7f3bcdead25ef8186dc00e3454c4f452841faf2893737960e1408a394ed081f3330b6eecbf38da082548930573dd0502171a3208a04300a6125ba86df0bae3f730a87bc9c7bfc78369d73ece8d708442b71d2a28ef0dfc69afd35e8d6714ba33c3f3ae54e2177544bd7a6585f6b232422ac44b246ee00aa511a2ed1daacf38ee5dbef3593914ce4bec707b8c5d1fa4d04988192a3802679d17817fa6c801337c7d3e80a1a8799f6cf86e1e54084340af41d4d809ef97be1ed4c7160a9ef5c8c83225828dce83d892a437660843010fb50b61b614ed4e745a80fd6bce6bf44b8fc9390ec64bc7ac5c1edbe74016a00e4dc0b04f0e46fe11d66f805d8b50b24bbe95d066deffe72b8f18b24e785f0507776005741bd95ce935894f12dfe7ccee1906bd6ef4d272d823f5bb92a0229f0f29f95ffd181491eb6278dd5f17ff1fc66f8d4f14aa8b0e833a93f74fe818e32db2dc767c15d5d03ee42965104bbce10bd5d66b871ba2a09f2269cbba8432f52327cc1e2710758e1804ea1fe8377f9a1b6b4ba850efc3004cca5203a7d7c473b88d91e6930b1c7c195ba3c47a130eb5e6354018b8907f00acae6f53702b63b3900f6a184c07d52665a7dd1dd94916dc7ba95cf75c8fb5f07e3ee904beaed3e7a58e6c17611b7048ff802d22dfc068e70bd9ab87a251fa151230592ba0c82bc43eba06b2391aa30bd3454373d556018c830c24afb90ae0d29d4fe1829478826c7052e092a32f27a9d63d5defa8f03d813eb6572fbff32dd85d8987a76d31daba9faf2cbed424bf6c47fbdf816450039199a834ec8989e7da9bd6bc285721d08af2de1767a11434eb257ebbdc034b7565e0cc0ceaff92f19dbf1431f32000b178409512a2ae24f4cbee8adafb602f38aba2f7a0344c7135fde5f898a69e622f0243ae7f543c1637128680ef50cb07eabb8bd5f303c697a150f41cccf2fbce4cc643ebaf65cf1a3d199248db86f69b82ab604c6866c26a4268f1154a8f94ec3ceea3531bb5fb1ac951dfa99496f21cec96baa359c2c08da23765578d5e585d527e6bc043d3da29612378f918674b1ef552973770f0c674d02dbb4f63a8f5cc8f896ba59e3f900c077ed8f8f6ac6083501296dba428a1180e1ceb6ead1e4fb31bb4fe70079d720d4dbb22e823d9167e12fc831d7092d1397f30a1366d5cc8731ffac2e0db9289080a91eafdcf29d90fb797f81d785dbf8e2481de57829cb2f9d17bb894e048e7051f449250b7c31255d056189f6c90090b81be3570d7c71ae78cb0f5169d6f142f73130d9283d0551adb3c268d1e169333b5864a226b7b4f86f7e24c44a991592304ff28559b195f8b32dcb97d1dcaaffbd16fbccd854c568e3e420fad1a486e0caa99c46aacad0268870424959687352b688151632a5dd7a5efe11f95b645fd1df236d479ffb918af56dcea8fd0781c37fdc3f7cf0092b7ca962ba71110aed51249b400935c39ee2fc263a7d70bbe850db6c570ce8aa7a7a25978169b7e2fff2a94971885cfb3433f62b6f6af4c3c129461b5613d2e12cca0772cc52fefeb4a1a54283b497d1d1e4fe8cc24b6f6cfb897077f1ecb105e53f2e0df0295540b1d24be8120438db8243c68d26e2bdfef3da4f1369d8dbf7866ce3169772fcaf62317bdead50b3feaf0b55b2163f8e59c60c40c5f1bf659534219fcec999193055020bb3a4687b4daf25f77d9c02846053c7458442a26410638a42baee5158416e00b240ee91f5c3805f2c500ac2231bd4b896c030f4e9d5f33430d3340736cfd9108a10e9b4dc893a57a260421736c988dc975dcde25675f1f5afee819576d1aaa04a4b84cf90de3d13757e48c22726470ca958b919db4296a41518e7ce62e7a7a208b17c527b8a6d1b068ee2f4858d83c6a748110b20fffdbe44916f3871cc6d20aea3df516f83318de00669e8124e47d2d05fad743b8a9d8f0cfcddce8355c8217a7e599be1bbc649224b1a9686f8f08dd6a333966f9d67841080a8285d912d51d0cd7a48d3d797f1d1da9d14b3af4d569fcce49ce0a08f29ab27e78df5775bd0da3985654618b91578ca1c44e9118e97fdfde9a44c2c6a01dd033e1afd9502613f050bb5f40cfb1ed125552ae4bcbb02cef49dcbd8d2ed1df54c12489007935023d9bd5bfb68106a5172232ac2f0adf0b8d46bebd8c319b1f293ec6ea0dcf2a1bcfd340f0a46e5d791d7d5c947b7d7606747d163c56fdd7dc1e5713b8a720c802f68cfec8f3426146da621b15d9183024fc5dfc6036ecad7d337ef4aec8de650465136cafb39b8b1d9e4adfa84f973c3e7c74aa3e42ce1c90c3e216cc26bdc80d2623a78eda113305e72f2f0723d87ea6444f1f62b0edb667eb67d5c8d43f1129c6db6410d513e3c04be3a3015c2f50235937731c558e0bed04877bd7d990ab2c551e977d18eb1d792ea80e561018cccbedf3c84f79e149cee13fe421a5c0af2339f442a974492692c512d4736fbda6926722de7d821cf2d141e4cbb17e516e13f2f2201c7f219c8958fe2fcdff5f4e5c4da2b19729e480820303c8359b4c1f16de9e6612a1230f882a6588c81e1d9d1ec50c15e2fd56eb57df3352d7e9c97b2c3cdfc11b2b771ca6da29f5dd9952868f39c8171074260fd700ef04dc5541521f36e6f861833c85d1199dc6efe365b8415583b002816cdd257b59fe2b2813bd0675f26629c1451b66772d23c1264d941b003abf41a3b7ec72799e08bd23c93326d02bf901b3314b130b48d5697d7ee7b21022dceb0de7a693a33e43c10f77d624b3e57dc0513d9ab7dda81c2b5230e9a9797ed9df075b1a9a04388b75e909bf13fc6a8e0963a6d09fe6feab2ca94fad001b3f2303b76b0da8953a6f7b864f4a10e5d487df213f00453d3b41de3f2af983ebae984c50722e4070dc76cee5e0ce2dd35f69ab5162d3cfa3ca47416420d1a6ae5736872c95f3cf4bd758b053abce06a3f3d27234d5351d377d19dbc31128c73104719af176fda95db7204fd783992e8f4d59931736663a97d75ca9fe5601fd6a89a0aac7967616304106a12073271eef8a88a6e435eed5c639b63aba53bdc40b039e0fc0c93d610cd5d8e66d17471ac366ff4f4c0a1b6cd7f7ea41e2357e1d43ca2d5b0ea75f120369fb9c8a21351872b158b652d6c6e15cc381c306c1013b6e1102bd43e75161742415d7c65456135e076db98d1f67573f1cd2d3937af97a66e2920f026cb6af506b49054bf5cd1bbd6f7cd5f654ba5454ea1f6afa635b9836ae0cdc637721c23fec7e36fc5b181cf56fd52dac7d9f1058fe069388c8d8f4aca742c881e2ade54160b68a6b36e51e973fdcfd0a8bc1a8c72682743423f4270dda04a6be272a1646a15eeee9e9960019a34eeae05129cd8c9b0d12ad5b3a1b4910ab269cea75a18cdc6602c90a3c2b0a7c79b306c76638f2f2eb54cbc41109fb4780479e8dd882dfa563e655b300177732817cde20e4dcfbe62477f7bd375d66ffeccb335787ab4069c3ea492fc80b24f697b3c496b0e39b5bf7a1e985673afc24a32ad2aec7045991e3a80acd80181dd6b84aefedc94d484f80faf20e43cc740c40eaf29a2eb6b459cb834db07912804bffbcad366f36d02398ff25b1b7d10e1eac43dffdc071bb0135bacb68ae0be269fd54ecaf04d6fc6e8ae3865d1a6723ca38e1a837e79529b1c53f8652c417a5f356703cc7a7728e38472edf6d2a7322eac5e1ea44360d99380c7f1ea79f067ece250223c72cee699b995d9e03c7e4fa7559f7fe31342cca0ce2cd31586311c664bacd8676d116691e2111774761f13bc228eb8c5246f2496c79a08e275608560bcc059db58b4fd957831e60ef939f1785f95e96e574f211781f6500937b02f0b4f9e89a0ac6ddb388fdb8bef0bfee2a1fa8b55030be4064653058876cec1bb0d419372104957e3826fce12a86acab2edb95f0466e8d974f72951a5850b42c417fb7da12f369945299761215b461b853087e5c72e543a420fbe81e08be59045685818d5d7b478095d711c6eb686827f6e20ccf3e1e378e5b1ca7df6324081b9c26e478a35ac337c3d835ec68e0e328fb30f2c608620d4c0896e0e57aa0180b17223b0607ee9e21a031712eacb1e784c4fd08540014cf3fc8d19726feca721e365bb366388683526e599a294927bc546a4d5011da30c7b2fab02efbdb18ab035ad5bbe7bfadd53b0885c220a897d3d8c2cb428e38273d250245cf1b65e0c81b39b2f0ecf38a82930cac7d2400315f74b76e918f5914155e9d2a59cc9cb4f107599dcba86033fa5b95e6a78e083a46613528b12d9df4156903cf53deefc83d00211d70b9cb5f95a01fda9d023008e546e99e3666b50e92e252bd5a24127fd3186841ec436a72ad2364426aa74bfd2283fe3478f06feced6398b87f34378fe81b599968d8a2284d9e7c9d90c75a2690a0b9654e2fa9d0a33fbab902a53da9160119d39eff9c63f7877567d4fff228def31cb88f95fcb9e40e7a5843472c2f231b185edcd6ca67c84bc81efbcce3e10a043706c74c42ff30e668e94b53f12eb70615289857ab1eef98b079d754e9f66c61ec68d56dd23b9bc806c6710357a1d92ee58e02b874474f90a619c06241a5ba212e60a6110e7f09bd3c4602f2e9c47e2a11dc54d9f8ab979bfb3371f85b99bf6c051a2f5fa64579f31538f959a56ad5099d741e40b4c985eca2a2fea2e28980c9056f07465c983e9fa28d34e104f13015cae6067451d4c5d18715e725ab97558b7f71519c013c91f4f00ae1b94e044a248647b6d63e0ff1ad866423770acf0264ba1bae38ba54540bfda09b51bea8c426b26292e241b03f8e86e62cbb982df0590a043c213b648e3e2de09c43af183918b224b74f1449fadf68e31b87fa1e3b8874ad883fa3f57958bf5580f487e35424d96689668d012f282397cb8470e003681f6327131c6dc5abc41ba6795657950729b0c57a17a548d7e59c09ab4d0af29f3986683963a4af08bde254ecee7d7e24f4eb820d5e11e1284ef470949a5caa0d59884b2e059cebcf42aac0ec87a4c2009982f7f2fcb6c54324d1ed3f1f2d20335d2c79e56669a45e0bf2094e53dfff22ee388b1d1874eb6261be6f441d1b61aabb25e280c3b1cca1210067228a29a52d5c10663d69b3740753607c6b92e4add07af47ad92c467bd5f150797aea8ad909f1ad4d166d9525968cba944c3a3b5df5dd3ece0882f273929ac009910aa4c029fb76bf4360b153fc4129ad496296b093fd7895225bd8c38ca9e6a13fd90f21115553ba51127185ab32cacef875f5d9485ff9d05d0462a440cdc5dc56543a210874b509ba6e118ad0ccc3e6f27f79aa521ee68c844cc89ffaf40c2c4923112404acc8365bddc685de4e41eeed9a989119f61727e61855007baa4f6d5aa47a6f069c7504953acaf19ebb02ca658da58c38e3eea0c710d1670dfd1586746f4bcc066990a6fe3f5c7b4f942179bb7f6cb3d0eff2841108b5f9fb6f0aa3dc297c750fbc9a532e247d09966e8fc9c3c08d3b93cda4d7da15ccb2c3d55aafaef7f6e720657e3b9c9a7aa110bfc42043b8e382020744ee0a38ffcbdcb176dace99c5782118e3412549d1e50c110eee24cf8a7ad5668fb5b059365b164cc6e2f9c51e7d17d578e1f940873003a4772cafd0e5e0fe61b2b818ef183d3c8442d4365671a32b2d023a91972ce6168a6cf4d6a9438a553c6dd4be9780dc514828202de442e926d2735a11b5e30445898962a6612abff243b02ecef4c52788f64ed2eec6dde32063b15d6e7b170e5159d78e57dd0649b116bdc9b3e1cfb2a5a713a546f7869000722c25bcfb1beac0e535fa3277f0120043a101b8116f60e8572a6325ac71bb159a939845b53d191316abbfd5228668258281c52411281cbdad0fb98efe18a81647a67703fc3259981967efe0e3dfb88f6e8de37db781960d5ad649b9cacea60c0daa9256ebac451ee59c50c337f68f1ce7c6c0b0d90fcfa20cb9ff0478be6a03e4bb40668370d05fb1a940ae15df5cb9c128c6daae54b73a0846e8a45a3bd31b6218aa542c305cc3ef949c30fd8234dd18cc5f927882215ab9d6d748b4518f04afa5d7e4c164916d9313b76d88b5f2d01130f40bdb3930412e44603c16bfa02751cab86e87f5a912d21a6df597b3f5cf207cbff7943cd983e7eedd529164f91fef3f5f440261cb789a9ca6899fe66a2b6f3eef2f821807c9abc02744a0957d1e2409b845583184de73db7dc7d896d609ef37de8b523289390b38b38f687f10026ec8d00353098475c6ded11fd4de5228422528eb710995599e5f284519ca7c29709736fe6a73c37092fc83a5737682a11aae30dfb0a6bf4791bcc7f63530341aa1b36a58ea685c0bc4aeb065dc63a50f54f0536a7364be2181f13c0b4d8cf607f474033d183eba62d93b7451932b6cfa092cc03c347474bf4906e0c8ddcbee13a7d725baf5ac8703784f84aeb7dd994e776a17c921b5d4dffaf56d4492fde123f2b26aa4213ed6ee5847ba93f0d779a0e33e9e76e9759d6dad50d74b225f8e0803b5466ae26cf2977d03370661ef5073a7258019a875f67b03e6dd5fd9cc512084a695aad7902800ceb7aaf22dabc4d9dc4479be57248513a57e0518b1223f1b313fd82807e35e2259298ba409c83ce0424f3639a13f759de733741acad8a10660a955e0ce6e2492dfe14637fea0770e02533eaadddd05d4d99a04f9620f4e106934ef962dce3a6d408321df0a65eb716ee892d98d3e1d6a347139e21b0ae81cc8a047185f77036988b57e5b11f79c73a9913aaa924c10318fcae1b8157a73162a5c5beee053165d8b1d1e2a63c28bd65a2a2384afeced0f75f59b2161275528e889bfd1f21d0268b13da9c623cc7ef6b36e3887cd85d9ff79f17f9e95bba02c644f4a592314c6e20543f17f0e5851cb56c4d8fc3494bc1db19de3eb9b7e27121ce1d4d7d89669e5805c2bce49735e67c217a479f00a31793c09b072cc379d00c4c5745c7492cd691c3b5a9217156aa14ba97c0143719d9437ed682fe6695a", + "public_inputs_hex": "0x1a207628cc6936816ccb62a7b56fdbbf8e975293b677c988644e018fc402e4411dfdc7cb6265f100524012f038ee1f205bf8789b70b46c57463dedb4998f7ac800000000000000000000000000000000a81b7087e1431ea26777fc20238aa980000000000000000000000000000000001991a803e262c7a38f41ff63f803b3c21806572c19ee2f3532e970d617919b3aa8cdc582782dfad0699badc631f75128000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021301f6e7fbbb73aa8fa2046f5a9854e60b7c72f0b56d2cdef4e3cb5e3d1a660b0827372d8ac27abb349e731af617d334968a1a677756357ab1b3eb22654a72340ed445f4ba59e36bb04bedc22d61894e7f47177273eb6efce052396d70477f050dd6ae6474cac3235c0eb911e38027c416320fdca3d180736d3a3359939e922b000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + } + }, + "test_exit_code": { + "crisp": 0, + "folded_export": 0, + "enclave_contracts": 0 + } +} diff --git a/circuits/benchmarks/results_insecure_agg_micro/integration_summary.json b/circuits/benchmarks/results_insecure_agg_micro/integration_summary.json new file mode 100644 index 0000000000..16442f414b --- /dev/null +++ b/circuits/benchmarks/results_insecure_agg_micro/integration_summary.json @@ -0,0 +1,244 @@ +{ + "integration_test": "test_trbfv_actor", + "benchmark_config": { + "mode": "insecure", + "bfv_preset_subdir": "insecure-512", + "bfv_preset": "InsecureThreshold512", + "lambda": 2, + "proof_aggregation_enabled": true, + "multithread_concurrent_jobs": 13, + "committee_h": 3, + "committee_n": 3, + "committee_t": 1, + "nodes_spawned": 20, + "network_model": "in_process_bus", + "testmode_harness": true + }, + "proof_aggregation_enabled": true, + "dkg_fold_attestation_verifier": "0x7969c5eD335650692Bc04293B07F5BF2e7A673C0", + "multithread": { + "rayon_threads": 13, + "max_simultaneous_rayon_tasks": 13, + "cores_available": 14 + }, + "operation_timings": [ + { + "name": "CalculateDecryptionKey", + "avg_seconds": 0.003899597, + "runs": 3, + "total_seconds": 0.011698792 + }, + { + "name": "CalculateDecryptionShare", + "avg_seconds": 0.020771278, + "runs": 3, + "total_seconds": 0.062313835 + }, + { + "name": "CalculateThresholdDecryption", + "avg_seconds": 0.019628875, + "runs": 1, + "total_seconds": 0.019628875 + }, + { + "name": "GenEsiSss", + "avg_seconds": 0.007804847, + "runs": 3, + "total_seconds": 0.023414541 + }, + { + "name": "GenPkShareAndSkSss", + "avg_seconds": 0.009254708, + "runs": 3, + "total_seconds": 0.027764126 + }, + { + "name": "NodeDkgFold/c2ab_fold", + "avg_seconds": 8.419060625, + "runs": 3, + "total_seconds": 25.257181876 + }, + { + "name": "NodeDkgFold/c3a_fold", + "avg_seconds": 36.69000318, + "runs": 3, + "total_seconds": 110.070009541 + }, + { + "name": "NodeDkgFold/c3ab_fold", + "avg_seconds": 7.678847138, + "runs": 3, + "total_seconds": 23.036541416 + }, + { + "name": "NodeDkgFold/c3b_fold", + "avg_seconds": 35.819565458, + "runs": 3, + "total_seconds": 107.458696375 + }, + { + "name": "NodeDkgFold/c4ab_fold", + "avg_seconds": 8.047481542, + "runs": 3, + "total_seconds": 24.142444626 + }, + { + "name": "NodeDkgFold/node_fold", + "avg_seconds": 19.279656625, + "runs": 3, + "total_seconds": 57.838969875 + }, + { + "name": "ZkDecryptedSharesAggregation", + "avg_seconds": 1.60953675, + "runs": 1, + "total_seconds": 1.60953675 + }, + { + "name": "ZkDecryptionAggregation", + "avg_seconds": 49.763333667, + "runs": 1, + "total_seconds": 49.763333667 + }, + { + "name": "ZkDkgAggregation", + "avg_seconds": 20.434941375, + "runs": 1, + "total_seconds": 20.434941375 + }, + { + "name": "ZkDkgShareDecryption", + "avg_seconds": 1.318937159, + "runs": 6, + "total_seconds": 7.913622958 + }, + { + "name": "ZkNodeDkgFold", + "avg_seconds": 115.937274027, + "runs": 3, + "total_seconds": 347.811822083 + }, + { + "name": "ZkPkAggregation", + "avg_seconds": 0.863779417, + "runs": 1, + "total_seconds": 0.863779417 + }, + { + "name": "ZkPkBfv", + "avg_seconds": 0.234095361, + "runs": 3, + "total_seconds": 0.702286084 + }, + { + "name": "ZkPkGeneration", + "avg_seconds": 2.564455153, + "runs": 3, + "total_seconds": 7.693365459 + }, + { + "name": "ZkShareComputation", + "avg_seconds": 2.554805451, + "runs": 6, + "total_seconds": 15.328832709 + }, + { + "name": "ZkShareEncryption", + "avg_seconds": 4.018045519, + "runs": 24, + "total_seconds": 96.433092457 + }, + { + "name": "ZkThresholdShareDecryption", + "avg_seconds": 3.493319013, + "runs": 3, + "total_seconds": 10.479957041 + }, + { + "name": "ZkVerifyShareDecryptionProofs", + "avg_seconds": 0.103515208, + "runs": 3, + "total_seconds": 0.310545626 + }, + { + "name": "ZkVerifyShareProofs", + "avg_seconds": 0.269947275, + "runs": 5, + "total_seconds": 1.349736376 + } + ], + "operation_timings_total_seconds": 908.64351588, + "operation_timings_metric": "tracked_job_wall", + "phase_timings": [ + { + "label": "Starting trbfv actor test", + "seconds": 0e-9, + "metric": "wall_clock" + }, + { + "label": "Setup completed", + "seconds": 2.96616925, + "metric": "wall_clock" + }, + { + "label": "Committee Setup Completed", + "seconds": 20.093379417, + "metric": "wall_clock" + }, + { + "label": "Committee Finalization Complete", + "seconds": 0.005040209, + "metric": "wall_clock" + }, + { + "label": "Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall)", + "seconds": 136.237549, + "metric": "wall_clock" + }, + { + "label": "ThresholdShares -> PublicKeyAggregated", + "seconds": 148.9261515, + "metric": "wall_clock" + }, + { + "label": "E3Request -> PublicKeyAggregated", + "seconds": 149.434793375, + "metric": "wall_clock" + }, + { + "label": "Application CT Gen", + "seconds": 0.009646083, + "metric": "wall_clock" + }, + { + "label": "Running FHE Application", + "seconds": 0.000103333, + "metric": "wall_clock" + }, + { + "label": "Aggregator P4: Aggregation pending -> PlaintextAggregated (wall)", + "seconds": 51.386342, + "metric": "wall_clock" + }, + { + "label": "Ciphertext published -> PlaintextAggregated", + "seconds": 55.335645666, + "metric": "wall_clock" + }, + { + "label": "Entire Test", + "seconds": 227.841801083, + "metric": "wall_clock" + } + ], + "folded_artifacts": { + "dkg_aggregator": { + "proof_hex": "0x000000000000000000000000000000000000000000000001fd49ea2995c1805a000000000000000000000000000000000000000000000009e130f8d07cbd35d1000000000000000000000000000000000000000000000002e5ab83f7a0ec41a9000000000000000000000000000000000000000000000000000180f1d364bc1200000000000000000000000000000000000000000000000b30855f54e294c86600000000000000000000000000000000000000000000000e219fb2ae146a494e000000000000000000000000000000000000000000000004d22012f74a7396a9000000000000000000000000000000000000000000000000000215c2c000275000000000000000000000000000000000000000000000000eac34294d15070d38000000000000000000000000000000000000000000000004e87191632119f7f70000000000000000000000000000000000000000000000015038dbe31f6ab0390000000000000000000000000000000000000000000000000000cf331e3e636f00000000000000000000000000000000000000000000000dd9f98878c5b6f7d6000000000000000000000000000000000000000000000007ee2134f16e8d33160000000000000000000000000000000000000000000000077df2fea764d8310f0000000000000000000000000000000000000000000000000001b58f64c88996077edaeb00d787972da96dd0edbb7c2b101fde53e5028931cdfa8158fa8937632cf53d683e41360f6e529b02d216642bc54fc3b5493f89225f4cdc35ec2dd75e008be81ba59678bc2845a0a790af2b8124f8730d49d964132d0a028970ab563a06cca51c91027c577ff402f93bd200243f9d344e8b2a354f1aaa5da3b43a24e11b6fc61db08de25bc5fd4bb73d7df7383cf857691020be5880f05c25bc8d19710d7eb2427e444196714589588ebf61cc54c552518e950b56b9a6fe08b9bbabd52b0db8963a40cc8dcf97ed101f513d60c9f7ce4bdd3fa84c9c7aa8e5706ef3af1cbdb85e131c9695dde95e1d161deca5430a0adec644f6fdf7c962cc0686cebc0e0f4d1d4c431a4ac5c17aa11206f288f79299605006038c506c284084f626822891b514eac670d39ab672fa43f20c0b65b0e10624a2e638ba001a4291f1740b24777273c445fe315e2193fb45060a7010a34afdaa48d5b4e215b66fbb18d3ba21045761d06795541b65751d20790ac3e1d74cfba39a6027cb9ac310ee2aea83024ab126d473d57e2cdcb9b5af0beb957c65d4308f1a4f7294a1b1ba16e047e50e92d2d26422ae9ca51949ebba20c96db2e5c1b6c8ba2898abf038e018d0e5f90d575b2f9b331683b451b53e7effee6c815296c427b181ae57448fa667f3e8d802eaa8611c3b5b5c25e74c64bc7f45e3112c669ef9f4e0d756670e89c34de6db2cdce2ee36eab74073def9ebb3fde8b4aeb2ee658c9acba864d80fb569c75a77022cb90ab0b77907d8103f901c21ff013851f12f8d4b6d24323694b2cdde560e0ad79dfa9ba2a692ea68660f563b9ca963f67786eacb35794db407e839a365a007463b9e1d2f0df8602e1bdf84d818a0395a5242aebdce60bb8bd4258fb126b52b9bb460323411c99fd5c4b42072c524a975df523f28156065e824e35dcb1d9c1f9a105ad7dc6269609922d8cae5d7c6ad37425e957cb25135476748a8beb332262959fdecd94ecff5648621ae55cb4cfeead8f1042dd04593040a8c76108e9a2c17f170d854dfbb9c9493bd58da3029edad3a4a5c2199ba8948515cb54dd87e14dc69acdfa3e5e67c481bc78cedec6e1af6ae498e8884c5482853dc3161a6dc1e301746d84e8d4f07dbb2de4b7789683203870a9ca01147cebc327a1f2a28e4273678b16eec7b05d7f220111d7b89455daea44633e1d1b73a1a5d698e87248a04a7d9705a4b7af209a598156203cb008220c25975ae7bf3c6e8ba9d3f2c678a09d66e4b7bfca0211c9e3a4a3114eadd1105982c019fa2c8520bff6a6a2fcb9e2cafb862a18a64b540895760e4cb1e8e82771188cb43ab3f0f2a81aa98f416c90a9aac4fba1a822c08cafb8ab98475aaace9e064745616e2eb1471cca54a219b0b6a7e7e884e9e938f7dbef5134e11e9a00492bada044d8eac8e1151a74775310af775f458352ce39e593aadfa030f8343b9c9cdb3c0a51eb8996724a40598f02d3b2758c53427318b585617fc8810f08e1aea10a43ac4d7c25fdbec155e32402d2bdec92c262abc30f56e45f1184e3b5b9190a16efbd59d4aeba4af3a9ec98e0c229a521676816c507fd4f92cb86b6aea59e8dd336b9e7fc1d7c1d38e4349b010332e0457598a26c2c4a3e0d02c20af948d75bbbd56465cc016af714c6ed89205b25caab1ef5e5d4753587b2c423911427ee11eafaa007459e515e54a2b068f128e5f87f9b760a72c83d37430c6ddb70270dcc64319d6416c3b30d37f80f4f209a81ea9f1d236a7b9bd55dc6ced0ec4e526908687831f3d95acd61aff8ff2372b0e2d95a1361900a977f9253a6c9d45f681e2f4011ff13db0c7219085bc33b223460a7bc760f25bdc85f1f16eadf15a59acd2cece7ca3eb789e926f49f7c786161f3e86f116612b5a5a429c31a1fa51e8fd9343031442f5c94fa2987182845a2c1ccb716fd77606020045903b109f92cf24f209754bb0f28a364db55c9b43aa2e51b7498f6e68e2abaf0b76b36d851b29a09217cdaf13c7ee7d0cabea08eccf11fa5693c9691c14321ed941fd08d7204931bc6e514b48ec12e985c8b557ee3708f89ec5b313a1f429eceedc627cbc8ac7b7b50086f6cd9afc75997bb3507c120c8bb726570f72529caf1535ee80af24f911081531cf149a92ed499a134b0eba01b8640b24f5cc592f7e79add4472256c4a49bedc5801a22b7ea65f8361e77ab2156b74036d7c9bdeaa69b37fdc5ec0b8dab05587f48e430f701e3163a917047170bbbccf4b84a16ea42894d2e25d01fbde3702619c8c38d7a06c6846f9ba67215ea2a312148e210efc156d4ebc28d6758efbce0d8d41839febeb131f0945fc01c84af60616bde2a2a4fa6d1715314c1ac81490793c91017a88de75fac5e20d3080548014b07a60120d857b6bf9f57967ba843d74a34204504e29671e4195b3b24281c43c58ee0b93d2af3f13e6314ecc938001ab4d296749dddb73ee17273382e2630ac48d1b66eeb3be980576c76ac6e7add3e4878cbee0724917f0ba962ff243a2e4a055851abd682ecf0908821cf3c1eeb788029b1335670075439c398190673bcc78e40c71398b948d57471fc669d174d2740c405199e6584f871b9e3012a0acab2e96a2afe838043a16becd5c3e687cc6bd2efcae982386f32962b7a88245310639393ccaa5331e97b7db1919bc2d50e86f065cae12b76b07d3348b6180fefa11f9b377c565b5b40383a76bd59af2437e9c72a05e49837b5ba60d7b1712fa7b9e47e883d1d4551c92330f85e8e8a3597879115735095c251d0bd3786bd22ee5a0c362112a3cd554387c3973d608c2aa579b5136e0de6e93d354f4c5a1408a644400d96627bd7b10ef88796326dcbfeeec6916e7462a5e90fd6e417bed428b6e56c827fee917c101bd208fba6a6a96b26c8609660036db1aab7fc68b01a0f050acb41424de2746c4680e9f50d6b1902287390809d57c071bda340980ade048787cf4d2dc03c343eca0db49299fb8b7e69303cbf16384971194fb4c68e3c2eba457fcfbae5f78a3ba7bd14147fc79cf5337190691398b6bd459251c131442a5aa476d922a21867112a84ae48ecd5b6fa90280f477bde61f721c68ee2d2f513ee827cedbf43918a4411f6845084504144059b545de93677a73f32296037de049c8166781f6e1424f72a05999f984b97fadc1ba8d10a7ee32be56c80adbf751ca15b8240f73f458e5b7048fa8db1c7a4abcd252e1f5862aaf75d9dc7ee243a1a0a8fc6f86b636a8616ddc653172189accd3bcdbf647c30f91d364c81c206962ff31db29a42d1aa4e88acc875d3eff57728bb3450ef218f7ce61a98e885b5772c08b80788b8e0221b56ffdb2e044a99df3ce955d77c486dc8ad7b19cc3f20eb2fdf6044932d8a24a9b47713da7d64bafdd7e72db9e8e9d1ce17c51ac428fc991f9b8d2ec0c1e7d1cadc63db8032a4246c2d93b41402b11ef34f0b3052e6b6101b1092f7a6d83b1aae323a8d093b0c50965514a1ccdd249ce909260d2e81ba4921c116c4dd85c556af575139c86bdc4b43305b9290fd471de29fc332e88e094c02253af4b0ddcc70e3c853ff8370f241c6a5af7a9124e46fb711d4710c8e0d860c83253e57c909cef046bded3d5ebaff650057ca72ed08a066a9dd3c5206d7f4293e361d99a9b24098ec04a441e46c7b2b8064dae8c70de8bf385ecca60724131d03a978a8f846bf6ed6b464b43514a9585a961de9dd2df10ef0ead69581821a2426aad64c076e2ef8c465ba244a8f3ab53eb4074c4687c2068724dc4dfb7fb40da880fa666b2ff11fee4198e828d0a81a16b67ab497f5fc6f9763c45cc5a3721d3747876e7d1f7597a136b34a7558eb5a2c775c4ea3a7d587ffeb9e363d52681203eb04847206683a5894d351f7ac067b90c6e2857fdcbbb0de3ae1b88c7e7025bb867319c0650dbb7199954bbb3dde0f1848f61f262b85139607a8194c25820b86479d8130ce090230b101052095e37928cd7b35cec64a52bf2f2d9309fa620a96840836aaa24508174d058c59d3243dfbb8dbfa910180139920b5bba0ba612a3137d9139def0d4c2dc96ead633a57f0deb2f385ef106a6b6e1f8552dcb04a1c7e438c02df964ad4cdf994b96bb5145852e4cff61b67e9d2207bd1f98742861128971620fc09258924db77d5849d4b01c133d5eb0ba35bb715676a8f0760b1209dbdeee1b98148722437e311c449871e52f424bf8af6d022cc9a8bf86c381a0ef751ddb94d31062c176215cc10a722cb13a3edc840154b075046e3d73a49511fa65de3f652272d12117f4922c89ebf154622a90cc22d48d852238d0d8f722a120f665f4406f4560fed8ccf003cc551e15a4619cf80218263ba803fd1f4f751188ce7efb3271294fd4e09cf38d5f5e94bcd90c48b69ba9033a907f50b9058f302d8bd87bf079867a8a7e546035a866bccd46a6b7ae786cf3bcb106b0ca4eea90e7a05252c11dbc7b11bc30a304735bde3abe0bebe3964700f93f6464297b8b708d1241352fe66286724eeaa7fe21b2a1b58fd9f125e39e8e30d6c6281e7177710661aee44cde894457f7694b7e7a097f95bc4b343132fb9bb618a26e7952b6d2db56ffb8b361ffe0789871aac4141603a1877b9da3b9cf0719a17683da02a8717c2b38f5d89e3719efa94ac694f52bc00b4a11822e900f54dfac530acaa4b2c28a91d4295d27ded396d129a08cfd2c717fa74161e1b9f7926288a32abce912e079096a999aad3cd00fa09f8caf340e2e49e665d4d008c12015303de4057f9972dd2677eb529ddbf4a050ab90c6c2c2eeaa88d9b13d277cbc7245c65e2ef0c42230b0a5b03a713209c518fb9ed18faf4b266b4f21c9977677bff73fa324431b70f757eda054f648fdf26a5211123ba1d0ea9dfd5d124e377cd0aa11312ffb0c420c23c32f1c3cdd37dd268e2feb48b54b0e6f19c0ee67a2ae7c01472d2623d1e2fbc69c45daa678a391a5504a0ed5a0a5e4cb250f36501072c265af823abb45b1dc5739f9eb5e10a37d356027db2f6faadfadffdb2ce7ac184bc7f997b53deae162a8ae642df97184ae988c8607ba165006f0dc926cde19a62ba777bfee040ad0da536704fe3046961eea59de7f504851c2b42f0948a576d02146d802592bea5296be00ec01d6bacdae3e08981c5d1e75bc6882c1694ddafe5f01450f0a019131667b2a26bf0f497d5e379f9e70b233d24e3d43d7ffa468c5d04a6ed530c07d20548fae6cd942426fbad40b064d09ba495711ff9ecbb7f8fa128841dadb433d9275b8602a28769edfc46311c99d70a33e6244c69d63d5f1f70312907faabe2b424ff92a16a1011d0b94ab5c70e20e3ddfd84ad4ec7a7cb8c7346a164394319ab2c7c716668fc8d1e4a01cacd713815860faa08a649f03d54cae0a85d453496f807d9c9d01d661377cbf497b95050d15852b24c069aefe635bd35329d9baa8f64108ea7e4af7d45bfd70af8aa9abc564b259e813614a906a560ee7a15f46cd3782c4257ad3ee80e97cb60726b65a4f5a2701c277e8edad07984f7c3753f6139b9276d4512a0541ea808942cf25dbf676e996b9f45c576baf6447a12bd93cffb930a398fc4ca770004b59848f3adedc44b1acbd0248ba516c564d1953f177e73eb288458a12f11a83a53ddd929bcff5c28f195b01cf27c1aafb14b1db691ea07882c25272f45280f7222fe7d7bff564dbbe9c1532e79807ca0d8709f610fdb292606b4d4023d10bcae31fa0f6389085e9e291905031f7c7c07f726cee059974210170ff701c030db637dc65b0c4855a7518fd3f6e08745e376cb32e37b932ae0ad0c5e118818c267aa7c8e9603614da1384b8cdf398b5afc98449b5f454f40b16b02625cbec8c5c8f6e191c0b5fbf55c922fcc68258b33a39ddf72c0beb9ac218911081f65e7af22fc123c58adf831317451c202135ac4d35bd4dac00ddd18f5692e7345c12abdc477eb8b415fda1bd3b6ff88009c5b6b6cf9623d6df79213a82c055506730507438bc795dc759a7c4057b3aafcd52e3d58cc90f9d2709add84cc01b3f56a26ced3f69913748de5d3b4c24b50051ade9e9700dfa8d1d0c5f14d5d1ad7644a107beae994ea0ff4532c54b89514c2d06af3d634ac0a53764eca55210b2f46facc611e557559920cf65593b6616db1eb394d0c20b040ee8a4b48537e1198823ed6cd160de66eb43e9022ffa950caf79c4b4e405d325b8e69bbc9454302ec177251fe8cb4c6c57542b2be93f91666a93ae052a355a731f806b16477b82d44c4d0b255663e6b548a9d8f69d6cd9e2d6a14d12768e38847a5bbafd3b94020502aecccde69569270bf06687f6617cf3eb0903c36f0449823d51a3393f9de19dce60cb1aae13a19b50e34b65ffbc680f412012ae0063d362a77c85be265ef2c7443d2dae210dd161a8c217b18620dcad17590cbae456a61d250fdbba547fd29b3c7854a3a36887dd4ec8c4e93e56907c62a4140aabc9da587617f961fca8d24d85a8c59e11cd64c84fea5e13d586d3e88fa439507f58e26d3c317a8bb7d32177abceee45d0b521eba525527ba8d739426e9c7f3e695a68b59414c0265e9752805ea9635e406b084a400034ba3da86ecc6c4b6217ef5fa2dd4f344913e08fe059c5a303964df6df32cd2788e65facb109fefad82dc156fe1c8b06aa84bf0ee033b4f7d9c3773cf9376080223b5c36409f8e94cf3d3f1d8c62e32276b2112a219cf162993c5c1e2e75c8d2167232efd83178a7570c0bf482866f3c0ab3d16dc2cb07d71751a27546ddf0c335b0f31edab3e88e7796d9347733c18786d5a570414c29fced4459d8dc19627c59aee6008f5e140d510490357cd98931a93de019217ea68fe14ac058df3fa9e9cae7727b03d933a66a23e217e97a5be9d14c762ff034f3d0afadfe715e5da693a3140044e0f392e07659b7fdc04c2fdcbded6fbdf2d4a4ceb366ba2ef2abc371969dfc1735ea35bb48f927360d3059877fd3631fc2604d08c98df80b00821a6a7ae5c5244fbd65539e4af2c0e50d6992fd4fa7184076abfd3c49e37a997c8db51c9e0cc01f39c1afcd92f34131292e2700f8a1957198b7ed6cffb3a7c201fd6ca40409bde83950f8de3f35e81d9fedbc3750eba372baf58a23be51087dea664645af910ca2c8e5044971d829aa0832cb8c72c574521740bc1aa918a1109b5bc99e0e1039c6e585e505a9db5531b76a4bd14a8b1442e37c1c4dfa7150fb43733a9b157c7a601526920599572946feabf80137ba1ad2322871b6aac745a9f874b9bb8ef9ee182a3db6d33de228bca5096f018e3e8a9023650fd0a202af87cfcf8c29efca5d3b980149ea855d69489f595554fb2f23c29a9aff0de611a87627cda3c879b542baaa1677827282a960542661baf13045c14836a3abd071e95bb8e0954b7655fba14a5712b67f5c2a8b44c8b2d9928fc6f0e10a87895332d36c58622031ee8d2d6ccf1973c0c77042c42d618a3dd2c9e512473afbf6d4180bac27744f2881457b5c9fb4b3ab84b4cf8416f1a8570899ff228bf7ad3970337fd65fc3e884d8fff552a7824001e73724072ad01b639d82f630229f0c3b29a4844d16a0e66fd9ab50c1a2a4c4f388c36143449e931aae4bcc22bd450a3e3bfaee4a3102afd669ba6f1b9e9e8f3404f8905bfbd2e49f9ed48db03174c95e1e7078a63f676e989df81004ad1c1d818676bc710aec939c791a2170f20a480ef9719f1f4b7e93c951af6c035835d60e312d54c3199a282f5da2ad40bf4385f43eae8609d03334049837d361c4ab902f4bdc2f8060a51888687db0a1b0af92cb490eefd3f631ad0a9002bcc844b686dfd15ee545a2d408d5b88e9f42171fe53d283a88b7188eb944c0cfb22d8e8f8e667944b5c62a1c7f1adb65e520b864b06dbed7fb1a6c446e24a39a476820bd68ff5b1d23584fe190a99a1e64724b1dac25560fdb393debfb31da4470b28448d42a031efa989617232d2a6ee2b1c258020f28d1b98e3c58a6a66fdc9dceef00668e30a409a699babce4913ebfb0dfaad87dfb55c5852970a9e232469b152967bb67d84b6ea2cccb2393a9ad06f06e79ef7e5f2ee98079b5f97b152dadb8e536ffae0af9209b7e97a18a6eb2a322ef63191d9f65612edbc1c6e9d997ed8415faea2a69318114dc55bb2256f7d522d88aab1575bdebbabb5c233d83e80258dadf60a1cadf436b1ef7536a545a50924af2ebeeddd230c21a822f1f1a1462a7f721f84702e55abecdb1d19adc11cbc1a40d54138980ed32bc41efc10e97fd6f73693807938a5dd3d094630acd94db10dd62a2c9d39431ee742dcd012aaf7b9b05606e9763bc56dd4ce73a00055cbbe2b1b95a359abe81c0fba341e408beb4ebf5fcb99d77386ae932f46597e059a652132dca997945d68bc03f4b8e6fdba705a4df8d264f03227a1d2417dc653698506f05f3ed316b551b2308c5cd275e979b84b05b00dbadea8b8c1f07a5dcdb5d4031bf03e7614209d0576cf3767c632dc3da608817b46a002e256ea39efc23c9f0b636c1539a4e8b2e7ead1b0f0922c4226513eae31d34a5c23aaeefa0c1035fd2217a8a1cf0f64f5bc124d8cdb72b7c110eb58e3895f987dc4a9a2f98cd43eca04b9354718910b3db7336377fb91fa15ecda37a5c97f4e0e845fb0b697f883c51ef3cc44eb53eadc94257571d17b8b2d9664ed59069a47d20d7c9f60c2dc2bb72589069de73a880be8c2d3dc8af7b126a1bfcd539ebf499d735976c4f9416dd125cda14c2fd6b9aadc9fa8e8742674406c850640b91434dbed6db5f6f955a45203f22c60fae57f247f5737a7d76d1e8fbb1c500b0a74103cb671b24a11773ad61ffd241db5e210987b5e0f4f684aded901be922f34095dc04db8cf2df743f08a2e344da58c25e72b35ba59db4cf80a8a405f34d801af11c44ea66a7fde80cd780ec70d8c6f21002b9ae5a48c55d4eaab17fc852ededb4fb7612793e41681769323a5ce7f25cc21e052cf512ca46a3e7d88831681aa60bbdea745630e53f0ba2a0b778aafce261c61c2b2735a8831f86673336cde49256abe49da15549eabbc37047e4676f2e6ba738e6b30aa7b42a99b3d446e938ea33223754a9f7fc73f8e892b868e2c6999aa25e43d53fd63bd8f7fe3ef79733fbac819dd9637b0960086a0244a05a8b2b7f32a0b15e666cd1febe8132991cb7b0ff170207b222e4cd62ac826db1dbce473329f0dc729173335506d3caf2b6c2d3a0390c2d7387e92b875850565046bef359a9fcfe33325f12ac75c3c655f4e21de7ff860fa67b6afe0ce390262e1c1c7fa0c9805fba8b8305755f70c1604a914ae41989a70318a63f0535b178ad7aae2288338fd806347b82943448c52c16da16a4c627f69aea4711e1db02ae912e02611df5100590a244bc928798d13fe02c7b549e060e36a271f556a41145aca25895b56b415c9d11281506c5255c43f0a0da9cd112962a4a1ef37f7842cc962938de54f19839eebba286c3d05d87c64b22667e356b168023df18001b70d89289947bc9fcd0132a253beeff9b1098d308094f88e798eb8756304917799135a1cad102a521af6050b358fb030b2ee513e7d19b214a1956050f85fa6f8c5212b8fd410b568adcd7299767779a372332406e5ebeaeb7f91ab37c7a480b51c09bccc0886917c3cc20c864ed96d4be02a4052219f904fc82992cb9c331c569816ef560c14a12c8a4eea11ee769ef46b124dc807b63015ca546098df6e6a16612abc9a2fd6238b510bc4c17a285359ea54583c384ae62ce76853124e43a9154029d7c520e41153b7dd343f0d7abf1c5220bde7bf5acbbf388a8d92c3100dd9271840cbf35b3829e7720df75a541f0f80423cedb23ced4e458c827ac2ff4e5bc204d8f76b69e4af9233c6965fd34486bb6384e35e4fbdfa557e37e859aa9286db27ac09426cac12567646aebc490e23eaecbcee175485dbb0f7473260a683b729096cdb72801ff55dcf60c26aceccad0274b30697220f5794e03320428b31f94c212aec9328b9e7d0e94f04173fa15d5c975b9993be40b68ebc56373f134721521c4a577a9469eb0c82b41ee48bab8feb84921bb8b8817fc2c6922a6656c9bfc7295954bc31ebe7e13058df8c65c765bed2e0f539adfa3fa1155e295b2dd7c9f41610853333dc74f9f586aca7724f1be833fda34ac29248f8e1c2e1f55f35c408005784fe91eaac93552a5583ecfdb07dc455382a4feecad5e0ea3a6037a3bf9f2e5a1168aa423832bc59965a9fb8d3fc3e4d70105170f5e1df8a269a4b960a8302ef2418b6a730095d73fda3d93f0eee8f2f8f4be4e509d6ebd50e5635ba142802125bd0c7afb84d93c47c4b97c17a5fe600d9a0b3dad54aec6cc7b120f4edee087ebac3ad362292ba295da087132bd932e8effce9cfc1ccee32154b81d601d50994b7bd9fd26dfaa7b9dab924162e185db0f748409770ae64782c447f469d5805cc69bc75589155860294f5a034495d3ae3e09ae450822bccf3a102d1c45fd71d395aac77280661e67c53d84b2b54d4f8d5b463b194a6feed38f1410a22bc990301c57a9c377515d508ce17531560f9430e20b6a2b3cc32d83bb6adbfb2de06170c93eb7f359b3e7a43b193d199f960f14c76c9a014bb8ff6943abf635594130789373290ef2c99000271cc417a41091ecb315478c020a26545812048ec1fe82c1420a8f5627d159eecc865ad5508424323165990eed29599b667fe076289d317ecdca2f802326072891f66f220cee8dc73725e2cb3651f85d42c07eb9bd79c261fc099cfabbb7c637d98e8eb3e1ce7d6a32b22a27e12f9d6c53c2d73d509ec2783d739fb5e079f0a7a3e9818e2b3eb0a5356043c05a3bc5a9a977865d9f5542fcc861efcba31be85280ca013d7f18f62ccc24f8018b60057536d7b36950eda19c4fdfbafb64660fe8d5675483ad49b01162a25a492b43cf00c6d7dae14b2cd2472eb6bfc77291b5cb46d852b9e4932c5a2fb92fdffed5ff915fc7f70459b1b18fb25990ca267319b5b37c6fa91d009aee19b3e9262b363b1e9613298edeb0319294bfc2e5978d4fb62e930ee84c478a6dd17acf6d6d14c01b0829180cf3d352822de17e8a508ceae2804b577cf25382714318836f288c434fcba684506ee27240c4821bb1504a26ff7dbf76dc53dddffa2a8fd185d4e74137c093c0926634809023f91f5b1d22d19b7708d0276f1ac904d1df90443a6feed3f0e58de3c57e71a84bea94561f1c51424b32361e96ec955f5797d3144be8c8f229550bc94fa8f1df6afb0d8842227c0cba3199c994e658e6746f9768093c95930862e3a0b56ac0c1c932e4bf356017cb2ca19e29be7a842b152d800ab0aedfa834a3c7d52a8c00f55f6eccfd21e6775f704cf030f8bc93c9b9f3cdacf89cedea1f828ba2a967c2ef571f0d8981360cc509a91c5c2bfc406a7c72906303d8d8e29c6abccae4cd406b0d0da7d2529d7a8cdb4dbbc5142972291b660b547e2afea0030d70045bad015942a73853124febd5be8350b3d83037a6b57ddfb1251faba5e36f34f01614c2cc4ac0a2353e74a9fcb3e1207eff81c29b29a4cd90d839ac0303ca4dc3c100a1309c1dab3e87b68141dc7e282f96d2913b3a11f5101a2dab52b3e4ad02d8db20ffd228dd53135b5f9a2e5f40efd33b2bba6caaa5579ca941e34290a8019ccbb0c05d9492aacfe8444ebba8ea2d51cd95037aaacb110ae0dd86a51ff39a4a7cf1ebaa014bebd420901a2aa991e18795c8bff01cb64436ade5c1720fff5defe252c89a6983fce2e13997238b6c375cd5838163219451cd3d6a95d617a3757e98627baf0249e295fb4a1cc27f404f1395e6cf613177748c35b5fb9dc002f5532a62e7bd8bac7a6e5374a45b2c066b8dfc9a40facce7765aaa525440acad0513cd71e9ba1123a92b3d6da0f6a6e4c29ce5ef71ca704217e6c985ae5c12409c83b2b2ccaeca49db869ce155e16b30675acdfb4e74f236b7abbdc3b25bc6654aeb3cd0bdd2fa5f0e8bde0fb255102c9980d85225b5f1122ac38bdfefb51ceb05d453f1772c63be41b33fde57974f26a4630df3f9b115b032591c02511255cc052375c145bdb795ea0561c0e86e47f2c40745beb4a9244543a8d8ebeba6553979389602296b4f2d074bd2251c2e7a693a2ab3efea312b8517a1186811cb1703d62c60d1e5b4add004cca09a56964444396391ac57d653f33c2cdfc44a6e63bb5bb073927613dcf926775993dffb6ea2c7e2f2f6ddbc7f534b6f023dbb43fb40518741e0c69103cce484b13de07024b6cd9c698e83d0829fc1dbb5f8f1ff8f7b4dca69a0eee9d7777297b8ae2276377c82b930dd6908de907c96815c2127f4446371dfd013a464b7a07c13da0527242c9f3e885f17879c6004d6031c1dc37a5308ed1eb2ab46a965af357c739981f9aea280d8fdeef48dfc08b31cfaf5f085764459bc611ec28126db3fefb6cd2e5877fa445354a4a3fda6568e11050764a9f17a33b770d5692ff0ea347dfde2feacd5f50bffac4b852fb04f3cc7be151bc6176433692219a35ace66f97b9ef140eda3e578da58e12b0c4d0ca5bd24cec0ad9de1f0aae19c2823c4d79be5f747898b6c1612659254ad4980954587145c25bcfc7bcd24513fb7fbd6388193b305c1f34d893636da9e249cab876bc6bee69c68ddb647f5c2570fbd44116ba2c6588b93e791d2804db739151114201602c986f95461869a8230689ed1771845fa544d40f0dcf069039547f671777d8adae4ba0da5ac598760d03b4a0e2e2debfbcb15663d48f629c06bd90495df5a05c07a4aacf80db859c09d245207ba23e0956ef6f43f3016cd3a16916134f0f30e7a9353c7ecb525d6a226a4d7b349c6b2cb215c1333ea2d15d89f46234fcde79a6ae903dc8194549b92bf37fa219e3847fa332380b064dd59f22d5979687959c467a626d72bc67dcdb272daa654f1e5de7bfc1753944c74f252b10d2a4ae5ebe6a5f8394bf074393d902c6efcd5235081ed472513b81daf4b503e9d47c61be4c45703cba89ebe3347a18a0a87208087cbca1983ff1b3e723d251c254ef889b459219b56c9de83451f7094e5686ecab23149bd755480e155babc78e1dfeb981650331250ad50c773c662a80c521d5493b6b56f4200127656346cda7705b9879f7cc66fe32096dc3b29627082dbc564b34ba021af2300fc84ae6f1d967e4c230b6bcd931e90f553dfd6728f4ebbea547f837170d218c2d2e12abbf0e8721ff8678032bf4d4d62027b58b0d26234f32b61b7c2c7d91619375132318e552b6703061f0b914192b04347c04202e8bddae95e7316edda12a71954f1c0704256f60a180bb3945e00ff5edfbd2056f61610e44aa5d9c5c74efc9720ac89a5c3dba37d12ba8e20b6fcd89db55a72069e3eb9892988392f3185035c36a5cd1aa98553e0c6524378377dff4550af1272462c0881513c64b2a36304cbb5f0673f25f1b2c23fe37cf3f61e6b7f610041ac1b1543baefb5c05f8e135161322189fb52dc0f48d205a1b4469d3f47a6768244ff729077a9e0fd3eb881ff244c1c6a1e034518c85a9990aae5080cd3285f91d23bc261f6b2c62274e887a801fb717eb48ffc0394b133bcaedda178d35be6021282281b29500af25729a69d63df92ae7a38ed24326954b0028d91bccc607371bf84f236dfb952bf8c507b41c9e02828eeeeda60fae8e851939145e2f31726f2af3ec7f3dac53b2ab60efd08863f1d8f007bd851f6a4415949fd7877fcc57221151595feadfe852d6a6104cc1ec027efb3a9bb0aea0bf1b6715826bb2d8712117ec6ce953cdb96931186fa1a153382393864e9da9ea6c814d835f9f3f1cfa0a0953d6acdb9a2b0ee74018584e4b68f0e81092b375c04419c008ea6a44f37e221cdeee906342a11f940350bd5cf4d30deb46f036619ee91884fe5b64189899411adcae708b69806db24bd9c4ce984a56a5761faa3befa8009f863b54a1346e333025e5975353f3f9f00372473e4cb843e9c3027367a9f3050f91563f19912a9b08ffc15b607e5786241168cb7d80cba40efe61cce234f567c163db710e5437720dd7a6cd1d1af665c65904142f41910247881e72c2a99af525c79b3944bc526a0c60c553eca5a1ba6f699890601f6bea59f612944687067a49eeff6af4cc194626a76ae13d56d858c1b172cca005ecd2485f74a469226a3d4664f4d4bc8986b11ead53845d95677719c36ed2cda007b01139be8ad9a496eb700a8f25203d091f15cf780427ba6f545e02c59df445463b2af51b6b3f7381276e6acfad2dfe6b0d2abf08e79e7052e6f723908e5c65f5d8fe6cace05eafacda5533ef8f894ac5160fb90825ae09b542780386f8844d77ae94cecb831fe9686c93ad0fc1b0d40ada1cbbcad58aa5834ceb17b57bf4c04a7e365ea6bc52759b30caf849534590eb3f1a5b815544cf5a2ee9d2a9d1c421347892aa0b527caf180f6ebf4c0c0f9d7ba6143e0e69024c0eb1a32b8ca2315d67fbbddf7d77d90250a9e2909cfa7d965bb4184e1975f16650a489901c9d18270414efd99e1557c7bc31aac748da48763aad10bcf3cfd2dff30bfee0d3517c9653e506aff2b776870c108282eca658a306402393c386217d6af987707aadb011bd56c1524f376166df9784f42c36004f36b106c2afa3130f132b708e79ebc8494aae79f21e15f24197fce5790ed32b7d4877", + "public_inputs_hex": "0x2138b0022ab9af3c96b082bbf307bc9e79f8f1401462e3ac1cb3a9913a5b856c03d33039d45432d4999b9964018d8d6552808849c83503f50a70d594c01b441900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000a81b7087e1431ea26777fc20238aa980000000000000000000000000000000001991a803e262c7a38f41ff63f803b3c202c2cf87674c88d6103108c767ab2ac48e35bee25bf5e92c02761b47af09b71a1301f6e7fbbb73aa8fa2046f5a9854e60b7c72f0b56d2cdef4e3cb5e3d1a660b0827372d8ac27abb349e731af617d334968a1a677756357ab1b3eb22654a72341345ab0ed28ab1183dd8d63e3beb4a6335b88bb03a12fdf4bd39c23c8ac80cce0ed445f4ba59e36bb04bedc22d61894e7f47177273eb6efce052396d70477f050dd6ae6474cac3235c0eb911e38027c416320fdca3d180736d3a3359939e922b2811e91f225484bfbc68da2f299388cf367b3de96e1a14934bcfdeec50d9cacd2aeac2bfcecc16e20fe23d8faa581b380bdf19f50db602737bf9076c967d4a63" + }, + "decryption_aggregator": { + "proof_hex": "0x00000000000000000000000000000000000000000000000d6c9a4126c3a603e7000000000000000000000000000000000000000000000008cb1f7bf2a218a271000000000000000000000000000000000000000000000005220283c0e4cf6a610000000000000000000000000000000000000000000000000002591f9a02cd3c000000000000000000000000000000000000000000000006b4d77dbcef69b44200000000000000000000000000000000000000000000000b66320eaf86a9871f00000000000000000000000000000000000000000000000cfa07aed851a7101e00000000000000000000000000000000000000000000000000016c1cb8b2fcc800000000000000000000000000000000000000000000000f6b54c12ff26b41660000000000000000000000000000000000000000000000076495127c7c04d56100000000000000000000000000000000000000000000000e1ec3aad4e5396ed60000000000000000000000000000000000000000000000000000c6ac8a0fbfd90000000000000000000000000000000000000000000000041e7e2af39eb6aefa00000000000000000000000000000000000000000000000130bbb0ec2348df5300000000000000000000000000000000000000000000000251eff1b962479d7c0000000000000000000000000000000000000000000000000002107a5bda7e69199f2a94bd552a20234800516d5c52446581bda405093494e043bdcf1801a76310ba6c8e991f0f1bb10efd9ba15e43b131799be90a874af8846173da178d91200e38f0d23809e4d22a0a3767df9079919265d5776dee38416f9e54d05efa9f21026b6afddc8486b2987c54a70a1fb90ce7b0dd72dda6973dab43142f3b7c62bc2443e268c7406b5b01022182c3afb35673d07f621b0bcc7a747e62360eeea8861a546fa7cb23c3a401f794ed59faacfc55d7765e050998d9ad542712f29da780041ff587976aaf1421ccd4435f03007f6c37e7dafb835f0a37406ceaa510b1fc0437344273d8e01c1a631f6bf40db17dc5e594cc1d8e13419d94db116a6f63ef2b25a3a0f0f43fdeb8df3b943dcb414dbc186b40075f9dd19c440d4f13e2ea4f1261011370f9d84096dfcecea4ac545ec8bd01b2b552c415b27635e12737dea80af400ea25a45b8a026bb811f5f77e6e5e560349bd500475780f3af5ba16dfd30fc3ee3b89fc56bc2b3f2063c45ba5122e78195e3cb250a46c151bbef8bf71231be39c0dcfd76204d23ae6d83df17d8388410dff5064eedecbb755b8d52a598708e5eaaef7ef3968626bb7989ff7b194254d91d19098ef22fd8fc7cd6c97da8f25913e0cd96488d96dd964aea8ee93c7b50a73328f986c6d022218af78d87d921f33d4df8c65a0de3880854b70a6fd3df79f4d46d652ba9cd18c708038152e9b21fe174f0132d48a6be51930c56f8675ff96a7501ee1345d8983e3f2efcf4b3d0635ff07bd1b0feb29b73fc08a8e6d44bc17adc0d7d721057573e78b494863ac113f7174975f5f8cbdc3582841f7a981ee7287554fb5e0904fb2f26d9d059c5802319633bd5657d8f256fac6d8270e2b0e700311c79cbd1ae54bdb995626e4e43057c3beadcfd029e9fc48b0cf9556ac1e2b5bdab07f3382b71da4cf18bd26ff199bddbe6d355810c13d7c8497215aa1553a7bcd65c2419e6c49743a57f9172016cb4480cff30256429a68654722c993e0cf5d1e02273253188f6e0f2fe02b831c8dc40c2c8ae783307fa58ce6b21600dd9d4c3bb32d0a43cdfc51d857632d1603cd9cf7070c6c25cf6376751f793e33661e47138e502bd104041df30e46ed8916e2935294fcf05139704ef7e4dce91000022db750ffbe816d8682c01735553d0fdf8965d9f0b60a0d5942a38cc0c8cdd801df32e6a3c32f715606733db762c1170630083b9750f29e2c81801a47c041e265cc098a9b56fb71c880f9855157a90b5c006ee62f80ae2f4502f3a9836a0f398fd19e33c30b011925034d2279508b2fc478e725d008b82a40c48b2a0e14b6947b85165b0421150a93e5c3b9a90d0312ffe681ca700827dedf57d5e1ea269fc6aa78d7d94dd5569ec8acc6356721951df72cd0b0a898b3e27f9045435a934420c2f822442973bfcfdf3d70512cec520409ba8be9c92513ac863214905b29b828a06f6ebbd8e6fa38e5c741b562348e17bfabce3fc3da4b3c11befccfa4e1ab94ca6ba8e47a7d51670c5d445a695ca90b41b8163c2ca2ae3df50498e4ba161d1cadad55432b1aae3c02b9b5a3ba5ef6051f498e2af0bfa316f0b5b7294aca4a796a3fb96b12ecc2dbd30eee2f8914e9175566fd353df69a6b30d68e43dc4c73da4fe6b118d427601f2a1097416ca37a2ae870a24a6bf7dec462fc575c31b3e3b27afd9d9f487de88512f8568aa7b9af033886004ee63dd5244a2a0a2a244a3c12c276760d5f7b661bd55ab675d0788e0d2010921dd6930d887853fc2825aa1d4f656fdf9d6651ad241b618c67aaff811f67ffdea89b2d84a49eeaa676c46f87bf1486aba21669c58cf79984e1b5ad4e03f2d2a7620cf1dc77efaef972101aefeef67dfa6b173e359a3c8dd588da4dff0145a95fe6ac10646b4f0039fc29404b9624bd376e7aa99775661f66a13658ed14e6e8e9071187e03ff2ec4197a886923a6d63f398143b8722f4b8d7e40621330fab2dbec944dbb294003a13275ed98772a2bc7c0309bbb3f267c62928eb0bb11c2a818c976dae9ea75f1db179da83afd5fab47a9d928b359b8296b3e7c5681e17ef34746579024874cfd4a2e91b0e25923867f0d683e60629588204b3f436a90453e44188d45a90441ee017dcadea9436511978d98e9feec41e6b4b0f64c9280bd57cdadcc695310630a881c2b8c879e50dbbf7af09b160e3af7004a412562b293932c7eb279063afbf7b5e7e29612bd37742ed3e78b96625184b4c2ff16ade00b53c4ab08dda1da933d9cbff8684f0089d20a9844970ebf3847467cd601f170efd71790b8f8f52899d4acb3013fc16a232704cb553bc03c0bf865bbc23e6620666d9e72d6636e942cef862dee9fba615c2c22f1a34c0f8173e63b12696718b19f9622624b218fcb2d87cfb2d1dc92442219873c5b79af021e6f240b1cd847c1aa40e772dd587203f5f419de22222d938236825aed8171228c123b47843a74e0751ee5b40ab328d7a33a98cf24eb02ca51c5f2023f5fd95fa43b5c238c096ac0ba82b1b166abc43e4a1b1e278bb0dc077809363661e34a1c30ef77c602a26fe28e63baff200a767377346995d6ad4892217a4896553be0ac025e1ede41ef53c0c1ab2df79278b24ad61d06ff2cf1e99b92966957817fa789565baebc4a9fef22c02e38b7cf2d338b14dd6bc9e9261c3a84358cc539b268d7e96ca2a560d62912e053dc8801b13a56bfd925be4f10b74a2d33db592593fe15f5b6ae37456a3db1bb592240e3c0e590ba7c7e570df56c52a8503aa726b9cd5084ef22604894be71653cd1372f1dea72ea6bfb27392c770c26eea1c428c34d2582e5b5113389b1327eee91a17d2d318619887eb7a108180798422b4e11839a665595b54dda52df423d6f85f95466bdafbc0b2e538d53a7d4f733a199c2cda89c3dab1bc31df32c50ae7bd187e664d05a964be01278b6f03b6c6da1432a6601a8ca27279f48a83d820de21149942e08fba15ef61f8f3c0260c7fec1e896f45fce5f717e68e6ad2e300f38827fad7d0591c8ecabb0312d20b4ba0d020fedd669cd16a2f249156de381587ff4a99c4c13e53f8186f56ab498d45067270751d5987782280866b8e377e034e8ab6590cb70665fa7966e3d4bd41536809913d45a3cdac73d54ff80d57b92b7935cb1c6243785dbcce5290f25c7cf59d6797fdaa8a2ef5edc5b8cda7ae7c0e04359721793eed6b29d0e1184dc50ead2075cb3569f05088fd68cedd4c38c82a5912260dd73dace2d9730cc8a448f9d40ebf74c49e40386bc6fcc0e1ea13e922cc424204850dda1c80424c5f4e70415783b45deb7a73e5ec46d53eafd10b0d2a4e6a15f72fb98d519fd708580ba6fb60d00cc7bbe849c8e5d574c6363800171605ada29a408f35d469ce8fcd5b63cc85e07643e6e9cfbb9159e74a85dfd3be0a6ce1e71fdef69fce06a5b6727a42a067ca81b7703558c0b1a8633ed66a5d75153bcea20e7baeef5ce7809e9b8c9f45086236128821a9b67b5d6ac74bad8b3c29f163c95c73b6f42f5807f40b55957a876eb2516a2825c8fc72f236778358a10696d52a36de7e93b3cdd1f394d5468ca71509dd2cb1afe0ca81276bd2b6e0681b663a1debc6de673483e96ce68c81b360440963fec2467d817d22c0337418be2e5201dc40241fd68105880e2848a822ab5bead6b956cfe38c37d219d1b181472a0d5868d78fc5d850c491c9532d1f59668b9a56026d3961b0611f3c5104579b265fce9fb13c67f876520e45417c923ac9aca521380e224dada03f9ebeb77c0d10f915f95affba13b231ba5543f85eaaa0ab392a90f3e93e4d252747863c86bb2b3bf82bad04cc91244f5371a7d0d68ab571456e77a3f6ff3e20cdb96161a3a00cfc8472c1c127c63107a7c94d23f8889452efc2ae6169659384855065b6067c2b24571e4896c3f2dcfb11d3897158601a0b5471282ab5891952b06321c532ba1eb386862d8d3b0686a7c99c178b5d3a32c7366ce8b8ad1062b6abc970821e2700469ae25a747acd5c3c6a03af6c7e85ec16627ee42b81cc9cd43aabc2416ab8265f5ca8f478c6760cbe3113c6b93497a0539042a7a3af49921ba8665c65cec32fb368ded3f4d89f8bff985f141b608c2bced985360313e04b7e19550d6df36806c0a29be7c7b37c27266eed5abf57195d855358db574843efe2a391b89ce88a272a33820cf99cf2088d8910e313d0764bdd1ca0e5bb2bb820c10c95b3c00b45250702d02cf0b3ce811e4dc5ac5b66b362325c9b68038cba8aa5232a79f2f45f2725890d9df66abf32181f24ffced0aa242cc221894a4d6817d5020394a9360822f251caf9082777de6b2b15f498232343238d0b6e90cf6921e6c6bf4d195171276bccae75dd0e48d618a01ec2ae7991247be2be45dccac73b20c9b2053c77171c28b2fd03c8d84440375e372e41ff6388f7bc589de81ea6a1d7ff4e8b331edc04d4168c04e70b35a450c4afdad791a4fa3513b19d276a0fffe50cd1869dbaae213a8ed73c39708cc2a4d032ee933f66e1b87e1973ac316a2026597246b14ef418188aab93dc1cc6e59a141eea6e7720bc28ae4c8e2958c129122b2e04399ff41063f60c4decf651d58774db8f5b881b26f22b0f01a672bfea51bed9ea26faab04a2fb96a880434196ca20aaccf4c97788359624aec9211bc108805c85fc3052288af408b04b4fee3556cd03541fbba5d2d5b14e0f6f828e13e2ee735093525800959b3fd7690e499cffcb85593a4daa08b6fcb8efea6777fdc54e28727458c81ade87c5fa2af0051347096a16c332beab21ba626d6e379b103ba7e543f6f5bd17c14cf881bf41ba471b821338b2dc52932f26363119366f49d4128833dba8290bd01fd27ee7340f46e5e7a624ca523c38def233755241c181bf12196588dde9096521920f4da8a2e09564ec78a72d92dd426bcccb070d4584efe10a39a4107d1438277c3f16a7e143ee690e0a852c9f740db2b8b4b41540f846d2aef734ce030a51f13f8d59a70aaf71cc7cc12fd395a4db636b5e74c83432c41fe61dd4cf9d03f7e1a35ca11c2e63e06dc48e7699d855b74d87cc50391eb8add9f75130db9c006f564cfac2a2c9360dd4f4707af7998aba1e49e881f5903b7667645bc81f851f138e589d303fbb9cbdc2f8b5fedb9d26ef8ff61fa38446c82a07d11d9f6d7403aecbb153c040dbf359d766fec4fb69487b910064c9d80dbbc212e040ea14ed0e3382b7e1b8ff62702059bdccd159a537da8c15cc3d934ea057d3f57b1815571b5944be7baf52ee28d3107bdb2dd8089a3b393012278996570a17ac785a010220f67ca35abef4256ac6dbb8acd27271fc42c11655cdacd5092607fe9c7ef105079e12fd6c3dfd3374318c9fc2ce1cb9042fde86344e62ea85205e6cf67184c214e2113b10ba0d246b330b65a2eb0eedbd559f30b76b2219d0299886433161e818cfe2068fe1012d9ab865942ba25fc3f5ed0f0c94bd74a189d6d8d8235c29a300a4a2c70b7eccee907343da09fc48aa03434a327bf4acddbad2e7c90f8e12c72e91d56142ba079d2864270121fa800ce229172d6d15b7edeebb006a61f3d93e2b5fd60cf7cee2787e78b919dddf2c69b16e56dd21f1b893af7a7bb42ebdad71279926d9650b95fa6d48d5f846880d83a759ee476ac90e4ab08ae7e9bb7254f72a1f9abedf335b7f3e5c194aff4aba68ffbc852ca3b2c1f9bee4ef135ceb63f5289dbfe20b413366895ec66b87d4718e9446e20eea8e80b4cac7e1b9a7988f4a25cfe80d31fe157ce96bb88b314e9b41a107335b3b433ff463e3aaa6cdb786c82fba795d5e57ea0b79f497a5f6bed28a25cad31f1fec901e10e19df77e7d2c380dcff49f691f6f96120c180db4f6f7e6a59c6e49b9974ab4aed86fc6715af5b70dd6e5cf3bef9e6ed6e8ea8f5657a296e0f30627533f24d73ff70c7a183cae5f00b844d94926af4e01bcd9a890f34c26c8e52f7b43c4d92d060abcfaa444dee2216ac436e277931eda67d179f8aa67c06714344452c5774ac784c30c441b638220ad1975ba226f13a81410750450ed3f4a6a02064578f28b111bf86f26e0b8250d256e1372e7e3b5dfa47445803a509501f547d05fb3a24e74a34af1e7d45df704c57a824adcff7851b4d7d67cdbbade3114f492fb634ec2e088f2783b978e5121515a83b8b4a6950d28c922efd67283140ce93baffb5d15eb72ef544c5c2e531a051ea8ae08f1f87f55fc446f7fe8e4fb25093dbb38bf03a2e399137d541b2504cd4288543c7b1c51cd9f54551d339149340ebae8a52401d0e26ee5341d89a31fa179ce5dfd2a4a9428cd64be345723b717dcd64b2929ad87b243fb7bcb3bb52339cd359dc854082703b9fbc15e87e87f39589a2054bc9828d92ee0b9cd165c13f35b457b0b7f484e3025192770ff1e333014cff16a594775ef17440e92212227553ce62d0ed4fc5417fa3d4863a6ac133aaa1ef8a238493863330d26841be91b6d417967ecd5590fe852fa8c692b2da8a96d836aeb6483c921a5e73bc19366199a1b5c847d7bf11b1c85f29c33fbc6f57aae6d2b799c31b2cf855e0c221ac623b42500d0e4995dc9729189c53e4ad9a8918244d5770d1846b14e13b64826b918f632917e0cf629542ba751f9ce57df94911db2e9d57c43a90a6b0d0b325d3f0be9c1625d2ac88f9915da498f34a6613cba927f2ab56416083992a378bc72aa09af520fcc520a1a8e5991b2a7271249afb3c848d6057ab4950d92579f62f7b5119ac63e6782976db8e9977e3fd5289a9296b70f899070308c729839490b27581ff7d90a4fe1578d2f895108b2c28c1c1b8ec174a37146ff4397c87b0cdf51261b88c198f4bec0b60838a72080f25236b6f6db072b3a4effd09d378c84d82bc703beb7ebf047d1b3f2bf4ece8b5e36284a1cfc0e0b57b862d781cbe696e77e650ebe5eadc8e3bfff1a4daf73bb4dc7ac9d88f49208d4e454f8d52018fb4c69570a3b0972fcb7a44ba524e43d779bcecc8f0f91d2ed80882db28686113fd6cbea26cea97ab08e431c705da6558f9c003d48fb2f9ac5f288c186cd189909aa9b7f0b25cf05b0bd940479d99dbceca591f5e2bdec7636476cf3ca59e3c4f912594200f45c0bd06867a9e8a24df50920f4d827a373be6582fefc1c9d179525908261032ae4d0bc4e51053b9e551927c993e92036b1a23f32832fe5040b9d0765235b03fd56870bdd2ccc031334058a9ecbd853d70df1f1840b45b98848285447b4a413ba58b32a3d3eeec6af4ce9ab146afc6551817d059f8e5612dd6d31ebbe415c23d9ba4b98e0ec420542b8fb7693cde2a6461a996e9b3b4d203bf66515a1af0116671f9de44bfffad700fce97fb29d638d0adf936f689b8c806fb26b26d89fa30c7d6149448ca434faf792c3e6a2a986a3ee36cc881ffb75f14c78d8245084a703beddd3684696503f46572e92f37ed233472a287f601d3751206d83bb17173c22b471f3255ea19fcac979fc8cf5a1c4acdb637b9d06352c8181bcbeef1e8d7c1222ed4147920c465875fbf43993b7673e938add0abca2c077afd4146d36d7890232c17223a3a6dbee9eb4b9c926a9f7972d06a8f4eda222b6a53f055be94f3116380494ecd15f4e289b533c34bb469e60a891e400696090772f3c29c3f4df121d2e1303f08114842b9c87903a7f3bcdead25ef8186dc00e3454c4f452841faf2893737960e1408a394ed081f3330b6eecbf38da082548930573dd0502171a3208a04300a6125ba86df0bae3f730a87bc9c7bfc78369d73ece8d708442b71d2a28ef0dfc69afd35e8d6714ba33c3f3ae54e2177544bd7a6585f6b232422ac44b246ee00aa511a2ed1daacf38ee5dbef3593914ce4bec707b8c5d1fa4d04988192a3802679d17817fa6c801337c7d3e80a1a8799f6cf86e1e54084340af41d4d809ef97be1ed4c7160a9ef5c8c83225828dce83d892a437660843010fb50b61b614ed4e745a80fd6bce6bf44b8fc9390ec64bc7ac5c1edbe74016a00e4dc0b04f0e46fe11d66f805d8b50b24bbe95d066deffe72b8f18b24e785f0507776005741bd95ce935894f12dfe7ccee1906bd6ef4d272d823f5bb92a0229f0f29f95ffd181491eb6278dd5f17ff1fc66f8d4f14aa8b0e833a93f74fe818e32db2dc767c15d5d03ee42965104bbce10bd5d66b871ba2a09f2269cbba8432f52327cc1e2710758e1804ea1fe8377f9a1b6b4ba850efc3004cca5203a7d7c473b88d91e6930b1c7c195ba3c47a130eb5e6354018b8907f00acae6f53702b63b3900f6a184c07d52665a7dd1dd94916dc7ba95cf75c8fb5f07e3ee904beaed3e7a58e6c17611b7048ff802d22dfc068e70bd9ab87a251fa151230592ba0c82bc43eba06b2391aa30bd3454373d556018c830c24afb90ae0d29d4fe1829478826c7052e092a32f27a9d63d5defa8f03d813eb6572fbff32dd85d8987a76d31daba9faf2cbed424bf6c47fbdf816450039199a834ec8989e7da9bd6bc285721d08af2de1767a11434eb257ebbdc034b7565e0cc0ceaff92f19dbf1431f32000b178409512a2ae24f4cbee8adafb602f38aba2f7a0344c7135fde5f898a69e622f0243ae7f543c1637128680ef50cb07eabb8bd5f303c697a150f41cccf2fbce4cc643ebaf65cf1a3d199248db86f69b82ab604c6866c26a4268f1154a8f94ec3ceea3531bb5fb1ac951dfa99496f21cec96baa359c2c08da23765578d5e585d527e6bc043d3da29612378f918674b1ef552973770f0c674d02dbb4f63a8f5cc8f896ba59e3f900c077ed8f8f6ac6083501296dba428a1180e1ceb6ead1e4fb31bb4fe70079d720d4dbb22e823d9167e12fc831d7092d1397f30a1366d5cc8731ffac2e0db9289080a91eafdcf29d90fb797f81d785dbf8e2481de57829cb2f9d17bb894e048e7051f449250b7c31255d056189f6c90090b81be3570d7c71ae78cb0f5169d6f142f73130d9283d0551adb3c268d1e169333b5864a226b7b4f86f7e24c44a991592304ff28559b195f8b32dcb97d1dcaaffbd16fbccd854c568e3e420fad1a486e0caa99c46aacad0268870424959687352b688151632a5dd7a5efe11f95b645fd1df236d479ffb918af56dcea8fd0781c37fdc3f7cf0092b7ca962ba71110aed51249b400935c39ee2fc263a7d70bbe850db6c570ce8aa7a7a25978169b7e2fff2a94971885cfb3433f62b6f6af4c3c129461b5613d2e12cca0772cc52fefeb4a1a54283b497d1d1e4fe8cc24b6f6cfb897077f1ecb105e53f2e0df0295540b1d24be8120438db8243c68d26e2bdfef3da4f1369d8dbf7866ce3169772fcaf62317bdead50b3feaf0b55b2163f8e59c60c40c5f1bf659534219fcec999193055020bb3a4687b4daf25f77d9c02846053c7458442a26410638a42baee5158416e00b240ee91f5c3805f2c500ac2231bd4b896c030f4e9d5f33430d3340736cfd9108a10e9b4dc893a57a260421736c988dc975dcde25675f1f5afee819576d1aaa04a4b84cf90de3d13757e48c22726470ca958b919db4296a41518e7ce62e7a7a208b17c527b8a6d1b068ee2f4858d83c6a748110b20fffdbe44916f3871cc6d20aea3df516f83318de00669e8124e47d2d05fad743b8a9d8f0cfcddce8355c8217a7e599be1bbc649224b1a9686f8f08dd6a333966f9d67841080a8285d912d51d0cd7a48d3d797f1d1da9d14b3af4d569fcce49ce0a08f29ab27e78df5775bd0da3985654618b91578ca1c44e9118e97fdfde9a44c2c6a01dd033e1afd9502613f050bb5f40cfb1ed125552ae4bcbb02cef49dcbd8d2ed1df54c12489007935023d9bd5bfb68106a5172232ac2f0adf0b8d46bebd8c319b1f293ec6ea0dcf2a1bcfd340f0a46e5d791d7d5c947b7d7606747d163c56fdd7dc1e5713b8a720c802f68cfec8f3426146da621b15d9183024fc5dfc6036ecad7d337ef4aec8de650465136cafb39b8b1d9e4adfa84f973c3e7c74aa3e42ce1c90c3e216cc26bdc80d2623a78eda113305e72f2f0723d87ea6444f1f62b0edb667eb67d5c8d43f1129c6db6410d513e3c04be3a3015c2f50235937731c558e0bed04877bd7d990ab2c551e977d18eb1d792ea80e561018cccbedf3c84f79e149cee13fe421a5c0af2339f442a974492692c512d4736fbda6926722de7d821cf2d141e4cbb17e516e13f2f2201c7f219c8958fe2fcdff5f4e5c4da2b19729e480820303c8359b4c1f16de9e6612a1230f882a6588c81e1d9d1ec50c15e2fd56eb57df3352d7e9c97b2c3cdfc11b2b771ca6da29f5dd9952868f39c8171074260fd700ef04dc5541521f36e6f861833c85d1199dc6efe365b8415583b002816cdd257b59fe2b2813bd0675f26629c1451b66772d23c1264d941b003abf41a3b7ec72799e08bd23c93326d02bf901b3314b130b48d5697d7ee7b21022dceb0de7a693a33e43c10f77d624b3e57dc0513d9ab7dda81c2b5230e9a9797ed9df075b1a9a04388b75e909bf13fc6a8e0963a6d09fe6feab2ca94fad001b3f2303b76b0da8953a6f7b864f4a10e5d487df213f00453d3b41de3f2af983ebae984c50722e4070dc76cee5e0ce2dd35f69ab5162d3cfa3ca47416420d1a6ae5736872c95f3cf4bd758b053abce06a3f3d27234d5351d377d19dbc31128c73104719af176fda95db7204fd783992e8f4d59931736663a97d75ca9fe5601fd6a89a0aac7967616304106a12073271eef8a88a6e435eed5c639b63aba53bdc40b039e0fc0c93d610cd5d8e66d17471ac366ff4f4c0a1b6cd7f7ea41e2357e1d43ca2d5b0ea75f120369fb9c8a21351872b158b652d6c6e15cc381c306c1013b6e1102bd43e75161742415d7c65456135e076db98d1f67573f1cd2d3937af97a66e2920f026cb6af506b49054bf5cd1bbd6f7cd5f654ba5454ea1f6afa635b9836ae0cdc637721c23fec7e36fc5b181cf56fd52dac7d9f1058fe069388c8d8f4aca742c881e2ade54160b68a6b36e51e973fdcfd0a8bc1a8c72682743423f4270dda04a6be272a1646a15eeee9e9960019a34eeae05129cd8c9b0d12ad5b3a1b4910ab269cea75a18cdc6602c90a3c2b0a7c79b306c76638f2f2eb54cbc41109fb4780479e8dd882dfa563e655b300177732817cde20e4dcfbe62477f7bd375d66ffeccb335787ab4069c3ea492fc80b24f697b3c496b0e39b5bf7a1e985673afc24a32ad2aec7045991e3a80acd80181dd6b84aefedc94d484f80faf20e43cc740c40eaf29a2eb6b459cb834db07912804bffbcad366f36d02398ff25b1b7d10e1eac43dffdc071bb0135bacb68ae0be269fd54ecaf04d6fc6e8ae3865d1a6723ca38e1a837e79529b1c53f8652c417a5f356703cc7a7728e38472edf6d2a7322eac5e1ea44360d99380c7f1ea79f067ece250223c72cee699b995d9e03c7e4fa7559f7fe31342cca0ce2cd31586311c664bacd8676d116691e2111774761f13bc228eb8c5246f2496c79a08e275608560bcc059db58b4fd957831e60ef939f1785f95e96e574f211781f6500937b02f0b4f9e89a0ac6ddb388fdb8bef0bfee2a1fa8b55030be4064653058876cec1bb0d419372104957e3826fce12a86acab2edb95f0466e8d974f72951a5850b42c417fb7da12f369945299761215b461b853087e5c72e543a420fbe81e08be59045685818d5d7b478095d711c6eb686827f6e20ccf3e1e378e5b1ca7df6324081b9c26e478a35ac337c3d835ec68e0e328fb30f2c608620d4c0896e0e57aa0180b17223b0607ee9e21a031712eacb1e784c4fd08540014cf3fc8d19726feca721e365bb366388683526e599a294927bc546a4d5011da30c7b2fab02efbdb18ab035ad5bbe7bfadd53b0885c220a897d3d8c2cb428e38273d250245cf1b65e0c81b39b2f0ecf38a82930cac7d2400315f74b76e918f5914155e9d2a59cc9cb4f107599dcba86033fa5b95e6a78e083a46613528b12d9df4156903cf53deefc83d00211d70b9cb5f95a01fda9d023008e546e99e3666b50e92e252bd5a24127fd3186841ec436a72ad2364426aa74bfd2283fe3478f06feced6398b87f34378fe81b599968d8a2284d9e7c9d90c75a2690a0b9654e2fa9d0a33fbab902a53da9160119d39eff9c63f7877567d4fff228def31cb88f95fcb9e40e7a5843472c2f231b185edcd6ca67c84bc81efbcce3e10a043706c74c42ff30e668e94b53f12eb70615289857ab1eef98b079d754e9f66c61ec68d56dd23b9bc806c6710357a1d92ee58e02b874474f90a619c06241a5ba212e60a6110e7f09bd3c4602f2e9c47e2a11dc54d9f8ab979bfb3371f85b99bf6c051a2f5fa64579f31538f959a56ad5099d741e40b4c985eca2a2fea2e28980c9056f07465c983e9fa28d34e104f13015cae6067451d4c5d18715e725ab97558b7f71519c013c91f4f00ae1b94e044a248647b6d63e0ff1ad866423770acf0264ba1bae38ba54540bfda09b51bea8c426b26292e241b03f8e86e62cbb982df0590a043c213b648e3e2de09c43af183918b224b74f1449fadf68e31b87fa1e3b8874ad883fa3f57958bf5580f487e35424d96689668d012f282397cb8470e003681f6327131c6dc5abc41ba6795657950729b0c57a17a548d7e59c09ab4d0af29f3986683963a4af08bde254ecee7d7e24f4eb820d5e11e1284ef470949a5caa0d59884b2e059cebcf42aac0ec87a4c2009982f7f2fcb6c54324d1ed3f1f2d20335d2c79e56669a45e0bf2094e53dfff22ee388b1d1874eb6261be6f441d1b61aabb25e280c3b1cca1210067228a29a52d5c10663d69b3740753607c6b92e4add07af47ad92c467bd5f150797aea8ad909f1ad4d166d9525968cba944c3a3b5df5dd3ece0882f273929ac009910aa4c029fb76bf4360b153fc4129ad496296b093fd7895225bd8c38ca9e6a13fd90f21115553ba51127185ab32cacef875f5d9485ff9d05d0462a440cdc5dc56543a210874b509ba6e118ad0ccc3e6f27f79aa521ee68c844cc89ffaf40c2c4923112404acc8365bddc685de4e41eeed9a989119f61727e61855007baa4f6d5aa47a6f069c7504953acaf19ebb02ca658da58c38e3eea0c710d1670dfd1586746f4bcc066990a6fe3f5c7b4f942179bb7f6cb3d0eff2841108b5f9fb6f0aa3dc297c750fbc9a532e247d09966e8fc9c3c08d3b93cda4d7da15ccb2c3d55aafaef7f6e720657e3b9c9a7aa110bfc42043b8e382020744ee0a38ffcbdcb176dace99c5782118e3412549d1e50c110eee24cf8a7ad5668fb5b059365b164cc6e2f9c51e7d17d578e1f940873003a4772cafd0e5e0fe61b2b818ef183d3c8442d4365671a32b2d023a91972ce6168a6cf4d6a9438a553c6dd4be9780dc514828202de442e926d2735a11b5e30445898962a6612abff243b02ecef4c52788f64ed2eec6dde32063b15d6e7b170e5159d78e57dd0649b116bdc9b3e1cfb2a5a713a546f7869000722c25bcfb1beac0e535fa3277f0120043a101b8116f60e8572a6325ac71bb159a939845b53d191316abbfd5228668258281c52411281cbdad0fb98efe18a81647a67703fc3259981967efe0e3dfb88f6e8de37db781960d5ad649b9cacea60c0daa9256ebac451ee59c50c337f68f1ce7c6c0b0d90fcfa20cb9ff0478be6a03e4bb40668370d05fb1a940ae15df5cb9c128c6daae54b73a0846e8a45a3bd31b6218aa542c305cc3ef949c30fd8234dd18cc5f927882215ab9d6d748b4518f04afa5d7e4c164916d9313b76d88b5f2d01130f40bdb3930412e44603c16bfa02751cab86e87f5a912d21a6df597b3f5cf207cbff7943cd983e7eedd529164f91fef3f5f440261cb789a9ca6899fe66a2b6f3eef2f821807c9abc02744a0957d1e2409b845583184de73db7dc7d896d609ef37de8b523289390b38b38f687f10026ec8d00353098475c6ded11fd4de5228422528eb710995599e5f284519ca7c29709736fe6a73c37092fc83a5737682a11aae30dfb0a6bf4791bcc7f63530341aa1b36a58ea685c0bc4aeb065dc63a50f54f0536a7364be2181f13c0b4d8cf607f474033d183eba62d93b7451932b6cfa092cc03c347474bf4906e0c8ddcbee13a7d725baf5ac8703784f84aeb7dd994e776a17c921b5d4dffaf56d4492fde123f2b26aa4213ed6ee5847ba93f0d779a0e33e9e76e9759d6dad50d74b225f8e0803b5466ae26cf2977d03370661ef5073a7258019a875f67b03e6dd5fd9cc512084a695aad7902800ceb7aaf22dabc4d9dc4479be57248513a57e0518b1223f1b313fd82807e35e2259298ba409c83ce0424f3639a13f759de733741acad8a10660a955e0ce6e2492dfe14637fea0770e02533eaadddd05d4d99a04f9620f4e106934ef962dce3a6d408321df0a65eb716ee892d98d3e1d6a347139e21b0ae81cc8a047185f77036988b57e5b11f79c73a9913aaa924c10318fcae1b8157a73162a5c5beee053165d8b1d1e2a63c28bd65a2a2384afeced0f75f59b2161275528e889bfd1f21d0268b13da9c623cc7ef6b36e3887cd85d9ff79f17f9e95bba02c644f4a592314c6e20543f17f0e5851cb56c4d8fc3494bc1db19de3eb9b7e27121ce1d4d7d89669e5805c2bce49735e67c217a479f00a31793c09b072cc379d00c4c5745c7492cd691c3b5a9217156aa14ba97c0143719d9437ed682fe6695a", + "public_inputs_hex": "0x1a207628cc6936816ccb62a7b56fdbbf8e975293b677c988644e018fc402e4411dfdc7cb6265f100524012f038ee1f205bf8789b70b46c57463dedb4998f7ac800000000000000000000000000000000a81b7087e1431ea26777fc20238aa980000000000000000000000000000000001991a803e262c7a38f41ff63f803b3c21806572c19ee2f3532e970d617919b3aa8cdc582782dfad0699badc631f75128000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021301f6e7fbbb73aa8fa2046f5a9854e60b7c72f0b56d2cdef4e3cb5e3d1a660b0827372d8ac27abb349e731af617d334968a1a677756357ab1b3eb22654a72340ed445f4ba59e36bb04bedc22d61894e7f47177273eb6efce052396d70477f050dd6ae6474cac3235c0eb911e38027c416320fdca3d180736d3a3359939e922b000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + } +} diff --git a/circuits/benchmarks/results_insecure_agg/report.md b/circuits/benchmarks/results_insecure_agg_micro/report.md similarity index 73% rename from circuits/benchmarks/results_insecure_agg/report.md rename to circuits/benchmarks/results_insecure_agg_micro/report.md index 5913ec05d7..ae02a4a762 100644 --- a/circuits/benchmarks/results_insecure_agg/report.md +++ b/circuits/benchmarks/results_insecure_agg_micro/report.md @@ -1,9 +1,9 @@ # Enclave ZK Circuit Benchmarks -**Generated:** 2026-05-23 11:19:46 UTC +**Generated:** 2026-05-27 13:55:12 UTC -**Git Branch:** `feat/1549` -**Git Commit:** `8a841717468169df094b7316e57e1008d4ba34b0` +**Git Branch:** `params/dyn-conf` +**Git Commit:** `e6189e08754c90981a3c359911e081c5f5ff3a90` **Committee Size:** `H=3`, `N=3`, `T=1` @@ -72,39 +72,39 @@ Single-circuit `bb prove` on the benchmark oracle witness (not the integration a | Circuit | Constraints | Prove (s) | Verify (ms) | Proof (KB) | | -------------------- | ----------- | --------- | ----------- | ---------- | -| C0 | 6847 | 0.12 | 26.22 | 15.88 | -| C1 | 57818 | 0.34 | 25.94 | 15.88 | -| C2a | 41244 | 0.31 | 25.78 | 15.88 | -| C2b | 79591 | 0.49 | 26.23 | 15.88 | -| C3a | 120114 | 0.57 | 26.46 | 15.88 | -| C3b | 120114 | 0.57 | 26.46 | 15.88 | -| C4a | 67494 | 0.46 | 26.53 | 15.88 | -| C4b | 67494 | 0.46 | 26.53 | 15.88 | -| C5 | 123624 | 0.55 | 26.63 | 15.88 | -| user_data_encryption | 53732 | 0.33 | 25.67 | 15.88 | -| C6 | 86927 | 0.53 | 27.16 | 15.88 | -| C7 | 90841 | 0.46 | 26.43 | 15.88 | +| C0 | 6847 | 0.14 | 28.39 | 15.88 | +| C1 | 57818 | 0.36 | 28.35 | 15.88 | +| C2a | 41244 | 0.32 | 27.93 | 15.88 | +| C2b | 79591 | 0.53 | 27.27 | 15.88 | +| C3a | 120114 | 0.60 | 27.47 | 15.88 | +| C3b | 120114 | 0.60 | 27.47 | 15.88 | +| C4a | 67494 | 0.46 | 25.09 | 15.88 | +| C4b | 67494 | 0.46 | 25.09 | 15.88 | +| C5 | 123624 | 0.58 | 35.81 | 15.88 | +| user_data_encryption | 53732 | 0.33 | 26.08 | 15.88 | +| C6 | 86927 | 0.58 | 27.25 | 15.88 | +| C7 | 90841 | 0.52 | 28.18 | 15.88 | ### Artifacts | Artifact | Proof size | Public input size | Verify gas | Calldata gas | Total gas | | -------- | ---------- | ----------------- | ---------- | ------------ | --------- | -| Π_DKG | 10.69 KB | 0.47 KB | 3125294 | 176148 | 3301442 | -| Π_user | 15.88 KB | 0.12 KB | 2972881 | 170272 | 3143153 | -| Π_dec | 10.69 KB | 3.47 KB | 3640985 | 187260 | 3828245 | +| Π_DKG | 10.69 KB | 0.47 KB | 3125379 | 176232 | 3301611 | +| Π_user | 15.88 KB | 0.12 KB | 2972989 | 170272 | 3143261 | +| Π_dec | 10.69 KB | 3.47 KB | 3640997 | 187272 | 3828269 | ### Role / Phase / Activity | Role | Phase | Activity | Metric | Duration | Proof size | Bandwidth | | --------------- | ----- | ----------------------------------------- | -------------- | -------- | ---------- | --------- | -| Each ciphernode | P1 | one-time DKG participation (test harness) | wall_clock | 144.27 s | 127.00 KB | 128.19 KB | -| Aggregator | P2 | C5 + Π_DKG fold (aggregator span) | wall_clock | 131.81 s | 10.69 KB | 11.16 KB | +| Each ciphernode | P1 | one-time DKG participation (test harness) | wall_clock | 148.93 s | 127.00 KB | 128.19 KB | +| Aggregator | P2 | C5 + Π_DKG fold (aggregator span) | wall_clock | 136.24 s | 10.69 KB | 11.16 KB | | User | P3 | per user input | isolated_nargo | 0.65 s | 15.88 KB | 16.00 KB | -| Each ciphernode | P4 | per computation output (C6) | isolated_nargo | 0.53 s | 15.88 KB | 16.00 KB | -| Aggregator | P4 | C7 + Π_dec fold (full publish→aggregate) | wall_clock | 53.36 s | 10.69 KB | 14.16 KB | -| Aggregator | P4 | C7 + fold only (pending→plaintext span) | wall_clock | 49.52 s | 10.69 KB | 14.16 KB | +| Each ciphernode | P4 | per computation output (C6) | isolated_nargo | 0.58 s | 15.88 KB | 16.00 KB | +| Aggregator | P4 | C7 + Π_dec fold (full publish→aggregate) | wall_clock | 55.34 s | 10.69 KB | 14.16 KB | +| Aggregator | P4 | C7 + fold only (pending→plaintext span) | wall_clock | 51.39 s | 10.69 KB | 14.16 KB | -_P2 **tracked_job_wall** sum (ZkDkgAggregation + ZkPkAggregation, parallelizable): **20.40 s** — not +_P2 **tracked_job_wall** sum (ZkDkgAggregation + ZkPkAggregation, parallelizable): **21.30 s** — not comparable to P2 wall_clock row above._ ## Integration test (`test_trbfv_actor`) @@ -114,72 +114,72 @@ comparable to P2 wall_clock row above._ | Phase | Metric | Duration (s) | | ------------------------------------------------------------------ | ------------ | ------------ | | Starting trbfv actor test | `wall_clock` | 0.00 | -| Setup completed | `wall_clock` | 2.66 | -| Committee Setup Completed | `wall_clock` | 20.17 | -| Committee Finalization Complete | `wall_clock` | 0.00 | -| Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall) | `wall_clock` | 131.81 | -| ThresholdShares -> PublicKeyAggregated | `wall_clock` | 144.27 | -| E3Request -> PublicKeyAggregated | `wall_clock` | 144.78 | +| Setup completed | `wall_clock` | 2.97 | +| Committee Setup Completed | `wall_clock` | 20.09 | +| Committee Finalization Complete | `wall_clock` | 0.01 | +| Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall) | `wall_clock` | 136.24 | +| ThresholdShares -> PublicKeyAggregated | `wall_clock` | 148.93 | +| E3Request -> PublicKeyAggregated | `wall_clock` | 149.43 | | Application CT Gen | `wall_clock` | 0.01 | | Running FHE Application | `wall_clock` | 0.00 | -| Aggregator P4: Aggregation pending -> PlaintextAggregated (wall) | `wall_clock` | 49.52 | -| Ciphertext published -> PlaintextAggregated | `wall_clock` | 53.36 | -| Entire Test | `wall_clock` | 220.99 | +| Aggregator P4: Aggregation pending -> PlaintextAggregated (wall) | `wall_clock` | 51.39 | +| Ciphertext published -> PlaintextAggregated | `wall_clock` | 55.34 | +| Entire Test | `wall_clock` | 227.84 | ### Multithread job timings (`tracked_job_wall`) | Name | Avg (s) | Runs | Total (s) | | ----------------------------- | ------- | ---- | --------- | -| CalculateDecryptionKey | 0.01 | 3 | 0.02 | +| CalculateDecryptionKey | 0.00 | 3 | 0.01 | | CalculateDecryptionShare | 0.02 | 3 | 0.06 | | CalculateThresholdDecryption | 0.02 | 1 | 0.02 | | GenEsiSss | 0.01 | 3 | 0.02 | | GenPkShareAndSkSss | 0.01 | 3 | 0.03 | -| NodeDkgFold/c2ab_fold | 8.17 | 3 | 24.52 | -| NodeDkgFold/c3a_fold | 35.19 | 3 | 105.58 | -| NodeDkgFold/c3ab_fold | 7.49 | 3 | 22.47 | -| NodeDkgFold/c3b_fold | 34.99 | 3 | 104.97 | -| NodeDkgFold/c4ab_fold | 7.89 | 3 | 23.68 | -| NodeDkgFold/node_fold | 18.33 | 3 | 55.00 | -| ZkDecryptedSharesAggregation | 1.56 | 1 | 1.56 | -| ZkDecryptionAggregation | 47.95 | 1 | 47.95 | -| ZkDkgAggregation | 19.77 | 1 | 19.77 | -| ZkDkgShareDecryption | 1.23 | 6 | 7.38 | -| ZkNodeDkgFold | 112.07 | 3 | 336.22 | -| ZkPkAggregation | 0.63 | 1 | 0.63 | -| ZkPkBfv | 0.22 | 3 | 0.66 | -| ZkPkGeneration | 2.36 | 3 | 7.09 | -| ZkShareComputation | 2.39 | 6 | 14.34 | -| ZkShareEncryption | 4.00 | 24 | 95.92 | -| ZkThresholdShareDecryption | 3.39 | 3 | 10.18 | +| NodeDkgFold/c2ab_fold | 8.42 | 3 | 25.26 | +| NodeDkgFold/c3a_fold | 36.69 | 3 | 110.07 | +| NodeDkgFold/c3ab_fold | 7.68 | 3 | 23.04 | +| NodeDkgFold/c3b_fold | 35.82 | 3 | 107.46 | +| NodeDkgFold/c4ab_fold | 8.05 | 3 | 24.14 | +| NodeDkgFold/node_fold | 19.28 | 3 | 57.84 | +| ZkDecryptedSharesAggregation | 1.61 | 1 | 1.61 | +| ZkDecryptionAggregation | 49.76 | 1 | 49.76 | +| ZkDkgAggregation | 20.43 | 1 | 20.43 | +| ZkDkgShareDecryption | 1.32 | 6 | 7.91 | +| ZkNodeDkgFold | 115.94 | 3 | 347.81 | +| ZkPkAggregation | 0.86 | 1 | 0.86 | +| ZkPkBfv | 0.23 | 3 | 0.70 | +| ZkPkGeneration | 2.56 | 3 | 7.69 | +| ZkShareComputation | 2.55 | 6 | 15.33 | +| ZkShareEncryption | 4.02 | 24 | 96.43 | +| ZkThresholdShareDecryption | 3.49 | 3 | 10.48 | | ZkVerifyShareDecryptionProofs | 0.10 | 3 | 0.31 | -| ZkVerifyShareProofs | 0.27 | 5 | 1.37 | +| ZkVerifyShareProofs | 0.27 | 5 | 1.35 | -Sum of tracked job wall time: **879.74 s** — **not** end-to-end latency (jobs run in parallel up to +Sum of tracked job wall time: **908.64 s** — **not** end-to-end latency (jobs run in parallel up to `BENCHMARK_MULTITHREAD_JOBS`). ### NodeDkgFold sub-steps (`tracked_job_wall`, per fold prove) | Step | Avg (s) | Runs | Total (s) | | --------- | ------- | ---- | --------- | -| c2ab_fold | 8.17 | 3 | 24.52 | -| c3a_fold | 35.19 | 3 | 105.58 | -| c3ab_fold | 7.49 | 3 | 22.47 | -| c3b_fold | 34.99 | 3 | 104.97 | -| c4ab_fold | 7.89 | 3 | 23.68 | -| node_fold | 18.33 | 3 | 55.00 | +| c2ab_fold | 8.42 | 3 | 25.26 | +| c3a_fold | 36.69 | 3 | 110.07 | +| c3ab_fold | 7.68 | 3 | 23.04 | +| c3b_fold | 35.82 | 3 | 107.46 | +| c4ab_fold | 8.05 | 3 | 24.14 | +| node_fold | 19.28 | 3 | 57.84 | ### Aggregation jobs (`tracked_job_wall`) | Operation | Avg (s) | Runs | Total (s) | | ---------------------------- | ------- | ---- | --------- | -| ZkDecryptedSharesAggregation | 1.56 | 1 | 1.56 | -| ZkDecryptionAggregation | 47.95 | 1 | 47.95 | -| ZkDkgAggregation | 19.77 | 1 | 19.77 | -| ZkNodeDkgFold | 112.07 | 3 | 336.22 | -| ZkPkAggregation | 0.63 | 1 | 0.63 | +| ZkDecryptedSharesAggregation | 1.61 | 1 | 1.61 | +| ZkDecryptionAggregation | 49.76 | 1 | 49.76 | +| ZkDkgAggregation | 20.43 | 1 | 20.43 | +| ZkNodeDkgFold | 115.94 | 3 | 347.81 | +| ZkPkAggregation | 0.86 | 1 | 0.86 | -Sum of aggregation job tracked time: **406.13 s** (parallel CPU work; not P1/P2 wall clock). +Sum of aggregation job tracked time: **420.48 s** (parallel CPU work; not P1/P2 wall clock). ### Folded on-chain artifacts (exported for Π_DKG / Π_dec gas) diff --git a/circuits/benchmarks/results_insecure_no_agg/crisp_verify_gas.json b/circuits/benchmarks/results_insecure_no_agg/crisp_verify_gas.json deleted file mode 100644 index af8f2834ef..0000000000 --- a/circuits/benchmarks/results_insecure_no_agg/crisp_verify_gas.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "verify_gas": { - "dkg": null, - "user": null, - "dec": null - }, - "source": "folded_proof_export_plus_crisp_verify_test", - "artifact_sizes_bytes": { - "dkg": { - "proof": 0, - "public_inputs": 0 - }, - "dec": { - "proof": 0, - "public_inputs": 0 - } - }, - "calldata_gas": { - "dkg": { - "proof": 0, - "public_inputs": 0, - "total": 0 - }, - "dec": { - "proof": 0, - "public_inputs": 0, - "total": 0 - } - }, - "integration_summary": { - "integration_test": "test_trbfv_actor", - "benchmark_config": { - "mode": "insecure", - "bfv_preset_subdir": "insecure-512", - "bfv_preset": "InsecureThreshold512", - "lambda": 2, - "proof_aggregation_enabled": false, - "multithread_concurrent_jobs": 13, - "committee_h": 3, - "committee_n": 3, - "committee_t": 1, - "nodes_spawned": 20, - "network_model": "in_process_bus", - "testmode_harness": true - }, - "proof_aggregation_enabled": false, - "multithread": { "rayon_threads": 13, "max_simultaneous_rayon_tasks": 13, "cores_available": 14 }, - "operation_timings": [ - { "name": "CalculateDecryptionKey", "avg_seconds": 0.119593152, "runs": 3, "total_seconds": 0.358779458 }, - { "name": "CalculateDecryptionShare", "avg_seconds": 0.625714819, "runs": 3, "total_seconds": 1.877144457 }, - { "name": "CalculateThresholdDecryption", "avg_seconds": 0.555039542, "runs": 1, "total_seconds": 0.555039542 }, - { "name": "GenEsiSss", "avg_seconds": 0.126707139, "runs": 3, "total_seconds": 0.380121417 }, - { "name": "GenPkShareAndSkSss", "avg_seconds": 0.256695819, "runs": 3, "total_seconds": 0.770087459 }, - { "name": "ZkDecryptedSharesAggregation", "avg_seconds": 8.225412791, "runs": 1, "total_seconds": 8.225412791 }, - { "name": "ZkDkgShareDecryption", "avg_seconds": 2.350571951, "runs": 6, "total_seconds": 14.103431707 }, - { "name": "ZkPkAggregation", "avg_seconds": 1.971270875, "runs": 1, "total_seconds": 1.971270875 }, - { "name": "ZkPkBfv", "avg_seconds": 0.429601166, "runs": 3, "total_seconds": 1.2888035 }, - { "name": "ZkPkGeneration", "avg_seconds": 2.953823722, "runs": 3, "total_seconds": 8.861471166 }, - { "name": "ZkShareComputation", "avg_seconds": 3.007209458, "runs": 6, "total_seconds": 18.04325675 }, - { "name": "ZkShareEncryption", "avg_seconds": 5.763399979, "runs": 24, "total_seconds": 138.321599497 }, - { "name": "ZkThresholdShareDecryption", "avg_seconds": 7.663020986, "runs": 3, "total_seconds": 22.989062958 }, - { "name": "ZkVerifyShareDecryptionProofs", "avg_seconds": 0.102607666, "runs": 3, "total_seconds": 0.307823 }, - { "name": "ZkVerifyShareProofs", "avg_seconds": 0.257090858, "runs": 5, "total_seconds": 1.285454293 } - ], - "operation_timings_total_seconds": 219.33875887, - "operation_timings_metric": "tracked_job_wall", - "phase_timings": [ - { "label": "Starting trbfv actor test", "seconds": 0e-9, "metric": "wall_clock" }, - { "label": "Setup completed", "seconds": 3.058201042, "metric": "wall_clock" }, - { "label": "Committee Setup Completed", "seconds": 20.257082542, "metric": "wall_clock" }, - { "label": "Committee Finalization Complete", "seconds": 0.005129541, "metric": "wall_clock" }, - { "label": "Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall)", "seconds": 1.981342, "metric": "wall_clock" }, - { "label": "ThresholdShares -> PublicKeyAggregated", "seconds": 22.251965458, "metric": "wall_clock" }, - { "label": "E3Request -> PublicKeyAggregated", "seconds": 24.866107292, "metric": "wall_clock" }, - { "label": "Application CT Gen", "seconds": 0.309383, "metric": "wall_clock" }, - { "label": "Running FHE Application", "seconds": 0.003993125, "metric": "wall_clock" }, - { "label": "Aggregator P4: Aggregation pending -> PlaintextAggregated (wall)", "seconds": 8.253253, "metric": "wall_clock" }, - { "label": "Ciphertext published -> PlaintextAggregated", "seconds": 18.401028833, "metric": "wall_clock" }, - { "label": "Entire Test", "seconds": 66.904175584, "metric": "wall_clock" } - ], - "folded_artifacts": null - }, - "test_exit_code": { - "crisp": 1, - "folded_export": 0, - "enclave_contracts": 0 - } -} diff --git a/circuits/benchmarks/results_insecure_no_agg/benchmark_run_meta.json b/circuits/benchmarks/results_insecure_no_agg_micro/benchmark_run_meta.json similarity index 100% rename from circuits/benchmarks/results_insecure_no_agg/benchmark_run_meta.json rename to circuits/benchmarks/results_insecure_no_agg_micro/benchmark_run_meta.json diff --git a/circuits/benchmarks/results_insecure_no_agg_micro/crisp_verify_gas.json b/circuits/benchmarks/results_insecure_no_agg_micro/crisp_verify_gas.json new file mode 100644 index 0000000000..3bbcf80c49 --- /dev/null +++ b/circuits/benchmarks/results_insecure_no_agg_micro/crisp_verify_gas.json @@ -0,0 +1,88 @@ +{ + "verify_gas": { + "dkg": null, + "user": 2972989, + "dec": null + }, + "source": "folded_proof_export_plus_crisp_verify_test", + "artifact_sizes_bytes": { + "dkg": { + "proof": 0, + "public_inputs": 0 + }, + "dec": { + "proof": 0, + "public_inputs": 0 + } + }, + "calldata_gas": { + "dkg": { + "proof": 0, + "public_inputs": 0, + "total": 0 + }, + "dec": { + "proof": 0, + "public_inputs": 0, + "total": 0 + } + }, + "integration_summary": { + "integration_test": "test_trbfv_actor", + "benchmark_config": { + "mode": "insecure", + "bfv_preset_subdir": "insecure-512", + "bfv_preset": "InsecureThreshold512", + "lambda": 2, + "proof_aggregation_enabled": false, + "multithread_concurrent_jobs": 13, + "committee_h": 3, + "committee_n": 3, + "committee_t": 1, + "nodes_spawned": 20, + "network_model": "in_process_bus", + "testmode_harness": true + }, + "proof_aggregation_enabled": false, + "multithread": { "rayon_threads": 13, "max_simultaneous_rayon_tasks": 13, "cores_available": 14 }, + "operation_timings": [ + { "name": "CalculateDecryptionKey", "avg_seconds": 0.004193153, "runs": 3, "total_seconds": 0.012579459 }, + { "name": "CalculateDecryptionShare", "avg_seconds": 0.020384319, "runs": 3, "total_seconds": 0.061152958 }, + { "name": "CalculateThresholdDecryption", "avg_seconds": 0.019784084, "runs": 1, "total_seconds": 0.019784084 }, + { "name": "GenEsiSss", "avg_seconds": 0.006832208, "runs": 3, "total_seconds": 0.020496625 }, + { "name": "GenPkShareAndSkSss", "avg_seconds": 0.010738166, "runs": 3, "total_seconds": 0.032214499 }, + { "name": "ZkDecryptedSharesAggregation", "avg_seconds": 1.581275625, "runs": 1, "total_seconds": 1.581275625 }, + { "name": "ZkDkgShareDecryption", "avg_seconds": 1.348800493, "runs": 6, "total_seconds": 8.092802958 }, + { "name": "ZkPkAggregation", "avg_seconds": 0.704008084, "runs": 1, "total_seconds": 0.704008084 }, + { "name": "ZkPkBfv", "avg_seconds": 0.222331778, "runs": 3, "total_seconds": 0.666995335 }, + { "name": "ZkPkGeneration", "avg_seconds": 2.461834375, "runs": 3, "total_seconds": 7.385503126 }, + { "name": "ZkShareComputation", "avg_seconds": 2.481999513, "runs": 6, "total_seconds": 14.891997083 }, + { "name": "ZkShareEncryption", "avg_seconds": 4.130910402, "runs": 24, "total_seconds": 99.141849665 }, + { "name": "ZkThresholdShareDecryption", "avg_seconds": 3.425231986, "runs": 3, "total_seconds": 10.275695958 }, + { "name": "ZkVerifyShareDecryptionProofs", "avg_seconds": 0.102147833, "runs": 3, "total_seconds": 0.306443501 }, + { "name": "ZkVerifyShareProofs", "avg_seconds": 0.272140033, "runs": 5, "total_seconds": 1.360700167 } + ], + "operation_timings_total_seconds": 144.553499127, + "operation_timings_metric": "tracked_job_wall", + "phase_timings": [ + { "label": "Starting trbfv actor test", "seconds": 0e-9, "metric": "wall_clock" }, + { "label": "Setup completed", "seconds": 2.701572083, "metric": "wall_clock" }, + { "label": "Committee Setup Completed", "seconds": 20.090864792, "metric": "wall_clock" }, + { "label": "Committee Finalization Complete", "seconds": 0.001990708, "metric": "wall_clock" }, + { "label": "Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall)", "seconds": 0.706576, "metric": "wall_clock" }, + { "label": "ThresholdShares -> PublicKeyAggregated", "seconds": 13.62430675, "metric": "wall_clock" }, + { "label": "E3Request -> PublicKeyAggregated", "seconds": 14.129209875, "metric": "wall_clock" }, + { "label": "Application CT Gen", "seconds": 0.009638083, "metric": "wall_clock" }, + { "label": "Running FHE Application", "seconds": 0.000051333, "metric": "wall_clock" }, + { "label": "Aggregator P4: Aggregation pending -> PlaintextAggregated (wall)", "seconds": 1.588489, "metric": "wall_clock" }, + { "label": "Ciphertext published -> PlaintextAggregated", "seconds": 5.418986167, "metric": "wall_clock" }, + { "label": "Entire Test", "seconds": 42.353041667, "metric": "wall_clock" } + ], + "folded_artifacts": null + }, + "test_exit_code": { + "crisp": 0, + "folded_export": 0, + "enclave_contracts": 0 + } +} diff --git a/circuits/benchmarks/results_insecure_no_agg/integration_summary.json b/circuits/benchmarks/results_insecure_no_agg_micro/integration_summary.json similarity index 67% rename from circuits/benchmarks/results_insecure_no_agg/integration_summary.json rename to circuits/benchmarks/results_insecure_no_agg_micro/integration_summary.json index 73e312b4f1..0b7e790e10 100644 --- a/circuits/benchmarks/results_insecure_no_agg/integration_summary.json +++ b/circuits/benchmarks/results_insecure_no_agg_micro/integration_summary.json @@ -23,96 +23,96 @@ "operation_timings": [ { "name": "CalculateDecryptionKey", - "avg_seconds": 0.119593152, + "avg_seconds": 0.004193153, "runs": 3, - "total_seconds": 0.358779458 + "total_seconds": 0.012579459 }, { "name": "CalculateDecryptionShare", - "avg_seconds": 0.625714819, + "avg_seconds": 0.020384319, "runs": 3, - "total_seconds": 1.877144457 + "total_seconds": 0.061152958 }, { "name": "CalculateThresholdDecryption", - "avg_seconds": 0.555039542, + "avg_seconds": 0.019784084, "runs": 1, - "total_seconds": 0.555039542 + "total_seconds": 0.019784084 }, { "name": "GenEsiSss", - "avg_seconds": 0.126707139, + "avg_seconds": 0.006832208, "runs": 3, - "total_seconds": 0.380121417 + "total_seconds": 0.020496625 }, { "name": "GenPkShareAndSkSss", - "avg_seconds": 0.256695819, + "avg_seconds": 0.010738166, "runs": 3, - "total_seconds": 0.770087459 + "total_seconds": 0.032214499 }, { "name": "ZkDecryptedSharesAggregation", - "avg_seconds": 8.225412791, + "avg_seconds": 1.581275625, "runs": 1, - "total_seconds": 8.225412791 + "total_seconds": 1.581275625 }, { "name": "ZkDkgShareDecryption", - "avg_seconds": 2.350571951, + "avg_seconds": 1.348800493, "runs": 6, - "total_seconds": 14.103431707 + "total_seconds": 8.092802958 }, { "name": "ZkPkAggregation", - "avg_seconds": 1.971270875, + "avg_seconds": 0.704008084, "runs": 1, - "total_seconds": 1.971270875 + "total_seconds": 0.704008084 }, { "name": "ZkPkBfv", - "avg_seconds": 0.429601166, + "avg_seconds": 0.222331778, "runs": 3, - "total_seconds": 1.2888035 + "total_seconds": 0.666995335 }, { "name": "ZkPkGeneration", - "avg_seconds": 2.953823722, + "avg_seconds": 2.461834375, "runs": 3, - "total_seconds": 8.861471166 + "total_seconds": 7.385503126 }, { "name": "ZkShareComputation", - "avg_seconds": 3.007209458, + "avg_seconds": 2.481999513, "runs": 6, - "total_seconds": 18.04325675 + "total_seconds": 14.891997083 }, { "name": "ZkShareEncryption", - "avg_seconds": 5.763399979, + "avg_seconds": 4.130910402, "runs": 24, - "total_seconds": 138.321599497 + "total_seconds": 99.141849665 }, { "name": "ZkThresholdShareDecryption", - "avg_seconds": 7.663020986, + "avg_seconds": 3.425231986, "runs": 3, - "total_seconds": 22.989062958 + "total_seconds": 10.275695958 }, { "name": "ZkVerifyShareDecryptionProofs", - "avg_seconds": 0.102607666, + "avg_seconds": 0.102147833, "runs": 3, - "total_seconds": 0.307823 + "total_seconds": 0.306443501 }, { "name": "ZkVerifyShareProofs", - "avg_seconds": 0.257090858, + "avg_seconds": 0.272140033, "runs": 5, - "total_seconds": 1.285454293 + "total_seconds": 1.360700167 } ], - "operation_timings_total_seconds": 219.33875887, + "operation_timings_total_seconds": 144.553499127, "operation_timings_metric": "tracked_job_wall", "phase_timings": [ { @@ -122,57 +122,57 @@ }, { "label": "Setup completed", - "seconds": 3.058201042, + "seconds": 2.701572083, "metric": "wall_clock" }, { "label": "Committee Setup Completed", - "seconds": 20.257082542, + "seconds": 20.090864792, "metric": "wall_clock" }, { "label": "Committee Finalization Complete", - "seconds": 0.005129541, + "seconds": 0.001990708, "metric": "wall_clock" }, { "label": "Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall)", - "seconds": 1.981342, + "seconds": 0.706576, "metric": "wall_clock" }, { "label": "ThresholdShares -> PublicKeyAggregated", - "seconds": 22.251965458, + "seconds": 13.62430675, "metric": "wall_clock" }, { "label": "E3Request -> PublicKeyAggregated", - "seconds": 24.866107292, + "seconds": 14.129209875, "metric": "wall_clock" }, { "label": "Application CT Gen", - "seconds": 0.309383, + "seconds": 0.009638083, "metric": "wall_clock" }, { "label": "Running FHE Application", - "seconds": 0.003993125, + "seconds": 0.000051333, "metric": "wall_clock" }, { "label": "Aggregator P4: Aggregation pending -> PlaintextAggregated (wall)", - "seconds": 8.253253, + "seconds": 1.588489, "metric": "wall_clock" }, { "label": "Ciphertext published -> PlaintextAggregated", - "seconds": 18.401028833, + "seconds": 5.418986167, "metric": "wall_clock" }, { "label": "Entire Test", - "seconds": 66.904175584, + "seconds": 42.353041667, "metric": "wall_clock" } ], diff --git a/circuits/benchmarks/results_insecure_no_agg/report.md b/circuits/benchmarks/results_insecure_no_agg_micro/report.md similarity index 75% rename from circuits/benchmarks/results_insecure_no_agg/report.md rename to circuits/benchmarks/results_insecure_no_agg_micro/report.md index 37d834f75b..5eba6523a9 100644 --- a/circuits/benchmarks/results_insecure_no_agg/report.md +++ b/circuits/benchmarks/results_insecure_no_agg_micro/report.md @@ -1,9 +1,9 @@ # Enclave ZK Circuit Benchmarks -**Generated:** 2026-05-23 10:09:34 UTC +**Generated:** 2026-05-27 13:34:36 UTC -**Git Branch:** `feat/1549` -**Git Commit:** `8a841717468169df094b7316e57e1008d4ba34b0` +**Git Branch:** `params/dyn-conf` +**Git Commit:** `fc3edc2c86446f20d46b875ca1fca5352645119e` **Committee Size:** `H=3`, `N=3`, `T=1` @@ -45,7 +45,7 @@ Settings for this benchmark run (integration test + Nargo circuit benches on the ## Audit status -> **Incomplete on-chain verify gas:** 3 of 3 artifact verify-gas values are **N/A**. Re-run +> **Incomplete on-chain verify gas:** 2 of 3 artifact verify-gas values are **N/A**. Re-run > `./run_benchmarks.sh` and ensure `extract_crisp_verify_gas.sh` completes (CRISP test + > `test_trbfv_actor` + EVM replay). Calldata gas alone is not sufficient for audit sign-off. @@ -74,39 +74,39 @@ Single-circuit `bb prove` on the benchmark oracle witness (not the integration a | Circuit | Constraints | Prove (s) | Verify (ms) | Proof (KB) | | -------------------- | ----------- | --------- | ----------- | ---------- | -| C0 | 6847 | 0.13 | 26.12 | 15.88 | -| C1 | 57818 | 0.34 | 27.04 | 15.88 | -| C2a | 41244 | 0.32 | 27.34 | 15.88 | -| C2b | 79591 | 0.52 | 27.21 | 15.88 | -| C3a | 120114 | 0.58 | 26.59 | 15.88 | -| C3b | 120114 | 0.58 | 26.59 | 15.88 | -| C4a | 67494 | 0.46 | 26.91 | 15.88 | -| C4b | 67494 | 0.46 | 26.91 | 15.88 | -| C5 | 123624 | 0.57 | 25.66 | 15.88 | -| user_data_encryption | 53732 | 0.34 | 27.20 | 15.88 | -| C6 | 86927 | 0.53 | 26.33 | 15.88 | -| C7 | 90841 | 0.49 | 26.71 | 15.88 | +| C0 | 6847 | 0.12 | 26.76 | 15.88 | +| C1 | 57818 | 0.33 | 25.96 | 15.88 | +| C2a | 41244 | 0.30 | 26.35 | 15.88 | +| C2b | 79591 | 0.49 | 25.77 | 15.88 | +| C3a | 120114 | 0.56 | 26.36 | 15.88 | +| C3b | 120114 | 0.56 | 26.36 | 15.88 | +| C4a | 67494 | 0.46 | 26.59 | 15.88 | +| C4b | 67494 | 0.46 | 26.59 | 15.88 | +| C5 | 123624 | 0.55 | 27.16 | 15.88 | +| user_data_encryption | 53732 | 0.34 | 25.92 | 15.88 | +| C6 | 86927 | 0.51 | 25.47 | 15.88 | +| C7 | 90841 | 0.46 | 26.23 | 15.88 | ### Artifacts | Artifact | Proof size | Public input size | Verify gas | Calldata gas | Total gas | | -------- | ---------- | ----------------- | ---------- | ------------ | --------- | -| Π_DKG | 15.88 KB | 0.12 KB | N/A | 175000 | N/A | -| Π_user | 15.88 KB | 0.12 KB | N/A | 170320 | N/A | -| Π_dec | 15.88 KB | 3.25 KB | N/A | 188232 | N/A | +| Π_DKG | 15.88 KB | 0.12 KB | N/A | 174988 | N/A | +| Π_user | 15.88 KB | 0.12 KB | 2972989 | 170284 | 3143273 | +| Π_dec | 15.88 KB | 3.25 KB | N/A | 188268 | N/A | ### Role / Phase / Activity | Role | Phase | Activity | Metric | Duration | Proof size | Bandwidth | | --------------- | ----- | ----------------------------------------- | -------------- | -------- | ---------- | --------- | -| Each ciphernode | P1 | one-time DKG participation (test harness) | wall_clock | 29.42 s | 127.00 KB | 128.19 KB | -| Aggregator | P2 | C5 + Π_DKG fold (aggregator span) | wall_clock | 2.13 s | 15.88 KB | 16.00 KB | -| User | P3 | per user input | isolated_nargo | 0.67 s | 15.88 KB | 16.00 KB | -| Each ciphernode | P4 | per computation output (C6) | isolated_nargo | 0.53 s | 15.88 KB | 16.00 KB | -| Aggregator | P4 | C7 + Π_dec fold (full publish→aggregate) | wall_clock | 18.68 s | 15.88 KB | 19.12 KB | -| Aggregator | P4 | C7 + fold only (pending→plaintext span) | wall_clock | 8.47 s | 15.88 KB | 19.12 KB | - -_P2 **tracked_job_wall** sum (ZkDkgAggregation + ZkPkAggregation, parallelizable): **2.12 s** — not +| Each ciphernode | P1 | one-time DKG participation (test harness) | wall_clock | 13.62 s | 127.00 KB | 128.19 KB | +| Aggregator | P2 | C5 + Π_DKG fold (aggregator span) | wall_clock | 0.71 s | 15.88 KB | 16.00 KB | +| User | P3 | per user input | isolated_nargo | 0.65 s | 15.88 KB | 16.00 KB | +| Each ciphernode | P4 | per computation output (C6) | isolated_nargo | 0.51 s | 15.88 KB | 16.00 KB | +| Aggregator | P4 | C7 + Π_dec fold (full publish→aggregate) | wall_clock | 5.42 s | 15.88 KB | 19.12 KB | +| Aggregator | P4 | C7 + fold only (pending→plaintext span) | wall_clock | 1.59 s | 15.88 KB | 19.12 KB | + +_P2 **tracked_job_wall** sum (ZkDkgAggregation + ZkPkAggregation, parallelizable): **0.70 s** — not comparable to P2 wall_clock row above._ ## Integration test (`test_trbfv_actor`) @@ -116,39 +116,39 @@ comparable to P2 wall_clock row above._ | Phase | Metric | Duration (s) | | ------------------------------------------------------------------ | ------------ | ------------ | | Starting trbfv actor test | `wall_clock` | 0.00 | -| Setup completed | `wall_clock` | 3.07 | -| Committee Setup Completed | `wall_clock` | 20.25 | -| Committee Finalization Complete | `wall_clock` | 0.01 | -| Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall) | `wall_clock` | 2.13 | -| ThresholdShares -> PublicKeyAggregated | `wall_clock` | 29.42 | -| E3Request -> PublicKeyAggregated | `wall_clock` | 31.98 | -| Application CT Gen | `wall_clock` | 0.31 | +| Setup completed | `wall_clock` | 2.70 | +| Committee Setup Completed | `wall_clock` | 20.09 | +| Committee Finalization Complete | `wall_clock` | 0.00 | +| Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall) | `wall_clock` | 0.71 | +| ThresholdShares -> PublicKeyAggregated | `wall_clock` | 13.62 | +| E3Request -> PublicKeyAggregated | `wall_clock` | 14.13 | +| Application CT Gen | `wall_clock` | 0.01 | | Running FHE Application | `wall_clock` | 0.00 | -| Aggregator P4: Aggregation pending -> PlaintextAggregated (wall) | `wall_clock` | 8.47 | -| Ciphertext published -> PlaintextAggregated | `wall_clock` | 18.68 | -| Entire Test | `wall_clock` | 74.29 | +| Aggregator P4: Aggregation pending -> PlaintextAggregated (wall) | `wall_clock` | 1.59 | +| Ciphertext published -> PlaintextAggregated | `wall_clock` | 5.42 | +| Entire Test | `wall_clock` | 42.35 | ### Multithread job timings (`tracked_job_wall`) | Name | Avg (s) | Runs | Total (s) | | ----------------------------- | ------- | ---- | --------- | -| CalculateDecryptionKey | 0.13 | 3 | 0.39 | -| CalculateDecryptionShare | 0.62 | 3 | 1.87 | -| CalculateThresholdDecryption | 0.55 | 1 | 0.55 | -| GenEsiSss | 0.15 | 3 | 0.45 | -| GenPkShareAndSkSss | 0.24 | 3 | 0.72 | -| ZkDecryptedSharesAggregation | 8.44 | 1 | 8.44 | -| ZkDkgShareDecryption | 2.96 | 6 | 17.79 | -| ZkPkAggregation | 2.12 | 1 | 2.12 | -| ZkPkBfv | 0.43 | 3 | 1.30 | -| ZkPkGeneration | 4.95 | 3 | 14.86 | -| ZkShareComputation | 7.23 | 6 | 43.40 | -| ZkShareEncryption | 7.58 | 24 | 181.95 | -| ZkThresholdShareDecryption | 7.74 | 3 | 23.21 | -| ZkVerifyShareDecryptionProofs | 0.10 | 3 | 0.30 | -| ZkVerifyShareProofs | 0.23 | 5 | 1.14 | - -Sum of tracked job wall time: **298.50 s** — **not** end-to-end latency (jobs run in parallel up to +| CalculateDecryptionKey | 0.00 | 3 | 0.01 | +| CalculateDecryptionShare | 0.02 | 3 | 0.06 | +| CalculateThresholdDecryption | 0.02 | 1 | 0.02 | +| GenEsiSss | 0.01 | 3 | 0.02 | +| GenPkShareAndSkSss | 0.01 | 3 | 0.03 | +| ZkDecryptedSharesAggregation | 1.58 | 1 | 1.58 | +| ZkDkgShareDecryption | 1.35 | 6 | 8.09 | +| ZkPkAggregation | 0.70 | 1 | 0.70 | +| ZkPkBfv | 0.22 | 3 | 0.67 | +| ZkPkGeneration | 2.46 | 3 | 7.39 | +| ZkShareComputation | 2.48 | 6 | 14.89 | +| ZkShareEncryption | 4.13 | 24 | 99.14 | +| ZkThresholdShareDecryption | 3.43 | 3 | 10.28 | +| ZkVerifyShareDecryptionProofs | 0.10 | 3 | 0.31 | +| ZkVerifyShareProofs | 0.27 | 5 | 1.36 | + +Sum of tracked job wall time: **144.55 s** — **not** end-to-end latency (jobs run in parallel up to `BENCHMARK_MULTITHREAD_JOBS`). _Baseline run: node DKG folds and folded Π_DKG / Π_dec export are disabled. Compare with @@ -158,10 +158,10 @@ _Baseline run: node DKG folds and folded Π_DKG / Π_dec export are disabled. Co | Operation | Avg (s) | Runs | Total (s) | | ---------------------------- | ------- | ---- | --------- | -| ZkDecryptedSharesAggregation | 8.44 | 1 | 8.44 | -| ZkPkAggregation | 2.12 | 1 | 2.12 | +| ZkDecryptedSharesAggregation | 1.58 | 1 | 1.58 | +| ZkPkAggregation | 0.70 | 1 | 0.70 | -Sum of aggregation job tracked time: **10.57 s** (parallel CPU work; not P1/P2 wall clock). +Sum of aggregation job tracked time: **2.29 s** (parallel CPU work; not P1/P2 wall clock). ## Raw circuit benchmark JSON (Nargo) diff --git a/circuits/benchmarks/results_secure_agg/crisp_verify_gas.json b/circuits/benchmarks/results_secure_agg/crisp_verify_gas.json deleted file mode 100644 index c758c6a15c..0000000000 --- a/circuits/benchmarks/results_secure_agg/crisp_verify_gas.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "verify_gas": { - "dkg": 3125282, - "user": 2973001, - "dec": 3641070 - }, - "source": "folded_proof_export_plus_crisp_verify_test", - "artifact_sizes_bytes": { - "dkg": { - "proof": 10944, - "public_inputs": 480 - }, - "dec": { - "proof": 10944, - "public_inputs": 3552 - } - }, - "calldata_gas": { - "dkg": { - "proof": 169992, - "public_inputs": 6144, - "total": 176136 - }, - "dec": { - "proof": 170052, - "public_inputs": 17292, - "total": 187344 - } - }, - "integration_summary": { - "integration_test": "test_trbfv_actor", - "benchmark_config": { - "mode": "secure", - "bfv_preset_subdir": "secure-8192", - "bfv_preset": "SecureThreshold8192", - "lambda": 60, - "proof_aggregation_enabled": true, - "multithread_concurrent_jobs": 13, - "committee_h": 3, - "committee_n": 3, - "committee_t": 1, - "nodes_spawned": 20, - "network_model": "in_process_bus", - "testmode_harness": true - }, - "proof_aggregation_enabled": true, - "dkg_fold_attestation_verifier": "0x7969c5eD335650692Bc04293B07F5BF2e7A673C0", - "multithread": { "rayon_threads": 13, "max_simultaneous_rayon_tasks": 13, "cores_available": 14 }, - "operation_timings": [ - { "name": "CalculateDecryptionKey", "avg_seconds": 0.036223306, "runs": 3, "total_seconds": 0.108669918 }, - { "name": "CalculateDecryptionShare", "avg_seconds": 0.156799111, "runs": 3, "total_seconds": 0.470397334 }, - { "name": "CalculateThresholdDecryption", "avg_seconds": 0.234711584, "runs": 1, "total_seconds": 0.234711584 }, - { "name": "GenEsiSss", "avg_seconds": 0.220404125, "runs": 3, "total_seconds": 0.661212376 }, - { "name": "GenPkShareAndSkSss", "avg_seconds": 0.202163278, "runs": 3, "total_seconds": 0.606489834 }, - { "name": "NodeDkgFold/c2ab_fold", "avg_seconds": 7.089881625, "runs": 3, "total_seconds": 21.269644876 }, - { "name": "NodeDkgFold/c3a_fold", "avg_seconds": 57.963919402, "runs": 3, "total_seconds": 173.891758208 }, - { "name": "NodeDkgFold/c3ab_fold", "avg_seconds": 6.906346736, "runs": 3, "total_seconds": 20.719040208 }, - { "name": "NodeDkgFold/c3b_fold", "avg_seconds": 50.328348527, "runs": 3, "total_seconds": 150.985045583 }, - { "name": "NodeDkgFold/c4ab_fold", "avg_seconds": 8.440406458, "runs": 3, "total_seconds": 25.321219375 }, - { "name": "NodeDkgFold/node_fold", "avg_seconds": 15.28584993, "runs": 3, "total_seconds": 45.857549792 }, - { "name": "ZkDecryptedSharesAggregation", "avg_seconds": 2.887353333, "runs": 1, "total_seconds": 2.887353333 }, - { "name": "ZkDecryptionAggregation", "avg_seconds": 47.438696625, "runs": 1, "total_seconds": 47.438696625 }, - { "name": "ZkDkgAggregation", "avg_seconds": 19.61153325, "runs": 1, "total_seconds": 19.61153325 }, - { "name": "ZkDkgShareDecryption", "avg_seconds": 22.058676235, "runs": 6, "total_seconds": 132.352057415 }, - { "name": "ZkNodeDkgFold", "avg_seconds": 146.017955028, "runs": 3, "total_seconds": 438.053865084 }, - { "name": "ZkPkAggregation", "avg_seconds": 24.53227325, "runs": 1, "total_seconds": 24.53227325 }, - { "name": "ZkPkBfv", "avg_seconds": 3.559760472, "runs": 3, "total_seconds": 10.679281417 }, - { "name": "ZkPkGeneration", "avg_seconds": 70.937173541, "runs": 3, "total_seconds": 212.811520625 }, - { "name": "ZkShareComputation", "avg_seconds": 36.93532184, "runs": 6, "total_seconds": 221.611931041 }, - { "name": "ZkShareEncryption", "avg_seconds": 116.868327526, "runs": 36, "total_seconds": 4207.259790957 }, - { "name": "ZkThresholdShareDecryption", "avg_seconds": 106.505539597, "runs": 3, "total_seconds": 319.516618791 }, - { "name": "ZkVerifyShareDecryptionProofs", "avg_seconds": 0.12560836, "runs": 3, "total_seconds": 0.376825082 }, - { "name": "ZkVerifyShareProofs", "avg_seconds": 0.320742583, "runs": 5, "total_seconds": 1.603712916 } - ], - "operation_timings_total_seconds": 6078.861198874, - "operation_timings_metric": "tracked_job_wall", - "phase_timings": [ - { "label": "Starting trbfv actor test", "seconds": 0e-9, "metric": "wall_clock" }, - { "label": "Setup completed", "seconds": 2.661124958, "metric": "wall_clock" }, - { "label": "Committee Setup Completed", "seconds": 20.166480416, "metric": "wall_clock" }, - { "label": "Committee Finalization Complete", "seconds": 0.0012645, "metric": "wall_clock" }, - { "label": "Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall)", "seconds": 162.089313, "metric": "wall_clock" }, - { "label": "ThresholdShares -> PublicKeyAggregated", "seconds": 604.932522792, "metric": "wall_clock" }, - { "label": "E3Request -> PublicKeyAggregated", "seconds": 605.453073833, "metric": "wall_clock" }, - { "label": "Application CT Gen", "seconds": 0.353204792, "metric": "wall_clock" }, - { "label": "Running FHE Application", "seconds": 0.000809292, "metric": "wall_clock" }, - { "label": "Aggregator P4: Aggregation pending -> PlaintextAggregated (wall)", "seconds": 50.493282, "metric": "wall_clock" }, - { "label": "Ciphertext published -> PlaintextAggregated", "seconds": 159.9251575, "metric": "wall_clock" }, - { "label": "Entire Test", "seconds": 788.561521291, "metric": "wall_clock" } - ], - "folded_artifacts": { - "dkg_aggregator": { - "proof_hex": "0x00000000000000000000000000000000000000000000000ddc537f44b53fe45e000000000000000000000000000000000000000000000005d2c364993f27cb360000000000000000000000000000000000000000000000036a97352d8068108600000000000000000000000000000000000000000000000000001db8386de0ea00000000000000000000000000000000000000000000000002bc93d2aa2c401600000000000000000000000000000000000000000000000c0d14f10c5fbb573a00000000000000000000000000000000000000000000000c707bc7be0aaa260c0000000000000000000000000000000000000000000000000002b67cbdce2a1e00000000000000000000000000000000000000000000000cd16482194b961ccf00000000000000000000000000000000000000000000000b86ad9a1e323001d700000000000000000000000000000000000000000000000de1eb22a6bb20778c00000000000000000000000000000000000000000000000000027eea9bef8094000000000000000000000000000000000000000000000002fc183d9b404e5b4f00000000000000000000000000000000000000000000000f8385a2178429603000000000000000000000000000000000000000000000000cb22ed841d6eb43670000000000000000000000000000000000000000000000000000cb1fcdefcffb1d74bb7961ace3f2f70c4e830de967288c03b173bd5158d3e5cd1d7fc55e865a03cd83a7ec11ca7d54aed446132af02f106c160b605361787022be5c8a7d0fd01c35e411edcdb143c708c052dfdedd4e54fc380814b419aa5341068557f1e98511bc88a7061ee755e52288824c391786d6adf9a09090ebdc23941b5572d247e416da2f3733c9efb99ba96eb277e14f3858272621b15735c4cf986eb6f9922ab32bb3beb4a44733ebabe5d94219e318b866bc934894e61df208758067275f6a7e1683d765e17405f0e76a58240bd4c830d911f26e464c227e57d2e92c9a1e85210ce7ac20d92d0db6dc8f9b9f63e554bb78536b2301522f2901d1fca0b0adee9402b670ab72f4bd26fa49e85c45951a984d4bee6c4bf2070544238ed41f1adaeb1ec052c80e75de7cb223007b5f194ed2f28d04cede81a64ab07783f001b76d942d16c4d740f877adb2dea5cb85ea18004f92f4f00e54481fefcd1115186ab43a0acfa1ca0a228aeaacf7ce2429f7a4e9581a243c4029a443ef72a3a321e1682d14a7f2f2757df78eff6768d1f653b2a2994b47864fc4f80e532b46354245b7a02a6e00ba0057129b07cf30279612ab0a64e41eaee79db02dd32ee1eae16f626201d6f39a4950369f70b76175c6dce4ba02eb128ebd52cb75682acc63f21b52792eb92c25245ec066ae29f6a9b69e7980e89a66b0e8ed0b8461e1a3cff3a41629169bb7a7faf7b158af57ac2a8814736fa48f50908a1cffc783e3dcea358a8dab05d4e8b1394a69227bf3fe6686bbd41b65ea8865f9616b853e55d01c263cf4601d3b429b3fbdbf6c3ccbc8bc7613a55080d4952205bea66a6487d50bdfdea2da1966d442fbb7b6d5de94a7f1f66b8f2be77d33671744de4db5ae847949c06e0509fb78c99816ad278049888bb597f7b08870142bb7cac68ad7bd9866571943eb26f4a3efeb2de8d56203502ad26bf6d582fafe6e893716505fca3da244cc36a329057929704d19799de43956ba1863b26da9a90cacdd883e5afe90272482e3831652a8b3992509c56f1c37be3f7da0d5ce3f5dff03f2f28f9f8971e78c0e257129790bad219e62911680c2b8262c491a19c65a69e2801de14920a8e49539f7782820f32def40017e1af00ec6d325e4c82b26d4dc738596294c15ecec975ad3b00ba9388f8956cfbafba1f6c76a2a9367c27738125e6f97cad3118711c432342e01a4efa9335931898b9d34cab011ec52bc1f426517facd578e65d3937685f8192b4abb55aaa96dfa5fc246f5bbe5bc9777f78e01e8c44a8fdb90646fd71d0d641738a84b0f2d2d822d017cbd5c5d9d7363eeb71b6098d280119b1ecf9b90f4610307dc478a39d30eb8998fad0001bd00ff2bed07374e5dd387830c146323519e08f35ab390d4282810ac470f17b1ca6326ea2421d6119c6742dcaacd76c30286282dba21e7d7389bde163c696622d88838635b4a546d17f1600c18b748c9f72c2553375c44b53f71a52bca0c87762df6552408a5f4500965614a5b03d4fede551658351460482c296ccb4154aab50e4ccca5cdc55fa75423c3d84c64f70518b208aa01ded1676e0474d468ad377ca4d2b89ab3cb3d3963de0a6b13b1debce552033885824e78ea0027af972aa760ccfc5e7fe7755a65a6c6e4d532a33aa47c39099e1828b109c1ac9114251607526ecbbaafb83e8fe2efb0c5388ce62ea3711b2b28c132f05e1a371ceaa48cbb778b4db0530d863efe66dc5a00840ee3bdc0f71cda948b42a5a7059b54dfbec5be13a982ecd3d08e07db4e9b740afe7b136f6129ebc34c7ec5021908b52d65363cd12854f10066c1a0e09a9733d4a304ed41801ee2ccf5b72db94d42ead97f746f5b92eabd9115d8d3c47c7198f0c59f61c82c2e6cd40132c27b3a7014a3d0404857ace260b2cef00871951e08d2fe4af80cdc20b67b6dec13d790f840cd45bc09fb36f7e9edb1576aac1fed6309d69d9b4bdc23a372afc89b2b8c7f8f0b4d5a8a9964d817ec367098dc3baf84a14233a8b24c160d1e3cc9588f8c29ee86bf38c8467751c54dc206ecd20dbc041b9edb0efcf721eb824ff79a781cfc29baa77eadc827e1faa60d2ca595aaaf41b05f47403df5054d2e48bd550fc31e258c9aea79d587deff0e66ab7e24df5ef60a675dc0d5d61b9ff4f004a2ccd4320ba46ab42593fa9ff56741d268418ad57e8cc69060e112173229ebb2deb9626294c2c341417b9274d7624bf0f7bfad9d66b10d28b8a03116f1913cce922e6dba33eb29a98210fb69f529a830d6040c5f0117608ca3ceeb2301f5fa825d225c3bbc88b05c33ea0e41eb014c66441d5a9947fc4680d35e421dee79f2143d0497c9179af370b754e0224e003d05fecab656f64a823fefe44313b30bf0007ad379d1ca866ab25f493e8e18900fb389ac5415f67156120bd77c1d83e3909193ba0d2b16ad19811ceb4ad3d742b50246378e6fb6e45468e9008a1775f8bde9dc6a8231c8f474efdd6f11f695e86315777cc234f2c04bf87252c12fc8850ee7143a98fb139e12b5cddcb9215993cd57f93020e31082160c1540fa0ee8fa70c9c36ae886a7e4a52840ac356a9c28b4a0cc432f0a57d049d9c60ea52f9afcaa6d4f8d79c21ae5b04777811f9960f0fffd52580320d0fa196009634e0b20b84cf5dda38ead8c9dfd830c5aeba4fc6a0d4ef749993b144954888993560f5144b9c881f632066f6c63c95f4066fafb419bd9601c028ca2546fd6c3efda0b99e191422cdca5d0e71bbad1c8f5e358b973d75042b1dbe0d437393ada02fe22b41dfbcfc9155f55bcc64ecf82d0a67d810009043901d592b0a810c89a910b1ea0e956bf5eed9782a9ee48cc3a97b989f1ccfd38e3a2c24cbed0109ef89d151c96ad5afa7c6d2e7219744a1338debcb9f41485d602f9c2cf30efb8f22adf390291fcf0d2a9ec8464d8180854056c10dadbb17a051f9c2fa1389962ae877246190150bc8fdf39bb570e596c3ef14377483c735c8325a32b2709ca1e939c9d3304855cb7c5d17fad910f9842c598b174fa9c275096076e45af017ffe4d0f9b41129d3cfe4ec19dc4f72a61ce91e290353e9d411dab365e3cfc43583fb9c8be7c2e0f7417e6953d9c8116c57bbde9964dc413f454ba813aa314c4c9dce76b00c9136add93dccb1318d338c95faf456f6ce48ddfea69c406741a3e59dbc207cc9a190806c021ece63a687d90e4ff7fc6172c53f1b23827409310b5a44f62fa60292055a94c5a8d3471dcb94e967000cb2decbcfa85aa6bfbe4743e08a1ee230ace1efac82370ba2f09fa77016274bbdd487475e100862dc8fbb80382bc69de285c0bd0047ba0aa8ec022bc23168d5afa5b1d3a1ad7bd4b9c2ebd431d3bbce150a70f29dd3aada8fba9f7cd5d5db945f024a9dea0dc51a27752f0be20b4483ed1f5134d34dfc8dda93da80b5cb0135d3e4f1b3acd5895afe9f691dfe5a41109caf52391b88832ea4c3d2b8627b03beda0692826fb896c237e415c9058a78be861841bb561ac86c2c8800167ddcec4067160125bbb52a30f0a1c7a8cbc2cf4e1dcc107d74dcf175389be3287894d9a8ca93a7f13f4b482f4d96b5a755388c175b67f077bf625750b2cc8492e3829624f6acaf7206c352edcb0860416f30c5900359518496a52f58dcffa59213f02a3968e939b821acf25c1d54ac8e27b5037799a971a45440c2bf0c8294f291765bb3f195dafc6cd825641f439c909de60f22df7d90570f8581fd144d8e336e732cf807c575696fc5974beb6d327d0f4e50fdece5c20104dda0e51dcec48d30f4ffe4765a5fa9f4a2bdcc2ba09ad027c2ebe4188cf02c493f0beec1b3aec852dff73de5ba65fd4704359f4e7954158bf624d937a0b09c929bc6fd95c537456c59599363f86fdfdf5b7d2b58ef05fb1b62c4f93945e1e9b7f217eab940cbd9d3dc027a2614a0e0ac55d6a5f4fc517c77a610772a6d5067e09832583efad6905bdbec52a599aa83ba05aa495f7cff70fe7fef1e8f9e322b71ffe815a45f39d91a5606a09f8725c76214aab8c32bc3a2ca3d1c4f6f342210f1e70ba357d8e93e48c3fb547aba790c9548057837506e9d4023e026050ca154cc3aaf0c7d60316c7f56a6ba004273b5c1a08881c83cd592b770e063f5db6194b4543e50e6b2d4fd1828703ebcd61f0e0e8238c7c2907f640ad2245e6f8df296178c5b6c882031dd6f0b4769251c1cc7243b4137447d868802cef801b2b7c214299d10918e2da7ef9a09e2bd9e11432798d3054d50e494c0da81d33d89a2607f681bd3f241f731f09477538456c7b3a0157ce568d7d4c828a4c24dce4e2b10cea115a9802c9cfbc41c26092502ace91f9937f175d77e3f165ee57b2ae6148293043f2a0c21b1110c61e1d48ebd32277db4f3f8fa1a44148cdcf7ae17d901310ba46c7249cb240b5c8e89ccbc193ea405bd845baf1616b538abd45acd32e250b0eb91ba32c5f67e81b79cc12e4b202a3a514ddf1c33f55d76a78dd2a6f431216cd9459be0440312a230538e2c08e9eb699323c3ea330fca18c022801cc6bcf1be0daec57bbbd18d2b11084198ea0cbe1d5b1f16f4c9c2f912d01e6f8b386610a28f67f554cd1490c99771a65f50623d2fd504f9c4ed37c92011ff0b00fd73f2e96733327ef59d02451b02b31243d6de810ab7d4bbe38cc5c4132712f9e649b292aeed91c210ad7f26e8b460f9a2cbd737062f3479f6790b0d85e6b128901da2c988129a0ed53916b48753bbce885de1a2f74afef8cf38b2dd4d8aad9fd5a7e13f32b602a56d2fe14c56a40cdb217be8516b43d718ae6218a02c8489fbe23562cfec06264e235fb768619a1c68daee1f5343fa2fbc9dd496b59aca837eafeca1c526e5ad567e4a3c658bd6de68af23a0a436df9f7f3f29f0ff683cc517a04580fa8bd2d49661956354885fb019f0cd95b7b7db7d8de723a7cf201babafb415f06da7a7d803e8584a58a41c24ae54f7ea86798affd2ec39e5971f63887d3bc631b8ebd9aebb270eebe21f676d194077a0492a039335bbc974e1a7e8e5e3b187b005cfce57954aa83f4f1373b857dd0e9108f15b8a3319cef2baf99a947447a6e0970c4556b9cf6a5f7c9b1c4a16e1327cfbb978db10ea891a2ef12d50a37cb040ff5378b30441161af327ce465ca56b4093e3eda29ec439c89dc32425bd33a6b0259d8d1d4319bab6eda9a614f0f78eee496b69ab9fdd9aedc3391378993c459027d87ba74779c68221b5b1e24712803e9f034793753d49d661fcc34af88b67a2eb483c76fa9350617c43cb676482acc4e4516cabb406264d4e41fed5f4d800b197e44dd76820dc1d207e1eadb5fbf61ac15b6dd1c7f34dba0210c84606971fb2094e779db97d0fe0250b61846c330025c5c951e7ea310f0482708886d6288c12527abb45cb435c1579afd6dea2799b69e5298f3e6325f2926583697b5e2b5e21515e902fd878d2706b6377e4a86dd3e75e9f1c6d5358b69898d7579e05df9ea09955053c4b5d8f47e09260b20094fc317222707a15fcad33d54ebb0a286f20522163de47ce56a75b960afcf3ad78fe489bce9499c2aaba40725da1d0d3753eb23e9215f54dc85bdd4633ee04cc3feac16e1961804fbc82b69144f0d02cdc09b08635aec4f87f85d0f8c2c235c257389f68de57c17570ea93bbdeb89aa489c7e2d06f6ddde1845c36d494c75adaeaf4e7f71ab4c3ddbff29c3a02b1d2df0bdff2fd17b65e8f3ef08cc0bfc3298b30a9ecbfa8748e5dfa71a6c479b7c5a2c68e60b8b5d197e76d358697acd62ca4d0f0b4ab5c7a1a6947508e0f1c5f9af1a4d2402ac2c8f342cff48a42c6cba919a995820f017a9215ad63a7cf6b85aea4bb44a2ddd40c367f7b0d4db0755f1f0513e8524e2fbcc4ea1cc65eb312ac3a0ff85f4287e803ad96215b8d15abb6a304a8c0f13bfb0d673d9b9a188e8bd6b56de3ee426c3ccbd67dd0b3996a9719948469dad9f074a13094f68e012cb4f6dcc18a9d92c504aaa12f96b40e0dcc1822332351be7c39d99a32b099abd4bef860b50e58a03bdb1f0fdd97afd4b44426fbbd310c7162282cb6cc5681a5d34c8792e7671840661eb520c57338c07b2b400bff64f9098a66d2aa940eeb9dd8d080e274620b022e6a97b9dea474a50239371cc56bed9a42501ee62a633aa6808daf395da3c8816947be7efd0e3c76672fd721740f8984d4c0529770f90560ba8a139c4f7ac6523acf595db0a22ad14e9552813447cb062fc03588da0bec34a24d282a7de1889063cd32f9dba2749bed618a058e3be4c300735d339e3f39afb597c470c287c3620c845653d8bda6ff9403c4e297a697a09dec0e9eac2cc5f590f152ddf12b0bd1f0425e8814a418457d8ced41d0d54e10057d8fe626ed42f6a69a7981809fb310a321c501eaf6f32dd062bdc21a63ad2b9a509a0d7d7362972449fba64911a3f0c850b147619d6f54f6437612fa2c18d1bec1016c640fe49367c05a1096894e4033f004ac462a4c4fc2aacf97f4303834e99878ccd540822891a8cf1baccc0042989e91fa78091f21264783ee35463fda706bd6bf6c3741cc7191892050c36c611395fae2e9bcdbb8d8d4a820a1391d5b4395cffb38f1a23d3ad3389c4e13e601842eec0dc4f455637e9912489865c89a373fa4d6e0cdd95b9a36043032523cf197a2f7a626193b18e466a3f5333ab0a576b7a6c572c8b67352f13d570809d6d0ae6457f3be1367321458a0e4cc1453d02460bc831f9c268488ad05f1433ccd0271ecde0885fc671c03a6d62646ea177e0bd6d7a3c579ad57ae0cafa74ccca141c15b844d1c1ab9deffc01df3f7fa8396ac7fa4c7576f689f22949b2915bd6c9161b73eeade29e2603da9d7d86e6cb95baa6c8bd0381b284378b2cf964fcbeee2d05ae518781466b3302f7561b144d6ac87de4bc42056911ca7f594555e4a5bd2c228205de015357c2903f7d9172e9789359250088e4797c458c6f439f57ec881fbbca82dc4ec32547233fd8b9d0f464e8c9cd656e151e6e7f573cce989e8335259537582f5e8096dc5b6c1a2d5f1941b9d01761ab23811b7e86df9d9a9ff7de2304576421d982b42b61ddc6148e03a73deee2e734616c495af2eb08c76cce640795dff87432b303fd8552a8e0bfc097667dde8f1434a2a4458e7e3e63b2d2e31fcc077096bd6aa45ffe9c70ae160cb4d5e2d28854bd889ba3155ce0ef9d087002539dc1ca5eaa4c94ee4f6b8f8199a1ddc619a061c261bda03b79c8c1ff158124ddd94fbe30c2ba65f28ecd47d77724340ec1fb1143c150a014e2241b78c8801364f1b969518cd9d8a46e0a4b2526680351086bfe08d3a0611f5402fc8ff7a2253c9dc9121f43c741d9059fdd5a5bfc68b8367576fcefeb2103d8f2057614a42e38726adf28f52dbc15715e283dd4d3e315ebea3d87cb5681e648783c45631b17489def600de32fe48770d6f8b47af009996c343952dc446322afe142c7a0ae2fa2ae3dd68945a1e5b1cb742a36aad5bf6ece555e28863ffcbbddd985b201132a1a3a08ac58724b1cd5330dd46b18833b3349816a5dd935d98cf89215f41bd51294aaff14004a783e89eec6acd648afb645793dfcd5e4ab7a6406a7b06c85cf00533eaf77c6ddbff3d25aa4839cc5d6aa0f14a5925c0a32d9a445768524164e2da427ccf8e54b7a9bf52299e01b91c868cf5b4044b45ef5ca65da8d3ee799fa20549181f77be66bc9817005e53bd1e531e6dee9dd0f20ca8c3fca42ae8908872fb3427f975bf8bdbbc304d78748317f4b67bd3dc7de4fe9b1b157edff159e561ebb0f00f5b33cb3909a8a497869f51887c3db6a9b772f81fe2884ede9caa523046986bd5d116527e1ea70b1f80828a499e31debc9b76844336025ad1b21b3d2015c6b1a54f0545b2cb529e8afeda16aa48ce0d0ece560f74ef2f581c66a081600066eba0b1bf195e16462af77610d6a151195830bd0d055bca6d1849483129a18ea91d797dfc1e0f6d07a3436d18c0c5f334a5c4aadf2e5056d19d0159c715e2cd650319d32667e302d8a9fef3af6a9545e0849f21a07796e59057adc42627a0a5f8c5ea318a090a49792860132f0fd5d4919ee50f200416a5a2af10acc58971f811402abf9047c9fccbabc6f83492467fb15148eefbf12e03cf4d5dc73c8b11cdc329719b4f8c52eaaf5815a0e933a84288d3b82bd6d386fbc4aeb2bc54ae70d67171c67f54db3f36baefa981e124737f1ba0695c790535ad233b152fa5892175ef3e3f23f536a8d0a6652c20e2e82576798cdbfcd649236dfc11538f345b405005ac1a5ccf6b49759d8798973e0df4e77e0c89fd098e8419abfe2f5896067246380154e1c9194733a0642df08c2e1298030c2cda913afccfd1f25e5bc92921e6e5271b9d827c85fe64ec46d1d6b1b7c7652c3fb8aea513e179568c8b9fae1064208d306916576137f0074229737030a22f693a6e1e27ba3a2799240cf04f21a4906b79794c495cc5a0c3172f64240935363b2a03b8a498403055b57fdcbe60e976d7a65534759f378a8367c72ca4e53cba16fb2fd4c269be99f9c0b95766e199b0cd0ea8195a74b08a789ef979eaff7f5b1f2d2304b25fe75959e4535e2842c510fd683ce6a57e9f88241a6f5e1c83b344d1e48e8eef6207f4c695a7160e42d9da2b737bfac00c86673a90cf1af4207b91965c1452df1cdbce7fcec877fe50ffb6145770c0185228a56decdab132677f095f41faa588913a7dbf6d99b9ebc195574350eb6ffec25f1454cb04f10bac2497afa7c07b1fe972a0d9a5130df5200d03cd4e2d8dd918eba724e04844ae0ef024e4d0816c80701c32d846e69b3d1099ab8d3f7a5bdc46fd4ebcfcf083126cd4f29058da7f6527510a56b2728c5a305a5890ea3956c25e5e70be606eed43f110c13e4e5c62a295060104eed434c290ccd370073feb94b0cb270833420422239240910eb8bf68d9e64695bae4ae47b0faa67b705e5dc498a3de1fea3e10d1f180ff73a45e47adec3bbfe0e6f74fc1508adca94c2940a080ed3201011cc8600a4587a4d7b5c118248d435316f6892b60e1c4cc049fed472eb006cabe94d3227a597107ee6ae46ac2b0495da4e2312bd2c2665f1e8f3b3af04bd11268ea793221028ac9a53af4de4469bcb38e6b7805a1bd4534282283baf404766e3aabc57e27eaafe6e3d526ff63ae74ad59ccaba350bdbc329066524225e4c83df6d4976b67c75a0fe0bf26ecb8917a001ff03e5182a561b20265f192fcc1e8913e9b604dd3a8c50dc6de4dcb715aa8c5ed6b1dee520849e74cf1e25c665e7ac8623d5786b551d0e83fdecb7a2e048918f795f25d9245e7c2b4b08639891fa08744c96c8ae610c5e00bbd4c00fb8c78cd5a56a6d9d1c3b91a8aa49d2bc9aa7487ee2675248afd559f2bf2e53241be700c20330aa98139849bbd25fa918c0d00ee715387f388e01ddafa0d9f32f535026c2a1d5e5ca1c7786f70297f692765b5c2060e003779ec678f25b0a8ad3f09003868e31d4ca1490751969755664bf9099ba09af48676c203ef6d893819fe75f9f080a9010cb0641d4108e4a034e1066aea62380082e9462d5dbd9763295152115d3d906e0f81405b67c03040f1fdba9e8a22291cee66a213da00a1a82939ca5585889443c582467dc98c1ec7db2ad0cc5675d6e57fdd11b0d261f95c9c493127173e9abb79820d59d5bc621de7d92f73eb795acc475365f9ec3e00f62de73e8aa17b0d82a2b0704b5f64f67f0a5bdf5b78ac8e7b56323104b97abfa18b8f618b6ff8ac515d30dc7e24688b5bc661dece854e144c2e6844fa0f73151bec43c707b8a904c1ba401150cf476ac133608609a2deeee4be71914f8e2dfa87d9eddab673fcefb8dcc149e3bd4398c3e21fe4f9c94a3a95b0af114e67e4d3256f6ca5769f8d030057a03c8392bee6c04094e843903fdeba4cb6b1200dbbf22b1c057b17d1fc74ebf0e2b948c48cfba494b57cf41d63076d21d63461940d91ad5c7e8b0b9119bd9f070029c395ffb2aa0e6a42c50428ab7b9e4601f855e3b2f5a517b47aaf4530d4c3703d108a6c9ef64f6333c26a8743f82a9de11622f91ba4df5453d0d8232a12f1807cdfe00795b0fce05816ae6000db48ff5a3b377cfc808ae6a34a1b751a2396709e981d204e448bf2944cf4eec8b08c07fe3e7d36d29378fe0aa213d1846767c0cbeda7d1d59676a17858927d239317a93d6abcbf2d85c35bf6887d987f8b1dc1ba48554530c6c891ae05d490a57578b9dd98d2f5ab56ef27e49d60fac56abd727f7d7d9b9edefd4b80adc1d26d96a02055030ae5b8b56f5370ac99312cb9490248fde5d277d0de526e0e8e4502190cd6bb86addadf33ce872838dff1bf67e8322c55d8f29137c13c8028fd4712a8c59ef5357e978b01bfd5de3caa9372195d51392e91f4e30a060d554050d0f5f69017511a188c84eed0eb705862f714268381e81321f0c2fd174a4c84063444dfe47ea087231e50acfe22137c25ce4d6bda02598f4d95b3b644a74e80a2dd2a9cbdfdc60db1cb3d9e81699915e8986c24a992b9c3c317cc4e2323de8a35c71a5b48b39196ae83ebaadc7b89c2614c187c4122b0d2003927f576ddf71f89698fcc08c9164a02dec95f7850e592dcc22c0d5532dafff7ed0586e92406009bf7252044ae37de2de248a0920419ccc9306243bd20d02984910cc33998f22c46a75e769312f46335cbe0839b44dc97f3a8dbe4c9b1eef663adf180e97f4dc8193376f7638a96512f0162bdf052c6f70b68712a9c52394216753b6e40d27875f59202d6169a3be15181c6820fdc55f5520a21feb402ad28a19292df4f84673c3e470e5f4bace0c17074649c80d78a2fceab1837af4286e0556a9b68e99edfda0f1b4d816edb9a17133b306fbd713cc57e73d7fbe4626e8a5db2e9ecefb436349c7c60683cfd01d8c292be9e7be832a93466e72662b06345508f78a1c229cad1d62974be787f3b43446e56c0ec14c7c1916909c59681f510273651cbbfd259282295fe30800d0abc96432b550df4b2cba15971768190a089a294e6395f7db1923b045ba49a9288344abde983e246667136886d1d6451c2e590f932f74a6919e95b43a356b38233212e30eb1ffa92a972031fabaa5992ff19f5e7adcfa424b76e1794930378c2ec7d417b0ba06c0995497b4bfb5193909852443a975b6f2f1eb35f76414bed66cdbb4d78127d777085949554cc066be0a389061a2612de4e3aff95ab471fca7edd7c325e46b6392741d0a8a6384393e1d88ee0ab0217ca4cdd7a540ebc592450a7ccefb601b787b8bb37f87acce0dcf05aa8dab9248671e0c4ae48e68be16c28e9fa7892392c327d920e7f228b1818c0fb6ce357e2a6f432a73b1625270de7598cfad78fcd4ed8cd61e0caeaea73e90025ad2263a0491cad774433a6a2a5603552d2432c3562df1960448cfc5c77e9600a342e5a0fb59d2d3c59a5cad80e7e89a6cde76404a5192b764aa2a5440ca4f2f53b36d1f973eb8a42f76cb8b85a96edbf9ede2a7e45e873caee089870a64d30154122507aef82763f71c119738f8e630ba183c3dad4bd7dcb22e154915ebed2d3049ad556433a3d477113a0d1ec2183cb40ecf9c7b2205a9d2313b9d284f881eaa5a0df0c779a62ec623fa625564c908819871d0eda6ebb87dae27cce9b217108c253412257762231fa826d1ca59d856d2422a3b70ad8db8f835e43facaa7517f412592fd56b55c738e15626155265f5e08a30f9e2380ff939680fd31d5c9818147d43dedd9a75c130e01343ebfcef42f34d9d58a395666159665edf5517a715e11370386245aaf38e979a6de8d004b021644af89e3a8af6a9895e15ffa5a62a85a2ce71fb035b791c43e9fc861c3fc0378cc445354c2aabe5fdc8fd6abc7e2dde7e824d41360f1c664770896d164a66d81f1c2099b852ac1b6231abccfa271554713725102613e592527272ee3de12a518a648515ab7bcbec838cba30bac22645dca6372e6823a08deebe71d5ea98807e9b3ceab9bcb3e98d3d21fb7bc97314374f8736eef149f81d7e60d6d08c3a748759a1e1b25f0d7aa34af578bd8d1909e5ee4dc730b341d2fa5b0f1e1c62d5491d963ef95bf6b074f471cd67bb3be21f25316306a63927aee248ea0e760d9e8991b53ae4344fefc91c6931964a25e70b13c0df04d755b1031a1bb9cc7c0cb893f033119f60ed7916b09a4744a7c4932f9d724b44a7274973743bd5ce061cfe78aaa07e08d9f7a69e8acd260ecd091a1ec7bd6bc2c86edeedea3839063635ccfc602b537edf32df8a6812eca9599b082cf34280289889631b9472c574029ebf387bdb6cbbcbc867e90519cf30e47224167b9eb6869fe71cd56741bfa44aa926f0373e0e53ffbc68d27fe5aaa2f7a7531407a65fe05dcc42adbbc2e15a6afd7a3c78e2f101fb8bc68725bd41f079ee5e2a5d465e57653e462f4cc3ec94e2a007b90caf34b0677c9e56aba559648b740822261f54ac4a38a21b66b734917e2db39284bad9731e58dbb666de753ab11f8121b935c281a326d7fe09dc225c0b5c0b5b0c315ba36d6f9671d83f86c238edc12e2a8ec4ef750cb0d3d098e85595ba077f002771dcab930abbce17624af0fc9803bb78964b8f69e83af710afe5d6cc8f47845633e779372fd4c378ae0a07544714bd1fab35ef607011c6d0928c03ac61f8bb16ef1689c63e520dd1e0061aa08502f49c527327715326a820d485cd07887a0d6e8adcaa8c1c4fb19ca753f2b4911717e8bf9d6de58b0ebfff6e1cb1c119116acfe1139ae905d532195621e8c7811b27a3237feb01af93b31c594c294f44db4b13d52caf64b91b28c85bdf10e3972e3fd306b16506999526687bffcc8b26ebae98d5458b10a56eadeb0359dafc771d5c821d5148fa5058ffd8ad8879ab993239dfa206269faa645b647f130ae331016c801d4200a4177566cc3d3838c45109a407b55de78941ffae8fe6177b1d1210644651ae0a77c1c7ab833a81a97e2b30766308b80045d91a5d4437f6c1b0bf205f4a40802c211764dac2ff9932cb07239480b1c0db1f67befdc739d191fcc40edb870842d4f014faae3b25722c93da7b5356ef9f59d394706fd9b4848e6cdd1f6d981d02c1e5830ae59799d597b732447560c47d82bd2a41ce7c3f119b064d10edee9a05fa19bba76589ab0deaf8706b80a7286618a2c66fe78004183c0fa91651a96260d0d914f3f8f3c43c77163254d0a09b3fc95cc11f92350ad2e33f6c169d8029d882d113f3fa27bcf5d4edadc971370be191b313598bf2649c391016007fb5174ccd52d7012d39d1d861a731cc45b296ba1f6845c912e4211782a09a2e82d38f190f8ffffab2e164ceb7a39337411ba9f57f9ea55d6f215a47a897bc2501d65e640c578dea884cd14c5c854f530741f7e45673d9391a3e40ef11f5080cd5e73f44a0a318bc94065bb85f4bc8bc8220b5dada187ffcac245a5fe5fcd61c0c2688914c38700447fc88588de588e942e4b73a32966af7b994d407f3bf2f1dc0d164711f06e29c2cde0f865e99b56e28f1c6d9b3a8d5976edc08efee5cc029959b87f456b940aff559971f91334860bbd138282f42369a3b9b1a298298201ca74935b9233330ad150343dae999e788a0914e33cd5dbc2125239ced1e0f922e57d857cdc852fbea618373df51bd7eb85d605c0765a81d70e07ff4870fb4512fa199f4529c894809df36783c415b4102b3671c9bfec49b039f6ec3af71a0420c9d9d7da74284cf82394e1fc3cda21c5a6f0b769bd841fcd4ec5cfdd94d18cd1ca649c949279e93aa7985fb1752a6c0535cdcd5290523cfb3b1e1675b9098341052cf410383a5991c77cb7c4c329dd77da3da6df0a086c596134a966dd14f71234e7b68f13b28313ec6e69d74f41532308f6582b6dd4090db9eef2e26b177391d074f90db2eea4083f25148f5585168aa5941b6086e78d1c5d7425329465ac9072d1d51448700c369ffafe578e56577af31dab3eb3581b151fb0c81435e9e451328ba5869ffc8b023bad9485a18be42d9b36f455a2fc8929b98b036257f6e3205b75ffb76fd5e259e348d4ba64aa2862c132fa015c12fe25fc56cbf76b370d51ba172bd0d5f4ac5f2fc2c1e9e33e5281ea25504a3121a5a9055fc28f59044702a750776c47fc301e959e462d940aa019d5d3e6993572d41848668f6687f3c30076bedcdf79e500dd3d6e39fb8dfb771e0c1f61d11a83ffd13deac03879d282d1751f5771ab8236b6303e5ca5ae50e12eaf2c64e02ad5aabe15ff5bbf2f7d20017165e21a1b3c39e90633fd4e52ffd25dabb3c2359a6bcae94177d3b069fb6632c0ec01b6dbd3c695bdce702564f350412c6c7826d036befcc5b1fb5f39735022780f41ab74fca8eb93edac43ce9fcee8979fd9c3fe80894878a0a75c89f962a2583188a91999edb980c6dc1c0b1cddbbfb0dc2f54c1831b97e1f2d58687fe2b0dfd7ed13545140103e66d9ef7bf01ab4c8d3b184295992a34f43683c66f373e29154b5ebcc4f8affbb07b63eae67d86c7e2a58f4c64b6c3e0d5f6e2e2f962860eb40f1c56f6b2cebe7e9af8b9b3ca86c23c3a7bd479a1df867a2dae4b41088c0e02a0e0688ee555038909a12383e469c8b5c8794a23e11b473776ff83ca8ec029961ad53a2b243dbcf6093ec89a9619606791535381bb773aa59d76a0bc0275", - "public_inputs_hex": "0x1d420eaa08a65528f470fd3e2a802913b611527f41fca008a0ad4e974750780303f2ad158d360e938540cb9fc2ecbc5168b0078e536f2a2c847cc131d440ec0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000c6e378e01efa1cb216ab0ced340b44360000000000000000000000000000000097621038a18ea02190913636079ece971a28590517ffbdf7ff33ba52157bce68c37c073712ba7f38d05290ebf864b98223de00e9e865ef8e388eeef184b6f39f6bc05eb3d0c54021d2345bd1729316ef17122a4b371cc1b35e37beb851894eee43c8b48d01f6e641ad9ba6e94da997fb154d92131d18a3d5e38ef60661e890f7ed9c3c630efffcd8e51ee7278f13333e167714b66b4e3e97a46578eceefc9955b033a18e6f8ec8add6f96a917a74414421b654b589d9ba8107e6007b5a8b71a20fb1deff0cf22904da6dd4303e7342972486fb2c422fc657a57fb1fa3501d8a94e68d15348674a20401c431592ca2aaf2dff57e20c39913382bfeaafbe4d2daf8171ebe9a277a845723db5482f9128cd" - }, - "decryption_aggregator": { - "proof_hex": "0x00000000000000000000000000000000000000000000000616da7fc6a6d8cf29000000000000000000000000000000000000000000000009587bbfcd4668d960000000000000000000000000000000000000000000000006121d7f725ab890ec000000000000000000000000000000000000000000000000000254c3d3438de000000000000000000000000000000000000000000000000da6daa0c6a5d1b5ee00000000000000000000000000000000000000000000000704ad42ddbc8965a70000000000000000000000000000000000000000000000044dae6888c0469bbc000000000000000000000000000000000000000000000000000038249694578500000000000000000000000000000000000000000000000cbe544e1f83d0969a00000000000000000000000000000000000000000000000f022e5672b0d807a7000000000000000000000000000000000000000000000007ea76b9db2039b97e0000000000000000000000000000000000000000000000000002b08a8ad0db8d00000000000000000000000000000000000000000000000d86835de0e0ee2dd80000000000000000000000000000000000000000000000069601171ff6c2bd9200000000000000000000000000000000000000000000000dc64e0a8399e2eb41000000000000000000000000000000000000000000000000000122eb6e0ea81d1d0f557691796b92e9da20b93e97a0863ab1fe2ee78478842a0c49f45fc99fad1db541b4e5adbd88c9ddba68378f955a0fb8fee6c21ddfc8e2fd73d6ff009a283005d6958a7b2064dcf37a906df83f6046a1c41199c4fcc7b1de51bc48831aa306e4801d58d108d333a100de61c3a7c902d11c47b1f3c7d3a0b25a6ad72132132f09bb7f0634f4b826b2ba79aed873c3f63f0bb72625a7d02b4ccc92408ae597051f526e4e6e94fee05e2ae2d8e4b12904bda66ebd9c9d51e9961cfced09cbe11d880ce4fb8dbfbd641d0c0636c70c7c15bf3e232af15eba8b04b2cd763212bf230710d91859e6bf1de118a016a84a1174041993b37a39e1bc004c1b8da7c3b82b019a2526f1f013dbb5954649960459a4c506bf44865e1d6806947274b51dbd0045c746ab31b273af3beb543fb20fc9cfff80cbe7db0a0b511d2f9b14502ff12f5766c56461c016ee71291019c84e22c333cd16bf76310569b0871fdfc9d31b1da62e4933273fec94c2a3cc680ba04e9b6b233a0d13147367ded65fcd59d53406e9772bf6e4ac857b26dc812bf34a1db26c1b64a233b0260626c2469164115910b03889019586c0037c32ea2286fbe1bb31259f82545e8627c3b9e841226d212afe130cf4a9b76961d989066bbbeb66a469dc0b056c285083d68c76bc2ee0f10f7a0f8441de08dad090e4f7d846c46c311aa23fd6f18f312c62c8b007bd61472a2fa97e9e5e5abbf3e1351c8275791fb7d97b289da247a09935c9d149beb26a1d562f06793f41cf7b646a4e457adf890d6f0bbfd0ac668e53ac69d0eea63b8329280e22aad07e3aed7cb334e20e466b04dcd0ce6085feb9a6e975f08da975cd1d816b4b170d94dabe92ba65bc039266a2814b2a91ff6d9cd59dc8488720894a04abd5ba314a630e81139ae7217116133f998269c10294813aa4775e0b16da5a0d23169f49db334305c3cbad59b33c9c08ca8fa4c5ddc084767a3a1005877fad196bbf853f6103f56544f009d9ae15132acb6b48466e73ae67d8c56770d2b4131997c4345fb6896ba5378db26aa654c77a7115a54cbabcf7acc4d40bfd53de0211274d7054ac3355db0cc69e8800a1e98400c4f70a8c9de3d8dbe179b2d44da025d39a26672fc01702344e9a0658c0b20ebe5a51f8508146f73ff6e1cdf6c2e81cfe68d354f0b72533115a2703b6cc5f3f8dbf779cacfacd8680218727155f0b04ea4cbb18eeb93963d0f419b0b5fa441d4a833c7ad7b0d24b0349478764c6f62fe88e483fb87415b1e327ea905d32ba4ba50397fa0c70425ca096d2311c8b0b154558e2f8ca674b7f71ca9de0c8a93088d9d70a28cbe908285aa453e8379f8d0157cca15c75f28dbfc29e918d2f3a7725b901fd5c757339442272b8e3598d912ed8c10828fc7349d1da35ebaacc78ba86ea2feb693b2de08575d8ec8a80515b2678034c4cb3e15920bc6461a3eec15d9f7c19db25ac3641a2af7839540cd2561645682683c9e16381f3c7eda13f44ff9d6f7ad00a8396d92aea2ea28dea93040360a0de2b389e3b93340a145e97c0ad1a45e8aba6843a4499fbf9a31ad6dcab0dd9a87ea40990c30fc82076461d9f27e407bc86df402f7b38797805c4f388ea242a50f5afc343005ec4fa3d15f37349d5201d60204b3948860efb12aca466de2e07da20d2bee1ff4b716cea16ea40c035b6434208394ef47618c9a05b36b21e04420cee3f04ed87c1f371c2454a90ea9fa4981de27084d981ee935b3956f92c2d9d41e8c45932a7ef1260ee236797594bd3f2617f863d45bbb60820882fdad924cd6ca6c8bad6af9027a28bf69d90ede735d5fe94327977bf453aeb327cb99c16b1f87895cc16b0a86d88b40959d9afa7d5dcafd282cadd2eda3b6828fdd574098fc2bf635fea1852b1d69346c936fcd4e7f0c3073514acfcd9c7330ee361e81c01c84df3070615eb2ac30aeca2f379dbc4f11d734bfeb6529aec25a20b26fd29bb71d9e56779e362feb0c4f8e27798321341a8e8f3d35e67acdc479c642fba17ba87677f815f1f8d15b79cef7e2533f16ec1626277ffa230fd678c3c9b12160bf78e02f78a2d70981a87a4e711c1422fdd536bef214655ab3385b4ac07f1d329cc67e97f5e1c25d04d7d26dfb744efac8ba4787e1f213c4a09145b0bb93b6a04070876e3c7f4e4f0dffcc247525f02d8114e0c8b5228a51726ea1a26ee0855239ec8f411387f77f5cba25a65d6872cbb34a7aee156f43c09b0b5b48fecd1a312c270ca2b8b5482fd832f9099c6438547f93cbf674271b26c23ef795ef582e81a36c5cf6a2564e10891b4ef9b29fce765bbd37c0fe30c95a81c1362399c4116280a46ff3973b0b348f98fa741e42fb67e0a4139da4306469e1bd02d119d28e116127b2be924e581533e1a290e3fa117c0f04d0738dbc69707286e5abfa8ddc405400d1f696a80b5aab65c2e70b13f6ec3ecd951208f975b6c80078d8e484c770a8f69c998648ea766a404486515637864a0663b029c14f33a2bb8a60e2894f02c5c82c192c6c2bf9f20eed8e920b778b3af947df672a8275836e7dfed4cbf662ce92080ab808e197dc14b88d00cb6319b4da02c9807078e38467a7e8d310d9207d13c61a05df7bf7766e5c4e5094f91f3d6078666ff1b7f6a02035143dafaa501d47fc044bfb43d453a18f286f09a28b99c7ea1ca9a3c035e7f2807e8431b660048afe711b39e0ab2714be4cc16e02bbff9485034d9c622be8cac586ac080ac1d76b5418f677e6a83252f7940af0a5daa3eafa21b4c7f812c8d2bb376862d2b1479d741f8dd2b08a6971f6e1a1583b315f6467763dc2167787ccdfdb40672900fe95ce635ba0d06e4ff638f6574dead7ea0290934e40e43e210026b650ca20d0e2d75171be19878f9882d0d1810cc8b6f25156033f014b18333518a1e57cff4245a086e4c21a79596f44871a4665222d28d62ff5b82f73dadab1f20344e2a301233df15fb850fca4f43366886b60dfb0c148e43f2c8e5505761054f031e45992e530a393a66137414996546d93ad7b66a0a86b52f547548eda7c5e9895524b511e5a1c458aaae8d6634de11003153f68f16206876b45e7188e948c3f1daa18525f9048ecbf0206c2f818b3cd6c8f8cbf4f3f3f53408ae779b0a870b51792546102234ba05de1caa383cff3c80772d58d6bf23c4ab08750bf84cffa0e9bf020f19d6a7e461d8404d52ed1bfbb6eb292abe3359d175170898a2480005f9db1abd0a8a310ce3514a6db37e25d075b0f1a0822d78ffeefd3be094301f2c1c6febba07df3bc9e983118eb146c90b068a7c634fba08a71f7e5972f225187a78420bf21a477c7e545db56ad031125723ecf029261e9167e4ced9243047061111c9d89002c6f0d4c6238de97e12c43b89611e498ca6f6d8e2c1d7f04f3424399f4094ab04f76c11ac9856f9164971c2ed828ca4ad43e26981c1132b1289800c2e5f0d5e1c30ca44cdd118597ee0f62df250d260a1eb744d707b82b118b985f1383d477e12acc2957c37c491c396614b2ad84c3969ec1ec4f1c7581c3712a103196948442a6907783e4ddc2a1462e6b13a13f9e217f4faf0361ce35af4ce7b349199ca6208be62a56edd8e4c45d7da43d9fc5acb3ff2c3a1e8ffce95fbafa4da21ead9210ad32d381443055f187a6cb02bb24c4c702af499b4de82124499262dbda32d5000057871f9cc917de7237618da0246598a125df8149b1e1dfaefb350506237b8280517a3cd38ba02d278db56960f92e1cda3d667cce290550ef00cef68cb311c28d981009c19e0c73a175e1f8bc43e7f43177c46940bfb9629b3dc8bc2865f5711618c23138e3ed27b59899f18792d4f410e9cee41597751d50144a0efb7722424247808d0c3c7605a628f75f7b33cee58e4a298f8db7e3556a42de5a519523e19edfbd5551c2412ec0d91b21065eb911c75f0c6580f76fe4ae919dd9e20d90e04ebc9b1779aa7db5c235c15d4d62bb0a614c2ba0ae188bb90c08929ac3425be266e6c0828ac369fe62ef6e37377a346655bb964fcd07085830f8e31f66c247e04086671961a732d6e9824f107aa9cb66132da736c241a93091ce4a5d0328775161a9a5cd0a7510adcda72d5380a8e4261b99479379f9ed014bb36aaf09886352d1750492991f7b968fe80a366b41edbe23fc91064a7b4f8279975369a805a2011d4255af3918a920c857fecb08ca970c3bbc183f7af6cd4ccfbcfae498429d219e4de0ff7b638d612d8a932c88edbdaf91dcda4fadc0dacfb8fd6d8d7a6d5f117feb2e63aa7b37005690a183b7cedd096681e4f472b36b0371e87462f5ad693052dea498ff2ddcbd3bfa0fe4e996a06b9790c26f6870dfc3e18c88981d8f8c214fbbb4970ed74213912e132feedfd355ba5273b00d34bbfa521e5126ee83ac50c6018d032e9b1316bf07d5f6961424bb63041a2c28c55f1c913b15b637204b41fc084c1b1a31602652d016d9178eda06ee7128c09bd600a10d18fd526163f0b081047676d393073b466e12d85711f61038a03e57ab4882971ac99b0d6b2bc0e1b9f299e58527f0f16aaf6871e1db4ee3c5dcf014c2dc65524fb5ea32001e92b2956a53aac0a6512d222970ba9e533b4ef412f10c7eb6d34924f6793bc34685402cdebfa8dfc72a3322f3dc298df0470a4a14b65a2cbd0cde85b0b03915631702e5cf7319251934efdca0c802137e7622627764a0f62e35ddd4fc29ef4624f36221330a033a4d4e45bd32d0e7515516aafac2543bceaf4d88c822a2807c777662cad17ca5faf0c64b97712ae199859317feb0b7a23b9e486edeb09299f8ec8a22d1fd21e145147c31830b3d2a93407687ad92abd6b383db919cd235516e7b45214e830bf52047cffaa97e4fdbffd6cf7cf874d4e71d9ccb92d11867be2577f4d1b61347937a154f0694e2db859286dee84b79269d8b9916562b17ee7e0b103f7068e0ea2e5d9262d13e0e915ceae4c80138a00a157779751498bb2f8f0cff30015fd049acd6daa9fd01a052506bcbd467d78f415b6b30de2ae22f9927017a0c22917f82f9b9c05bf6547479aa55ae683aa7457eb8bfeda7a07e913307f4760440135b956996aded6319d9aa9abe0f76ed72488a3e22473ef0cde7c3736429108095e21cc0b47f3bbc9a0a1da00244efe410bdb1bd733792978b3e361144c3ec927c7cfe7b3fbc8c17738558bc2c90ce2ae06cd4ca92ec2f2ec62a5421a5148e62085eefb1a3092518429b7aeaaa7866b65ec7b74cf4e71696633f53f3ff622592a632e91d5af2332983ae86a98559f65d8f82edd814b7fdc257a8502ba0909071d670f16a22cc60642c30fb9fb7fc98474649efdd11acef790c632579810fbb80f8759feceb7061413e6df2f73cb040cdc5381d4b538866d384c44fae8b3ab330ff0b21753498352e5546550f9b114baea0ba201a86b12ad1d15d04ac3b3057507f7640a2cdb667262b3474a10ef58cf41d2ab58694bb562a2cd8feeab13fcdc1ae46053432cb7c5a671455ef7d8f7d8854fd13f9aad973eec42d9a27d2573162102b926891d0b8b81ff1ec89388965457c077b5e77106d056476a8d69cc035a2a6236cef525b4202ec9b49a7a24d33243c0fd4a57372970a46f7bbb685c8f2b2f02c81eedc45a4ba4ecb5a1601d9266daa5b594dd00dd8c5ac2c98bc6d1397001ccaca031b909879d6f36b49dce0e71c0a1f552d908dd7e18c37b2665cff1bb17fc40b5c7c46fe46827effb3dea634f7493abcaa3f21f974122b393ee3f97340a901c45b90fff46f3ee3a2b88256048094e6fc5d49b8ec566413d651b4bfd481f8bea6c3f158d26f2814a0a21165f5ce25ad588073f7747a302d40898305e5d0fbb41e6583ab90ccf4ade432ec1cf063ed319eeb2b6586abb670a4e8ab4f5d3207aaeb87540df8e47a12e79a8e73b6e9743aae8d5e55aae5da5fc551bdc8c5f150b1b55695d5420881d1aea8e1752398bec30da81de0b0601121045cd1dda9f19f7b5d2266d18c3df2b61d1b471737c2add361519680c8d0c3c151baa9a9c5619cd24214810f337d33af7a5438cb1cb419f4c2e4d5a0827a0e9cf91ff2947c6000ce6c8b213350402828339d996c44c2e7ac96b0452a829022fac28bf9c513e1701296727556febb60ef2acb478eb6d9a0e1eba99466e98aae13867404d352107d66c4708e57fafdc69de80c7817ae046f41cfb2882d3babbf5139a9ae4faa80bebdd2ad2e68bec5fcbbff945c5e7fdfe97bbc3093ba2b1f10c60af59cc60d80e5b6a0eb2cebee9e3537a4eb9f002c108a26738f9bde875b7749a07bac29cf527959a05a688c56c9d390a5dd346626ba04a0363646e6967033b9be18399be09288a4cb2e5a0fa4d656881bba6ed66180b6f4c0cede4ef98e34c5b0857bbc95b2f58bb87ee1c1fd91b5f887521033bc3155654bf8ac1a8c05cebc1f8be7e3a6917485cd6e95d67dc1c766117a3180fbbddaa099949c5bf1151c1cbefa10857b62e9d1116130f8343f772e091058db76e77567417464b0ff93d4585abed3886971f259252fa965f51868653047aee30d5e15c10cec90b2b99109910042dd655cb221cd2533b22397a15f8a4476ae6fd822077f56d3802f01d0b00aecca818ddca1f43544eb3cdf138b816ff5895940945597a7655e30b80c98616ef432c9da35323c7927924b4c1046711099315ec5d58169732b4b75b0a28bc279de6465a42b90ccf643157c4ba6eb5bcdcc7995ca022f0fe91c0eaf1fa910a775e32c70877ce29e5bde84a1189da233e3ace11f96364467be583eef1bfe52b1649a05a8bb44303db325b8fab5908df7878a508c6154937ffeea18cbf43fbf14200106941b8f42de76932b23e689995af9e3d04c0b37765389d1dbd1ad2fd720fb20bc864c025182b41e019aace2abcb7567da8a2449e1887286aeceaccdebf9dac751432f38e2e4ccdca3ac87ee7fad352d7ff41cf060d830a5568773f292d983ed3ea9c87b721b01df39b09be61d87dfac5dd5aee60dcdcfc8bb862c758500b189a324db3262f51d10e38f6d42a7fd9f051204231a06595de9ce681e9966313df7734363ffe1852b06dd157c08d974d7191399967c251acaea70c1376924e9082dd3d6eada315522ab87463acd7faba38e7e2f45677c6d6e2f93d64cd3ea57f855228b29086168d443b8768761cd92dce3ec5e7eb49ce0206c45b0d6c5633a8f7cfe5239b1d2ef1e141cc5a4c73ebd5827d91ea4feae63329ab93aaf49f8621647c7658eeac053de71515e765e1bf41d9e57fd7688cb8978b70edd88cc5f397c16e8bdae86806e7f6a5181704db97138fd3ad30bfe8f3f86cbb665f4a7de7916007e45137ad2edd56a1985f9a10a3df3458a734a9ecae9b3592e43bac49201782855b2155523019488b64b546a7aafc563a9b59f929ee0cf71f5faeb4ba027809a47ea91bc61156c1995627c4998f6ff7e8f59e552aac13a31d70e69b88bb179167f0ccad681dd077952dd05dd90a5cf24f2e5bc1e1915a996366fbd7e356358e0b92108bcc2fa60960482e8b422993ce58bfb7cd058f8e714f1e4d777dd4df6d94d185bb590e76ec3c2c47001f0726c38f0e9d2063f3ef67f0fb63023bd6617a9f53d4ebef1e0280a270fe757aac0af79058d909b8ae0361301fbf4252ec5b19dfcb88c9fb2e453ff90a2a56614dece9e3c3c8872a5116a230c48c7f987f257cda6cb8190c2d11786ae6a859b224093cfc916d924d1dffd0c72c60f04a7a4b525b9de3c0ad217f975e26a887400711a9ad9f1026afadfd263d3bf89dfed2e10939f0b3750912ca93f9498d6ef6f01d557fdb07a8e1bacb8f971f56788cc049b36ebc9944bc164843ed2f857d5b80c2d0e8a54340d6dc5ea6bd33dbf0197ac869cba99390d72ef15e01f0a8bcf394dae09bea03d0b6275f95009008923effce8d6c3fd71d7d05169b021ab02551c8061118dfe49ca2b249b80e1b31b35da1e0bb2986d8fde91e7e932c864120afc164374863379619a5f7f42a733faffb78e3c0307955c30f16aaa12541ee9edbdf1bbada45853c95bb84b6ae8b55727fecfd211aa981feb3195902cdf9c47b466eed7df5c99ed5c1a9986be4bff1f8ba0ca9028dca194a571ccdf56160d35f7db7b9b546457a3f58ee88f804b0af4c9d0ac2197afe5cdca827db53677c6c22cb123f66ed7c9a3a5d66631b4e2d28ec1ac2944dd8928c17b600462658fffb922dd59de1b5c4e3c596b135e5b3ec648c55487c4a4e9d03d0fb0eb1aaf689e5664411d678754c62a9c454cf433246204e7f0d35023465870ee1083f29e501695957c73780f0a97b7fedbc2a9d8659ee308637eeeef72467516b07db68fb78a9a9cd0d7e80ec1855e2370dc2a3fc5da2c00a6f2178d5ef6791a32ca0f2ab588997a20dc02b565f20a93ce84018b4f5e9e91b64f1b8fbb4451072010a3a6d25e1e1269b12967a77469f708063e9bb522a5f044414337ce58745a61bfbc7d14ec22abb3b904e2e7ef401b391fe764815648a73250f96d53b6291d924bd03aa9a5f58d5e893c14850fa85f01e939049ac3a56ace1b73fe06cf1bf4d1ae95413410c335e7dd27b9d0ae5db94283f75ff30557ee6ee8c2facd4fd1cd130640da57669309ad2ee076dcb7b4c485d0a68146b2a687a92c2645fde606d7e29fcd5920546f402de4ab466d0ee17e4dc11a167a17ecb77d8d34b4a67c18e1509ddf08b7a929b2aa92918a0032fa4dbcd8a735a34d11034f82e6f0c111a36490c0d9e41bb0b47ec8bbee1492876a765913a332f93bcc3dab8210c067becc09a0ad7426250cb94602452a54e1c073e2ca216a5f107ce4cfbb6b355d09bd65957285448bd1289902f5e9570e7aa2227117d4db540b9c97d3ed0f759545a81e4d1011380c194c5ea5db9507c00f61b87d20d1220fe4985e2e1d30065a23bd3156f23347b8df7af3454b8739d379debb9a5ab71dc50af6f215ec2a15792ba0450250004b392546927bd58a85055a05eadb613806d86914b6d62bffc79eccb75a7540a5b8d2e55bb8014d6618e71455a8f7b2f7f68dd008ba1cc25d355b90bc3ba1429fb08d96be9b5c21c7999f266cd03b43dd942ea09c55fb5bc11c6c5a174425c2a14c41fabff96d751937819c1ba20020918f9b381431322ef154b7363dd8ba90e7fec6e1072b896789f0f4822c0c147367c3fe82792879a0ab3caa19873431814955df92af2d824e8f1c3e879df0cc0d8a0f5bd76189cf2acc89a777aba170407d7788ecbb0c719fe9a150ad45a5dcc5d8d0a6923b7b27ef6c6b7d61c8d36551f74a4356e4dd1ebcef55bc96b0f6d4ec261619111bbbf7d01cfd4886d1de53623b33764960fed4f0310cf5bc7c27fbd4cc043bcb52e3e5a5855388cccac4c3e2326086873a0072e2bd03e12c78207d91b323343a2be00ca1d316015e6b7b9ae16dc2e72f35764059963da57573115adac29eaae415033e5500b11b392df0090240eedc5326ba3c4de726767dc7cbb6ce92f8cae01a136f39e72c82a7f455def1235497e0d5e3950864202a2f45edf6b800dc64b74b696f2aba673b08e4a2d822a929abc9e6ec8f99049f780d6281f48c9e92978df5d80724eb41681b3d4d2551149adab600d300405f0d78e43bd382f5011ce30554f420273618ed4474aeeba226d1c60827a4975c016ce132ac2bff671715085fa050d9512bc678279dabc7e2937ae6846d97736f3c49eb111407b8a9e9b127e5e2447d4901fc973a421ab3d22eb9ea67ff3094ae76e2adf6da4a0384008de2fd1fc52336fae0c0eb8a1f44109530dec9ba7bf4d1b3d51afae1f5d20392178cdb6f4122e1d9241d3d5b2630d22170047f6dfcf200ad991bccb04299c0400ae830abd161c6f16fd7f5ad7d55e2a91a91c308686453239d3a527c4b1761dfdcbee18db8f02e8efacf3628e99f32ee6e7244763d56e037832853423134a5f8a5641ae4f979e50ca4865ef06643f02fabe75f0cace0c0b039d4452ae0f365ff529891fa3f371e664b389ef7886eb3030b411db22fc59dfab6170e4a1ec4e136124a10896528963dfc5c96ed4259d1332ebc2b184c375fb6481b068abfa1c8d7b863b3c764d18dec95f55a13b807a1ddca78ef66c3f679f534b30384f7a796467db5f4e8595e0500d634744ca3ede0313c61ecc7c3c379c7edd4a9e711aac6dbb1768dd7604ad4ede42a037cda84d13a90845592175da3e3c72f9eff83911da8d0f3279fdb75c5057a140ad1feba217ff17582509379007b855924ad126cea015f23da97b9ff1a85d2e26178e7f492e38990677a0396678b98a389e5050c5a74ce4a769d0f445746bbff937f7c2032cfc6627c5c3af996ef37c2bc10c5a7c94c2c6ce88e04e466b9c01bcdaab60491533b97ef4a264153289662cee698be8ef26b021adcff3be3655a6de1f89d2271992a5af8f646b8d1d1887b122539bf5ff80b0d73282d288a0b7b1f6b15b7177151794da1af79b8a3265adbe34932c3a5ddc7cc991ae4280d005ed69ee78a1f612d55895627f1bbc0425d4f27aea7f2030c68852f2e2a869abc8c656282a69d91f4ce47b4ac4253caf925dd52ff54d1cc443761800deab6659b954208a22c27c09d9bc509923b5af45933add7cd707235c987f02bc0f609b1ca5a831eb61ae990d69687bbcbd8889eeab15fba07d77666bac222248c9a11092cfa1368f7ad93e2c70a325f6f55bfb9c2714850e968c5f9159bbdc4da5b5845ab1f4b196b06b860c8eca51ef7ee7ea1c5ac6741c3b45eeddfa510a3b35c87046b84859d192a7482e3c7825d060b1598765bead1f4993717136208fa56b48f2ce52669d7c2aff3d0bbd8cf1549ca6332ec3df67c16d599ebeba774d36a3c23e47fb3893ba793a9a2825bf3dcd7dfde5259eabdc59b130726508bf5285e8e462de85cc1fce521dd40ba15d9af05a686ca5bc521d4f87492904e9471a27df178a9c32b4cd292debb3083e36159fbd062777ce3a5cf7e42b68cfe357293dccb10a66ad7605de413bb62b339778547ae76ac7a2e1ed9831ef465da55fa64c661288a01252ecd7b9f5a62e5b8687ec4064245e7c14f1b044bfb5833f5f5354a5e52a118f30523e80fef11c4a642b47eabd6c27c18e8834c0aa44ee3353aeca611d41d5a139741f106ea329f5a4ca9b810877f6a0530f157229cbd931de9be6ab060c9c7aedf12a6d31bd1416ac65e49f6fc1ba4fcc40934eed1ed6750feab533cee8d2a5bf77b70860230d4bcc80e332fd6dc8eaa597a64910504bb9f7a5951e0b1cc5549b084e62d3612f42240d9fe81c6c474f9c91184edd5d3d9b5b9211e72d85f6d4307f89b015d01987a2ba529b3e3de4305c8d91a646ccc82a4bedb2a4907e9159c7c99ad0ff59036d6623b151c78f80b23febf74f81d0a92495ef3b64f19e66ed2f41012533980476096427924dc67d52afd687936db302e8bd625ceac02ee8d96da3ffaaf18d0dba69b142c534b2af9d4c54d09bd072b0abf5dd514fc97ba8887ba0a3cd11601669661d81e87b4a811cb36b178dd20b80a0f2a7d30e3cf1be317eca455d578327e0b8517954ae519d46c43b511ff7b5b5faec58ba349aaf5e9869f04c2c67a30474deb6a73b2ebd5ac1134811f1a36c4b25196a574cc0466bae6b3fcdfa67a40beb8730f67992873081dd969bcb5fc718be38b7f2d905e0a956005ef56acc7229696bbf0b5783493ae613da7d540be2d78baa3c0ae8ef5dad872e5ddde1b4801ab09d3a847d4e7b763d045842143da7dd7506cfea1768cf8f6c02498045a5c12e7e1694b77217b83e4398daa91eede9dfd0e756b5454f4a53c44db1ed78b05f180801c4a0e6ecd9dd3c75364074acb511c8c2388bda38e4082a2f52d456d690044ac311feb298ab6d7975886247df78d1f764d91992ed87babb126fc4260470063cc176948b6830efede55d9dd95863e7000b0d6449779f26cc2fe918cbf16b0b156dc79e15d687a3ceb7f9e89f387efa6739bc8694a0663c4ddd1034e732d82d98654f4ab727422694f967ff95c25cdcfb0a7b67a9ddbdb38b02ff739702532bf9776901d83b68bcd265e6b441044b18a466db1744e60f715828741c53b38c2234f0062231eb92cbd23949615f9564eeca7e3d36a66eb8379ef32d66fadfa4142727380dc5ad292c52c7a073b76f8cd789835175390cd2e01c49670d4d66062ff44e2d186ace9c739f41b6027976d14bfc760f07d82c033b950d9239f066c31719f4e87afcdaf9ee8d0278b99a0e3d18849003d3be00c682b37ccc6095110605f89adb2b7f013fce5b354fb68b2b32577fbd6c48a89bc1217c32ba2023b975219cee35356409db3827f407d60777d58e8348a4b165a09faa7e89660e811f2b093603ded70cd3e08e680830d676175ecd7efe2b0425ec8d5d7927f40d04ad5902b02397c2b75482dafe445739acb0e8ac4e53158ebd6e15185513efe9d06f38251951521b1b37ee05c9ecf7335e1d561617b68823ee6ff207eecb139bfaf3c919fb94c51769dd2fcc89cceb51856e10d9739407ced8a9849efdc2411496ccd72ba430028754d7f3e1d7aa46a8a78e0a0b05709edb0612241c0431cb38d32a8c05fba833cbbe1077cbb83aced24898c91227ae2ebb7c185a8d7be7353f8a0cfa2b1e7248dc2974a6e373f4c716681a6f5067fe446777c3d31571ef38e09783501336d31654c7c5d95a34d5671e1079566c33d4f32cc5195d4a999f56be81b1c9041c23e40a59a05ba40da1f97eaa2f83d737c4ee7767a7f75d44f94b08c838cb26c9c73e59f573dd389732d09fd9fe9eae468c6b879ae3d2a9d2afc712a9330a21f7670683303dee05ccfc96beb8f2d894df04693179e2973cef115c09354775010f3c5156faba3e58bbf7bd54bee5e5308a25e94fe3b1147078b6147c753db4288927e082ab365f6cd4f74d0e850a3afcf01629f899df35a216e1d3adfcbecc0b5176ab93d7221145c6d3f2011852b1b0d5e52595b97c6d75e6551b6c018464068a4250a21e45c570aef973ff978e2d0c3d1f32ca88295e8dad9a6b665faa3700a8ff8659e594a167530a95f3f4327d7210e6b5963fc3a3444d16cf05a888dc17cd53ef517b3ca9f2c4da57eea412b405d27341a8f3da610420f8cff8fabcc22ea7167258ec2e0e0153836c5e3fcf168f25aa7172528b7a7a10e6a961520d320657abd3feb900a60de5d920a78a84b6b91bd86a032714f0729541468bc628b42fb2580aa35a66684f00e8aa78ccea16a6e2c2a76962a2c97d2bfdc28c1a14b1029c7b68587d6cec18c23893dfb394fa183bfe597d4d9f41afc074c0eff30ee90ac83636244fc935d52d9f8c32884d8ff049e073a3dbfe2e7f3a9fabe056db851b8a0ab427bd70186dac196be85cdd9cf6a472db35588775a41d8f5bcf95cb1d2a0a34567b854f3d22327387c2b32d30ab6abce341820cb40065f24e9b4bf7a111bc7a424546ad33f509901289798a8b7978dfb8db35dce1f6b3dba62a1c5ecd1b0b6ebca55130fff8bf52b3f525c4b8b490664fccc47262ff3df8b6042652960484ce932170e3593575f723508e98ee25bfd80c7c9d432d952dcd2eca28ab9b2294cc39122d4d6c0eb32e53e70a7e8036c79c0c0dbd3799259c82cfc1c7d0910d399780e2969a47f912e8b716239eede7888a4f541bb71f30133851e10cafa40d3e8226743bae7711324bc4ec129c85002d3083a2af215f38359d37b8d6ece90f6c000b0d56175158febef5a203c3fbf701312bf3d11667ba4c0409642de183162b2a7fd33f67c8f2c4df85c2749615563b0a782dd38927c24f0adb3dcd67a82c8d98745e75c91c8cb14a48a18cdc21c337d33defe7a34ee52d58f2ecb0f33e1b2f7ace0a364d7b999319eac3e703147b0f0289d13b496a5baf1132e2d69fea1c05498e6412f68f8157fd373a87e35aa4e60aed1ca9035054dc4624cdc293e6106ab5b7636b1eb293919de2f9cfa94f8106140a2fede50519fec44ee3b4d12a01f74160bfbe701af451915e10e836bf9dada21bcde42f5c5f62adcb5ddf571b2ed223c42e6671814eb85aabd89968c5d0fd5cd71293c45f665190f6dc4e71161bdb143eae947ac64357958b27ebfd7b7d747c635220135d07e5dff8c97c02671cc1498962fd55a7444e856319b117c443a4ede613035f4771414a54e3a189b7030d05c4fed5241d83bcbb4bfde04683b10d845642ea853252e0588d953592541017b5276b6057e49402142dff4a01b46e0577963f1d46395fdf2d11092f0ffe15681c8e2c65ed60de0c5a4fb3be87a9ae7795bbfe16c96f2a2fe963c12e7eea0f851773e33fd8eba81fcbd8a3f51081726eabd522109b504e688c1367f7a831019103d297cdd5e7d383882d43a1e392dde72d8b45f74206cb3a4af9dd534e881a1c9c5304e1951778074af2513419fcda57d4002f8ee3fa959e69394fe07757026d016f186a85c5dcf4736885598c99220b8e32c16c41fa25e9757c796abf710612a3fdac0fd88526f8fffc53774f41d7d5b985ed1af86b398aed2074aad96d09cd2356845017140ee303a82f21315d018a149cb23f4098c5096334152791f128495dec89751238d8f03030911d3d2975e8c637bc65a3c308ee81ee28022f001befbd0c957929a6cf5e6682b645d001a3ff9a5a118325a69b543d179f878b2d0c7808b8477eff26b1c176fd463289dddecf4765b048bd6cb82468bd00c5fb42", - "public_inputs_hex": "0x1a207628cc6936816ccb62a7b56fdbbf8e975293b677c988644e018fc402e44107940cf3c3a18e9c2b8af0fc91a18c91a709c00a8093bbe606a2e9fd472457bc00000000000000000000000000000000c6e378e01efa1cb216ab0ced340b44360000000000000000000000000000000097621038a18ea02190913636079ece970b3f37898c93078120c11921f007446ceef9867e6da4e341fb3bf8991edcbd630000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000223de00e9e865ef8e388eeef184b6f39f6bc05eb3d0c54021d2345bd1729316ef17122a4b371cc1b35e37beb851894eee43c8b48d01f6e641ad9ba6e94da997fb167714b66b4e3e97a46578eceefc9955b033a18e6f8ec8add6f96a917a74414421b654b589d9ba8107e6007b5a8b71a20fb1deff0cf22904da6dd4303e734297000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - } - } - }, - "test_exit_code": { - "crisp": 0, - "folded_export": 0, - "enclave_contracts": 0 - } -} diff --git a/circuits/benchmarks/results_secure_agg/integration_summary.json b/circuits/benchmarks/results_secure_agg/integration_summary.json deleted file mode 100644 index 9466c36d58..0000000000 --- a/circuits/benchmarks/results_secure_agg/integration_summary.json +++ /dev/null @@ -1,244 +0,0 @@ -{ - "integration_test": "test_trbfv_actor", - "benchmark_config": { - "mode": "secure", - "bfv_preset_subdir": "secure-8192", - "bfv_preset": "SecureThreshold8192", - "lambda": 60, - "proof_aggregation_enabled": true, - "multithread_concurrent_jobs": 13, - "committee_h": 3, - "committee_n": 3, - "committee_t": 1, - "nodes_spawned": 20, - "network_model": "in_process_bus", - "testmode_harness": true - }, - "proof_aggregation_enabled": true, - "dkg_fold_attestation_verifier": "0x7969c5eD335650692Bc04293B07F5BF2e7A673C0", - "multithread": { - "rayon_threads": 13, - "max_simultaneous_rayon_tasks": 13, - "cores_available": 14 - }, - "operation_timings": [ - { - "name": "CalculateDecryptionKey", - "avg_seconds": 0.036223306, - "runs": 3, - "total_seconds": 0.108669918 - }, - { - "name": "CalculateDecryptionShare", - "avg_seconds": 0.156799111, - "runs": 3, - "total_seconds": 0.470397334 - }, - { - "name": "CalculateThresholdDecryption", - "avg_seconds": 0.234711584, - "runs": 1, - "total_seconds": 0.234711584 - }, - { - "name": "GenEsiSss", - "avg_seconds": 0.220404125, - "runs": 3, - "total_seconds": 0.661212376 - }, - { - "name": "GenPkShareAndSkSss", - "avg_seconds": 0.202163278, - "runs": 3, - "total_seconds": 0.606489834 - }, - { - "name": "NodeDkgFold/c2ab_fold", - "avg_seconds": 7.089881625, - "runs": 3, - "total_seconds": 21.269644876 - }, - { - "name": "NodeDkgFold/c3a_fold", - "avg_seconds": 57.963919402, - "runs": 3, - "total_seconds": 173.891758208 - }, - { - "name": "NodeDkgFold/c3ab_fold", - "avg_seconds": 6.906346736, - "runs": 3, - "total_seconds": 20.719040208 - }, - { - "name": "NodeDkgFold/c3b_fold", - "avg_seconds": 50.328348527, - "runs": 3, - "total_seconds": 150.985045583 - }, - { - "name": "NodeDkgFold/c4ab_fold", - "avg_seconds": 8.440406458, - "runs": 3, - "total_seconds": 25.321219375 - }, - { - "name": "NodeDkgFold/node_fold", - "avg_seconds": 15.28584993, - "runs": 3, - "total_seconds": 45.857549792 - }, - { - "name": "ZkDecryptedSharesAggregation", - "avg_seconds": 2.887353333, - "runs": 1, - "total_seconds": 2.887353333 - }, - { - "name": "ZkDecryptionAggregation", - "avg_seconds": 47.438696625, - "runs": 1, - "total_seconds": 47.438696625 - }, - { - "name": "ZkDkgAggregation", - "avg_seconds": 19.61153325, - "runs": 1, - "total_seconds": 19.61153325 - }, - { - "name": "ZkDkgShareDecryption", - "avg_seconds": 22.058676235, - "runs": 6, - "total_seconds": 132.352057415 - }, - { - "name": "ZkNodeDkgFold", - "avg_seconds": 146.017955028, - "runs": 3, - "total_seconds": 438.053865084 - }, - { - "name": "ZkPkAggregation", - "avg_seconds": 24.53227325, - "runs": 1, - "total_seconds": 24.53227325 - }, - { - "name": "ZkPkBfv", - "avg_seconds": 3.559760472, - "runs": 3, - "total_seconds": 10.679281417 - }, - { - "name": "ZkPkGeneration", - "avg_seconds": 70.937173541, - "runs": 3, - "total_seconds": 212.811520625 - }, - { - "name": "ZkShareComputation", - "avg_seconds": 36.93532184, - "runs": 6, - "total_seconds": 221.611931041 - }, - { - "name": "ZkShareEncryption", - "avg_seconds": 116.868327526, - "runs": 36, - "total_seconds": 4207.259790957 - }, - { - "name": "ZkThresholdShareDecryption", - "avg_seconds": 106.505539597, - "runs": 3, - "total_seconds": 319.516618791 - }, - { - "name": "ZkVerifyShareDecryptionProofs", - "avg_seconds": 0.12560836, - "runs": 3, - "total_seconds": 0.376825082 - }, - { - "name": "ZkVerifyShareProofs", - "avg_seconds": 0.320742583, - "runs": 5, - "total_seconds": 1.603712916 - } - ], - "operation_timings_total_seconds": 6078.861198874, - "operation_timings_metric": "tracked_job_wall", - "phase_timings": [ - { - "label": "Starting trbfv actor test", - "seconds": 0e-9, - "metric": "wall_clock" - }, - { - "label": "Setup completed", - "seconds": 2.661124958, - "metric": "wall_clock" - }, - { - "label": "Committee Setup Completed", - "seconds": 20.166480416, - "metric": "wall_clock" - }, - { - "label": "Committee Finalization Complete", - "seconds": 0.0012645, - "metric": "wall_clock" - }, - { - "label": "Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall)", - "seconds": 162.089313, - "metric": "wall_clock" - }, - { - "label": "ThresholdShares -> PublicKeyAggregated", - "seconds": 604.932522792, - "metric": "wall_clock" - }, - { - "label": "E3Request -> PublicKeyAggregated", - "seconds": 605.453073833, - "metric": "wall_clock" - }, - { - "label": "Application CT Gen", - "seconds": 0.353204792, - "metric": "wall_clock" - }, - { - "label": "Running FHE Application", - "seconds": 0.000809292, - "metric": "wall_clock" - }, - { - "label": "Aggregator P4: Aggregation pending -> PlaintextAggregated (wall)", - "seconds": 50.493282, - "metric": "wall_clock" - }, - { - "label": "Ciphertext published -> PlaintextAggregated", - "seconds": 159.9251575, - "metric": "wall_clock" - }, - { - "label": "Entire Test", - "seconds": 788.561521291, - "metric": "wall_clock" - } - ], - "folded_artifacts": { - "dkg_aggregator": { - "proof_hex": "0x00000000000000000000000000000000000000000000000ddc537f44b53fe45e000000000000000000000000000000000000000000000005d2c364993f27cb360000000000000000000000000000000000000000000000036a97352d8068108600000000000000000000000000000000000000000000000000001db8386de0ea00000000000000000000000000000000000000000000000002bc93d2aa2c401600000000000000000000000000000000000000000000000c0d14f10c5fbb573a00000000000000000000000000000000000000000000000c707bc7be0aaa260c0000000000000000000000000000000000000000000000000002b67cbdce2a1e00000000000000000000000000000000000000000000000cd16482194b961ccf00000000000000000000000000000000000000000000000b86ad9a1e323001d700000000000000000000000000000000000000000000000de1eb22a6bb20778c00000000000000000000000000000000000000000000000000027eea9bef8094000000000000000000000000000000000000000000000002fc183d9b404e5b4f00000000000000000000000000000000000000000000000f8385a2178429603000000000000000000000000000000000000000000000000cb22ed841d6eb43670000000000000000000000000000000000000000000000000000cb1fcdefcffb1d74bb7961ace3f2f70c4e830de967288c03b173bd5158d3e5cd1d7fc55e865a03cd83a7ec11ca7d54aed446132af02f106c160b605361787022be5c8a7d0fd01c35e411edcdb143c708c052dfdedd4e54fc380814b419aa5341068557f1e98511bc88a7061ee755e52288824c391786d6adf9a09090ebdc23941b5572d247e416da2f3733c9efb99ba96eb277e14f3858272621b15735c4cf986eb6f9922ab32bb3beb4a44733ebabe5d94219e318b866bc934894e61df208758067275f6a7e1683d765e17405f0e76a58240bd4c830d911f26e464c227e57d2e92c9a1e85210ce7ac20d92d0db6dc8f9b9f63e554bb78536b2301522f2901d1fca0b0adee9402b670ab72f4bd26fa49e85c45951a984d4bee6c4bf2070544238ed41f1adaeb1ec052c80e75de7cb223007b5f194ed2f28d04cede81a64ab07783f001b76d942d16c4d740f877adb2dea5cb85ea18004f92f4f00e54481fefcd1115186ab43a0acfa1ca0a228aeaacf7ce2429f7a4e9581a243c4029a443ef72a3a321e1682d14a7f2f2757df78eff6768d1f653b2a2994b47864fc4f80e532b46354245b7a02a6e00ba0057129b07cf30279612ab0a64e41eaee79db02dd32ee1eae16f626201d6f39a4950369f70b76175c6dce4ba02eb128ebd52cb75682acc63f21b52792eb92c25245ec066ae29f6a9b69e7980e89a66b0e8ed0b8461e1a3cff3a41629169bb7a7faf7b158af57ac2a8814736fa48f50908a1cffc783e3dcea358a8dab05d4e8b1394a69227bf3fe6686bbd41b65ea8865f9616b853e55d01c263cf4601d3b429b3fbdbf6c3ccbc8bc7613a55080d4952205bea66a6487d50bdfdea2da1966d442fbb7b6d5de94a7f1f66b8f2be77d33671744de4db5ae847949c06e0509fb78c99816ad278049888bb597f7b08870142bb7cac68ad7bd9866571943eb26f4a3efeb2de8d56203502ad26bf6d582fafe6e893716505fca3da244cc36a329057929704d19799de43956ba1863b26da9a90cacdd883e5afe90272482e3831652a8b3992509c56f1c37be3f7da0d5ce3f5dff03f2f28f9f8971e78c0e257129790bad219e62911680c2b8262c491a19c65a69e2801de14920a8e49539f7782820f32def40017e1af00ec6d325e4c82b26d4dc738596294c15ecec975ad3b00ba9388f8956cfbafba1f6c76a2a9367c27738125e6f97cad3118711c432342e01a4efa9335931898b9d34cab011ec52bc1f426517facd578e65d3937685f8192b4abb55aaa96dfa5fc246f5bbe5bc9777f78e01e8c44a8fdb90646fd71d0d641738a84b0f2d2d822d017cbd5c5d9d7363eeb71b6098d280119b1ecf9b90f4610307dc478a39d30eb8998fad0001bd00ff2bed07374e5dd387830c146323519e08f35ab390d4282810ac470f17b1ca6326ea2421d6119c6742dcaacd76c30286282dba21e7d7389bde163c696622d88838635b4a546d17f1600c18b748c9f72c2553375c44b53f71a52bca0c87762df6552408a5f4500965614a5b03d4fede551658351460482c296ccb4154aab50e4ccca5cdc55fa75423c3d84c64f70518b208aa01ded1676e0474d468ad377ca4d2b89ab3cb3d3963de0a6b13b1debce552033885824e78ea0027af972aa760ccfc5e7fe7755a65a6c6e4d532a33aa47c39099e1828b109c1ac9114251607526ecbbaafb83e8fe2efb0c5388ce62ea3711b2b28c132f05e1a371ceaa48cbb778b4db0530d863efe66dc5a00840ee3bdc0f71cda948b42a5a7059b54dfbec5be13a982ecd3d08e07db4e9b740afe7b136f6129ebc34c7ec5021908b52d65363cd12854f10066c1a0e09a9733d4a304ed41801ee2ccf5b72db94d42ead97f746f5b92eabd9115d8d3c47c7198f0c59f61c82c2e6cd40132c27b3a7014a3d0404857ace260b2cef00871951e08d2fe4af80cdc20b67b6dec13d790f840cd45bc09fb36f7e9edb1576aac1fed6309d69d9b4bdc23a372afc89b2b8c7f8f0b4d5a8a9964d817ec367098dc3baf84a14233a8b24c160d1e3cc9588f8c29ee86bf38c8467751c54dc206ecd20dbc041b9edb0efcf721eb824ff79a781cfc29baa77eadc827e1faa60d2ca595aaaf41b05f47403df5054d2e48bd550fc31e258c9aea79d587deff0e66ab7e24df5ef60a675dc0d5d61b9ff4f004a2ccd4320ba46ab42593fa9ff56741d268418ad57e8cc69060e112173229ebb2deb9626294c2c341417b9274d7624bf0f7bfad9d66b10d28b8a03116f1913cce922e6dba33eb29a98210fb69f529a830d6040c5f0117608ca3ceeb2301f5fa825d225c3bbc88b05c33ea0e41eb014c66441d5a9947fc4680d35e421dee79f2143d0497c9179af370b754e0224e003d05fecab656f64a823fefe44313b30bf0007ad379d1ca866ab25f493e8e18900fb389ac5415f67156120bd77c1d83e3909193ba0d2b16ad19811ceb4ad3d742b50246378e6fb6e45468e9008a1775f8bde9dc6a8231c8f474efdd6f11f695e86315777cc234f2c04bf87252c12fc8850ee7143a98fb139e12b5cddcb9215993cd57f93020e31082160c1540fa0ee8fa70c9c36ae886a7e4a52840ac356a9c28b4a0cc432f0a57d049d9c60ea52f9afcaa6d4f8d79c21ae5b04777811f9960f0fffd52580320d0fa196009634e0b20b84cf5dda38ead8c9dfd830c5aeba4fc6a0d4ef749993b144954888993560f5144b9c881f632066f6c63c95f4066fafb419bd9601c028ca2546fd6c3efda0b99e191422cdca5d0e71bbad1c8f5e358b973d75042b1dbe0d437393ada02fe22b41dfbcfc9155f55bcc64ecf82d0a67d810009043901d592b0a810c89a910b1ea0e956bf5eed9782a9ee48cc3a97b989f1ccfd38e3a2c24cbed0109ef89d151c96ad5afa7c6d2e7219744a1338debcb9f41485d602f9c2cf30efb8f22adf390291fcf0d2a9ec8464d8180854056c10dadbb17a051f9c2fa1389962ae877246190150bc8fdf39bb570e596c3ef14377483c735c8325a32b2709ca1e939c9d3304855cb7c5d17fad910f9842c598b174fa9c275096076e45af017ffe4d0f9b41129d3cfe4ec19dc4f72a61ce91e290353e9d411dab365e3cfc43583fb9c8be7c2e0f7417e6953d9c8116c57bbde9964dc413f454ba813aa314c4c9dce76b00c9136add93dccb1318d338c95faf456f6ce48ddfea69c406741a3e59dbc207cc9a190806c021ece63a687d90e4ff7fc6172c53f1b23827409310b5a44f62fa60292055a94c5a8d3471dcb94e967000cb2decbcfa85aa6bfbe4743e08a1ee230ace1efac82370ba2f09fa77016274bbdd487475e100862dc8fbb80382bc69de285c0bd0047ba0aa8ec022bc23168d5afa5b1d3a1ad7bd4b9c2ebd431d3bbce150a70f29dd3aada8fba9f7cd5d5db945f024a9dea0dc51a27752f0be20b4483ed1f5134d34dfc8dda93da80b5cb0135d3e4f1b3acd5895afe9f691dfe5a41109caf52391b88832ea4c3d2b8627b03beda0692826fb896c237e415c9058a78be861841bb561ac86c2c8800167ddcec4067160125bbb52a30f0a1c7a8cbc2cf4e1dcc107d74dcf175389be3287894d9a8ca93a7f13f4b482f4d96b5a755388c175b67f077bf625750b2cc8492e3829624f6acaf7206c352edcb0860416f30c5900359518496a52f58dcffa59213f02a3968e939b821acf25c1d54ac8e27b5037799a971a45440c2bf0c8294f291765bb3f195dafc6cd825641f439c909de60f22df7d90570f8581fd144d8e336e732cf807c575696fc5974beb6d327d0f4e50fdece5c20104dda0e51dcec48d30f4ffe4765a5fa9f4a2bdcc2ba09ad027c2ebe4188cf02c493f0beec1b3aec852dff73de5ba65fd4704359f4e7954158bf624d937a0b09c929bc6fd95c537456c59599363f86fdfdf5b7d2b58ef05fb1b62c4f93945e1e9b7f217eab940cbd9d3dc027a2614a0e0ac55d6a5f4fc517c77a610772a6d5067e09832583efad6905bdbec52a599aa83ba05aa495f7cff70fe7fef1e8f9e322b71ffe815a45f39d91a5606a09f8725c76214aab8c32bc3a2ca3d1c4f6f342210f1e70ba357d8e93e48c3fb547aba790c9548057837506e9d4023e026050ca154cc3aaf0c7d60316c7f56a6ba004273b5c1a08881c83cd592b770e063f5db6194b4543e50e6b2d4fd1828703ebcd61f0e0e8238c7c2907f640ad2245e6f8df296178c5b6c882031dd6f0b4769251c1cc7243b4137447d868802cef801b2b7c214299d10918e2da7ef9a09e2bd9e11432798d3054d50e494c0da81d33d89a2607f681bd3f241f731f09477538456c7b3a0157ce568d7d4c828a4c24dce4e2b10cea115a9802c9cfbc41c26092502ace91f9937f175d77e3f165ee57b2ae6148293043f2a0c21b1110c61e1d48ebd32277db4f3f8fa1a44148cdcf7ae17d901310ba46c7249cb240b5c8e89ccbc193ea405bd845baf1616b538abd45acd32e250b0eb91ba32c5f67e81b79cc12e4b202a3a514ddf1c33f55d76a78dd2a6f431216cd9459be0440312a230538e2c08e9eb699323c3ea330fca18c022801cc6bcf1be0daec57bbbd18d2b11084198ea0cbe1d5b1f16f4c9c2f912d01e6f8b386610a28f67f554cd1490c99771a65f50623d2fd504f9c4ed37c92011ff0b00fd73f2e96733327ef59d02451b02b31243d6de810ab7d4bbe38cc5c4132712f9e649b292aeed91c210ad7f26e8b460f9a2cbd737062f3479f6790b0d85e6b128901da2c988129a0ed53916b48753bbce885de1a2f74afef8cf38b2dd4d8aad9fd5a7e13f32b602a56d2fe14c56a40cdb217be8516b43d718ae6218a02c8489fbe23562cfec06264e235fb768619a1c68daee1f5343fa2fbc9dd496b59aca837eafeca1c526e5ad567e4a3c658bd6de68af23a0a436df9f7f3f29f0ff683cc517a04580fa8bd2d49661956354885fb019f0cd95b7b7db7d8de723a7cf201babafb415f06da7a7d803e8584a58a41c24ae54f7ea86798affd2ec39e5971f63887d3bc631b8ebd9aebb270eebe21f676d194077a0492a039335bbc974e1a7e8e5e3b187b005cfce57954aa83f4f1373b857dd0e9108f15b8a3319cef2baf99a947447a6e0970c4556b9cf6a5f7c9b1c4a16e1327cfbb978db10ea891a2ef12d50a37cb040ff5378b30441161af327ce465ca56b4093e3eda29ec439c89dc32425bd33a6b0259d8d1d4319bab6eda9a614f0f78eee496b69ab9fdd9aedc3391378993c459027d87ba74779c68221b5b1e24712803e9f034793753d49d661fcc34af88b67a2eb483c76fa9350617c43cb676482acc4e4516cabb406264d4e41fed5f4d800b197e44dd76820dc1d207e1eadb5fbf61ac15b6dd1c7f34dba0210c84606971fb2094e779db97d0fe0250b61846c330025c5c951e7ea310f0482708886d6288c12527abb45cb435c1579afd6dea2799b69e5298f3e6325f2926583697b5e2b5e21515e902fd878d2706b6377e4a86dd3e75e9f1c6d5358b69898d7579e05df9ea09955053c4b5d8f47e09260b20094fc317222707a15fcad33d54ebb0a286f20522163de47ce56a75b960afcf3ad78fe489bce9499c2aaba40725da1d0d3753eb23e9215f54dc85bdd4633ee04cc3feac16e1961804fbc82b69144f0d02cdc09b08635aec4f87f85d0f8c2c235c257389f68de57c17570ea93bbdeb89aa489c7e2d06f6ddde1845c36d494c75adaeaf4e7f71ab4c3ddbff29c3a02b1d2df0bdff2fd17b65e8f3ef08cc0bfc3298b30a9ecbfa8748e5dfa71a6c479b7c5a2c68e60b8b5d197e76d358697acd62ca4d0f0b4ab5c7a1a6947508e0f1c5f9af1a4d2402ac2c8f342cff48a42c6cba919a995820f017a9215ad63a7cf6b85aea4bb44a2ddd40c367f7b0d4db0755f1f0513e8524e2fbcc4ea1cc65eb312ac3a0ff85f4287e803ad96215b8d15abb6a304a8c0f13bfb0d673d9b9a188e8bd6b56de3ee426c3ccbd67dd0b3996a9719948469dad9f074a13094f68e012cb4f6dcc18a9d92c504aaa12f96b40e0dcc1822332351be7c39d99a32b099abd4bef860b50e58a03bdb1f0fdd97afd4b44426fbbd310c7162282cb6cc5681a5d34c8792e7671840661eb520c57338c07b2b400bff64f9098a66d2aa940eeb9dd8d080e274620b022e6a97b9dea474a50239371cc56bed9a42501ee62a633aa6808daf395da3c8816947be7efd0e3c76672fd721740f8984d4c0529770f90560ba8a139c4f7ac6523acf595db0a22ad14e9552813447cb062fc03588da0bec34a24d282a7de1889063cd32f9dba2749bed618a058e3be4c300735d339e3f39afb597c470c287c3620c845653d8bda6ff9403c4e297a697a09dec0e9eac2cc5f590f152ddf12b0bd1f0425e8814a418457d8ced41d0d54e10057d8fe626ed42f6a69a7981809fb310a321c501eaf6f32dd062bdc21a63ad2b9a509a0d7d7362972449fba64911a3f0c850b147619d6f54f6437612fa2c18d1bec1016c640fe49367c05a1096894e4033f004ac462a4c4fc2aacf97f4303834e99878ccd540822891a8cf1baccc0042989e91fa78091f21264783ee35463fda706bd6bf6c3741cc7191892050c36c611395fae2e9bcdbb8d8d4a820a1391d5b4395cffb38f1a23d3ad3389c4e13e601842eec0dc4f455637e9912489865c89a373fa4d6e0cdd95b9a36043032523cf197a2f7a626193b18e466a3f5333ab0a576b7a6c572c8b67352f13d570809d6d0ae6457f3be1367321458a0e4cc1453d02460bc831f9c268488ad05f1433ccd0271ecde0885fc671c03a6d62646ea177e0bd6d7a3c579ad57ae0cafa74ccca141c15b844d1c1ab9deffc01df3f7fa8396ac7fa4c7576f689f22949b2915bd6c9161b73eeade29e2603da9d7d86e6cb95baa6c8bd0381b284378b2cf964fcbeee2d05ae518781466b3302f7561b144d6ac87de4bc42056911ca7f594555e4a5bd2c228205de015357c2903f7d9172e9789359250088e4797c458c6f439f57ec881fbbca82dc4ec32547233fd8b9d0f464e8c9cd656e151e6e7f573cce989e8335259537582f5e8096dc5b6c1a2d5f1941b9d01761ab23811b7e86df9d9a9ff7de2304576421d982b42b61ddc6148e03a73deee2e734616c495af2eb08c76cce640795dff87432b303fd8552a8e0bfc097667dde8f1434a2a4458e7e3e63b2d2e31fcc077096bd6aa45ffe9c70ae160cb4d5e2d28854bd889ba3155ce0ef9d087002539dc1ca5eaa4c94ee4f6b8f8199a1ddc619a061c261bda03b79c8c1ff158124ddd94fbe30c2ba65f28ecd47d77724340ec1fb1143c150a014e2241b78c8801364f1b969518cd9d8a46e0a4b2526680351086bfe08d3a0611f5402fc8ff7a2253c9dc9121f43c741d9059fdd5a5bfc68b8367576fcefeb2103d8f2057614a42e38726adf28f52dbc15715e283dd4d3e315ebea3d87cb5681e648783c45631b17489def600de32fe48770d6f8b47af009996c343952dc446322afe142c7a0ae2fa2ae3dd68945a1e5b1cb742a36aad5bf6ece555e28863ffcbbddd985b201132a1a3a08ac58724b1cd5330dd46b18833b3349816a5dd935d98cf89215f41bd51294aaff14004a783e89eec6acd648afb645793dfcd5e4ab7a6406a7b06c85cf00533eaf77c6ddbff3d25aa4839cc5d6aa0f14a5925c0a32d9a445768524164e2da427ccf8e54b7a9bf52299e01b91c868cf5b4044b45ef5ca65da8d3ee799fa20549181f77be66bc9817005e53bd1e531e6dee9dd0f20ca8c3fca42ae8908872fb3427f975bf8bdbbc304d78748317f4b67bd3dc7de4fe9b1b157edff159e561ebb0f00f5b33cb3909a8a497869f51887c3db6a9b772f81fe2884ede9caa523046986bd5d116527e1ea70b1f80828a499e31debc9b76844336025ad1b21b3d2015c6b1a54f0545b2cb529e8afeda16aa48ce0d0ece560f74ef2f581c66a081600066eba0b1bf195e16462af77610d6a151195830bd0d055bca6d1849483129a18ea91d797dfc1e0f6d07a3436d18c0c5f334a5c4aadf2e5056d19d0159c715e2cd650319d32667e302d8a9fef3af6a9545e0849f21a07796e59057adc42627a0a5f8c5ea318a090a49792860132f0fd5d4919ee50f200416a5a2af10acc58971f811402abf9047c9fccbabc6f83492467fb15148eefbf12e03cf4d5dc73c8b11cdc329719b4f8c52eaaf5815a0e933a84288d3b82bd6d386fbc4aeb2bc54ae70d67171c67f54db3f36baefa981e124737f1ba0695c790535ad233b152fa5892175ef3e3f23f536a8d0a6652c20e2e82576798cdbfcd649236dfc11538f345b405005ac1a5ccf6b49759d8798973e0df4e77e0c89fd098e8419abfe2f5896067246380154e1c9194733a0642df08c2e1298030c2cda913afccfd1f25e5bc92921e6e5271b9d827c85fe64ec46d1d6b1b7c7652c3fb8aea513e179568c8b9fae1064208d306916576137f0074229737030a22f693a6e1e27ba3a2799240cf04f21a4906b79794c495cc5a0c3172f64240935363b2a03b8a498403055b57fdcbe60e976d7a65534759f378a8367c72ca4e53cba16fb2fd4c269be99f9c0b95766e199b0cd0ea8195a74b08a789ef979eaff7f5b1f2d2304b25fe75959e4535e2842c510fd683ce6a57e9f88241a6f5e1c83b344d1e48e8eef6207f4c695a7160e42d9da2b737bfac00c86673a90cf1af4207b91965c1452df1cdbce7fcec877fe50ffb6145770c0185228a56decdab132677f095f41faa588913a7dbf6d99b9ebc195574350eb6ffec25f1454cb04f10bac2497afa7c07b1fe972a0d9a5130df5200d03cd4e2d8dd918eba724e04844ae0ef024e4d0816c80701c32d846e69b3d1099ab8d3f7a5bdc46fd4ebcfcf083126cd4f29058da7f6527510a56b2728c5a305a5890ea3956c25e5e70be606eed43f110c13e4e5c62a295060104eed434c290ccd370073feb94b0cb270833420422239240910eb8bf68d9e64695bae4ae47b0faa67b705e5dc498a3de1fea3e10d1f180ff73a45e47adec3bbfe0e6f74fc1508adca94c2940a080ed3201011cc8600a4587a4d7b5c118248d435316f6892b60e1c4cc049fed472eb006cabe94d3227a597107ee6ae46ac2b0495da4e2312bd2c2665f1e8f3b3af04bd11268ea793221028ac9a53af4de4469bcb38e6b7805a1bd4534282283baf404766e3aabc57e27eaafe6e3d526ff63ae74ad59ccaba350bdbc329066524225e4c83df6d4976b67c75a0fe0bf26ecb8917a001ff03e5182a561b20265f192fcc1e8913e9b604dd3a8c50dc6de4dcb715aa8c5ed6b1dee520849e74cf1e25c665e7ac8623d5786b551d0e83fdecb7a2e048918f795f25d9245e7c2b4b08639891fa08744c96c8ae610c5e00bbd4c00fb8c78cd5a56a6d9d1c3b91a8aa49d2bc9aa7487ee2675248afd559f2bf2e53241be700c20330aa98139849bbd25fa918c0d00ee715387f388e01ddafa0d9f32f535026c2a1d5e5ca1c7786f70297f692765b5c2060e003779ec678f25b0a8ad3f09003868e31d4ca1490751969755664bf9099ba09af48676c203ef6d893819fe75f9f080a9010cb0641d4108e4a034e1066aea62380082e9462d5dbd9763295152115d3d906e0f81405b67c03040f1fdba9e8a22291cee66a213da00a1a82939ca5585889443c582467dc98c1ec7db2ad0cc5675d6e57fdd11b0d261f95c9c493127173e9abb79820d59d5bc621de7d92f73eb795acc475365f9ec3e00f62de73e8aa17b0d82a2b0704b5f64f67f0a5bdf5b78ac8e7b56323104b97abfa18b8f618b6ff8ac515d30dc7e24688b5bc661dece854e144c2e6844fa0f73151bec43c707b8a904c1ba401150cf476ac133608609a2deeee4be71914f8e2dfa87d9eddab673fcefb8dcc149e3bd4398c3e21fe4f9c94a3a95b0af114e67e4d3256f6ca5769f8d030057a03c8392bee6c04094e843903fdeba4cb6b1200dbbf22b1c057b17d1fc74ebf0e2b948c48cfba494b57cf41d63076d21d63461940d91ad5c7e8b0b9119bd9f070029c395ffb2aa0e6a42c50428ab7b9e4601f855e3b2f5a517b47aaf4530d4c3703d108a6c9ef64f6333c26a8743f82a9de11622f91ba4df5453d0d8232a12f1807cdfe00795b0fce05816ae6000db48ff5a3b377cfc808ae6a34a1b751a2396709e981d204e448bf2944cf4eec8b08c07fe3e7d36d29378fe0aa213d1846767c0cbeda7d1d59676a17858927d239317a93d6abcbf2d85c35bf6887d987f8b1dc1ba48554530c6c891ae05d490a57578b9dd98d2f5ab56ef27e49d60fac56abd727f7d7d9b9edefd4b80adc1d26d96a02055030ae5b8b56f5370ac99312cb9490248fde5d277d0de526e0e8e4502190cd6bb86addadf33ce872838dff1bf67e8322c55d8f29137c13c8028fd4712a8c59ef5357e978b01bfd5de3caa9372195d51392e91f4e30a060d554050d0f5f69017511a188c84eed0eb705862f714268381e81321f0c2fd174a4c84063444dfe47ea087231e50acfe22137c25ce4d6bda02598f4d95b3b644a74e80a2dd2a9cbdfdc60db1cb3d9e81699915e8986c24a992b9c3c317cc4e2323de8a35c71a5b48b39196ae83ebaadc7b89c2614c187c4122b0d2003927f576ddf71f89698fcc08c9164a02dec95f7850e592dcc22c0d5532dafff7ed0586e92406009bf7252044ae37de2de248a0920419ccc9306243bd20d02984910cc33998f22c46a75e769312f46335cbe0839b44dc97f3a8dbe4c9b1eef663adf180e97f4dc8193376f7638a96512f0162bdf052c6f70b68712a9c52394216753b6e40d27875f59202d6169a3be15181c6820fdc55f5520a21feb402ad28a19292df4f84673c3e470e5f4bace0c17074649c80d78a2fceab1837af4286e0556a9b68e99edfda0f1b4d816edb9a17133b306fbd713cc57e73d7fbe4626e8a5db2e9ecefb436349c7c60683cfd01d8c292be9e7be832a93466e72662b06345508f78a1c229cad1d62974be787f3b43446e56c0ec14c7c1916909c59681f510273651cbbfd259282295fe30800d0abc96432b550df4b2cba15971768190a089a294e6395f7db1923b045ba49a9288344abde983e246667136886d1d6451c2e590f932f74a6919e95b43a356b38233212e30eb1ffa92a972031fabaa5992ff19f5e7adcfa424b76e1794930378c2ec7d417b0ba06c0995497b4bfb5193909852443a975b6f2f1eb35f76414bed66cdbb4d78127d777085949554cc066be0a389061a2612de4e3aff95ab471fca7edd7c325e46b6392741d0a8a6384393e1d88ee0ab0217ca4cdd7a540ebc592450a7ccefb601b787b8bb37f87acce0dcf05aa8dab9248671e0c4ae48e68be16c28e9fa7892392c327d920e7f228b1818c0fb6ce357e2a6f432a73b1625270de7598cfad78fcd4ed8cd61e0caeaea73e90025ad2263a0491cad774433a6a2a5603552d2432c3562df1960448cfc5c77e9600a342e5a0fb59d2d3c59a5cad80e7e89a6cde76404a5192b764aa2a5440ca4f2f53b36d1f973eb8a42f76cb8b85a96edbf9ede2a7e45e873caee089870a64d30154122507aef82763f71c119738f8e630ba183c3dad4bd7dcb22e154915ebed2d3049ad556433a3d477113a0d1ec2183cb40ecf9c7b2205a9d2313b9d284f881eaa5a0df0c779a62ec623fa625564c908819871d0eda6ebb87dae27cce9b217108c253412257762231fa826d1ca59d856d2422a3b70ad8db8f835e43facaa7517f412592fd56b55c738e15626155265f5e08a30f9e2380ff939680fd31d5c9818147d43dedd9a75c130e01343ebfcef42f34d9d58a395666159665edf5517a715e11370386245aaf38e979a6de8d004b021644af89e3a8af6a9895e15ffa5a62a85a2ce71fb035b791c43e9fc861c3fc0378cc445354c2aabe5fdc8fd6abc7e2dde7e824d41360f1c664770896d164a66d81f1c2099b852ac1b6231abccfa271554713725102613e592527272ee3de12a518a648515ab7bcbec838cba30bac22645dca6372e6823a08deebe71d5ea98807e9b3ceab9bcb3e98d3d21fb7bc97314374f8736eef149f81d7e60d6d08c3a748759a1e1b25f0d7aa34af578bd8d1909e5ee4dc730b341d2fa5b0f1e1c62d5491d963ef95bf6b074f471cd67bb3be21f25316306a63927aee248ea0e760d9e8991b53ae4344fefc91c6931964a25e70b13c0df04d755b1031a1bb9cc7c0cb893f033119f60ed7916b09a4744a7c4932f9d724b44a7274973743bd5ce061cfe78aaa07e08d9f7a69e8acd260ecd091a1ec7bd6bc2c86edeedea3839063635ccfc602b537edf32df8a6812eca9599b082cf34280289889631b9472c574029ebf387bdb6cbbcbc867e90519cf30e47224167b9eb6869fe71cd56741bfa44aa926f0373e0e53ffbc68d27fe5aaa2f7a7531407a65fe05dcc42adbbc2e15a6afd7a3c78e2f101fb8bc68725bd41f079ee5e2a5d465e57653e462f4cc3ec94e2a007b90caf34b0677c9e56aba559648b740822261f54ac4a38a21b66b734917e2db39284bad9731e58dbb666de753ab11f8121b935c281a326d7fe09dc225c0b5c0b5b0c315ba36d6f9671d83f86c238edc12e2a8ec4ef750cb0d3d098e85595ba077f002771dcab930abbce17624af0fc9803bb78964b8f69e83af710afe5d6cc8f47845633e779372fd4c378ae0a07544714bd1fab35ef607011c6d0928c03ac61f8bb16ef1689c63e520dd1e0061aa08502f49c527327715326a820d485cd07887a0d6e8adcaa8c1c4fb19ca753f2b4911717e8bf9d6de58b0ebfff6e1cb1c119116acfe1139ae905d532195621e8c7811b27a3237feb01af93b31c594c294f44db4b13d52caf64b91b28c85bdf10e3972e3fd306b16506999526687bffcc8b26ebae98d5458b10a56eadeb0359dafc771d5c821d5148fa5058ffd8ad8879ab993239dfa206269faa645b647f130ae331016c801d4200a4177566cc3d3838c45109a407b55de78941ffae8fe6177b1d1210644651ae0a77c1c7ab833a81a97e2b30766308b80045d91a5d4437f6c1b0bf205f4a40802c211764dac2ff9932cb07239480b1c0db1f67befdc739d191fcc40edb870842d4f014faae3b25722c93da7b5356ef9f59d394706fd9b4848e6cdd1f6d981d02c1e5830ae59799d597b732447560c47d82bd2a41ce7c3f119b064d10edee9a05fa19bba76589ab0deaf8706b80a7286618a2c66fe78004183c0fa91651a96260d0d914f3f8f3c43c77163254d0a09b3fc95cc11f92350ad2e33f6c169d8029d882d113f3fa27bcf5d4edadc971370be191b313598bf2649c391016007fb5174ccd52d7012d39d1d861a731cc45b296ba1f6845c912e4211782a09a2e82d38f190f8ffffab2e164ceb7a39337411ba9f57f9ea55d6f215a47a897bc2501d65e640c578dea884cd14c5c854f530741f7e45673d9391a3e40ef11f5080cd5e73f44a0a318bc94065bb85f4bc8bc8220b5dada187ffcac245a5fe5fcd61c0c2688914c38700447fc88588de588e942e4b73a32966af7b994d407f3bf2f1dc0d164711f06e29c2cde0f865e99b56e28f1c6d9b3a8d5976edc08efee5cc029959b87f456b940aff559971f91334860bbd138282f42369a3b9b1a298298201ca74935b9233330ad150343dae999e788a0914e33cd5dbc2125239ced1e0f922e57d857cdc852fbea618373df51bd7eb85d605c0765a81d70e07ff4870fb4512fa199f4529c894809df36783c415b4102b3671c9bfec49b039f6ec3af71a0420c9d9d7da74284cf82394e1fc3cda21c5a6f0b769bd841fcd4ec5cfdd94d18cd1ca649c949279e93aa7985fb1752a6c0535cdcd5290523cfb3b1e1675b9098341052cf410383a5991c77cb7c4c329dd77da3da6df0a086c596134a966dd14f71234e7b68f13b28313ec6e69d74f41532308f6582b6dd4090db9eef2e26b177391d074f90db2eea4083f25148f5585168aa5941b6086e78d1c5d7425329465ac9072d1d51448700c369ffafe578e56577af31dab3eb3581b151fb0c81435e9e451328ba5869ffc8b023bad9485a18be42d9b36f455a2fc8929b98b036257f6e3205b75ffb76fd5e259e348d4ba64aa2862c132fa015c12fe25fc56cbf76b370d51ba172bd0d5f4ac5f2fc2c1e9e33e5281ea25504a3121a5a9055fc28f59044702a750776c47fc301e959e462d940aa019d5d3e6993572d41848668f6687f3c30076bedcdf79e500dd3d6e39fb8dfb771e0c1f61d11a83ffd13deac03879d282d1751f5771ab8236b6303e5ca5ae50e12eaf2c64e02ad5aabe15ff5bbf2f7d20017165e21a1b3c39e90633fd4e52ffd25dabb3c2359a6bcae94177d3b069fb6632c0ec01b6dbd3c695bdce702564f350412c6c7826d036befcc5b1fb5f39735022780f41ab74fca8eb93edac43ce9fcee8979fd9c3fe80894878a0a75c89f962a2583188a91999edb980c6dc1c0b1cddbbfb0dc2f54c1831b97e1f2d58687fe2b0dfd7ed13545140103e66d9ef7bf01ab4c8d3b184295992a34f43683c66f373e29154b5ebcc4f8affbb07b63eae67d86c7e2a58f4c64b6c3e0d5f6e2e2f962860eb40f1c56f6b2cebe7e9af8b9b3ca86c23c3a7bd479a1df867a2dae4b41088c0e02a0e0688ee555038909a12383e469c8b5c8794a23e11b473776ff83ca8ec029961ad53a2b243dbcf6093ec89a9619606791535381bb773aa59d76a0bc0275", - "public_inputs_hex": "0x1d420eaa08a65528f470fd3e2a802913b611527f41fca008a0ad4e974750780303f2ad158d360e938540cb9fc2ecbc5168b0078e536f2a2c847cc131d440ec0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000c6e378e01efa1cb216ab0ced340b44360000000000000000000000000000000097621038a18ea02190913636079ece971a28590517ffbdf7ff33ba52157bce68c37c073712ba7f38d05290ebf864b98223de00e9e865ef8e388eeef184b6f39f6bc05eb3d0c54021d2345bd1729316ef17122a4b371cc1b35e37beb851894eee43c8b48d01f6e641ad9ba6e94da997fb154d92131d18a3d5e38ef60661e890f7ed9c3c630efffcd8e51ee7278f13333e167714b66b4e3e97a46578eceefc9955b033a18e6f8ec8add6f96a917a74414421b654b589d9ba8107e6007b5a8b71a20fb1deff0cf22904da6dd4303e7342972486fb2c422fc657a57fb1fa3501d8a94e68d15348674a20401c431592ca2aaf2dff57e20c39913382bfeaafbe4d2daf8171ebe9a277a845723db5482f9128cd" - }, - "decryption_aggregator": { - "proof_hex": "0x00000000000000000000000000000000000000000000000616da7fc6a6d8cf29000000000000000000000000000000000000000000000009587bbfcd4668d960000000000000000000000000000000000000000000000006121d7f725ab890ec000000000000000000000000000000000000000000000000000254c3d3438de000000000000000000000000000000000000000000000000da6daa0c6a5d1b5ee00000000000000000000000000000000000000000000000704ad42ddbc8965a70000000000000000000000000000000000000000000000044dae6888c0469bbc000000000000000000000000000000000000000000000000000038249694578500000000000000000000000000000000000000000000000cbe544e1f83d0969a00000000000000000000000000000000000000000000000f022e5672b0d807a7000000000000000000000000000000000000000000000007ea76b9db2039b97e0000000000000000000000000000000000000000000000000002b08a8ad0db8d00000000000000000000000000000000000000000000000d86835de0e0ee2dd80000000000000000000000000000000000000000000000069601171ff6c2bd9200000000000000000000000000000000000000000000000dc64e0a8399e2eb41000000000000000000000000000000000000000000000000000122eb6e0ea81d1d0f557691796b92e9da20b93e97a0863ab1fe2ee78478842a0c49f45fc99fad1db541b4e5adbd88c9ddba68378f955a0fb8fee6c21ddfc8e2fd73d6ff009a283005d6958a7b2064dcf37a906df83f6046a1c41199c4fcc7b1de51bc48831aa306e4801d58d108d333a100de61c3a7c902d11c47b1f3c7d3a0b25a6ad72132132f09bb7f0634f4b826b2ba79aed873c3f63f0bb72625a7d02b4ccc92408ae597051f526e4e6e94fee05e2ae2d8e4b12904bda66ebd9c9d51e9961cfced09cbe11d880ce4fb8dbfbd641d0c0636c70c7c15bf3e232af15eba8b04b2cd763212bf230710d91859e6bf1de118a016a84a1174041993b37a39e1bc004c1b8da7c3b82b019a2526f1f013dbb5954649960459a4c506bf44865e1d6806947274b51dbd0045c746ab31b273af3beb543fb20fc9cfff80cbe7db0a0b511d2f9b14502ff12f5766c56461c016ee71291019c84e22c333cd16bf76310569b0871fdfc9d31b1da62e4933273fec94c2a3cc680ba04e9b6b233a0d13147367ded65fcd59d53406e9772bf6e4ac857b26dc812bf34a1db26c1b64a233b0260626c2469164115910b03889019586c0037c32ea2286fbe1bb31259f82545e8627c3b9e841226d212afe130cf4a9b76961d989066bbbeb66a469dc0b056c285083d68c76bc2ee0f10f7a0f8441de08dad090e4f7d846c46c311aa23fd6f18f312c62c8b007bd61472a2fa97e9e5e5abbf3e1351c8275791fb7d97b289da247a09935c9d149beb26a1d562f06793f41cf7b646a4e457adf890d6f0bbfd0ac668e53ac69d0eea63b8329280e22aad07e3aed7cb334e20e466b04dcd0ce6085feb9a6e975f08da975cd1d816b4b170d94dabe92ba65bc039266a2814b2a91ff6d9cd59dc8488720894a04abd5ba314a630e81139ae7217116133f998269c10294813aa4775e0b16da5a0d23169f49db334305c3cbad59b33c9c08ca8fa4c5ddc084767a3a1005877fad196bbf853f6103f56544f009d9ae15132acb6b48466e73ae67d8c56770d2b4131997c4345fb6896ba5378db26aa654c77a7115a54cbabcf7acc4d40bfd53de0211274d7054ac3355db0cc69e8800a1e98400c4f70a8c9de3d8dbe179b2d44da025d39a26672fc01702344e9a0658c0b20ebe5a51f8508146f73ff6e1cdf6c2e81cfe68d354f0b72533115a2703b6cc5f3f8dbf779cacfacd8680218727155f0b04ea4cbb18eeb93963d0f419b0b5fa441d4a833c7ad7b0d24b0349478764c6f62fe88e483fb87415b1e327ea905d32ba4ba50397fa0c70425ca096d2311c8b0b154558e2f8ca674b7f71ca9de0c8a93088d9d70a28cbe908285aa453e8379f8d0157cca15c75f28dbfc29e918d2f3a7725b901fd5c757339442272b8e3598d912ed8c10828fc7349d1da35ebaacc78ba86ea2feb693b2de08575d8ec8a80515b2678034c4cb3e15920bc6461a3eec15d9f7c19db25ac3641a2af7839540cd2561645682683c9e16381f3c7eda13f44ff9d6f7ad00a8396d92aea2ea28dea93040360a0de2b389e3b93340a145e97c0ad1a45e8aba6843a4499fbf9a31ad6dcab0dd9a87ea40990c30fc82076461d9f27e407bc86df402f7b38797805c4f388ea242a50f5afc343005ec4fa3d15f37349d5201d60204b3948860efb12aca466de2e07da20d2bee1ff4b716cea16ea40c035b6434208394ef47618c9a05b36b21e04420cee3f04ed87c1f371c2454a90ea9fa4981de27084d981ee935b3956f92c2d9d41e8c45932a7ef1260ee236797594bd3f2617f863d45bbb60820882fdad924cd6ca6c8bad6af9027a28bf69d90ede735d5fe94327977bf453aeb327cb99c16b1f87895cc16b0a86d88b40959d9afa7d5dcafd282cadd2eda3b6828fdd574098fc2bf635fea1852b1d69346c936fcd4e7f0c3073514acfcd9c7330ee361e81c01c84df3070615eb2ac30aeca2f379dbc4f11d734bfeb6529aec25a20b26fd29bb71d9e56779e362feb0c4f8e27798321341a8e8f3d35e67acdc479c642fba17ba87677f815f1f8d15b79cef7e2533f16ec1626277ffa230fd678c3c9b12160bf78e02f78a2d70981a87a4e711c1422fdd536bef214655ab3385b4ac07f1d329cc67e97f5e1c25d04d7d26dfb744efac8ba4787e1f213c4a09145b0bb93b6a04070876e3c7f4e4f0dffcc247525f02d8114e0c8b5228a51726ea1a26ee0855239ec8f411387f77f5cba25a65d6872cbb34a7aee156f43c09b0b5b48fecd1a312c270ca2b8b5482fd832f9099c6438547f93cbf674271b26c23ef795ef582e81a36c5cf6a2564e10891b4ef9b29fce765bbd37c0fe30c95a81c1362399c4116280a46ff3973b0b348f98fa741e42fb67e0a4139da4306469e1bd02d119d28e116127b2be924e581533e1a290e3fa117c0f04d0738dbc69707286e5abfa8ddc405400d1f696a80b5aab65c2e70b13f6ec3ecd951208f975b6c80078d8e484c770a8f69c998648ea766a404486515637864a0663b029c14f33a2bb8a60e2894f02c5c82c192c6c2bf9f20eed8e920b778b3af947df672a8275836e7dfed4cbf662ce92080ab808e197dc14b88d00cb6319b4da02c9807078e38467a7e8d310d9207d13c61a05df7bf7766e5c4e5094f91f3d6078666ff1b7f6a02035143dafaa501d47fc044bfb43d453a18f286f09a28b99c7ea1ca9a3c035e7f2807e8431b660048afe711b39e0ab2714be4cc16e02bbff9485034d9c622be8cac586ac080ac1d76b5418f677e6a83252f7940af0a5daa3eafa21b4c7f812c8d2bb376862d2b1479d741f8dd2b08a6971f6e1a1583b315f6467763dc2167787ccdfdb40672900fe95ce635ba0d06e4ff638f6574dead7ea0290934e40e43e210026b650ca20d0e2d75171be19878f9882d0d1810cc8b6f25156033f014b18333518a1e57cff4245a086e4c21a79596f44871a4665222d28d62ff5b82f73dadab1f20344e2a301233df15fb850fca4f43366886b60dfb0c148e43f2c8e5505761054f031e45992e530a393a66137414996546d93ad7b66a0a86b52f547548eda7c5e9895524b511e5a1c458aaae8d6634de11003153f68f16206876b45e7188e948c3f1daa18525f9048ecbf0206c2f818b3cd6c8f8cbf4f3f3f53408ae779b0a870b51792546102234ba05de1caa383cff3c80772d58d6bf23c4ab08750bf84cffa0e9bf020f19d6a7e461d8404d52ed1bfbb6eb292abe3359d175170898a2480005f9db1abd0a8a310ce3514a6db37e25d075b0f1a0822d78ffeefd3be094301f2c1c6febba07df3bc9e983118eb146c90b068a7c634fba08a71f7e5972f225187a78420bf21a477c7e545db56ad031125723ecf029261e9167e4ced9243047061111c9d89002c6f0d4c6238de97e12c43b89611e498ca6f6d8e2c1d7f04f3424399f4094ab04f76c11ac9856f9164971c2ed828ca4ad43e26981c1132b1289800c2e5f0d5e1c30ca44cdd118597ee0f62df250d260a1eb744d707b82b118b985f1383d477e12acc2957c37c491c396614b2ad84c3969ec1ec4f1c7581c3712a103196948442a6907783e4ddc2a1462e6b13a13f9e217f4faf0361ce35af4ce7b349199ca6208be62a56edd8e4c45d7da43d9fc5acb3ff2c3a1e8ffce95fbafa4da21ead9210ad32d381443055f187a6cb02bb24c4c702af499b4de82124499262dbda32d5000057871f9cc917de7237618da0246598a125df8149b1e1dfaefb350506237b8280517a3cd38ba02d278db56960f92e1cda3d667cce290550ef00cef68cb311c28d981009c19e0c73a175e1f8bc43e7f43177c46940bfb9629b3dc8bc2865f5711618c23138e3ed27b59899f18792d4f410e9cee41597751d50144a0efb7722424247808d0c3c7605a628f75f7b33cee58e4a298f8db7e3556a42de5a519523e19edfbd5551c2412ec0d91b21065eb911c75f0c6580f76fe4ae919dd9e20d90e04ebc9b1779aa7db5c235c15d4d62bb0a614c2ba0ae188bb90c08929ac3425be266e6c0828ac369fe62ef6e37377a346655bb964fcd07085830f8e31f66c247e04086671961a732d6e9824f107aa9cb66132da736c241a93091ce4a5d0328775161a9a5cd0a7510adcda72d5380a8e4261b99479379f9ed014bb36aaf09886352d1750492991f7b968fe80a366b41edbe23fc91064a7b4f8279975369a805a2011d4255af3918a920c857fecb08ca970c3bbc183f7af6cd4ccfbcfae498429d219e4de0ff7b638d612d8a932c88edbdaf91dcda4fadc0dacfb8fd6d8d7a6d5f117feb2e63aa7b37005690a183b7cedd096681e4f472b36b0371e87462f5ad693052dea498ff2ddcbd3bfa0fe4e996a06b9790c26f6870dfc3e18c88981d8f8c214fbbb4970ed74213912e132feedfd355ba5273b00d34bbfa521e5126ee83ac50c6018d032e9b1316bf07d5f6961424bb63041a2c28c55f1c913b15b637204b41fc084c1b1a31602652d016d9178eda06ee7128c09bd600a10d18fd526163f0b081047676d393073b466e12d85711f61038a03e57ab4882971ac99b0d6b2bc0e1b9f299e58527f0f16aaf6871e1db4ee3c5dcf014c2dc65524fb5ea32001e92b2956a53aac0a6512d222970ba9e533b4ef412f10c7eb6d34924f6793bc34685402cdebfa8dfc72a3322f3dc298df0470a4a14b65a2cbd0cde85b0b03915631702e5cf7319251934efdca0c802137e7622627764a0f62e35ddd4fc29ef4624f36221330a033a4d4e45bd32d0e7515516aafac2543bceaf4d88c822a2807c777662cad17ca5faf0c64b97712ae199859317feb0b7a23b9e486edeb09299f8ec8a22d1fd21e145147c31830b3d2a93407687ad92abd6b383db919cd235516e7b45214e830bf52047cffaa97e4fdbffd6cf7cf874d4e71d9ccb92d11867be2577f4d1b61347937a154f0694e2db859286dee84b79269d8b9916562b17ee7e0b103f7068e0ea2e5d9262d13e0e915ceae4c80138a00a157779751498bb2f8f0cff30015fd049acd6daa9fd01a052506bcbd467d78f415b6b30de2ae22f9927017a0c22917f82f9b9c05bf6547479aa55ae683aa7457eb8bfeda7a07e913307f4760440135b956996aded6319d9aa9abe0f76ed72488a3e22473ef0cde7c3736429108095e21cc0b47f3bbc9a0a1da00244efe410bdb1bd733792978b3e361144c3ec927c7cfe7b3fbc8c17738558bc2c90ce2ae06cd4ca92ec2f2ec62a5421a5148e62085eefb1a3092518429b7aeaaa7866b65ec7b74cf4e71696633f53f3ff622592a632e91d5af2332983ae86a98559f65d8f82edd814b7fdc257a8502ba0909071d670f16a22cc60642c30fb9fb7fc98474649efdd11acef790c632579810fbb80f8759feceb7061413e6df2f73cb040cdc5381d4b538866d384c44fae8b3ab330ff0b21753498352e5546550f9b114baea0ba201a86b12ad1d15d04ac3b3057507f7640a2cdb667262b3474a10ef58cf41d2ab58694bb562a2cd8feeab13fcdc1ae46053432cb7c5a671455ef7d8f7d8854fd13f9aad973eec42d9a27d2573162102b926891d0b8b81ff1ec89388965457c077b5e77106d056476a8d69cc035a2a6236cef525b4202ec9b49a7a24d33243c0fd4a57372970a46f7bbb685c8f2b2f02c81eedc45a4ba4ecb5a1601d9266daa5b594dd00dd8c5ac2c98bc6d1397001ccaca031b909879d6f36b49dce0e71c0a1f552d908dd7e18c37b2665cff1bb17fc40b5c7c46fe46827effb3dea634f7493abcaa3f21f974122b393ee3f97340a901c45b90fff46f3ee3a2b88256048094e6fc5d49b8ec566413d651b4bfd481f8bea6c3f158d26f2814a0a21165f5ce25ad588073f7747a302d40898305e5d0fbb41e6583ab90ccf4ade432ec1cf063ed319eeb2b6586abb670a4e8ab4f5d3207aaeb87540df8e47a12e79a8e73b6e9743aae8d5e55aae5da5fc551bdc8c5f150b1b55695d5420881d1aea8e1752398bec30da81de0b0601121045cd1dda9f19f7b5d2266d18c3df2b61d1b471737c2add361519680c8d0c3c151baa9a9c5619cd24214810f337d33af7a5438cb1cb419f4c2e4d5a0827a0e9cf91ff2947c6000ce6c8b213350402828339d996c44c2e7ac96b0452a829022fac28bf9c513e1701296727556febb60ef2acb478eb6d9a0e1eba99466e98aae13867404d352107d66c4708e57fafdc69de80c7817ae046f41cfb2882d3babbf5139a9ae4faa80bebdd2ad2e68bec5fcbbff945c5e7fdfe97bbc3093ba2b1f10c60af59cc60d80e5b6a0eb2cebee9e3537a4eb9f002c108a26738f9bde875b7749a07bac29cf527959a05a688c56c9d390a5dd346626ba04a0363646e6967033b9be18399be09288a4cb2e5a0fa4d656881bba6ed66180b6f4c0cede4ef98e34c5b0857bbc95b2f58bb87ee1c1fd91b5f887521033bc3155654bf8ac1a8c05cebc1f8be7e3a6917485cd6e95d67dc1c766117a3180fbbddaa099949c5bf1151c1cbefa10857b62e9d1116130f8343f772e091058db76e77567417464b0ff93d4585abed3886971f259252fa965f51868653047aee30d5e15c10cec90b2b99109910042dd655cb221cd2533b22397a15f8a4476ae6fd822077f56d3802f01d0b00aecca818ddca1f43544eb3cdf138b816ff5895940945597a7655e30b80c98616ef432c9da35323c7927924b4c1046711099315ec5d58169732b4b75b0a28bc279de6465a42b90ccf643157c4ba6eb5bcdcc7995ca022f0fe91c0eaf1fa910a775e32c70877ce29e5bde84a1189da233e3ace11f96364467be583eef1bfe52b1649a05a8bb44303db325b8fab5908df7878a508c6154937ffeea18cbf43fbf14200106941b8f42de76932b23e689995af9e3d04c0b37765389d1dbd1ad2fd720fb20bc864c025182b41e019aace2abcb7567da8a2449e1887286aeceaccdebf9dac751432f38e2e4ccdca3ac87ee7fad352d7ff41cf060d830a5568773f292d983ed3ea9c87b721b01df39b09be61d87dfac5dd5aee60dcdcfc8bb862c758500b189a324db3262f51d10e38f6d42a7fd9f051204231a06595de9ce681e9966313df7734363ffe1852b06dd157c08d974d7191399967c251acaea70c1376924e9082dd3d6eada315522ab87463acd7faba38e7e2f45677c6d6e2f93d64cd3ea57f855228b29086168d443b8768761cd92dce3ec5e7eb49ce0206c45b0d6c5633a8f7cfe5239b1d2ef1e141cc5a4c73ebd5827d91ea4feae63329ab93aaf49f8621647c7658eeac053de71515e765e1bf41d9e57fd7688cb8978b70edd88cc5f397c16e8bdae86806e7f6a5181704db97138fd3ad30bfe8f3f86cbb665f4a7de7916007e45137ad2edd56a1985f9a10a3df3458a734a9ecae9b3592e43bac49201782855b2155523019488b64b546a7aafc563a9b59f929ee0cf71f5faeb4ba027809a47ea91bc61156c1995627c4998f6ff7e8f59e552aac13a31d70e69b88bb179167f0ccad681dd077952dd05dd90a5cf24f2e5bc1e1915a996366fbd7e356358e0b92108bcc2fa60960482e8b422993ce58bfb7cd058f8e714f1e4d777dd4df6d94d185bb590e76ec3c2c47001f0726c38f0e9d2063f3ef67f0fb63023bd6617a9f53d4ebef1e0280a270fe757aac0af79058d909b8ae0361301fbf4252ec5b19dfcb88c9fb2e453ff90a2a56614dece9e3c3c8872a5116a230c48c7f987f257cda6cb8190c2d11786ae6a859b224093cfc916d924d1dffd0c72c60f04a7a4b525b9de3c0ad217f975e26a887400711a9ad9f1026afadfd263d3bf89dfed2e10939f0b3750912ca93f9498d6ef6f01d557fdb07a8e1bacb8f971f56788cc049b36ebc9944bc164843ed2f857d5b80c2d0e8a54340d6dc5ea6bd33dbf0197ac869cba99390d72ef15e01f0a8bcf394dae09bea03d0b6275f95009008923effce8d6c3fd71d7d05169b021ab02551c8061118dfe49ca2b249b80e1b31b35da1e0bb2986d8fde91e7e932c864120afc164374863379619a5f7f42a733faffb78e3c0307955c30f16aaa12541ee9edbdf1bbada45853c95bb84b6ae8b55727fecfd211aa981feb3195902cdf9c47b466eed7df5c99ed5c1a9986be4bff1f8ba0ca9028dca194a571ccdf56160d35f7db7b9b546457a3f58ee88f804b0af4c9d0ac2197afe5cdca827db53677c6c22cb123f66ed7c9a3a5d66631b4e2d28ec1ac2944dd8928c17b600462658fffb922dd59de1b5c4e3c596b135e5b3ec648c55487c4a4e9d03d0fb0eb1aaf689e5664411d678754c62a9c454cf433246204e7f0d35023465870ee1083f29e501695957c73780f0a97b7fedbc2a9d8659ee308637eeeef72467516b07db68fb78a9a9cd0d7e80ec1855e2370dc2a3fc5da2c00a6f2178d5ef6791a32ca0f2ab588997a20dc02b565f20a93ce84018b4f5e9e91b64f1b8fbb4451072010a3a6d25e1e1269b12967a77469f708063e9bb522a5f044414337ce58745a61bfbc7d14ec22abb3b904e2e7ef401b391fe764815648a73250f96d53b6291d924bd03aa9a5f58d5e893c14850fa85f01e939049ac3a56ace1b73fe06cf1bf4d1ae95413410c335e7dd27b9d0ae5db94283f75ff30557ee6ee8c2facd4fd1cd130640da57669309ad2ee076dcb7b4c485d0a68146b2a687a92c2645fde606d7e29fcd5920546f402de4ab466d0ee17e4dc11a167a17ecb77d8d34b4a67c18e1509ddf08b7a929b2aa92918a0032fa4dbcd8a735a34d11034f82e6f0c111a36490c0d9e41bb0b47ec8bbee1492876a765913a332f93bcc3dab8210c067becc09a0ad7426250cb94602452a54e1c073e2ca216a5f107ce4cfbb6b355d09bd65957285448bd1289902f5e9570e7aa2227117d4db540b9c97d3ed0f759545a81e4d1011380c194c5ea5db9507c00f61b87d20d1220fe4985e2e1d30065a23bd3156f23347b8df7af3454b8739d379debb9a5ab71dc50af6f215ec2a15792ba0450250004b392546927bd58a85055a05eadb613806d86914b6d62bffc79eccb75a7540a5b8d2e55bb8014d6618e71455a8f7b2f7f68dd008ba1cc25d355b90bc3ba1429fb08d96be9b5c21c7999f266cd03b43dd942ea09c55fb5bc11c6c5a174425c2a14c41fabff96d751937819c1ba20020918f9b381431322ef154b7363dd8ba90e7fec6e1072b896789f0f4822c0c147367c3fe82792879a0ab3caa19873431814955df92af2d824e8f1c3e879df0cc0d8a0f5bd76189cf2acc89a777aba170407d7788ecbb0c719fe9a150ad45a5dcc5d8d0a6923b7b27ef6c6b7d61c8d36551f74a4356e4dd1ebcef55bc96b0f6d4ec261619111bbbf7d01cfd4886d1de53623b33764960fed4f0310cf5bc7c27fbd4cc043bcb52e3e5a5855388cccac4c3e2326086873a0072e2bd03e12c78207d91b323343a2be00ca1d316015e6b7b9ae16dc2e72f35764059963da57573115adac29eaae415033e5500b11b392df0090240eedc5326ba3c4de726767dc7cbb6ce92f8cae01a136f39e72c82a7f455def1235497e0d5e3950864202a2f45edf6b800dc64b74b696f2aba673b08e4a2d822a929abc9e6ec8f99049f780d6281f48c9e92978df5d80724eb41681b3d4d2551149adab600d300405f0d78e43bd382f5011ce30554f420273618ed4474aeeba226d1c60827a4975c016ce132ac2bff671715085fa050d9512bc678279dabc7e2937ae6846d97736f3c49eb111407b8a9e9b127e5e2447d4901fc973a421ab3d22eb9ea67ff3094ae76e2adf6da4a0384008de2fd1fc52336fae0c0eb8a1f44109530dec9ba7bf4d1b3d51afae1f5d20392178cdb6f4122e1d9241d3d5b2630d22170047f6dfcf200ad991bccb04299c0400ae830abd161c6f16fd7f5ad7d55e2a91a91c308686453239d3a527c4b1761dfdcbee18db8f02e8efacf3628e99f32ee6e7244763d56e037832853423134a5f8a5641ae4f979e50ca4865ef06643f02fabe75f0cace0c0b039d4452ae0f365ff529891fa3f371e664b389ef7886eb3030b411db22fc59dfab6170e4a1ec4e136124a10896528963dfc5c96ed4259d1332ebc2b184c375fb6481b068abfa1c8d7b863b3c764d18dec95f55a13b807a1ddca78ef66c3f679f534b30384f7a796467db5f4e8595e0500d634744ca3ede0313c61ecc7c3c379c7edd4a9e711aac6dbb1768dd7604ad4ede42a037cda84d13a90845592175da3e3c72f9eff83911da8d0f3279fdb75c5057a140ad1feba217ff17582509379007b855924ad126cea015f23da97b9ff1a85d2e26178e7f492e38990677a0396678b98a389e5050c5a74ce4a769d0f445746bbff937f7c2032cfc6627c5c3af996ef37c2bc10c5a7c94c2c6ce88e04e466b9c01bcdaab60491533b97ef4a264153289662cee698be8ef26b021adcff3be3655a6de1f89d2271992a5af8f646b8d1d1887b122539bf5ff80b0d73282d288a0b7b1f6b15b7177151794da1af79b8a3265adbe34932c3a5ddc7cc991ae4280d005ed69ee78a1f612d55895627f1bbc0425d4f27aea7f2030c68852f2e2a869abc8c656282a69d91f4ce47b4ac4253caf925dd52ff54d1cc443761800deab6659b954208a22c27c09d9bc509923b5af45933add7cd707235c987f02bc0f609b1ca5a831eb61ae990d69687bbcbd8889eeab15fba07d77666bac222248c9a11092cfa1368f7ad93e2c70a325f6f55bfb9c2714850e968c5f9159bbdc4da5b5845ab1f4b196b06b860c8eca51ef7ee7ea1c5ac6741c3b45eeddfa510a3b35c87046b84859d192a7482e3c7825d060b1598765bead1f4993717136208fa56b48f2ce52669d7c2aff3d0bbd8cf1549ca6332ec3df67c16d599ebeba774d36a3c23e47fb3893ba793a9a2825bf3dcd7dfde5259eabdc59b130726508bf5285e8e462de85cc1fce521dd40ba15d9af05a686ca5bc521d4f87492904e9471a27df178a9c32b4cd292debb3083e36159fbd062777ce3a5cf7e42b68cfe357293dccb10a66ad7605de413bb62b339778547ae76ac7a2e1ed9831ef465da55fa64c661288a01252ecd7b9f5a62e5b8687ec4064245e7c14f1b044bfb5833f5f5354a5e52a118f30523e80fef11c4a642b47eabd6c27c18e8834c0aa44ee3353aeca611d41d5a139741f106ea329f5a4ca9b810877f6a0530f157229cbd931de9be6ab060c9c7aedf12a6d31bd1416ac65e49f6fc1ba4fcc40934eed1ed6750feab533cee8d2a5bf77b70860230d4bcc80e332fd6dc8eaa597a64910504bb9f7a5951e0b1cc5549b084e62d3612f42240d9fe81c6c474f9c91184edd5d3d9b5b9211e72d85f6d4307f89b015d01987a2ba529b3e3de4305c8d91a646ccc82a4bedb2a4907e9159c7c99ad0ff59036d6623b151c78f80b23febf74f81d0a92495ef3b64f19e66ed2f41012533980476096427924dc67d52afd687936db302e8bd625ceac02ee8d96da3ffaaf18d0dba69b142c534b2af9d4c54d09bd072b0abf5dd514fc97ba8887ba0a3cd11601669661d81e87b4a811cb36b178dd20b80a0f2a7d30e3cf1be317eca455d578327e0b8517954ae519d46c43b511ff7b5b5faec58ba349aaf5e9869f04c2c67a30474deb6a73b2ebd5ac1134811f1a36c4b25196a574cc0466bae6b3fcdfa67a40beb8730f67992873081dd969bcb5fc718be38b7f2d905e0a956005ef56acc7229696bbf0b5783493ae613da7d540be2d78baa3c0ae8ef5dad872e5ddde1b4801ab09d3a847d4e7b763d045842143da7dd7506cfea1768cf8f6c02498045a5c12e7e1694b77217b83e4398daa91eede9dfd0e756b5454f4a53c44db1ed78b05f180801c4a0e6ecd9dd3c75364074acb511c8c2388bda38e4082a2f52d456d690044ac311feb298ab6d7975886247df78d1f764d91992ed87babb126fc4260470063cc176948b6830efede55d9dd95863e7000b0d6449779f26cc2fe918cbf16b0b156dc79e15d687a3ceb7f9e89f387efa6739bc8694a0663c4ddd1034e732d82d98654f4ab727422694f967ff95c25cdcfb0a7b67a9ddbdb38b02ff739702532bf9776901d83b68bcd265e6b441044b18a466db1744e60f715828741c53b38c2234f0062231eb92cbd23949615f9564eeca7e3d36a66eb8379ef32d66fadfa4142727380dc5ad292c52c7a073b76f8cd789835175390cd2e01c49670d4d66062ff44e2d186ace9c739f41b6027976d14bfc760f07d82c033b950d9239f066c31719f4e87afcdaf9ee8d0278b99a0e3d18849003d3be00c682b37ccc6095110605f89adb2b7f013fce5b354fb68b2b32577fbd6c48a89bc1217c32ba2023b975219cee35356409db3827f407d60777d58e8348a4b165a09faa7e89660e811f2b093603ded70cd3e08e680830d676175ecd7efe2b0425ec8d5d7927f40d04ad5902b02397c2b75482dafe445739acb0e8ac4e53158ebd6e15185513efe9d06f38251951521b1b37ee05c9ecf7335e1d561617b68823ee6ff207eecb139bfaf3c919fb94c51769dd2fcc89cceb51856e10d9739407ced8a9849efdc2411496ccd72ba430028754d7f3e1d7aa46a8a78e0a0b05709edb0612241c0431cb38d32a8c05fba833cbbe1077cbb83aced24898c91227ae2ebb7c185a8d7be7353f8a0cfa2b1e7248dc2974a6e373f4c716681a6f5067fe446777c3d31571ef38e09783501336d31654c7c5d95a34d5671e1079566c33d4f32cc5195d4a999f56be81b1c9041c23e40a59a05ba40da1f97eaa2f83d737c4ee7767a7f75d44f94b08c838cb26c9c73e59f573dd389732d09fd9fe9eae468c6b879ae3d2a9d2afc712a9330a21f7670683303dee05ccfc96beb8f2d894df04693179e2973cef115c09354775010f3c5156faba3e58bbf7bd54bee5e5308a25e94fe3b1147078b6147c753db4288927e082ab365f6cd4f74d0e850a3afcf01629f899df35a216e1d3adfcbecc0b5176ab93d7221145c6d3f2011852b1b0d5e52595b97c6d75e6551b6c018464068a4250a21e45c570aef973ff978e2d0c3d1f32ca88295e8dad9a6b665faa3700a8ff8659e594a167530a95f3f4327d7210e6b5963fc3a3444d16cf05a888dc17cd53ef517b3ca9f2c4da57eea412b405d27341a8f3da610420f8cff8fabcc22ea7167258ec2e0e0153836c5e3fcf168f25aa7172528b7a7a10e6a961520d320657abd3feb900a60de5d920a78a84b6b91bd86a032714f0729541468bc628b42fb2580aa35a66684f00e8aa78ccea16a6e2c2a76962a2c97d2bfdc28c1a14b1029c7b68587d6cec18c23893dfb394fa183bfe597d4d9f41afc074c0eff30ee90ac83636244fc935d52d9f8c32884d8ff049e073a3dbfe2e7f3a9fabe056db851b8a0ab427bd70186dac196be85cdd9cf6a472db35588775a41d8f5bcf95cb1d2a0a34567b854f3d22327387c2b32d30ab6abce341820cb40065f24e9b4bf7a111bc7a424546ad33f509901289798a8b7978dfb8db35dce1f6b3dba62a1c5ecd1b0b6ebca55130fff8bf52b3f525c4b8b490664fccc47262ff3df8b6042652960484ce932170e3593575f723508e98ee25bfd80c7c9d432d952dcd2eca28ab9b2294cc39122d4d6c0eb32e53e70a7e8036c79c0c0dbd3799259c82cfc1c7d0910d399780e2969a47f912e8b716239eede7888a4f541bb71f30133851e10cafa40d3e8226743bae7711324bc4ec129c85002d3083a2af215f38359d37b8d6ece90f6c000b0d56175158febef5a203c3fbf701312bf3d11667ba4c0409642de183162b2a7fd33f67c8f2c4df85c2749615563b0a782dd38927c24f0adb3dcd67a82c8d98745e75c91c8cb14a48a18cdc21c337d33defe7a34ee52d58f2ecb0f33e1b2f7ace0a364d7b999319eac3e703147b0f0289d13b496a5baf1132e2d69fea1c05498e6412f68f8157fd373a87e35aa4e60aed1ca9035054dc4624cdc293e6106ab5b7636b1eb293919de2f9cfa94f8106140a2fede50519fec44ee3b4d12a01f74160bfbe701af451915e10e836bf9dada21bcde42f5c5f62adcb5ddf571b2ed223c42e6671814eb85aabd89968c5d0fd5cd71293c45f665190f6dc4e71161bdb143eae947ac64357958b27ebfd7b7d747c635220135d07e5dff8c97c02671cc1498962fd55a7444e856319b117c443a4ede613035f4771414a54e3a189b7030d05c4fed5241d83bcbb4bfde04683b10d845642ea853252e0588d953592541017b5276b6057e49402142dff4a01b46e0577963f1d46395fdf2d11092f0ffe15681c8e2c65ed60de0c5a4fb3be87a9ae7795bbfe16c96f2a2fe963c12e7eea0f851773e33fd8eba81fcbd8a3f51081726eabd522109b504e688c1367f7a831019103d297cdd5e7d383882d43a1e392dde72d8b45f74206cb3a4af9dd534e881a1c9c5304e1951778074af2513419fcda57d4002f8ee3fa959e69394fe07757026d016f186a85c5dcf4736885598c99220b8e32c16c41fa25e9757c796abf710612a3fdac0fd88526f8fffc53774f41d7d5b985ed1af86b398aed2074aad96d09cd2356845017140ee303a82f21315d018a149cb23f4098c5096334152791f128495dec89751238d8f03030911d3d2975e8c637bc65a3c308ee81ee28022f001befbd0c957929a6cf5e6682b645d001a3ff9a5a118325a69b543d179f878b2d0c7808b8477eff26b1c176fd463289dddecf4765b048bd6cb82468bd00c5fb42", - "public_inputs_hex": "0x1a207628cc6936816ccb62a7b56fdbbf8e975293b677c988644e018fc402e44107940cf3c3a18e9c2b8af0fc91a18c91a709c00a8093bbe606a2e9fd472457bc00000000000000000000000000000000c6e378e01efa1cb216ab0ced340b44360000000000000000000000000000000097621038a18ea02190913636079ece970b3f37898c93078120c11921f007446ceef9867e6da4e341fb3bf8991edcbd630000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000223de00e9e865ef8e388eeef184b6f39f6bc05eb3d0c54021d2345bd1729316ef17122a4b371cc1b35e37beb851894eee43c8b48d01f6e641ad9ba6e94da997fb167714b66b4e3e97a46578eceefc9955b033a18e6f8ec8add6f96a917a74414421b654b589d9ba8107e6007b5a8b71a20fb1deff0cf22904da6dd4303e734297000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - } - } -} diff --git a/circuits/benchmarks/results_secure_agg/benchmark_run_meta.json b/circuits/benchmarks/results_secure_agg_micro/benchmark_run_meta.json similarity index 100% rename from circuits/benchmarks/results_secure_agg/benchmark_run_meta.json rename to circuits/benchmarks/results_secure_agg_micro/benchmark_run_meta.json diff --git a/circuits/benchmarks/results_secure_agg_micro/crisp_verify_gas.json b/circuits/benchmarks/results_secure_agg_micro/crisp_verify_gas.json new file mode 100644 index 0000000000..e565f469f0 --- /dev/null +++ b/circuits/benchmarks/results_secure_agg_micro/crisp_verify_gas.json @@ -0,0 +1,107 @@ +{ + "verify_gas": { + "dkg": 3125318, + "user": 2972965, + "dec": 3640997 + }, + "source": "folded_proof_export_plus_crisp_verify_test", + "artifact_sizes_bytes": { + "dkg": { + "proof": 10944, + "public_inputs": 480 + }, + "dec": { + "proof": 10944, + "public_inputs": 3552 + } + }, + "calldata_gas": { + "dkg": { + "proof": 170028, + "public_inputs": 6144, + "total": 176172 + }, + "dec": { + "proof": 169968, + "public_inputs": 17304, + "total": 187272 + } + }, + "integration_summary": { + "integration_test": "test_trbfv_actor", + "benchmark_config": { + "mode": "secure", + "bfv_preset_subdir": "secure-8192", + "bfv_preset": "SecureThreshold8192", + "lambda": 60, + "proof_aggregation_enabled": true, + "multithread_concurrent_jobs": 13, + "committee_h": 3, + "committee_n": 3, + "committee_t": 1, + "nodes_spawned": 20, + "network_model": "in_process_bus", + "testmode_harness": true + }, + "proof_aggregation_enabled": true, + "dkg_fold_attestation_verifier": "0x7969c5eD335650692Bc04293B07F5BF2e7A673C0", + "multithread": { "rayon_threads": 13, "max_simultaneous_rayon_tasks": 13, "cores_available": 14 }, + "operation_timings": [ + { "name": "CalculateDecryptionKey", "avg_seconds": 0.041132764, "runs": 3, "total_seconds": 0.123398292 }, + { "name": "CalculateDecryptionShare", "avg_seconds": 0.156390416, "runs": 3, "total_seconds": 0.46917125 }, + { "name": "CalculateThresholdDecryption", "avg_seconds": 0.238677542, "runs": 1, "total_seconds": 0.238677542 }, + { "name": "GenEsiSss", "avg_seconds": 0.060112764, "runs": 3, "total_seconds": 0.180338292 }, + { "name": "GenPkShareAndSkSss", "avg_seconds": 0.092604958, "runs": 3, "total_seconds": 0.277814875 }, + { "name": "NodeDkgFold/c2ab_fold", "avg_seconds": 7.479159527, "runs": 3, "total_seconds": 22.437478582 }, + { "name": "NodeDkgFold/c3a_fold", "avg_seconds": 59.442402111, "runs": 3, "total_seconds": 178.327206334 }, + { "name": "NodeDkgFold/c3ab_fold", "avg_seconds": 6.878937805, "runs": 3, "total_seconds": 20.636813417 }, + { "name": "NodeDkgFold/c3b_fold", "avg_seconds": 52.507483708, "runs": 3, "total_seconds": 157.522451126 }, + { "name": "NodeDkgFold/c4ab_fold", "avg_seconds": 8.781505236, "runs": 3, "total_seconds": 26.344515709 }, + { "name": "NodeDkgFold/node_fold", "avg_seconds": 15.673083958, "runs": 3, "total_seconds": 47.019251875 }, + { "name": "ZkDecryptedSharesAggregation", "avg_seconds": 2.76144725, "runs": 1, "total_seconds": 2.76144725 }, + { "name": "ZkDecryptionAggregation", "avg_seconds": 48.1789355, "runs": 1, "total_seconds": 48.1789355 }, + { "name": "ZkDkgAggregation", "avg_seconds": 20.013341666, "runs": 1, "total_seconds": 20.013341666 }, + { "name": "ZkDkgShareDecryption", "avg_seconds": 28.810868159, "runs": 6, "total_seconds": 172.865208958 }, + { "name": "ZkNodeDkgFold", "avg_seconds": 150.765525, "runs": 3, "total_seconds": 452.296575 }, + { "name": "ZkPkAggregation", "avg_seconds": 25.608851458, "runs": 1, "total_seconds": 25.608851458 }, + { "name": "ZkPkBfv", "avg_seconds": 3.605216528, "runs": 3, "total_seconds": 10.815649584 }, + { "name": "ZkPkGeneration", "avg_seconds": 108.799082041, "runs": 3, "total_seconds": 326.397246124 }, + { "name": "ZkShareComputation", "avg_seconds": 75.595901146, "runs": 6, "total_seconds": 453.575406876 }, + { "name": "ZkShareEncryption", "avg_seconds": 124.987066109, "runs": 36, "total_seconds": 4499.534379957 }, + { "name": "ZkThresholdShareDecryption", "avg_seconds": 98.947407777, "runs": 3, "total_seconds": 296.842223333 }, + { "name": "ZkVerifyShareDecryptionProofs", "avg_seconds": 0.120913319, "runs": 3, "total_seconds": 0.362739958 }, + { "name": "ZkVerifyShareProofs", "avg_seconds": 0.353542567, "runs": 5, "total_seconds": 1.767712835 } + ], + "operation_timings_total_seconds": 6764.596835793, + "operation_timings_metric": "tracked_job_wall", + "phase_timings": [ + { "label": "Starting trbfv actor test", "seconds": 0e-9, "metric": "wall_clock" }, + { "label": "Setup completed", "seconds": 3.001494625, "metric": "wall_clock" }, + { "label": "Committee Setup Completed", "seconds": 20.095969166, "metric": "wall_clock" }, + { "label": "Committee Finalization Complete", "seconds": 0.001439291, "metric": "wall_clock" }, + { "label": "Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall)", "seconds": 166.661482, "metric": "wall_clock" }, + { "label": "ThresholdShares -> PublicKeyAggregated", "seconds": 646.101478541, "metric": "wall_clock" }, + { "label": "E3Request -> PublicKeyAggregated", "seconds": 646.660075833, "metric": "wall_clock" }, + { "label": "Application CT Gen", "seconds": 0.320969583, "metric": "wall_clock" }, + { "label": "Running FHE Application", "seconds": 0.000853875, "metric": "wall_clock" }, + { "label": "Aggregator P4: Aggregation pending -> PlaintextAggregated (wall)", "seconds": 51.080123, "metric": "wall_clock" }, + { "label": "Ciphertext published -> PlaintextAggregated", "seconds": 152.638885459, "metric": "wall_clock" }, + { "label": "Entire Test", "seconds": 822.722301083, "metric": "wall_clock" } + ], + "folded_artifacts": { + "dkg_aggregator": { + "proof_hex": "0x0000000000000000000000000000000000000000000000079c889e8dce73661c00000000000000000000000000000000000000000000000e3e83da1b8676afce000000000000000000000000000000000000000000000008da4b92b18c5e81c10000000000000000000000000000000000000000000000000002514e27f7c4e000000000000000000000000000000000000000000000000db01f6e05c6e1a20a000000000000000000000000000000000000000000000002059c7f08ca9e35b500000000000000000000000000000000000000000000000f8f38e4c226c82f3900000000000000000000000000000000000000000000000000004edb478b855c0000000000000000000000000000000000000000000000003c8d103c4d61a3ad0000000000000000000000000000000000000000000000096cbc9847f8fedff70000000000000000000000000000000000000000000000058eded07624268fed00000000000000000000000000000000000000000000000000003c50daa2a25200000000000000000000000000000000000000000000000c985a54e92c3faaf400000000000000000000000000000000000000000000000044ddcdfa0c734c240000000000000000000000000000000000000000000000063a829d40e439f4870000000000000000000000000000000000000000000000000001cdeb374021c91075909caaf6e009b1ca605a4a31ee30bd9da5f9fca6bb3c54923dff85b2b73b0da22039330fb83d3ea29540b29236c60275b27f8d38ebd7fd93397415121a5010cdd787b6473185051c384f0bc18f17c0db6d9dbed6ea91fe0f5fb1f88e81041c5b1307f3b0e37a7215174c8d5cd16f4cb921a36d29d1bfff26e5bb60b9fcc722868f4eeed0d3e728ae7f6f885c8c17fc51d831ed61d4802d86d3bf6af968c311e6f78f72e07c4d0626a845fa37caf84393e0371921fb89b035f314d6a62dc7108b0fee11fed570546aaecf737d9d119ef047f9125d6930f9e713ca31012b71212eab1d9a27e6f2b8aa8ceee7041a03dbc98c197992dbd0bc88ea98e655f1e6285a0be8dc30ef740b380b73b6d9f09213aad88a4508208b18027cdbc5cddb23024d349cbce7e706f58660bd43cea5e72df06f8acfef5becf169f95b2600ce6b1f62a04a0f35879d2b8eda6bfba70d2a3df57baca8ab3b9767b9338e141b8ca02e92efd940bd0a1d35f6d71b0a1b6656c65231f848ade4c443efe8513452b5f22f0b4bba7977b55581bdefd9a88858e9431f805ad1f4351a86a4beebb493a9e114e6572cfcf9043261bcf7fb9e8db94ffe96c6625652b24861d5d36682d19ca70f2caf423cbb01eec4cd0439fae159c344c1993fbe7c88d73d83aa0a325dbf990a6f8ad176a86a372f086adf49142b8aab388a972e1b84507420e8947719671904e9cab98d8abc1db7b0568c110f250bc86bf64f73a906bcc972de1a5becef0120d1e656c81a2eb92d57eec612b0bce8688d7d239e7727a414975da9afd7867d20125debacdb9a1994ec4b00980c24f9dd6e8f21be2b16af45b28bde6faa56462edc8621dd4cbe543a444dc6728bb6f502c23066060ab2f6a38ddcc3eea7ec2b27425afcbe4fe9889b44985351dfba0a5f3391efb2528de4f2927d6860820cc623cdfc3f85491f07714761976da2064e0fe4df37f22847fc2bec5f9e1b09f1b613aef22e979dddf204a28937b340c80296244544205cb00bf8d99a7d22258177137e1c2a7e14e72311a2b9dc91b383d366349851c0511881d2c9f2568666456500ed26b066f1471281ebb1c166d06a20c32f7fac5330d0cd51dfb87f0ebcc38e15f07e98b45174b609a893e3a82a7cba63ce2f3beaa994d9cb70afb9e09a9d432ed9236ad92a89cc114bc80ea494f084922a0518f20b63e0070569b5dfe95c751934567548e6c0c01719777cd116533583295cc739c18cbcf7a7702126c051e60659ef8dfe218724d29d7b42a4b8529a5400da1bfc66aee9ace80bd7f3a5c5f92222e9e71f29cedb38847fc1c64e2dd4c44c51e20c3dea712197866d63e1b5142ff7c91ccb1f35f7b45e5c981f29396f45562c73408ac4ae1cf460f1ff8100062e3784170798fc88e58c6f5882b024a7cf37d4300da0148ccaa124820a3612530f8cd772d3eee0d1eff58c0eb0ad9e72c8e4df9dd1f91bc8faae1ae20b4a68d60803f9e26db6b80430e21adc709e1c11fafb473d6dfc52d5d7bb95d040825a1f0ba8e03aec6a23034d2760520c8fe56e4dd91ae8e1bfc9ea78f9633191abd3360a5de96c27f9c9b444ad97d607254741a6792993ebc023ed1a5e67ae40ee868c2e73ae3764ce5f2df9696a19b1885d128296a609e9fde9e3aa575608280da0990ae803a70c1450a1e6a037cec85dc3d866081c68542df69e737aff2fc3689f8722e6001ebf6f0e127b2f55dc50ea3a07a917132e40de45c2f6599b5457945e34073f7e2b901fb12979381dcdf400f220a8278da513ecc193f8e3f2908ee0c3772e18d7e734f0999d7485396867fa7126f469221809353431e16f42403f2279bc08c098433d8d0ac992d3d2ac61c09e06c926aade8ac753c3830d2ccf964ac14212fa1d3031bc519e5f297b26845f7098905f6d8218b802b87f89c89dfb9d147814b19433f552caa4cca8e1a6bc89d22b9f90cdaf93f99f936a2be9352e55ab052667434c7a809ce77a2ec68f8e193e56d30449a294c46de96cc4d801c07c7a0f2075fd36b3def98f284075c4942401d120af5e05de639155a274f7340285ac852f8caf721a758386ebdfd5b19527420d1dac567b6446a1f5e2ebcffb09edbb530ea035f1af0259a0b9de2f368fadf267b244ee882881d59374129a86bfa78cd0223995ac07428bef30fd7844b30d84b392c73f6db308779a9ed95df0eab87a1d26ca04e3acc28a8365a01eb4a9e3cb721972bc98da4a1889e8d08d22f97b97b5173b44760b6486c5379a45d87d7c9d2dcfbced4fefb2e15feb703aa4525a39571fcc09ed0c4116972053f96e230c0f7e387b59e0359b43c1bfcc030578ba32342b5f9d96dbf73d07ca3197a73ee0c6109d3b1105ddffdd98a06eab7cce6197830e9006e3c05c989f9b931d5bbb1855106c6cd41ed44a46fa86e4d2277db75694071e795681fc6acbf2f497cb009cffccf37ce8f931115945ed139d8c9fa0db791373ddc8bced6e0bfee86023f8a7b5726715ccf4153fb9c65ed586f61e3cdd652a8972f01cb4b2860cd3666720f1d92d0c83277720ca3ba207b9ec440016a6300c0f76d9e2afde29f10270972f61253985284111d485e4dd513c393da16a42181e7b6fdec0e06c4d40b738d745013555e41e0d2401f498060d76b43080e32f9512672cace135bfb75a267ac01431638e6e4defc612ccee63dd51d7bf2a1e3b522b5fca7370b1d0c077f5426f94a6b9e1b1c05693ca2a68d66f97305b65ac937714a93acdf0b49c13e36e2c5fb3c480d315c0858d23e663137564c93d25cb06bb0a70b5e557f72e1daaf66e09634975972586c64bb84b66679ace358a051679132b680710ff757d2603d2eb25e9657cc1cc71d0cfd474aa43976d7b10f80d81ff24c7a67662635826aab095ba54905650ef7de9f984a5f88547ac2bc72a49cb5f0c5b7961132b760040e56e1cec9386b18981243a0a569f5d83e06bbe5bfd71b4168901dceb5fabe6c719025d9199911c9dfe9993a8b6922ccfa50d5f159663171ac6ae03e74d70ff71eb20d74d352c6a8735e56ddc1c391286012837345f07eb28bca2233373568be9fc576341d839f91f62ab970cd492ceab5e14698870e6d02602b94b5b61a33de8f1ac810cb97758a926f087d2722eb800d603d0f6a81c5a028e3edc3492d338326572d83d3ba494dcf2fa7015e6b96ff8f9122991826c851652719a15471939cfc876e615ad2400e62aa973ec2410d1ee89a790c3915d252f969aecdabff87451f4e927cd25260287584bd9bf45b09a3fe4c343dd5bb22c1899fc3e54668eaba5151785efd270b359eb95f5e9f6d85e5d77a6a2de9b16150f50a233a6b8af910a2bb808f9bd029873098f8538552170cadca93fea41442f022712161b47d9f3c4b40bf8caf04bc3e22a2454a08e9ac8bae90ce964269aad050fb702010a48074e3b479022aef29e1f54073f9234523b5714f60d709c9330288039fd49622ba1c2a91fc881a2053f288f3c0ca0670ed624295336dd24022c2529d66eb05281e69f6da9495bf02ddf3fe8858d554569bf889de63c338ea12e0eb67a1bf8a11c8d4e607768411c49f00030d27869cb8806ed6bce28850cb56526cb309006b51d4690409b63134e48aa55bdf5e6f2a1f9343e70d95543ecb5ce13887499aec571fae66782e751ff2c287716d53d95273b56a0bfd8e9834562fb00edad9de5deacf497197b89d6fd75ad297c3de44dda8678e56d9882ad9aeeb9285c6a2f0d8a2ed6eacdd669a7e61c98c58c207a941952c88b917faed69ce6461fda1ec064a92df587e92bc0e1ced200b571065c8d5b996162c7931251e8c358210f4e8cfd451d2d04d4a789dd65c488b42e3c08235bf7d89f4c50156caa19cf056c2b87d3abc179f07d50c9fa84bcf0a802ad11b753d4390a084d2cfc7b310b0c77296b91ee2f8bdc475a6588e81d0143c4ca6521a56144280a54de9492d8041bf4f64269e3484a5cc5519f216d00b65d505ed149f6be72ebb6bcc4e978ab420d4411fcc7478c7438878cf2ea3e78b96f5a3e4880f92ce12cc3711882aaaf8104143dfd91a14f4aed89d1e6def69ca15e3ceadb3dbab590f924e56990135b33162aa9b99cb75aeb0df6e1f26a6d1d99bdb3c98efd1437a636854447c668a53311ac9de3a021fadf4eb3bc44b4647681af1211068236ce7c35d9a3295c7163040387dcef7af836cb87561bdc2339a6831d7343bc140c71dac8e86116e817e7401ac8d80c2b87087b8f6529112a1140d223577072af6106489b98e1234e53e16100840c44641c6189e726f6eb4fec56591b15ec35dcd61770dffbca22de00689619cf2dd0ee4a7ce2a70a66d88481953da7a0a1a8d8f96e7d776e3525f850d2521aba3fd333f96c4ba290582168b9ceec12a5bea6e54ab0a5964db5fce30c084b2c448db0ed04fc5690996c5e514e0deaedd6f420e916e437cf04ab3f8774422503cd74298a5f7b7bf599f4587fed07628cedae79178cb194aeb8a9d21ea1243002b0d65da6fe8d18eda0a1c0b6797daaf36d92a010c273d36d604d088bc4ad6b13426c8dc73686040efef1b8dbe635247a6215bed3ae07b9bf1a9bdd28da80622043a091a73c0a5a96d5e64815f5d6ef9b4fd678db61c80ebbeaff7735869a5b24ffcb0e232241a5e340c40bfa86ab7af4d10f651d4584ad026acef609e582e42f290a921dcb51d3ab26c370d1c63bb60c6e82f0a74eaadbf394a1812397fcb01ba6e0a13e7cda682a13aa4f15d79e8924fee9908bf15da6cfbe02a100dccb1a290bbcffcb477ea70d6f21d4d4c85ae454c57f3941fee61c7de90db8d9890b83170969198e22db4665380f332aaa1448ecbfc059bff94b1de169c43ef8b5086a151f94882c0ab8c74599eb324de8ab0f4d989b7b02dcaf0ebdfa39748b33b842279440c8b1bee7cda4a7fa9f28fa35b572b379d35d5a2bdad34849fb5d4722260b46b389c65f60f644b24b79bc6665ba2d87b9ba88a13f13ca8a3ad259b22b3c2c31e29dc3f8e5cb4f8225eed1141d03d28a491eeddd2536bf0cecdbd8bcbddd160b792458a6542a506a70e908f7f1c0890c68e33c820681c8769faa158b96a9025765df4b4dbe0b9a5ccc45704f9eebd321e099d1f2f6d9662e517f7ea1965b0c86d6b6e909599a2e37e7c53361abd91e2b91e21a2c8646d869dd5c656d5edf183730de0ac9ced7d544efca5ace9a32c6bd1ac33119eeffec92b5f08da06dae16de5bbd8ab21b075dad63931f6b97dd80b5491bd4fb67051103b4004035f2ed30040ff8a36b77ed49793c373447724eb7e8dcd8f101f3a2127ddec0929bc4fb2c2f9565d5f09089f092dc3093f1ee34c22ef35755537b60edf71d58ba101045171a60a00478ab6cef32ac863af2bf2e917e518e847f4a5feeb61576d10c992a16c206f17db0d1d8a2b8a83e6fcb831335ae02493cd8d0239dce2240f87f04da2911a698db35ec34119dedc93a3beaaee621c0c51c9cdbb4dc47c56ef09c2f442a7808f4eedd258b3e120c3b07bac002472fbe4b1fb779a6163533801f4a563201f54bc1910259d393869c61789b4854d1bfec865a56b33b6d49a5f2c0a06f341ad04185861e6a01ed828850a9d14a1f0ab9aee602a499e2bb4058ad04fbfafa1c7c640cd6f665424b81793b9ebdf3b73b59c2903f22e2c4605b9992f7d3b54307ad31febc7f4225cb803175314c8bf10ffa7fb9213c1a381b9d3e53838c6b230c0c5698f2308cefcdfc4f7a3cf7af8ffa90ba9879268c5f29e1ca74e17a269e2f43c589a9293572d2892624fc2f5d377db94290027b5399bf8283855c29512715821b90fce136f51531c3bea90dfc86a8cb5e349ff8daed89880c946218db87216e1a086588e49fe3213488f5c55198925fecd314f7041680294ef5de9a752825663a86b7bcef416361bc5ed880aa06d1bc05553ed80f71363de87a4950c2dd08c7915da105786e949c1d280563bc17d81f4c03aaabe0e5865816f048d61c3e2fd0a65b236cae38a8816cc31053774db4feeb4c4c8377d673ca6796704002ae038173fc5062ec761bd16645f5cf40aa6290756fa05c842caa1215415a37f0cb1a5aee970b990e92f3c1a154273850529608c88e76ffa399d031788196392d2b2fe9d531b890f0cd3a7f439683a981e1b670c4d2c57f1d3ad21a01307308ccd6185d11d51dfa93c95d4bd4e6719aed7b43a9430cbdda7a8f87f8e8308d86e2a92bbf49ed6c6c438caf791099c12cf1a68ae2a4d1104af3900719fa36e73a10901a9bec448067fa5c769f996e09726f188a7fc194d3df6eeed4cdda0b37a5679824dbeb98e534d661a672dc76f6bdb8746130b701173c80dd79f2695f5f05505114c878ae6d8dc5b72cf507642e3099114c0f269a1b0edbbbf6c705f37c405ca924f354c0b21032c131371e46961f6882a3ad7e7a73d27b4a8eccdb0a6cdffbb90925fb47a34ab46dcad51b49c308d64e9fdd13579e2f088f94404a710ea1dc1121baa83dc698b92a1057cd227c57870c8e8c9c20dcc391efc53ab1210680b2af0f328ccc394e04a4020b92b417f2da734de89bea6be280b4cf3510bc9b9936b82f950273bf1dd17ff7e8cb9b8586e1e58b59a7ec915a06ff3f3eac2d98640b0d1fde6e2de0ba3181cec207313b229d03c649960e4a052a5812a1e546f4e7a12e0567fd8d042e607c82234ea09e4d501010c17c827b7a9e0d3faa2ef45889a6571b1c75ca8b43af715e8c0cf0b74b859de0bad3f2e5715cfe4738956bd0c7180021c84d9eebee716c6a2914c04acf41f01235ead9dd9d62b3d62ae91cac389e800e0d7679ad59b3bab165507930a74b4cbeffdb54b06a64a79e0f346918515b380959d9d0cbfe81b561c11f81016f0779694afc0daa53d01286071facc04fdee103e2668ae4473d71b00f717fa127026f6463a0478005fd7554d0d104510ff7d7233f6b8f195a0d6d34b9d13716ae462449a7b20db60b9e03bee2b782c412d94d026f7207e2db35d1201cd2f331cfe53b0985c8c9a74f96867342bf393c8f6fb82569c8bc822f5f93f9035e45f44288f42fc2a91e3a83c0960e3106a21a247af628286b74f03df5fee75cba749b5e2be9d1bd6b12123cc46b7c7514ab19ce23b72ddfc719ecdcc1043c263c6945cec1f81b0da0507026d0b2912982d11ff06f522dffde03515dc1b5687501ff4c7d73f33cbb4157739de8f96f73c6bba0ed1486113117a3875809ce89070f82c24eb55d73241a7e6ca39fa96882067f91d1e7241cf66237db7a08e5706d17318210ef23c692982e291cf3b18cbc94c46751e7272eb00ff91c83c0011d36221422c95f4b02f25a4780c1b5ac9b805ba97143a2c5096f1b4e50d778b46679e08daa3adf0aa8ba0c946f5ccb8deebc2cff2da62c921d826ebf66cd8149e30070fc47bdd8cf231728cf1f975bc96027b85f5fe107800d74128cd3d370b37f9928284349ad89a97b454224b0c90238e288992dc0e66e0fc09cc6f1c28434113cd027dd5189b86b05eeb03b81e33dfac34f58be3b63a41dc204ee9d5b1a9685cf2c075075e4c96b326bd235947aceda1e317562673e650dc3f514d4976a664d7773382d780b7e4aa8d1b5520eb4b1e5c8cd5113f0f64e233130ebe456c31acb17403c6dcf06dd7df0ca2bd44d6007f037e0101bf5778506305af712e8bc9fdbfb5ca7f377ccb559e6534a27e7cd93db6bfe8e0dba14500aae879a4cede2084915882157ac650eda1d5a31d30ef13935fe25b94d6d409d11f2f47f52849d9174d2f9510a3c55fb04f80c89c83d67b6455d17103819d33416d2b663adcecaced40141bd51975d29d5e5985cf3b4b02e8522ce6464d4454f1961d99e5bcb7a102b4281beb50743a5b2f1553668b3267310dea74a99fa976327b5e9ed370065b5832f8bbaffef3a11ddc4799d65198cc4a9e205dd80da29521cdaec743cc00baf4f6ec115d4841be17c13940367702c5e1e0f4a49ca37dd510370378e51a6e1f60a2ddbdd13df8c8aa28f9a746a1c9a576921e1fde854ef5401f0af0d62b789e8e28d21019ab0d02efac472a19b820995dc1970095f7ffeea0d83a1286226b5bd378a9235892f65565dfbf850425b6096f69f8e4e8b18c50d00f0a69b85ee1d745877fd35cd607d3fbd726c3f03c077eb7196712c948bf1e527d00eb7c5f3961d23416f700ab9f3f8cbc15f817d1dc5d8d8ea326d47a7bf01078dd96a4ca17f3f50dbdda04ddd5f71e58baf5d8798e216f9411e8ece22572b30280312f5cd1d022f7827dd73d2ab0b1024e1f82c8d2fed0f808af5f26d1bb023c6e3deefb2e1a9eac14f8efde05760ef7b5124420f95a53ac1c427f5c5660c0a96da9a71c19068b921e9f90d0617cd6a76e5ccad558e4268690112f54957e11329ae735bd291fa3c275f4efe282e59d8cac61379ecbc0d80bd2f11330943461d1401c866de889f7f84323411face95ebfdf6c2392d6d5f5ec45ac127b3d3b20d04dc833b9afe0997bc70d1977cc91caa758e98161c5b35b8ece4a923ec952700914f61bc997bf65382eb13d9b11205457cf5274d685c7b4fea3a7a8b61f7321c911925db079a8ea2025db2e599578949a2df680247d71a1be355d0a0f8a66e118a9db684abd90c9183f5b0f32a88f119b3dbe7ad5353671e90db09017fb262198c128322953576172e5c881e395bf874df2b8fc796995617187fd6a351783f199df295fcfe6388f1b62e69e9c8d5f6830fa6afc7023627bedf92f783c5b9ab13b79e505c47b1d80b0cf9d3b8d396b1e858224a8ad6e694395c670cfa98c22008225dc71f34b1d5f0f218d3c121aa851bb85d4aee52a73438d55ccacf6fcebf0265fb1ade7ba9d0cfdb1f601973413972c2d3d3b0323262a9975de075ee83560ef23bef045fecc74f2a0612246813f9593fb93e46cd90860f84e1e28ed777e127a67c4e38f95d21c1bae5fe5913ce1597963e0d279d7c9f3d3b6a8599c1b28a044808699df165722bdc784c023df8e4a5807c5aa29e3b89c3b68cab4a97abbf2c78ad450014204928da95e4ca74f9c1da2e12e4f1ab750758bb515aafd880c619e24d8ff768ccb6bdd0586cae866b405d7b37e4d42a03f0ad17eb1f8187fc641da0970169f927f7bf9e1c384f942c3278fe88839509d2b2bd644fe583f70fa40ac1f3e58441874ab673f3a7401d73385ef215358ded3f974bb69de93468454629fc31e1a014680834348e2487e0da2d31f4f2a392ff96e05e910f7ffcbf21491c21ed8afa3d870636cd2cabb4f8327f400fedca7f0f17d995ebffe22678f46e091d38a9e3dd6dcff1789df56d6118340c46cef3cd0da9d6866a190f4f0841052ae036d221e1a649198cad8a804c4d0063ae4f53e39d350d724ba3ba776f49380c5ba5aed82b50041a676c0985a3af3a87673e40ef02761506ae9b8a9747c1d12a817f1fd7285867098d80313c6bb7712e2e5d29e8bc0171c05cd1e32ee3005800dbdce2e7fc587e5b61be874d085375c11510b16f1880fe72b0138b487f12fa08968d9b61e1f507044a4fa5789b2e64abff247934383351a1523fc5b1642fed0d64575a26c69f2d8495194c259788cd2f198f364104f70c5474aedb4338e8370ba9bd649b615a834bdecc3a81814e5341261262b81ea5750752090206e88a4b0464d074b6f282ea46c471a7fa5fca9f7d152bd52fa1da7472865856acd372a4277b76f44fd805174f05c3bbdcc6b19ff4aba69c0c4d4d551977ec58748cde1302c31292b2a31eb3411af654e4950fdbb1498552e1960e177ae165da22c2752b2df395df52503c8214ebb389582efb8a9ed573b97c715cbfc7f124e071f2bcc629101a902bfac0c1628391049848b1a4cdeab6ac67da87c059f94aa07d043ae704568761f61db3a85009558c192e60152706c95395a041f447a77d01778238822acecffad7de06a7e561247e04cacc0839b1ecb48c3604285851ed468324f7ea0dd39077706043090ed84ee41c128d924ee2ac1d7ee52ff06c77f4e6bbba1a7f08c1fe44c08bcb3f8b30b28c1fe413e28c2540c9d6020447312e74058a446a1c28f2507e0c762d4cd81b8cc616777f35243031e18c1f7c927bdc4f6fb09850d800ff4fa042db15ac9923c7acc0a23eb21ecf3951d8b6069d7e9e6963293dc6af0660f21c97c56f041167dd0752681447171fac2b10482a732cb83d7bfc8d200801938f6a67a812126b5869ecb716ad9139ac248f74b846a660bf1fa69b04d95c270b5ab8232141f4affd1b8107c09f30a8e46895f08a8523ff3aa384d4ffe2d705bdbc30d959ca63431241d8b5e01ae3787a696943af65ed91c83e607f7a1b482d4eb07e1924e091d622ff4e7d5ebe5145c4efc0d2b41523fd1d9f42e3c2b6ce211c89f1823292c192a59adb05b32ae0cbc6488722677e2006c9263fe02a7a5b079553eb23e1960fea54923af76e15a80896323dd20c2d8e6d3335f60579b5750f1c7a488d9342d15a29b885df33d2f3bbd1402166dd7bfda9e1f316958623cb2fff8369ff6c93762c36d35b2d682203cd3e0e49090911cdc76e46f633d7459f145bab91de6e42c2b01c82cbe0387f079a901bdb2b36edec896a6cd81eb5023a1068158dc5b99f7ecb78d9f1b1bfceb0509772d4f0868e308aab8e26f65f27340933b6b6571a29e20b90c345601a0cc8b539dc85c5ba7d50e635a9629a8813a600323980699381f7d3c31d0ca3657b5d2dbd00f427a428cb8e7fd2b415317c6b24b617c682b94295918d7b7a0eb8dc1dd2649887b782c7d707648ab7cc244bd9142e970240df323684c6368528c115735ad5a502f3f9749cba348a389123ea522ce8f8530eaac8aaedadbf928a547960049754238a73321c5568967adc49ef38218440cf8689d89b32657940e801ce7f1ef29a2d5a05685f199fa15b924a6ccd05a42b013a4633f8d1ebecadcfc0d421d53b64bb9fe5bfaeddefdadc8c0271b01c06acd4d10fe9ebcd5b1f23ecf741873c478dbafc3dcc2fb174fb2a43e22ee10e5d29ad7406f2249a5f9874529b9b6a4acdb4e05c88ede6fcafef35dcea185201a1162101b85a14bcd95f92c40d88178553ad3de9e9d1c6ad299bf4ea9339a013fbc520e7cd416eb1e5c468e67c7130c17bc7a3a19af5ff71d1674c77fdef8023043de08199726c6b565279df338e806235b88a9e4a9150eab8452e31a3962619800fc18c9c85e03a0b27cf9da0a9125edc795bec6a70d1e35cac63618ebf7f2bd063fc16a27ea2c2c69197d7c380e6e7cb4f92face6d972fa686dbe7dd42c61d2c2ebf7b711d09c3887f8df2367df68b5a79f8a8bc882a892e0fdc47155bc61eb55ed860c0b490478861c473db6ea731a7521aa718ef64f8bf42436635dd9b24e8d126a1ddad46a676273f34b9524ef94f5e15c4a54d4aca9ef13a422c80802288154c205a53cfa862266129a48f55d5fbed32e7339d08b0b0f90ea8269f8b13faeca680f5c89a8a2f47395e3761dffbd94d10ff5ad645c3abee5aabea26fb113471ee6d71d25795ebd2b9306c1fc09f8f60fbe1ab5f80990b981ac48504d82e7c0779b863e947006791d70fda2a16eb06efd7a2d31359fb0cec7a08098e1e10cba3dec9ad6b020690a8e003596b4bf2718815906d70b3f39b3fccf8486fdb1337b095c8d62a2435d583d19a6d6ae416d407060817b08e31ff7b8ef8d76f0e157019c2bd7d826d8067ab485e35fef24addab5f890cf4064b24d5c036c490a616f673fc10cbbb0a89cba2a481b9416a87b962ea665af99090548813305b8e7e16962de30630903282955570c86ef018218f11a3968de5839fe712b434e9c60f2f4640ef056aa651ab26025ad8be12ad827f41e624f703ad21b344c13c7700961c1dce1a8cc3d9a43a0a07a55a1f12b98ea97f69f9b511c79b8d080432f177d11643bce69f4b15c5039b20bb6640e5a5b4a7716f68a777af4625f519e37ca965002000583dbe32d61b254a1869c840c2728fbc6c08b6d023f37771f505def86619f0f5a76d7cbc6eed927683a4858202654fc38e08b46ae56046c76e2326e12305b512043d8c044fd98a6bc0eb7e627ad19fbf0c7c6dd273a607116669b6ce5e088a91ecf3d9aee4f5c738f6bbfb4df57cb03f8e3c376cf0d5ebd04a7dc2b9692c13d4a2bd79b936a38f36122c7d260f40c0a30a215e517f6fed8bdde84d517b11eead861320478b77003a45e0111e3ba9ff2ca2b9526e3a7d368922418a57c3086c29b2b83b6f17e1d6acf42a402707f5488b392f036143dce34fb8e4efef59124bb2a8559d5cf14c8f91d0c3a59bfc48b1b4e306fe88eef7743880b82b36b2092e99c3269785e67b53ee2ff5221093ae056e3aa033b028b018631c0b3c712801d0141ca2e0605e36e6e284254f5b5f494e0066c012e1350f937950d7e08d170d251b4496e34d128431bdac280e2feca2023ab233eb87e319b364bafad8655c2c7708e8084834e47739912bd0adff1ddad10340e964b59f8a78a821930d8835062e5adafd3983412b616197a87164907454487ac39d2ebf9cc9b849e3fd1e5527f6c8f32bf0c7aef717c852b5684a0ea33e286a6e35d7f5eb65a86d0a20c9cd0c9365ddea3d67fa5d5a276bd8815817e8125624338c688ba0df13675403522e0e79fb09d9b649806197b03fa0bfd88d183ac2aad3e5a563458f75f374915e8b270d827ad01cbfc701aad8c723d8bd32f28bdb5224f6213c7c565043fb868bb42a6de5a6dcc4275cd9ea8a3c6cb4f5056e19f9533d56cd2620dcd52127f39495202710c990105b3ef35cc3221c7c9d5a7f855b67c5a98649d56c5f251c54c9500b127e4097131b40f3c1e68eea407d40eedbe5f69f20b813cb3ad19bec62c98f0a2ff7e8c9e0a9cf519531046545a3c3a5d7a2538c8c866df88a92b6442cbd8017c0bebd1c384df8fbb4fa1581886d996cb5ba7ffa5f6128e67a41ce1106967416b5d1a257b9a48ebe50a03724c4e0d01f8ebf6f45a3dc38b28a60cc6307308a0f6e4b146e68634304ed84248cb2c0540a0d4e9dd3a853d0bc281ce0f2efd7cd0dfad6ae1aa05c7fd773583f4255bea06bf5290303326058d258d1159617acd22d430bbe1f5899c0576c8ad0b6fa2d7b21c50b1c2e502b388a0fc483486ba1a40dcdd0dcda309bae788697f16506f407c94dd7a762ee2173c580d636a7b3274a21e043cf074a991c5e34a713a6e9e08cf7dc2bb19d50e038292c5ac5853aac700bcd1be3590c00bb700bc670efb47a460450efb29d6197ed57101ca2dcd325d9254baacf26189c9b295cab1a665eaf54fa87cc3f4e2ed4308973e33f9aa485c80f2f81e8e039f142a8e752ab4cb4ee17a982ec5d5df8702148bc438e3f2f4ef90a12799c7aa06dc471ef800325cbbb1d3de04ef8de025d8f59db178eb1de374b22ce9b031568c9bc172fffadf4bb951159582cf654e84b8ca2d3a8439ea3a97b0a1f247ef178d5d360b08e430d47a4d5754f189d0f58cc7bdbcac5035a1616ca01302dd5475297933fb62511b775b3663fa4e62bbe0fd79be1a5aca222863e941f0e89f92e565740ad8284ad155135327288cab0c48d039fb4e25a75ca610b091d2aac358e01fdced622650c9b7423f82914a740954a10a8030a8f2dcab1e06f276a4b0ed333baf2ef75e5221207b654f0a2a18e98ff47208eb79a3277d3288c2968b4e2ae36472158ae6bed4220d782c5be998e029ccd39a4ab2eb370143efb249057fce91b09decbc5bd00b418165a05948a796081e07b4eeda4306f5ceb1f1722f512a2c14a72cf38bcb4a730f956a1cda6aeb7ac5d536083ca02358c5efc05157c27c8749d6947f2da6d9b336a2fba145cac930b9e3b1e4b618b938abfa625d85081dc7c0da2752f75249f8c3d3589772941cd0ab5149abe6995a660b74c07f674dd77c1fa53df9803b39b4109bb92e1c61c2ac1564a4559e6970fec3eb20f6fdf0d77a0bfd9872009ee2a2cf0067affa0037aff0a27354d44409d0dba4b0cfb53abf13b57f93b7ee1eb26b23df128bad45b399821bbdd88adff2ade31090b44250e9d3eed773ad4d329a0092d2d7e07447047fe9056f21e652797a50752227b8f052326634a6c640cb08bd7c7c0437c466d8e858962351856c31eacd44a174eeaf021bbb9d9e21fb576047eed27c3e1af92ccf6bd69c4c553b9275089832ea9d9313ac3d1618d5c2037d767f62b4b24b2c280efd4fd9076f76df70bd73e18d46ef7cc36369536a5fdb14a5be259f5a5451df790cd2f48e90aa9256f51181b922923de6a813722c63d4790db3aac7df604cf4903c771526acebf05b9a89e28fded5408ba411cf8b563d77999d799d25b86bb7c69988a8e6f6128ccb6044926d3df49945420af9bf47edc6c0073cd0774b878015d49966c8d303fbaff296e0e07d45d4bfcf46ee6172c08d1074371c3bb9b79768623bdd7f23e9d2fa1f1d4246fe9fe90bdbfddad2c984cadb78e43ccf854c772b5e2ea901cb2a141652907219d626039f1a343e4d7b925fbfa329f10009276a9e5c8bc4a7e0b60f5d8e96f13bd1deca8c1635d444b9e89feef62d57f3cd2260515f08d5bf1a92c4ad61d14158a471fbecf9237297c47c8f4664560fa96c58a6198eb550d00e4344db18fff156d5640c469267ad03bd2ddfd0745b5e87148e0a0926716f1a7987beb9353fd28511e1e9314e92c5ad89e61f49f3adc9cd6f3d3edecd68f8a40cf8d4a75ce73", + "public_inputs_hex": "0x1d420eaa08a65528f470fd3e2a802913b611527f41fca008a0ad4e974750780303f2ad158d360e938540cb9fc2ecbc5168b0078e536f2a2c847cc131d440ec01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000005874be0dda5bf3cee7d33e2ac260833700000000000000000000000000000000c484d632fca06937651e18db1cebd2a61a28590517ffbdf7ff33ba52157bce68c37c073712ba7f38d05290ebf864b98214b346a1e0b88b78ee55229a563175a39a591790754460f52f2c62ba9209ec682c52b19c6d060045e45222e0d8e0b98f4ed39d1828106df7922a57e9dfb4e3612adf2b3b5c0fb3ee6dabb0598567f04e5399940174b52f2e6f21f820ae1423c32c171bec038f3c507bc03153950b824f23b8c9bee914c66ffffd81476e3d8274248698204cea2dcbfb2a3f50cad9df0ee2be785bc9d51b32240ff14a38e634701d004c01249dd31199204e4af023d3953454b3eff07d78ace9c9390491b0bb270c5c089316c361ab8c67cda08511f331604badf371b748b2209c1a93694851b1" + }, + "decryption_aggregator": { + "proof_hex": "0x00000000000000000000000000000000000000000000000c48630be311f1f962000000000000000000000000000000000000000000000009094d928902bade6b000000000000000000000000000000000000000000000003276d7f70998c8a6a00000000000000000000000000000000000000000000000000014b10c3ef742d0000000000000000000000000000000000000000000000059dabdb8a1104760500000000000000000000000000000000000000000000000cbd24ba9f08a5a4b9000000000000000000000000000000000000000000000006dde9afc78170cd7e00000000000000000000000000000000000000000000000000006ebbcb69bef100000000000000000000000000000000000000000000000815651da716490ee1000000000000000000000000000000000000000000000002dfbfb0ea6015cc0d00000000000000000000000000000000000000000000000a006ddebc8260adf900000000000000000000000000000000000000000000000000026bca52f3432f000000000000000000000000000000000000000000000003abe7bdf35b12324300000000000000000000000000000000000000000000000d78e97fbf6f41b5d900000000000000000000000000000000000000000000000fed06b22f3348ccd0000000000000000000000000000000000000000000000000000177bd3993bb1900745f882f4933774d30e9a1a715921ee9c1deaabfe8d8b00a75f50c02a291210c7906129ed7f95df356228e1afb1ee7d2c4eedabbc0ff255b387ad45beb860f1834d808cce18a2f82f98a9f7b0ccb28f0e7ea6e83f942964039ef11876aa672102cdf23de1a57c84618b4f41fa62e730e713ce3504835cc8f76971a73efaa5422a4ecf28aeeadfeebd41cf0a5d3efb4839e9e85afd27c43a99a0fe87ddaafb8196059999059478d9ffa41dca4f6d7d81d48d58a0c30df6f48db58e71d1ec6961318e088bde136b51d63c83d9df77a8cf759876137decdeaca7d26edd5af872f18a88adba15fc2d6c452a6a77363067f5c96b232690e5d926000f5835a5860f30b972c618cf393850457131d3d04f838ac4970287b03bd3d9193f2055753db7201b5cb49d8f446c2603fbe74fb10f5fd737a04862eeeee35997bbd47ef7725f12871fa30db4aa88e433f3bcabcafc0b753daef044f69b58022f3cfc0d82e87b61ac35e45692655552d2123d527a983bbaaccae4c481fbd1cd7ebc8fe01a8cee90147a0c38b93aedbc670319a46fcad126582d57c3a3f5e77b209771d08aaed520caaaa19ff0f4347d238c1cd9df02bd048d2b88ff77c95aaf18bfdb0f54a0a4d282b87af61c7bbe102264bdced08ed6d509ffcb2f4274435c60ff805de4061952efe6b65e37958492ea0af7a55f5a9f63f3cdfb51e1a8cbd06cca94254a0664a285b19f84494a5550722ee2dc7d405148d40a312eb19caab840ea0447841b92622f60bfee9aeec6949b5eeae18499e29176a9f30736c499247936abe337445381ac036614165e412b2919586e233ef46bd3de2c3698d645cc7d3525cbb54fad00b7153365114e1e8c003326f014ce2bf525c0ab22132c83a65624e1ff513ccf00934202ccd1809839b47c506c78ba46a1a08c498dc9a8c3d29e8ac968c22e50d0faa86e7d3fa85426521ccc15e7e8db062a8ddad6df9bd98f5161b2277bdfdd82d5e6fb53e470f08dad8c9d6a679ae6ac38816d155ee74882a18896fd8787dea0c84b449538ebe74f4fdc0abb3617378d9bafadf565629b8fff511990d65b9ba02adf458d1a8907f735bae7b108bd8a711d14a2b26944ef0864f55e61e98b19e0bb3ad97e31dc9a35693b44ec21a82fb8422edb4a4720015f044b9b22eab37d42dd0cf96bd3676ed7674d199c350bff173b472be442a94417c1af5402bd899ea1b72adcb09ab85580aaf25d1f5aeb1012bdb3ad06de1a5afe1544a59ed92465a177355256de35ab467bb6f578b91a360d0276f56f6acc076b3e188ee1bd8faf113384a6c297bfe1448b3aecd0008e3ee22fcd1468e92f0c2adb0577b7a7e3ccf127cc5f6c669dc90e7f04d177f605c7a6ea70a9a9ae72500e85735e3809c474b0e942a7631d7144d74aaa78b052e0f1fec5dee7659de0afe2d5b3cd86aefc7a5209e329df0479e8ee3c73cc1176db21efbdee75cd733437c6d77f74545d673e822e1ef845de14e49bffef9ae2766cf974ccc723915ec7d8f9d0a62d66db6eae31a9a43de1f4b7e08bb514afe1557dd20323ac31ab956f0ca0c8e1ddc2770219a25673e12cc23b5bd31e3db44b86184feaf44111919257b284faa330d6407b09d148888f150a06a6bb9eb79bdddf567f9449435147a138f796b88466b31ca90d4250d48c7ea3b2cb83979c4433643155524e69665728c8234f021da24a9e86475033220cc04c9f50ab16ec9f1ef61566c01ddc144f19592b2ab034a4cc67044a70784872790c05b9430eea6ae6d915b6a37b6384437d4734883aaa65c1c14faf124b116d95bbc3afa60b5295f5920cc29b904f43cc4609bf10b33d95a0b20d27b1cca8c4ba458eda7e800e7c3819f963e2d7d5f7c2f1e7d32fa54bc61f00c8a141428a4a49ca4de281ea6562d1d044f96ff4037456663e92b29ad6cc0f8ed987d2917107e9b91dcc6627a87b55e5e9cc9f301d83976500ab72da2b5274942781513766227cba3fe36547829a32997e945d4864267602a93c8dca29df504ab342407666f1133f877bb58da2e440d1212bde80af6920804ab8a9c02d40010fcb1c3070c6ff952b0274f2d6d1a15a89f647c4292c5526b476bc5444fb7972d1d73de1500872412e79a184a617cbbec29f8c54ff05fddae5ecd77f5378f7ef8ecdf2416ad5f6b2a4280b3666cc76afb5d37d1e05193f882e33ff469678a5574afcb462bc172273991f7ac3d737d0fe587e662e9a889812229c3c698aba1aafe8ed21625e07b561c35fe049510519f3961a4e216eba4e8fe18e2f7517b686d5308eb462a2915804e5503ef25e177977026560f87155d37dd095e808394d3576603cb592d8f8589807ad93e1f1363d79a8f2081dc0257e5dc14d92a587ca3b21e61df271870a9f6ef519d14a154495c0f62236ea7bbaf6c4a325546d33a9c063ba33fe21ed92c092d512bbf330524f0b224da2987bdd30e9da88ba6f2bb97d2a79980de025298a2413eb020e039f31f70aafa0da1337a0614f6ac0bb4a463e63a0cba361d0619dd00864064458450ffcd778827e41d63da2c9d0ab4afe5b5c4d87857662d0227308dae4827ed96865305924ce907dfb5782cf5ed0e5399bbb0073934771e6b226bc2b36e4dd351ae5a40bf9126a0e6775ff4c8536c15fb61949b3290bb187116c1c2eb4b0b8b064a6440f4054c5736147c1f0729c01190818e147d5ecd2aacd235b489401ec0615402cd9fec3b7e7dd0a3a1fa0146022a187eb7f37b620a9579bcc115ddaf83acc5af58e66db7f1db3fdb9a29d4b2e95e8b5bf68993010d2a11cad09eb78cbadd63b78acef6a7e5c94bdeea2fdc3f3a50148cb152a2a91acd337de539d43bb0785f19e2830add41b7ca48b9412ed781f833c9d428082026715976f5bda0c6f55329d2df6df074055cc52d6fb4c05440b2c1a907cbe85e1676ed53c33df7816d1ab0c2c998a7e7e89451b696986cd2a45e341d5e7271de2c6b9b45192740cf23dd12b5fbe90d24ee1d7206b42116b8c0ef67c2e6642dd715ed3a570dc0b5730ca5f06b6ecaecc9452b502010234aad2f4497e57ca36da80a73a6da3fa532b095d29b6cb628a4e47cd4a72dc30c4fb4b6a1e8b906ca1f422dc5c75b0953935f15a81549825bc0fcff274efebedad0116fb484723acf21ef00f292189cf7fb7fd95c607331ce8163d98eca656a050e313d0c6c6b01327e0e2fc4674669466cdee6652485aa109174631fa688b85d6e03467e0ca4ac17d8e11aaa9a8694f65e91af6b9f32a4cc3333e1e6b00efd12e9b7ccf899d63141b72c092f22f0d61a19077b146a77d929864a18e667c332ef8783c5ce93e55530d5f00c1b0d21202e170d009b08aeee517acc2422c23535a920bf6c0ac423ef00c762227ee738ab5736520f77ef14dced495be5fe5e050ba5f732d5263ddce615f01a2499561eb221ba50f7f829c7640c27300a3d95fa3da0d05f22810c6f358ea9bc04d51a1041c4267595146c41723072f277714d2aefa4a24ed771cca0c6cae035246b9c4b7c3ced3338ca2f126815275c531f9991f757379286023733bc7226e6061fc89f33013eee2a9a6e46da673ae8d2b768db22fb3d19c5538a7e378a518502a7528efda5b359114b70fe88ec40ee48b7df7548951146d3726b944b6abbcb1e00f5465be285fc50a6257929d7197106c8f5bb94b7fad2ed848d987cb90d6b061541e69a35ee81aad42e8ffe42a7d55e0a54f67ace4f8a881b10e3f15b5f9005e9611b4f9cff3651e9da3922d8b166268dc70e920c1bd426250f391bd4a23d018e721f396dc4aa5926d36519269623e54634fbc568118cf8833b14bf2f0f9c2408ef297f5bd7529c9e199fdf843129e1709870e829f727f30c5323a92355d6031d7764a8c1059e6ee659de164d2f52a78c31364ae9badedba237ee8f84255705909bf520653973493924d598636ca89b7d541ace420ac4340d29cb4273b5d32de51b202c11bbdfd327f9a4938bc9b528780e9d55db14a4a49e25ec67851ae908c03a3bd6b5688b8fa80584971ea4a7a810101f0ce15609319ff637b638a57102b07336582f42861c05dc94f32398d0f89255e4934442f0b0d3c585f1bcfa512c1a2ca556fa3932883d32a3466836b393df44648d81374833f534e1484d779d14bf87ed0d5db60c426075474f0083cf5bc37395e28ff991b22ae5fd5d557ac7012d5c433edcda19b749861ab7931deb37a046bed34d32fe9065ae09682c5eb61b3efda55bccbfd7d25cfd3b80db5d69a5850670275b5818bc737a193fb3a9e9024760eb652d70eb3ab5f712a92b44265d57d8a4854ef9e55088ccf335e2f9040428aff91d34912db111388e6a3cbf301ae316363a9d9a2e36a64612c033367b244ca9c7ac21d13e47c2d883d23d803c470c038c682f10fe2405c9ea557de22c1ca92fffb3b0ea9411886a7338b51a183050fe97622a3e650248d0c228b4f98022f12daca4b4314980b9880fba7633fcb15be0a6394965e1945c7e8a3a99e80301d83ec98c932bb90daceee9387ef62cdb9da04cfc4e6501a4aca08b9f39ec0b2160ae2c2d8a07f07b3ccd792ca5f40903123fe6d299eab5377a3b6f5bd7eae3034d29284aeadeb4ff78da1cb8f349857059381a613324e45fe33951e1732ff126323082eb785850c626c60cc5b8a4384612b7ac0debda63779869af4a7ac9c32a23878fccefd2c5b944b923e7682a78bd970bf2b7bab3094a70a4d3da19cb2526bd654cd10fd2a0423c761fbfa0da080b547cff8d763bf7d8fcb811dfcd9b622bb3dfccab710ea0721519857102a66d31a900fa9f40ec5c793ccc33d0c8c33e2bf6362c665d695c88870fb36a87fefa6d52c1809a79d76a7ec90080bb4d4c1f0733bc18a85d5e6b67912ec5ee87af74e5ea0a42e68560046e956cd9ff9c0d672441ff72085faac7df73a19408fca81b68ef4674bccb2054c23db7fc123f901d2f7bbcc34a46b06efe0ceaa8865be8bc091ba28ac27bc165fc8ae8aa8e1844d8295fd0e24c586724197a6bba19537e6f616b2a7d77e67305fc9c634e999432eb25badd33c6863de00c63d0dc0def6e4849fd6e2b2df0014d4ab355e239870fbe2ecaeede9abfcfb7e314923aa3fb127698a3bb028b51c3645a52e464b81584d7169a2a83bf3e5133d06e1aaa879506964625e29c2f4cf0c78055a93e2091c3b415cdef36f794c8c1f7f9cfa9ad1c62880b767df5c07a7b54930fb6428048d48e25e662a0332ab1e6f0aecce9f6c4f1f3270edbe606a45bef508beefe9db7a2871fb91f1ef3fe9290f58143b81b21140d2ee9c155792cef559d8d0ab6556550cf01e96f289c21331f28096710f92057003b543b0ed7c34a31e6dd33ef8ed2bee102decee0c87f67b0f3d5c2b8451094bc0457042ebd95c506001787750e9d061e2b1e350ccf2a89b329d57c4780b006e297469b359729a8344336eb1b27ff1785247c5ae080cd0cc5b8f404959249a5a94c72f907ff7470f1b96d4b28f216b4302a264bf6671a6c6240847a9bf0f209d637902371d9bb702cf1ab61b2256522791990cfe77ee80f96f336cb9af05e9f13454108f9fa8a315c1753fffe47a7e46014c2168608d6c63e70112a3813559687fd6f986892a5391c35f2bc99a7d782db10ffaf1385dc8d8eea02e82f2259b27e18fe0f03d457272d25d0f4bed62cdd4b30067152881fa2c91394d7fd5577156ae826cdf3ff1080f8758776c605264bb10115e845d4735696d3ea96e14bae7a5c6ad95ad97ebd93bde67a62b6964963ff2ccbbe458f8bf252f10c3d39f820f0cfcdebb167d253cae57d42362eb6000e221e5ee7d0a4f1552fd4862e88e6de342fdbcac2e15f67543bb1d87124e01ecfc7195474dacbe1fe031a33f2fdeeb86639ec42fb42f0577c718686343e5e3a67b403e7c957eac1ea723e6843beaaea32b798c22c62858ba97cd71fca644b8ee5481d643fafa4911cfe3606bd36ddbcff8aa625615cf55045efe09c720b75b8da002a4a1edf1d2f1cd31f5b10df8f0511c3b10f55be14c31c6ca298129ce7a9cd3d1a741f98c2682ec2d45caf2074d6a156995405d03e56ea5e8b54b7deffc2ddeb0de075bfea7001090c584a2d3548d838ea3659e2197723f2a3b5bc15acf9c5f82d78d0ebbe7d05ce5d403609ef9b9c808ddb5afe59950074bf327d2a6e06e65a0ec4288f5d286b80e3c55f32d20f5367bf41fcecc92de57b76cb5ec4eef3ca312289f837e4918216a39f411f879a5d625a8934490d1d518ed96dbe5f1350e73d0fbbb31f50a74b73398ecc1ffe2569e09b39b5faea93850e3fb1d7ba62c4bb960902f1fc2ea763b223c0a2fba633657b9367a044b7fe5aff25a830886db7271d02402c90f0131b822bdd895731ed2ebcb41cacd436136e9733e5c2092a4712231bb7b467810ddbea4671a8bcbb9314b24f3a6f825f36f826320c723f1737e8ab2377dcdc1c018e8e128df26a1bfce1c72cd6a1366b28d2819da0fcae532c09771f82ce33a2548712e66fc60cec5772d302e69d1f2df6d60fe2a6383a98c44a3f2dd94ae12729dd3c3f4a7d5e64f9b934c639cc0a7ec642c135b983ad2adc336f14d9b20808c00bb40549a9e544eebd53d7949c990f9b0828e7de51b758a04f7d03001bdeee20777af07151ad8656d122694b9dd0e1bee7f3b2a3244056b5454a1898af35794759223c9347bc9f78bf8fe4b94e5977bc2ff5fa80a37def24da5b093ea1e7414bef1e418adbe7622ae9a81c0f40eeb94a6f06b7c7139530ce622015a8d0b35cc4a77ff97038e85382ea32409c3d7722cb104c9991609e6aa7f28c078cb0f8f8451b679a04431d0a7b35eb9e249acf659f02f115bdbfc3d97c162a1618ffe3eeccdce29bfd365c50ef925a9cdb6792273f2c5349d9e690e61feb170a7a8d828ef5e26703904ed3678a2e996e1fed6a094e8bb418bfa7c7166d43720f6dcdaebd42d290c2aa070762cf3667fef41235bfbce8c70d8bedd7c1749bee024f7f33bbc47cd9b7db07f4a3b45857582d77ea71acd4c604df900612be43fd1cfa3840cfaf1b0a9270b553a56d3c9bbb518bfb8dddced9a04787181d3212cd0b274d4f697ec304ce3a070d882713c71e078b8a71062b6ae5edc90827b1ada00532887071825f085481624d66b338c735e1afa78795d04bfa439b3d4f93fd4026ab28108d0d8ff1297721ae41514d3fa3b272b088e33a4c8878e6efcfb7a6ce1f80ebcf65a5eff98e95749c4f70b1968a96d8e057bdf3f1e60cd5c1830756b62daa2ccdf58c5f0a2f8534824bcb2463b0cb5709e2be340037a8313d9f09365c1bb52455c0389ed9b2052cb1d78d2fc5ef7236f2fd35ee9a91d592efe14b8f783021f01328fc18ece366589934704f227d8a7c7c282d084daa41d35ecd3aa8ec2e4673e29869e6e297522e4fdfb4904506935d533eb42a7ddbd49e6a0c816eb42eebcbe73dbea6b5930b0efe546834e89f1d6c63c64b3c28a530234483423964253045cb001a298bb6007785aa0a0ba3f86bc92495ee7977a0583db41178d9b607226c4552986cc353d78325112c844cbc184103b89d48474e07eb2da807e6701d05c6142154dca876d4aa16ef524cd435221e25e070eab4ec524fb11441c9a62e70c84621711975ef9e18e1707aaf27dcba0c7627c71a92d0776c3c4eccc0d41fcf98f7c2bfac75d69cce01d058be3f58e4a51249629d7eaa149dd69e68ea8f2b193e1e178af41ad154844c0ca3d543030ad385960e8fc7cb64f8a06625d0eb2d6a1b4cf1d13f5f3b6b5de9e0748df23d8d80245a89873515a5715896c9d8481dcf53d63a2fe893f3814de873b577a29c47baa36033c2df2518748e803a427622121f16170a7c5ab7c468564630def77f88bf5079ab89579a3666172e36a59e184a68538aa4a428345540f2e3e104574db2e5ac6e969adcf560474d7ab9042125d0a02aac77af0fd65cad3ac912515008fe3a5365340d5d1323fea34560319b2ca0a7d2cc4a4f1bb3a273e6493a8afc68d118497a0c9090bfe7832e914bb44f29bc63026dbeda84673be1dc2493df4fafb316fbd4bcbe872c12e258141f45a224a7aa37f1623202127a443b242df30be8c9e51cfa58981c108ba0d5e175749e0bb01a825c77a26345ae07c881f54f0cd312e69d84c47a6e35171d511480c7a623c0686555c3d16f732f51a6bb8310683af2a1b89c8de3f7ad7839a3299ea5c91fbbd780b436ad5822f8bb61a3cc9091e59bc458b37010ac2c26024cc52cb5ca2cda90b76ae1e0815d194c3f61a51a21edd361e236ddc58067c5ef28abce834c20b3b7bbc718400cf3f0f8641d0ff9f4790e08958bdb07e6f8c8f5ce0a9fe5fc10ab65eb491b589e3e3d5db8ee8ad35b24e796ed08d3c019493ce5cb8b9558190ddd4bce04d23ebad8d2b7e32f5ee142ac3be219e9c5d9c1af4cbf6096fbb01d01949b1a870272a624332f0c02ff857ea20aa761cd723ce6d6831b85df78f6fa0573a41def76f0cea5dfac64a6153d3d828207573f1f848a94f3124d814054c81da77050c122cb8320403cfd319ee805654250e69233929733053d984ef80ec02c39b2e8a227a81cd36cd62cc79efd8d82009b634d44a367be48652fe18e4dfb1cadf878d4a6e0055105ca2dc38b58e21ca07b8a2dfc857134d539d8ebfd8cc92d15ddd4e24f6456754f6ecdb00e85db62cc0742ed00409ef49aea1d5cfe539e0dde1bc03e991fb8c93fb96ebb190a4cef5b1a7b87f8895e37a200a5ecea805029f66fe3f696c6fc2ef1b60a377f7b3da9dc4ae8f786453548ed49867b43df3f080b10827db91f6bb2069912f0b907fdd194a1dcf76b1c1bd51227839df832b015eb7d8a71b5caf4b9dd13c61499c50df6800f788e09445da160fe68a52debf813950fe7b976dd58e77215cf615f1eb35b8445b821c6c318e8d194a132607d181a125a777def0dadd03854c88a4c3eb870c734e288d60844cb23cd906a658f6f2fdca70eead38cc483aefa8dfa409e7450b29a4f7c998dfb39be9a46848bb9410e26911139b211ef86278eea2f6af7ed6b9a502355c920b4cea607fd9f5227751e127df19b5636726b7673f28cd8475fb9d658e87d6193d27c1f1bac151d955806b940988d597cdda152be63e702af40ff2afac18ccb71365781ec8dcc84376b16bfdb6946840650156b02c0c99120db71b53828b582c36ec2ca96cd34f522df17f6e776b5fe1368982546833cfc95969f656a26ded12437c9fd0bf89ae540c216bb0cae2ef7f97b46db72a93eeb11930c955444611cc15876b1ea0f5e8fe6bf2b05b3fc0f2a6b93b7543e53dcb1c09156477f48f2ce61b2a0b6c24c2b86185b1cfce2c00966f876a7ad0d9d33cbf494c5c469bbe59f3a7bfc3f1ff57484091f0dbd377667ee30adc93888599dd36efd7943e63de39fca03441ceea9c6995fce1822808da97a302d5fe9b87bc89da33c2db970ca7efadce17d24a714ebdcf3bb27839ffb318141eca7f013af5f673715018f1bdeb04b71529f0ea46e702b24d32cd5d0e7e717439e1bea535901c535fedcb68e035a9bd934a2e3aa42effedd600d038c00c434af813d7ae3e81e1054ad8ebd3056aa885058101bb548c83f23b929ca029d14363e8b937de5c1689f723eca79f986dce6110a83a853c028bbf616103e4122f8c15d594fb8ffd2ec83b0d0ebf76136a1a2dfb25df6b2031961872319a4d909bb8b41a1ddf11a19175e1065244b8c439765de3420842fe0a26f693617ee1ff0add77c43a374a8e8ccc5986db941722c754816c44f686bfeebfa05a61835b59331aa8f8746ce1e597e567a86dda92dd37fb069e4c7f651c8e5eaff2526fc6b1af5d3f08ea03aa5ed0511600538de7f23da11bde04d9d4e861960a17321a3d8d7a2a6125e5d1d896c00c7c502f4ea433134599c1d0ec465b276c17a8902880131a292ecccf38beaf20b8d363589adee688b040b08812966c062854f061cc0a3111de4da97d2a95b6e0697a34af3b961c1468ea331e91e848b044b35522608c3eba0fed478ed7ad206cb0096971ff1d323564891e9776529aa1cddaa77126e4417de32dabe06141cfbbfa3921f613baedea2c163cdf6fa6612e8bbf36b29b6e6045f8ef8c9626754ecdd71d692237bf421469a7d35a5c766a2798a618d157ce05f74ec0ff68a292f6ec068ab05a1cb582a3494c750d5234d23474050c202b70d20b30a587bb023bdfdcbd03a85668cf85621429913770cd4a2213730e31d4cf90d501fd21243616a43830015378128eeead4d80d94aed7532994885afd0a67b8f015363abc354bbcc64c0c6cf38d0dfbe730ef61cbe8f721059287603406bb909455949a17212218a2054576e347bfbe41bde4abefd659c6681f8ee01e1c7b1917f5778c1b4a05867f5d7d3ffec2d545cf9d450b9631370bb8188ee95b151209d415f6f186c816516cb4d81f3e10e6ca17a8988775fba24b9c41c517b822e93b2f3631ee916d9cf099532ed9aae35734dc0e932e76f8cfb464fd21fc030b0a0bc9e8e967c73313f1ec276e26c178c0565863cd438684389ce6086161222b9b7d0944205b642e83aabaf88fab2027beb3223ceaf76cbe5f5a9d0367f7842582feda0d1dd7e4d9083fef75c35b505dfb1cd735a59921937fbe06e0032bba0078567034645c741772689758a3fe57ab5f78df30de943007a5a68791e2c4912a53f642121e984b3609a1536ff50352968c434ab8e94124f48e4ec5f56976af2212992b9406027a5783ea73c4003554f01dcf845efb0523a54e9ebb3436e6bf12ec81a92c3a60cfe4ae3ec4372b99123f0032bc39e5938fe1fd10f0bacaac9908374a6a5a7a7772b97dfe3ed854883a0ab3d8363d3879e6caef86f67ca16d87065be426730ae06ad1ce3a8b53c7fd2ccbb7ba4714f2eebcfa7f094822713ed52b684c8e80a6bf90d4a06e9f984df68a607e6e73aed098d19528ee0e2a2cdb3e08dbfbd5e8f4be8d58ab13541f43af3c44df16dae420ffb2c31eb88bf6a69010251956d0d6c04b50d14da8393fee7cc9bab7a83d195954f63ac9ba8dd23a76ba085d7ca28d17aabc1eaf183b2d29cd7037707137b3081c1f88f0c3dbe027cd3b24361b9b42e2d74e3d7ddc0deffae8284572e2d701f5b858556064cf6990534d103e4cac6729dd067f8b8e129fae2d48b1459535ed3af0cbabfef2f6437687601dc24cb6f3afec32975f0edbe7457a4eb601fd9b31f1884cfd71c63cf85428af098d92974449b398dbd3abd6ef1417000cbc96487d1c86d8e308fbb58c355b1a20b47390a257cc8cf26356f3dddcc3f86374f847b6f2fa92a2aabbd2933f555a2aaaf1aac262e2177dac30d537766e89511503a4c66e18767d424f7420820b3f037682fc0d1e17f264b37bd1675f616a13a96ba71e9fae85e335f9719f30631f2904e6448b9c0681de5893e8b8b707bc13eaef7a5987c4a978d9655a2148088117eed85fe8955714ae95e32d3f576ca0b488f24ded321a7fcbec2655bee6e67b0f76e8ed228785e68fde668b12506905f02378f933b203618faacb3a6d5bd1f8013f76cc464379353ec9eed3e754c2e2b6f8b21b8cfe7ecae33986653e464bcb3052be548815bf0b73d1613ad822847cc61e3e3a629855fa5f6cc67ef44898782ae2188052f05e0985bbe24ac528b506c6ae308c092b450c6d5e124dd3a4f73a2ff54a2cc7d3a9fcd6517d5455ac8307346c2747b6862428b29773042c3430a023e2176fe58e6abab972ee2fd51cf4f1d12341b393857d864462572cbe892c822ed55ef37abe0d55b5e094bba8be9bc15707d75f62f9d4d35dbcadbdf7f178472f458924487e86627522f2bcf9d9a432e6c481bae82ecdb4b11385df0e8e2bc92c39c8d59d441dc289dd6ae1f414f2a4daf9802fd44e962bf8ae29d8c7731edd1a44fb6aaaffd4daeed2abd97eb0a2154a93eeb0b3001f6ade26c3e2fd4dfb3616ed049cc776e5b93b9b0ea9cb2b4b2d98dcadb63526b00b9b465e3cf607c9eb0a508904be5c33fdc141dcded6cb8e15a9f5f9cf787336c199ad2e12c7077015218472e9b6221101ccc760cfce6239ab08a594d22ab0d8fc0340265f41fef1730b1c59c995735a75140606f2e7f0ba722567f2ba53750fea1915673f4a41bda11425d213acb84ab066795955d083151485c18615e9ec1423d8d1426752cd2d4b011ea1c41aef1f7911b2826210eb63440ddbfc404125d1295f0229489e40beb72cdf305854142ca6b985f3a6a3add75c316476adb6c49077151b92014886d047167c0b2cd68a15fa851bba38a3d2096a6370ec1be612914c42bb75d9a9531a3d0490829f224f9e23e2a5918b4c093d650da9e00c26761238908e65a07748d0a4239d5782c3b55f78591ec52d5265b2b3690668d8f8daf85e245aec06df52d5bb02ea4a1fc1724b83a2e5e10bb61c0f9f7e45392914c03a851206291cdde2421a0d67d99a279504a25fc2456fc513814853f38f3acf4a3de2f8ced7b974c3cafe1bafa3e5db4239ef4ab0887a397d1ac7d4089042aa0da14dbf69ab63cd8be3402dbde015c3accfc04388f54670271fc8a0abf607f694ab3fe308f1bce3a74c48050118178b3c952fdf0d3c32227b81377efffb94759da81ea4259dc4590fa1a30dfd1246bc14b754402ef8584da0f02073350efe9ac906ed8c9416a8e41c7e7a25573c26cfbae07a1484fdb072b7b9bb4b8f088338f24a15a056e828f3ca898f1cfadcf0bb38844a57ccf35bd832ea21d41b119d1c974a852484982820ba37d11bc6768972da0d4e5bb6da275417d1a4742899e2d5b9b258eb26399df9578700121148abd9c18a123399dc0dfc8a5c7e0d2a265e9a5346d8ce7df300d80252bb01ebdb1a01f3c18c183669c153a04a8d8679f500bc95fdbd6a556ba14d57a641234833b1b855ff632c6d7ebef1260aa2b0c5fa9443f5a0334f3ef1f98c619121216d3755343ede9097165dc12e15e32b140d52a0a4c17e9ba55ce8ec95f9e78b0e093afce59357457d7d34f90d5f7cbbbd2fdd5a12d718cf15675e49997f19ff1b238e407482be973e027a84cfd5095656887765ae6d9bcd619b959bff2d5dad1f7dcc2545e68ed7c4b3f380e8a534370c2e7346593f4c06f40d775005c23af704294a3cfec6b973d867d7853d943d1bbcf7b15649bdea6d1325260216cb91e017785fe8b1257580e4d82d6d09f83482322b3b70ab57c4fa8b4e1a919551cb250031084b29a0eadcfc494129f0e8670d12c9b27274e1500e1e76429bf5b424a619c8a4958459024e4859bdd69f96e07c02109ca93e63679440047e92e4e0161615e9d1332bc06b18d08d4526646b4e8cb5229325d75170396cb4c50cad3a6ab92aa9834dd538c528fdadac1ae6617bcc2d53cc6ea78762e325c68d58b6faebe22d949f507a1a9c9a379a3b7d553107f143ec98abeabfb16cbe6cb5f6cd7a039e2d9c547336699d6ca653b22e61dcbdf713b9b53020ed4a6da8dfee3ffef5f8b227b79ff0084ba475413a7dbece24fbe30aa85d9d2c916f14f6a8b4d0fa49c811155d77e55db88a21d46d18b38cfcf1d323901f4e449f8f5b7059ba53f0f8346d0ff2936114e8a530772045928793ab3b3fdaae3449a28e780f9c799c7bb26ab906a151f404a7022275bcd128e81f411a2363e07907c90d10a7b15186094860a420bb4122ddad2a55a2cf34ad69b2c28deb69db0a709a4d8242f248c79b648d0c1744c73fb0eb16b73e2697bd97f3989b7bc7796d5093b4e3fb68be145facd3c626fa4f14c54443a0094e97239c2b75bfdca5eefd2f596a75fd3db9a675f85afa2b9a3f81ac84d3afc834d4e59a0075c3df4d40d7935da3e8106a4c4e787f780c3014fdd09658ed6e107d656b858a79adfb1f89df218ba81b120ca2f8669d03ee008f365965325696051878d50c58ace4409d323d3bbb301fb846e51cb75de55c067dac000325021ea22bcb0ed5470977dca93f2f9e3d585f4c9fba53473123d61ff90243ee6925c8b8395c8174bdea515993c0be76a5c46c08e2bc465626f65a2e8c994229c40247ff05a3b9cf78c6c58663049b9f0151552d242cb998e76f0c10a7f482e6bd655d0694774852037f677163d095ccdfe90194df386bec988a0b057af032793f01b40dbe68ffb4c535233b12d7221a002d9cbf11ea23e4859540214b88576722c5f3b42b6e3e02c5005a75324cdf17ba37abe02335e35fa7725b1303fd3f4450a701b56f1938e2b1f467bdec6bed4295c9cc27ec9c58b10e3531162e00eb08d52bcc7c69f52645cecb2521e6ceebaeaf700f93d5785688a59f1e26556ede9f2af979effb30fdce03a9f4b005abe5570263acc1548f61634a97c91e66e5217cb5914c227efe1b94644fcf249048fce02a2d6cb547177987305c9d113159dd34770e5737eee4d47259f4b4f320d521dcff218e6dac7f31dcbc9e7927745d31c8ebe73ed8db274f3fbe894d97bf69b2d83bcf051f7494074e9dad7300665b8d469d4c14a10c996e4b46d2b4e42948d78910ab4d108b2d4bae9787800990cc67f5a027ada3e2a9158289fe3cf9a45e75bd97966806c45542350ab9ef124185f4aa972d51cdc7c0fbcf9e28d0ddbc34bef1457dc10084dcfee9ce59dd07ad285735f5f80dc502b3a58eafca9b7528bf7b3c7205806efdbb632fa410d12266e6cb1403986ac4d08d3ee6fe0070b03f87808ded440c9ef2f7d58af172c1", + "public_inputs_hex": "0x1a207628cc6936816ccb62a7b56fdbbf8e975293b677c988644e018fc402e44107940cf3c3a18e9c2b8af0fc91a18c91a709c00a8093bbe606a2e9fd472457bc000000000000000000000000000000005874be0dda5bf3cee7d33e2ac260833700000000000000000000000000000000c484d632fca06937651e18db1cebd2a60b3f37898c93078120c11921f007446ceef9867e6da4e341fb3bf8991edcbd630000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000214b346a1e0b88b78ee55229a563175a39a591790754460f52f2c62ba9209ec682c52b19c6d060045e45222e0d8e0b98f4ed39d1828106df7922a57e9dfb4e3612c171bec038f3c507bc03153950b824f23b8c9bee914c66ffffd81476e3d8274248698204cea2dcbfb2a3f50cad9df0ee2be785bc9d51b32240ff14a38e634700000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + } + }, + "test_exit_code": { + "crisp": 0, + "folded_export": 0, + "enclave_contracts": 0 + } +} diff --git a/circuits/benchmarks/results_secure_agg_micro/integration_summary.json b/circuits/benchmarks/results_secure_agg_micro/integration_summary.json new file mode 100644 index 0000000000..1a5bd79e83 --- /dev/null +++ b/circuits/benchmarks/results_secure_agg_micro/integration_summary.json @@ -0,0 +1,244 @@ +{ + "integration_test": "test_trbfv_actor", + "benchmark_config": { + "mode": "secure", + "bfv_preset_subdir": "secure-8192", + "bfv_preset": "SecureThreshold8192", + "lambda": 60, + "proof_aggregation_enabled": true, + "multithread_concurrent_jobs": 13, + "committee_h": 3, + "committee_n": 3, + "committee_t": 1, + "nodes_spawned": 20, + "network_model": "in_process_bus", + "testmode_harness": true + }, + "proof_aggregation_enabled": true, + "dkg_fold_attestation_verifier": "0x7969c5eD335650692Bc04293B07F5BF2e7A673C0", + "multithread": { + "rayon_threads": 13, + "max_simultaneous_rayon_tasks": 13, + "cores_available": 14 + }, + "operation_timings": [ + { + "name": "CalculateDecryptionKey", + "avg_seconds": 0.041132764, + "runs": 3, + "total_seconds": 0.123398292 + }, + { + "name": "CalculateDecryptionShare", + "avg_seconds": 0.156390416, + "runs": 3, + "total_seconds": 0.46917125 + }, + { + "name": "CalculateThresholdDecryption", + "avg_seconds": 0.238677542, + "runs": 1, + "total_seconds": 0.238677542 + }, + { + "name": "GenEsiSss", + "avg_seconds": 0.060112764, + "runs": 3, + "total_seconds": 0.180338292 + }, + { + "name": "GenPkShareAndSkSss", + "avg_seconds": 0.092604958, + "runs": 3, + "total_seconds": 0.277814875 + }, + { + "name": "NodeDkgFold/c2ab_fold", + "avg_seconds": 7.479159527, + "runs": 3, + "total_seconds": 22.437478582 + }, + { + "name": "NodeDkgFold/c3a_fold", + "avg_seconds": 59.442402111, + "runs": 3, + "total_seconds": 178.327206334 + }, + { + "name": "NodeDkgFold/c3ab_fold", + "avg_seconds": 6.878937805, + "runs": 3, + "total_seconds": 20.636813417 + }, + { + "name": "NodeDkgFold/c3b_fold", + "avg_seconds": 52.507483708, + "runs": 3, + "total_seconds": 157.522451126 + }, + { + "name": "NodeDkgFold/c4ab_fold", + "avg_seconds": 8.781505236, + "runs": 3, + "total_seconds": 26.344515709 + }, + { + "name": "NodeDkgFold/node_fold", + "avg_seconds": 15.673083958, + "runs": 3, + "total_seconds": 47.019251875 + }, + { + "name": "ZkDecryptedSharesAggregation", + "avg_seconds": 2.76144725, + "runs": 1, + "total_seconds": 2.76144725 + }, + { + "name": "ZkDecryptionAggregation", + "avg_seconds": 48.1789355, + "runs": 1, + "total_seconds": 48.1789355 + }, + { + "name": "ZkDkgAggregation", + "avg_seconds": 20.013341666, + "runs": 1, + "total_seconds": 20.013341666 + }, + { + "name": "ZkDkgShareDecryption", + "avg_seconds": 28.810868159, + "runs": 6, + "total_seconds": 172.865208958 + }, + { + "name": "ZkNodeDkgFold", + "avg_seconds": 150.765525, + "runs": 3, + "total_seconds": 452.296575 + }, + { + "name": "ZkPkAggregation", + "avg_seconds": 25.608851458, + "runs": 1, + "total_seconds": 25.608851458 + }, + { + "name": "ZkPkBfv", + "avg_seconds": 3.605216528, + "runs": 3, + "total_seconds": 10.815649584 + }, + { + "name": "ZkPkGeneration", + "avg_seconds": 108.799082041, + "runs": 3, + "total_seconds": 326.397246124 + }, + { + "name": "ZkShareComputation", + "avg_seconds": 75.595901146, + "runs": 6, + "total_seconds": 453.575406876 + }, + { + "name": "ZkShareEncryption", + "avg_seconds": 124.987066109, + "runs": 36, + "total_seconds": 4499.534379957 + }, + { + "name": "ZkThresholdShareDecryption", + "avg_seconds": 98.947407777, + "runs": 3, + "total_seconds": 296.842223333 + }, + { + "name": "ZkVerifyShareDecryptionProofs", + "avg_seconds": 0.120913319, + "runs": 3, + "total_seconds": 0.362739958 + }, + { + "name": "ZkVerifyShareProofs", + "avg_seconds": 0.353542567, + "runs": 5, + "total_seconds": 1.767712835 + } + ], + "operation_timings_total_seconds": 6764.596835793, + "operation_timings_metric": "tracked_job_wall", + "phase_timings": [ + { + "label": "Starting trbfv actor test", + "seconds": 0e-9, + "metric": "wall_clock" + }, + { + "label": "Setup completed", + "seconds": 3.001494625, + "metric": "wall_clock" + }, + { + "label": "Committee Setup Completed", + "seconds": 20.095969166, + "metric": "wall_clock" + }, + { + "label": "Committee Finalization Complete", + "seconds": 0.001439291, + "metric": "wall_clock" + }, + { + "label": "Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall)", + "seconds": 166.661482, + "metric": "wall_clock" + }, + { + "label": "ThresholdShares -> PublicKeyAggregated", + "seconds": 646.101478541, + "metric": "wall_clock" + }, + { + "label": "E3Request -> PublicKeyAggregated", + "seconds": 646.660075833, + "metric": "wall_clock" + }, + { + "label": "Application CT Gen", + "seconds": 0.320969583, + "metric": "wall_clock" + }, + { + "label": "Running FHE Application", + "seconds": 0.000853875, + "metric": "wall_clock" + }, + { + "label": "Aggregator P4: Aggregation pending -> PlaintextAggregated (wall)", + "seconds": 51.080123, + "metric": "wall_clock" + }, + { + "label": "Ciphertext published -> PlaintextAggregated", + "seconds": 152.638885459, + "metric": "wall_clock" + }, + { + "label": "Entire Test", + "seconds": 822.722301083, + "metric": "wall_clock" + } + ], + "folded_artifacts": { + "dkg_aggregator": { + "proof_hex": "0x0000000000000000000000000000000000000000000000079c889e8dce73661c00000000000000000000000000000000000000000000000e3e83da1b8676afce000000000000000000000000000000000000000000000008da4b92b18c5e81c10000000000000000000000000000000000000000000000000002514e27f7c4e000000000000000000000000000000000000000000000000db01f6e05c6e1a20a000000000000000000000000000000000000000000000002059c7f08ca9e35b500000000000000000000000000000000000000000000000f8f38e4c226c82f3900000000000000000000000000000000000000000000000000004edb478b855c0000000000000000000000000000000000000000000000003c8d103c4d61a3ad0000000000000000000000000000000000000000000000096cbc9847f8fedff70000000000000000000000000000000000000000000000058eded07624268fed00000000000000000000000000000000000000000000000000003c50daa2a25200000000000000000000000000000000000000000000000c985a54e92c3faaf400000000000000000000000000000000000000000000000044ddcdfa0c734c240000000000000000000000000000000000000000000000063a829d40e439f4870000000000000000000000000000000000000000000000000001cdeb374021c91075909caaf6e009b1ca605a4a31ee30bd9da5f9fca6bb3c54923dff85b2b73b0da22039330fb83d3ea29540b29236c60275b27f8d38ebd7fd93397415121a5010cdd787b6473185051c384f0bc18f17c0db6d9dbed6ea91fe0f5fb1f88e81041c5b1307f3b0e37a7215174c8d5cd16f4cb921a36d29d1bfff26e5bb60b9fcc722868f4eeed0d3e728ae7f6f885c8c17fc51d831ed61d4802d86d3bf6af968c311e6f78f72e07c4d0626a845fa37caf84393e0371921fb89b035f314d6a62dc7108b0fee11fed570546aaecf737d9d119ef047f9125d6930f9e713ca31012b71212eab1d9a27e6f2b8aa8ceee7041a03dbc98c197992dbd0bc88ea98e655f1e6285a0be8dc30ef740b380b73b6d9f09213aad88a4508208b18027cdbc5cddb23024d349cbce7e706f58660bd43cea5e72df06f8acfef5becf169f95b2600ce6b1f62a04a0f35879d2b8eda6bfba70d2a3df57baca8ab3b9767b9338e141b8ca02e92efd940bd0a1d35f6d71b0a1b6656c65231f848ade4c443efe8513452b5f22f0b4bba7977b55581bdefd9a88858e9431f805ad1f4351a86a4beebb493a9e114e6572cfcf9043261bcf7fb9e8db94ffe96c6625652b24861d5d36682d19ca70f2caf423cbb01eec4cd0439fae159c344c1993fbe7c88d73d83aa0a325dbf990a6f8ad176a86a372f086adf49142b8aab388a972e1b84507420e8947719671904e9cab98d8abc1db7b0568c110f250bc86bf64f73a906bcc972de1a5becef0120d1e656c81a2eb92d57eec612b0bce8688d7d239e7727a414975da9afd7867d20125debacdb9a1994ec4b00980c24f9dd6e8f21be2b16af45b28bde6faa56462edc8621dd4cbe543a444dc6728bb6f502c23066060ab2f6a38ddcc3eea7ec2b27425afcbe4fe9889b44985351dfba0a5f3391efb2528de4f2927d6860820cc623cdfc3f85491f07714761976da2064e0fe4df37f22847fc2bec5f9e1b09f1b613aef22e979dddf204a28937b340c80296244544205cb00bf8d99a7d22258177137e1c2a7e14e72311a2b9dc91b383d366349851c0511881d2c9f2568666456500ed26b066f1471281ebb1c166d06a20c32f7fac5330d0cd51dfb87f0ebcc38e15f07e98b45174b609a893e3a82a7cba63ce2f3beaa994d9cb70afb9e09a9d432ed9236ad92a89cc114bc80ea494f084922a0518f20b63e0070569b5dfe95c751934567548e6c0c01719777cd116533583295cc739c18cbcf7a7702126c051e60659ef8dfe218724d29d7b42a4b8529a5400da1bfc66aee9ace80bd7f3a5c5f92222e9e71f29cedb38847fc1c64e2dd4c44c51e20c3dea712197866d63e1b5142ff7c91ccb1f35f7b45e5c981f29396f45562c73408ac4ae1cf460f1ff8100062e3784170798fc88e58c6f5882b024a7cf37d4300da0148ccaa124820a3612530f8cd772d3eee0d1eff58c0eb0ad9e72c8e4df9dd1f91bc8faae1ae20b4a68d60803f9e26db6b80430e21adc709e1c11fafb473d6dfc52d5d7bb95d040825a1f0ba8e03aec6a23034d2760520c8fe56e4dd91ae8e1bfc9ea78f9633191abd3360a5de96c27f9c9b444ad97d607254741a6792993ebc023ed1a5e67ae40ee868c2e73ae3764ce5f2df9696a19b1885d128296a609e9fde9e3aa575608280da0990ae803a70c1450a1e6a037cec85dc3d866081c68542df69e737aff2fc3689f8722e6001ebf6f0e127b2f55dc50ea3a07a917132e40de45c2f6599b5457945e34073f7e2b901fb12979381dcdf400f220a8278da513ecc193f8e3f2908ee0c3772e18d7e734f0999d7485396867fa7126f469221809353431e16f42403f2279bc08c098433d8d0ac992d3d2ac61c09e06c926aade8ac753c3830d2ccf964ac14212fa1d3031bc519e5f297b26845f7098905f6d8218b802b87f89c89dfb9d147814b19433f552caa4cca8e1a6bc89d22b9f90cdaf93f99f936a2be9352e55ab052667434c7a809ce77a2ec68f8e193e56d30449a294c46de96cc4d801c07c7a0f2075fd36b3def98f284075c4942401d120af5e05de639155a274f7340285ac852f8caf721a758386ebdfd5b19527420d1dac567b6446a1f5e2ebcffb09edbb530ea035f1af0259a0b9de2f368fadf267b244ee882881d59374129a86bfa78cd0223995ac07428bef30fd7844b30d84b392c73f6db308779a9ed95df0eab87a1d26ca04e3acc28a8365a01eb4a9e3cb721972bc98da4a1889e8d08d22f97b97b5173b44760b6486c5379a45d87d7c9d2dcfbced4fefb2e15feb703aa4525a39571fcc09ed0c4116972053f96e230c0f7e387b59e0359b43c1bfcc030578ba32342b5f9d96dbf73d07ca3197a73ee0c6109d3b1105ddffdd98a06eab7cce6197830e9006e3c05c989f9b931d5bbb1855106c6cd41ed44a46fa86e4d2277db75694071e795681fc6acbf2f497cb009cffccf37ce8f931115945ed139d8c9fa0db791373ddc8bced6e0bfee86023f8a7b5726715ccf4153fb9c65ed586f61e3cdd652a8972f01cb4b2860cd3666720f1d92d0c83277720ca3ba207b9ec440016a6300c0f76d9e2afde29f10270972f61253985284111d485e4dd513c393da16a42181e7b6fdec0e06c4d40b738d745013555e41e0d2401f498060d76b43080e32f9512672cace135bfb75a267ac01431638e6e4defc612ccee63dd51d7bf2a1e3b522b5fca7370b1d0c077f5426f94a6b9e1b1c05693ca2a68d66f97305b65ac937714a93acdf0b49c13e36e2c5fb3c480d315c0858d23e663137564c93d25cb06bb0a70b5e557f72e1daaf66e09634975972586c64bb84b66679ace358a051679132b680710ff757d2603d2eb25e9657cc1cc71d0cfd474aa43976d7b10f80d81ff24c7a67662635826aab095ba54905650ef7de9f984a5f88547ac2bc72a49cb5f0c5b7961132b760040e56e1cec9386b18981243a0a569f5d83e06bbe5bfd71b4168901dceb5fabe6c719025d9199911c9dfe9993a8b6922ccfa50d5f159663171ac6ae03e74d70ff71eb20d74d352c6a8735e56ddc1c391286012837345f07eb28bca2233373568be9fc576341d839f91f62ab970cd492ceab5e14698870e6d02602b94b5b61a33de8f1ac810cb97758a926f087d2722eb800d603d0f6a81c5a028e3edc3492d338326572d83d3ba494dcf2fa7015e6b96ff8f9122991826c851652719a15471939cfc876e615ad2400e62aa973ec2410d1ee89a790c3915d252f969aecdabff87451f4e927cd25260287584bd9bf45b09a3fe4c343dd5bb22c1899fc3e54668eaba5151785efd270b359eb95f5e9f6d85e5d77a6a2de9b16150f50a233a6b8af910a2bb808f9bd029873098f8538552170cadca93fea41442f022712161b47d9f3c4b40bf8caf04bc3e22a2454a08e9ac8bae90ce964269aad050fb702010a48074e3b479022aef29e1f54073f9234523b5714f60d709c9330288039fd49622ba1c2a91fc881a2053f288f3c0ca0670ed624295336dd24022c2529d66eb05281e69f6da9495bf02ddf3fe8858d554569bf889de63c338ea12e0eb67a1bf8a11c8d4e607768411c49f00030d27869cb8806ed6bce28850cb56526cb309006b51d4690409b63134e48aa55bdf5e6f2a1f9343e70d95543ecb5ce13887499aec571fae66782e751ff2c287716d53d95273b56a0bfd8e9834562fb00edad9de5deacf497197b89d6fd75ad297c3de44dda8678e56d9882ad9aeeb9285c6a2f0d8a2ed6eacdd669a7e61c98c58c207a941952c88b917faed69ce6461fda1ec064a92df587e92bc0e1ced200b571065c8d5b996162c7931251e8c358210f4e8cfd451d2d04d4a789dd65c488b42e3c08235bf7d89f4c50156caa19cf056c2b87d3abc179f07d50c9fa84bcf0a802ad11b753d4390a084d2cfc7b310b0c77296b91ee2f8bdc475a6588e81d0143c4ca6521a56144280a54de9492d8041bf4f64269e3484a5cc5519f216d00b65d505ed149f6be72ebb6bcc4e978ab420d4411fcc7478c7438878cf2ea3e78b96f5a3e4880f92ce12cc3711882aaaf8104143dfd91a14f4aed89d1e6def69ca15e3ceadb3dbab590f924e56990135b33162aa9b99cb75aeb0df6e1f26a6d1d99bdb3c98efd1437a636854447c668a53311ac9de3a021fadf4eb3bc44b4647681af1211068236ce7c35d9a3295c7163040387dcef7af836cb87561bdc2339a6831d7343bc140c71dac8e86116e817e7401ac8d80c2b87087b8f6529112a1140d223577072af6106489b98e1234e53e16100840c44641c6189e726f6eb4fec56591b15ec35dcd61770dffbca22de00689619cf2dd0ee4a7ce2a70a66d88481953da7a0a1a8d8f96e7d776e3525f850d2521aba3fd333f96c4ba290582168b9ceec12a5bea6e54ab0a5964db5fce30c084b2c448db0ed04fc5690996c5e514e0deaedd6f420e916e437cf04ab3f8774422503cd74298a5f7b7bf599f4587fed07628cedae79178cb194aeb8a9d21ea1243002b0d65da6fe8d18eda0a1c0b6797daaf36d92a010c273d36d604d088bc4ad6b13426c8dc73686040efef1b8dbe635247a6215bed3ae07b9bf1a9bdd28da80622043a091a73c0a5a96d5e64815f5d6ef9b4fd678db61c80ebbeaff7735869a5b24ffcb0e232241a5e340c40bfa86ab7af4d10f651d4584ad026acef609e582e42f290a921dcb51d3ab26c370d1c63bb60c6e82f0a74eaadbf394a1812397fcb01ba6e0a13e7cda682a13aa4f15d79e8924fee9908bf15da6cfbe02a100dccb1a290bbcffcb477ea70d6f21d4d4c85ae454c57f3941fee61c7de90db8d9890b83170969198e22db4665380f332aaa1448ecbfc059bff94b1de169c43ef8b5086a151f94882c0ab8c74599eb324de8ab0f4d989b7b02dcaf0ebdfa39748b33b842279440c8b1bee7cda4a7fa9f28fa35b572b379d35d5a2bdad34849fb5d4722260b46b389c65f60f644b24b79bc6665ba2d87b9ba88a13f13ca8a3ad259b22b3c2c31e29dc3f8e5cb4f8225eed1141d03d28a491eeddd2536bf0cecdbd8bcbddd160b792458a6542a506a70e908f7f1c0890c68e33c820681c8769faa158b96a9025765df4b4dbe0b9a5ccc45704f9eebd321e099d1f2f6d9662e517f7ea1965b0c86d6b6e909599a2e37e7c53361abd91e2b91e21a2c8646d869dd5c656d5edf183730de0ac9ced7d544efca5ace9a32c6bd1ac33119eeffec92b5f08da06dae16de5bbd8ab21b075dad63931f6b97dd80b5491bd4fb67051103b4004035f2ed30040ff8a36b77ed49793c373447724eb7e8dcd8f101f3a2127ddec0929bc4fb2c2f9565d5f09089f092dc3093f1ee34c22ef35755537b60edf71d58ba101045171a60a00478ab6cef32ac863af2bf2e917e518e847f4a5feeb61576d10c992a16c206f17db0d1d8a2b8a83e6fcb831335ae02493cd8d0239dce2240f87f04da2911a698db35ec34119dedc93a3beaaee621c0c51c9cdbb4dc47c56ef09c2f442a7808f4eedd258b3e120c3b07bac002472fbe4b1fb779a6163533801f4a563201f54bc1910259d393869c61789b4854d1bfec865a56b33b6d49a5f2c0a06f341ad04185861e6a01ed828850a9d14a1f0ab9aee602a499e2bb4058ad04fbfafa1c7c640cd6f665424b81793b9ebdf3b73b59c2903f22e2c4605b9992f7d3b54307ad31febc7f4225cb803175314c8bf10ffa7fb9213c1a381b9d3e53838c6b230c0c5698f2308cefcdfc4f7a3cf7af8ffa90ba9879268c5f29e1ca74e17a269e2f43c589a9293572d2892624fc2f5d377db94290027b5399bf8283855c29512715821b90fce136f51531c3bea90dfc86a8cb5e349ff8daed89880c946218db87216e1a086588e49fe3213488f5c55198925fecd314f7041680294ef5de9a752825663a86b7bcef416361bc5ed880aa06d1bc05553ed80f71363de87a4950c2dd08c7915da105786e949c1d280563bc17d81f4c03aaabe0e5865816f048d61c3e2fd0a65b236cae38a8816cc31053774db4feeb4c4c8377d673ca6796704002ae038173fc5062ec761bd16645f5cf40aa6290756fa05c842caa1215415a37f0cb1a5aee970b990e92f3c1a154273850529608c88e76ffa399d031788196392d2b2fe9d531b890f0cd3a7f439683a981e1b670c4d2c57f1d3ad21a01307308ccd6185d11d51dfa93c95d4bd4e6719aed7b43a9430cbdda7a8f87f8e8308d86e2a92bbf49ed6c6c438caf791099c12cf1a68ae2a4d1104af3900719fa36e73a10901a9bec448067fa5c769f996e09726f188a7fc194d3df6eeed4cdda0b37a5679824dbeb98e534d661a672dc76f6bdb8746130b701173c80dd79f2695f5f05505114c878ae6d8dc5b72cf507642e3099114c0f269a1b0edbbbf6c705f37c405ca924f354c0b21032c131371e46961f6882a3ad7e7a73d27b4a8eccdb0a6cdffbb90925fb47a34ab46dcad51b49c308d64e9fdd13579e2f088f94404a710ea1dc1121baa83dc698b92a1057cd227c57870c8e8c9c20dcc391efc53ab1210680b2af0f328ccc394e04a4020b92b417f2da734de89bea6be280b4cf3510bc9b9936b82f950273bf1dd17ff7e8cb9b8586e1e58b59a7ec915a06ff3f3eac2d98640b0d1fde6e2de0ba3181cec207313b229d03c649960e4a052a5812a1e546f4e7a12e0567fd8d042e607c82234ea09e4d501010c17c827b7a9e0d3faa2ef45889a6571b1c75ca8b43af715e8c0cf0b74b859de0bad3f2e5715cfe4738956bd0c7180021c84d9eebee716c6a2914c04acf41f01235ead9dd9d62b3d62ae91cac389e800e0d7679ad59b3bab165507930a74b4cbeffdb54b06a64a79e0f346918515b380959d9d0cbfe81b561c11f81016f0779694afc0daa53d01286071facc04fdee103e2668ae4473d71b00f717fa127026f6463a0478005fd7554d0d104510ff7d7233f6b8f195a0d6d34b9d13716ae462449a7b20db60b9e03bee2b782c412d94d026f7207e2db35d1201cd2f331cfe53b0985c8c9a74f96867342bf393c8f6fb82569c8bc822f5f93f9035e45f44288f42fc2a91e3a83c0960e3106a21a247af628286b74f03df5fee75cba749b5e2be9d1bd6b12123cc46b7c7514ab19ce23b72ddfc719ecdcc1043c263c6945cec1f81b0da0507026d0b2912982d11ff06f522dffde03515dc1b5687501ff4c7d73f33cbb4157739de8f96f73c6bba0ed1486113117a3875809ce89070f82c24eb55d73241a7e6ca39fa96882067f91d1e7241cf66237db7a08e5706d17318210ef23c692982e291cf3b18cbc94c46751e7272eb00ff91c83c0011d36221422c95f4b02f25a4780c1b5ac9b805ba97143a2c5096f1b4e50d778b46679e08daa3adf0aa8ba0c946f5ccb8deebc2cff2da62c921d826ebf66cd8149e30070fc47bdd8cf231728cf1f975bc96027b85f5fe107800d74128cd3d370b37f9928284349ad89a97b454224b0c90238e288992dc0e66e0fc09cc6f1c28434113cd027dd5189b86b05eeb03b81e33dfac34f58be3b63a41dc204ee9d5b1a9685cf2c075075e4c96b326bd235947aceda1e317562673e650dc3f514d4976a664d7773382d780b7e4aa8d1b5520eb4b1e5c8cd5113f0f64e233130ebe456c31acb17403c6dcf06dd7df0ca2bd44d6007f037e0101bf5778506305af712e8bc9fdbfb5ca7f377ccb559e6534a27e7cd93db6bfe8e0dba14500aae879a4cede2084915882157ac650eda1d5a31d30ef13935fe25b94d6d409d11f2f47f52849d9174d2f9510a3c55fb04f80c89c83d67b6455d17103819d33416d2b663adcecaced40141bd51975d29d5e5985cf3b4b02e8522ce6464d4454f1961d99e5bcb7a102b4281beb50743a5b2f1553668b3267310dea74a99fa976327b5e9ed370065b5832f8bbaffef3a11ddc4799d65198cc4a9e205dd80da29521cdaec743cc00baf4f6ec115d4841be17c13940367702c5e1e0f4a49ca37dd510370378e51a6e1f60a2ddbdd13df8c8aa28f9a746a1c9a576921e1fde854ef5401f0af0d62b789e8e28d21019ab0d02efac472a19b820995dc1970095f7ffeea0d83a1286226b5bd378a9235892f65565dfbf850425b6096f69f8e4e8b18c50d00f0a69b85ee1d745877fd35cd607d3fbd726c3f03c077eb7196712c948bf1e527d00eb7c5f3961d23416f700ab9f3f8cbc15f817d1dc5d8d8ea326d47a7bf01078dd96a4ca17f3f50dbdda04ddd5f71e58baf5d8798e216f9411e8ece22572b30280312f5cd1d022f7827dd73d2ab0b1024e1f82c8d2fed0f808af5f26d1bb023c6e3deefb2e1a9eac14f8efde05760ef7b5124420f95a53ac1c427f5c5660c0a96da9a71c19068b921e9f90d0617cd6a76e5ccad558e4268690112f54957e11329ae735bd291fa3c275f4efe282e59d8cac61379ecbc0d80bd2f11330943461d1401c866de889f7f84323411face95ebfdf6c2392d6d5f5ec45ac127b3d3b20d04dc833b9afe0997bc70d1977cc91caa758e98161c5b35b8ece4a923ec952700914f61bc997bf65382eb13d9b11205457cf5274d685c7b4fea3a7a8b61f7321c911925db079a8ea2025db2e599578949a2df680247d71a1be355d0a0f8a66e118a9db684abd90c9183f5b0f32a88f119b3dbe7ad5353671e90db09017fb262198c128322953576172e5c881e395bf874df2b8fc796995617187fd6a351783f199df295fcfe6388f1b62e69e9c8d5f6830fa6afc7023627bedf92f783c5b9ab13b79e505c47b1d80b0cf9d3b8d396b1e858224a8ad6e694395c670cfa98c22008225dc71f34b1d5f0f218d3c121aa851bb85d4aee52a73438d55ccacf6fcebf0265fb1ade7ba9d0cfdb1f601973413972c2d3d3b0323262a9975de075ee83560ef23bef045fecc74f2a0612246813f9593fb93e46cd90860f84e1e28ed777e127a67c4e38f95d21c1bae5fe5913ce1597963e0d279d7c9f3d3b6a8599c1b28a044808699df165722bdc784c023df8e4a5807c5aa29e3b89c3b68cab4a97abbf2c78ad450014204928da95e4ca74f9c1da2e12e4f1ab750758bb515aafd880c619e24d8ff768ccb6bdd0586cae866b405d7b37e4d42a03f0ad17eb1f8187fc641da0970169f927f7bf9e1c384f942c3278fe88839509d2b2bd644fe583f70fa40ac1f3e58441874ab673f3a7401d73385ef215358ded3f974bb69de93468454629fc31e1a014680834348e2487e0da2d31f4f2a392ff96e05e910f7ffcbf21491c21ed8afa3d870636cd2cabb4f8327f400fedca7f0f17d995ebffe22678f46e091d38a9e3dd6dcff1789df56d6118340c46cef3cd0da9d6866a190f4f0841052ae036d221e1a649198cad8a804c4d0063ae4f53e39d350d724ba3ba776f49380c5ba5aed82b50041a676c0985a3af3a87673e40ef02761506ae9b8a9747c1d12a817f1fd7285867098d80313c6bb7712e2e5d29e8bc0171c05cd1e32ee3005800dbdce2e7fc587e5b61be874d085375c11510b16f1880fe72b0138b487f12fa08968d9b61e1f507044a4fa5789b2e64abff247934383351a1523fc5b1642fed0d64575a26c69f2d8495194c259788cd2f198f364104f70c5474aedb4338e8370ba9bd649b615a834bdecc3a81814e5341261262b81ea5750752090206e88a4b0464d074b6f282ea46c471a7fa5fca9f7d152bd52fa1da7472865856acd372a4277b76f44fd805174f05c3bbdcc6b19ff4aba69c0c4d4d551977ec58748cde1302c31292b2a31eb3411af654e4950fdbb1498552e1960e177ae165da22c2752b2df395df52503c8214ebb389582efb8a9ed573b97c715cbfc7f124e071f2bcc629101a902bfac0c1628391049848b1a4cdeab6ac67da87c059f94aa07d043ae704568761f61db3a85009558c192e60152706c95395a041f447a77d01778238822acecffad7de06a7e561247e04cacc0839b1ecb48c3604285851ed468324f7ea0dd39077706043090ed84ee41c128d924ee2ac1d7ee52ff06c77f4e6bbba1a7f08c1fe44c08bcb3f8b30b28c1fe413e28c2540c9d6020447312e74058a446a1c28f2507e0c762d4cd81b8cc616777f35243031e18c1f7c927bdc4f6fb09850d800ff4fa042db15ac9923c7acc0a23eb21ecf3951d8b6069d7e9e6963293dc6af0660f21c97c56f041167dd0752681447171fac2b10482a732cb83d7bfc8d200801938f6a67a812126b5869ecb716ad9139ac248f74b846a660bf1fa69b04d95c270b5ab8232141f4affd1b8107c09f30a8e46895f08a8523ff3aa384d4ffe2d705bdbc30d959ca63431241d8b5e01ae3787a696943af65ed91c83e607f7a1b482d4eb07e1924e091d622ff4e7d5ebe5145c4efc0d2b41523fd1d9f42e3c2b6ce211c89f1823292c192a59adb05b32ae0cbc6488722677e2006c9263fe02a7a5b079553eb23e1960fea54923af76e15a80896323dd20c2d8e6d3335f60579b5750f1c7a488d9342d15a29b885df33d2f3bbd1402166dd7bfda9e1f316958623cb2fff8369ff6c93762c36d35b2d682203cd3e0e49090911cdc76e46f633d7459f145bab91de6e42c2b01c82cbe0387f079a901bdb2b36edec896a6cd81eb5023a1068158dc5b99f7ecb78d9f1b1bfceb0509772d4f0868e308aab8e26f65f27340933b6b6571a29e20b90c345601a0cc8b539dc85c5ba7d50e635a9629a8813a600323980699381f7d3c31d0ca3657b5d2dbd00f427a428cb8e7fd2b415317c6b24b617c682b94295918d7b7a0eb8dc1dd2649887b782c7d707648ab7cc244bd9142e970240df323684c6368528c115735ad5a502f3f9749cba348a389123ea522ce8f8530eaac8aaedadbf928a547960049754238a73321c5568967adc49ef38218440cf8689d89b32657940e801ce7f1ef29a2d5a05685f199fa15b924a6ccd05a42b013a4633f8d1ebecadcfc0d421d53b64bb9fe5bfaeddefdadc8c0271b01c06acd4d10fe9ebcd5b1f23ecf741873c478dbafc3dcc2fb174fb2a43e22ee10e5d29ad7406f2249a5f9874529b9b6a4acdb4e05c88ede6fcafef35dcea185201a1162101b85a14bcd95f92c40d88178553ad3de9e9d1c6ad299bf4ea9339a013fbc520e7cd416eb1e5c468e67c7130c17bc7a3a19af5ff71d1674c77fdef8023043de08199726c6b565279df338e806235b88a9e4a9150eab8452e31a3962619800fc18c9c85e03a0b27cf9da0a9125edc795bec6a70d1e35cac63618ebf7f2bd063fc16a27ea2c2c69197d7c380e6e7cb4f92face6d972fa686dbe7dd42c61d2c2ebf7b711d09c3887f8df2367df68b5a79f8a8bc882a892e0fdc47155bc61eb55ed860c0b490478861c473db6ea731a7521aa718ef64f8bf42436635dd9b24e8d126a1ddad46a676273f34b9524ef94f5e15c4a54d4aca9ef13a422c80802288154c205a53cfa862266129a48f55d5fbed32e7339d08b0b0f90ea8269f8b13faeca680f5c89a8a2f47395e3761dffbd94d10ff5ad645c3abee5aabea26fb113471ee6d71d25795ebd2b9306c1fc09f8f60fbe1ab5f80990b981ac48504d82e7c0779b863e947006791d70fda2a16eb06efd7a2d31359fb0cec7a08098e1e10cba3dec9ad6b020690a8e003596b4bf2718815906d70b3f39b3fccf8486fdb1337b095c8d62a2435d583d19a6d6ae416d407060817b08e31ff7b8ef8d76f0e157019c2bd7d826d8067ab485e35fef24addab5f890cf4064b24d5c036c490a616f673fc10cbbb0a89cba2a481b9416a87b962ea665af99090548813305b8e7e16962de30630903282955570c86ef018218f11a3968de5839fe712b434e9c60f2f4640ef056aa651ab26025ad8be12ad827f41e624f703ad21b344c13c7700961c1dce1a8cc3d9a43a0a07a55a1f12b98ea97f69f9b511c79b8d080432f177d11643bce69f4b15c5039b20bb6640e5a5b4a7716f68a777af4625f519e37ca965002000583dbe32d61b254a1869c840c2728fbc6c08b6d023f37771f505def86619f0f5a76d7cbc6eed927683a4858202654fc38e08b46ae56046c76e2326e12305b512043d8c044fd98a6bc0eb7e627ad19fbf0c7c6dd273a607116669b6ce5e088a91ecf3d9aee4f5c738f6bbfb4df57cb03f8e3c376cf0d5ebd04a7dc2b9692c13d4a2bd79b936a38f36122c7d260f40c0a30a215e517f6fed8bdde84d517b11eead861320478b77003a45e0111e3ba9ff2ca2b9526e3a7d368922418a57c3086c29b2b83b6f17e1d6acf42a402707f5488b392f036143dce34fb8e4efef59124bb2a8559d5cf14c8f91d0c3a59bfc48b1b4e306fe88eef7743880b82b36b2092e99c3269785e67b53ee2ff5221093ae056e3aa033b028b018631c0b3c712801d0141ca2e0605e36e6e284254f5b5f494e0066c012e1350f937950d7e08d170d251b4496e34d128431bdac280e2feca2023ab233eb87e319b364bafad8655c2c7708e8084834e47739912bd0adff1ddad10340e964b59f8a78a821930d8835062e5adafd3983412b616197a87164907454487ac39d2ebf9cc9b849e3fd1e5527f6c8f32bf0c7aef717c852b5684a0ea33e286a6e35d7f5eb65a86d0a20c9cd0c9365ddea3d67fa5d5a276bd8815817e8125624338c688ba0df13675403522e0e79fb09d9b649806197b03fa0bfd88d183ac2aad3e5a563458f75f374915e8b270d827ad01cbfc701aad8c723d8bd32f28bdb5224f6213c7c565043fb868bb42a6de5a6dcc4275cd9ea8a3c6cb4f5056e19f9533d56cd2620dcd52127f39495202710c990105b3ef35cc3221c7c9d5a7f855b67c5a98649d56c5f251c54c9500b127e4097131b40f3c1e68eea407d40eedbe5f69f20b813cb3ad19bec62c98f0a2ff7e8c9e0a9cf519531046545a3c3a5d7a2538c8c866df88a92b6442cbd8017c0bebd1c384df8fbb4fa1581886d996cb5ba7ffa5f6128e67a41ce1106967416b5d1a257b9a48ebe50a03724c4e0d01f8ebf6f45a3dc38b28a60cc6307308a0f6e4b146e68634304ed84248cb2c0540a0d4e9dd3a853d0bc281ce0f2efd7cd0dfad6ae1aa05c7fd773583f4255bea06bf5290303326058d258d1159617acd22d430bbe1f5899c0576c8ad0b6fa2d7b21c50b1c2e502b388a0fc483486ba1a40dcdd0dcda309bae788697f16506f407c94dd7a762ee2173c580d636a7b3274a21e043cf074a991c5e34a713a6e9e08cf7dc2bb19d50e038292c5ac5853aac700bcd1be3590c00bb700bc670efb47a460450efb29d6197ed57101ca2dcd325d9254baacf26189c9b295cab1a665eaf54fa87cc3f4e2ed4308973e33f9aa485c80f2f81e8e039f142a8e752ab4cb4ee17a982ec5d5df8702148bc438e3f2f4ef90a12799c7aa06dc471ef800325cbbb1d3de04ef8de025d8f59db178eb1de374b22ce9b031568c9bc172fffadf4bb951159582cf654e84b8ca2d3a8439ea3a97b0a1f247ef178d5d360b08e430d47a4d5754f189d0f58cc7bdbcac5035a1616ca01302dd5475297933fb62511b775b3663fa4e62bbe0fd79be1a5aca222863e941f0e89f92e565740ad8284ad155135327288cab0c48d039fb4e25a75ca610b091d2aac358e01fdced622650c9b7423f82914a740954a10a8030a8f2dcab1e06f276a4b0ed333baf2ef75e5221207b654f0a2a18e98ff47208eb79a3277d3288c2968b4e2ae36472158ae6bed4220d782c5be998e029ccd39a4ab2eb370143efb249057fce91b09decbc5bd00b418165a05948a796081e07b4eeda4306f5ceb1f1722f512a2c14a72cf38bcb4a730f956a1cda6aeb7ac5d536083ca02358c5efc05157c27c8749d6947f2da6d9b336a2fba145cac930b9e3b1e4b618b938abfa625d85081dc7c0da2752f75249f8c3d3589772941cd0ab5149abe6995a660b74c07f674dd77c1fa53df9803b39b4109bb92e1c61c2ac1564a4559e6970fec3eb20f6fdf0d77a0bfd9872009ee2a2cf0067affa0037aff0a27354d44409d0dba4b0cfb53abf13b57f93b7ee1eb26b23df128bad45b399821bbdd88adff2ade31090b44250e9d3eed773ad4d329a0092d2d7e07447047fe9056f21e652797a50752227b8f052326634a6c640cb08bd7c7c0437c466d8e858962351856c31eacd44a174eeaf021bbb9d9e21fb576047eed27c3e1af92ccf6bd69c4c553b9275089832ea9d9313ac3d1618d5c2037d767f62b4b24b2c280efd4fd9076f76df70bd73e18d46ef7cc36369536a5fdb14a5be259f5a5451df790cd2f48e90aa9256f51181b922923de6a813722c63d4790db3aac7df604cf4903c771526acebf05b9a89e28fded5408ba411cf8b563d77999d799d25b86bb7c69988a8e6f6128ccb6044926d3df49945420af9bf47edc6c0073cd0774b878015d49966c8d303fbaff296e0e07d45d4bfcf46ee6172c08d1074371c3bb9b79768623bdd7f23e9d2fa1f1d4246fe9fe90bdbfddad2c984cadb78e43ccf854c772b5e2ea901cb2a141652907219d626039f1a343e4d7b925fbfa329f10009276a9e5c8bc4a7e0b60f5d8e96f13bd1deca8c1635d444b9e89feef62d57f3cd2260515f08d5bf1a92c4ad61d14158a471fbecf9237297c47c8f4664560fa96c58a6198eb550d00e4344db18fff156d5640c469267ad03bd2ddfd0745b5e87148e0a0926716f1a7987beb9353fd28511e1e9314e92c5ad89e61f49f3adc9cd6f3d3edecd68f8a40cf8d4a75ce73", + "public_inputs_hex": "0x1d420eaa08a65528f470fd3e2a802913b611527f41fca008a0ad4e974750780303f2ad158d360e938540cb9fc2ecbc5168b0078e536f2a2c847cc131d440ec01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000005874be0dda5bf3cee7d33e2ac260833700000000000000000000000000000000c484d632fca06937651e18db1cebd2a61a28590517ffbdf7ff33ba52157bce68c37c073712ba7f38d05290ebf864b98214b346a1e0b88b78ee55229a563175a39a591790754460f52f2c62ba9209ec682c52b19c6d060045e45222e0d8e0b98f4ed39d1828106df7922a57e9dfb4e3612adf2b3b5c0fb3ee6dabb0598567f04e5399940174b52f2e6f21f820ae1423c32c171bec038f3c507bc03153950b824f23b8c9bee914c66ffffd81476e3d8274248698204cea2dcbfb2a3f50cad9df0ee2be785bc9d51b32240ff14a38e634701d004c01249dd31199204e4af023d3953454b3eff07d78ace9c9390491b0bb270c5c089316c361ab8c67cda08511f331604badf371b748b2209c1a93694851b1" + }, + "decryption_aggregator": { + "proof_hex": "0x00000000000000000000000000000000000000000000000c48630be311f1f962000000000000000000000000000000000000000000000009094d928902bade6b000000000000000000000000000000000000000000000003276d7f70998c8a6a00000000000000000000000000000000000000000000000000014b10c3ef742d0000000000000000000000000000000000000000000000059dabdb8a1104760500000000000000000000000000000000000000000000000cbd24ba9f08a5a4b9000000000000000000000000000000000000000000000006dde9afc78170cd7e00000000000000000000000000000000000000000000000000006ebbcb69bef100000000000000000000000000000000000000000000000815651da716490ee1000000000000000000000000000000000000000000000002dfbfb0ea6015cc0d00000000000000000000000000000000000000000000000a006ddebc8260adf900000000000000000000000000000000000000000000000000026bca52f3432f000000000000000000000000000000000000000000000003abe7bdf35b12324300000000000000000000000000000000000000000000000d78e97fbf6f41b5d900000000000000000000000000000000000000000000000fed06b22f3348ccd0000000000000000000000000000000000000000000000000000177bd3993bb1900745f882f4933774d30e9a1a715921ee9c1deaabfe8d8b00a75f50c02a291210c7906129ed7f95df356228e1afb1ee7d2c4eedabbc0ff255b387ad45beb860f1834d808cce18a2f82f98a9f7b0ccb28f0e7ea6e83f942964039ef11876aa672102cdf23de1a57c84618b4f41fa62e730e713ce3504835cc8f76971a73efaa5422a4ecf28aeeadfeebd41cf0a5d3efb4839e9e85afd27c43a99a0fe87ddaafb8196059999059478d9ffa41dca4f6d7d81d48d58a0c30df6f48db58e71d1ec6961318e088bde136b51d63c83d9df77a8cf759876137decdeaca7d26edd5af872f18a88adba15fc2d6c452a6a77363067f5c96b232690e5d926000f5835a5860f30b972c618cf393850457131d3d04f838ac4970287b03bd3d9193f2055753db7201b5cb49d8f446c2603fbe74fb10f5fd737a04862eeeee35997bbd47ef7725f12871fa30db4aa88e433f3bcabcafc0b753daef044f69b58022f3cfc0d82e87b61ac35e45692655552d2123d527a983bbaaccae4c481fbd1cd7ebc8fe01a8cee90147a0c38b93aedbc670319a46fcad126582d57c3a3f5e77b209771d08aaed520caaaa19ff0f4347d238c1cd9df02bd048d2b88ff77c95aaf18bfdb0f54a0a4d282b87af61c7bbe102264bdced08ed6d509ffcb2f4274435c60ff805de4061952efe6b65e37958492ea0af7a55f5a9f63f3cdfb51e1a8cbd06cca94254a0664a285b19f84494a5550722ee2dc7d405148d40a312eb19caab840ea0447841b92622f60bfee9aeec6949b5eeae18499e29176a9f30736c499247936abe337445381ac036614165e412b2919586e233ef46bd3de2c3698d645cc7d3525cbb54fad00b7153365114e1e8c003326f014ce2bf525c0ab22132c83a65624e1ff513ccf00934202ccd1809839b47c506c78ba46a1a08c498dc9a8c3d29e8ac968c22e50d0faa86e7d3fa85426521ccc15e7e8db062a8ddad6df9bd98f5161b2277bdfdd82d5e6fb53e470f08dad8c9d6a679ae6ac38816d155ee74882a18896fd8787dea0c84b449538ebe74f4fdc0abb3617378d9bafadf565629b8fff511990d65b9ba02adf458d1a8907f735bae7b108bd8a711d14a2b26944ef0864f55e61e98b19e0bb3ad97e31dc9a35693b44ec21a82fb8422edb4a4720015f044b9b22eab37d42dd0cf96bd3676ed7674d199c350bff173b472be442a94417c1af5402bd899ea1b72adcb09ab85580aaf25d1f5aeb1012bdb3ad06de1a5afe1544a59ed92465a177355256de35ab467bb6f578b91a360d0276f56f6acc076b3e188ee1bd8faf113384a6c297bfe1448b3aecd0008e3ee22fcd1468e92f0c2adb0577b7a7e3ccf127cc5f6c669dc90e7f04d177f605c7a6ea70a9a9ae72500e85735e3809c474b0e942a7631d7144d74aaa78b052e0f1fec5dee7659de0afe2d5b3cd86aefc7a5209e329df0479e8ee3c73cc1176db21efbdee75cd733437c6d77f74545d673e822e1ef845de14e49bffef9ae2766cf974ccc723915ec7d8f9d0a62d66db6eae31a9a43de1f4b7e08bb514afe1557dd20323ac31ab956f0ca0c8e1ddc2770219a25673e12cc23b5bd31e3db44b86184feaf44111919257b284faa330d6407b09d148888f150a06a6bb9eb79bdddf567f9449435147a138f796b88466b31ca90d4250d48c7ea3b2cb83979c4433643155524e69665728c8234f021da24a9e86475033220cc04c9f50ab16ec9f1ef61566c01ddc144f19592b2ab034a4cc67044a70784872790c05b9430eea6ae6d915b6a37b6384437d4734883aaa65c1c14faf124b116d95bbc3afa60b5295f5920cc29b904f43cc4609bf10b33d95a0b20d27b1cca8c4ba458eda7e800e7c3819f963e2d7d5f7c2f1e7d32fa54bc61f00c8a141428a4a49ca4de281ea6562d1d044f96ff4037456663e92b29ad6cc0f8ed987d2917107e9b91dcc6627a87b55e5e9cc9f301d83976500ab72da2b5274942781513766227cba3fe36547829a32997e945d4864267602a93c8dca29df504ab342407666f1133f877bb58da2e440d1212bde80af6920804ab8a9c02d40010fcb1c3070c6ff952b0274f2d6d1a15a89f647c4292c5526b476bc5444fb7972d1d73de1500872412e79a184a617cbbec29f8c54ff05fddae5ecd77f5378f7ef8ecdf2416ad5f6b2a4280b3666cc76afb5d37d1e05193f882e33ff469678a5574afcb462bc172273991f7ac3d737d0fe587e662e9a889812229c3c698aba1aafe8ed21625e07b561c35fe049510519f3961a4e216eba4e8fe18e2f7517b686d5308eb462a2915804e5503ef25e177977026560f87155d37dd095e808394d3576603cb592d8f8589807ad93e1f1363d79a8f2081dc0257e5dc14d92a587ca3b21e61df271870a9f6ef519d14a154495c0f62236ea7bbaf6c4a325546d33a9c063ba33fe21ed92c092d512bbf330524f0b224da2987bdd30e9da88ba6f2bb97d2a79980de025298a2413eb020e039f31f70aafa0da1337a0614f6ac0bb4a463e63a0cba361d0619dd00864064458450ffcd778827e41d63da2c9d0ab4afe5b5c4d87857662d0227308dae4827ed96865305924ce907dfb5782cf5ed0e5399bbb0073934771e6b226bc2b36e4dd351ae5a40bf9126a0e6775ff4c8536c15fb61949b3290bb187116c1c2eb4b0b8b064a6440f4054c5736147c1f0729c01190818e147d5ecd2aacd235b489401ec0615402cd9fec3b7e7dd0a3a1fa0146022a187eb7f37b620a9579bcc115ddaf83acc5af58e66db7f1db3fdb9a29d4b2e95e8b5bf68993010d2a11cad09eb78cbadd63b78acef6a7e5c94bdeea2fdc3f3a50148cb152a2a91acd337de539d43bb0785f19e2830add41b7ca48b9412ed781f833c9d428082026715976f5bda0c6f55329d2df6df074055cc52d6fb4c05440b2c1a907cbe85e1676ed53c33df7816d1ab0c2c998a7e7e89451b696986cd2a45e341d5e7271de2c6b9b45192740cf23dd12b5fbe90d24ee1d7206b42116b8c0ef67c2e6642dd715ed3a570dc0b5730ca5f06b6ecaecc9452b502010234aad2f4497e57ca36da80a73a6da3fa532b095d29b6cb628a4e47cd4a72dc30c4fb4b6a1e8b906ca1f422dc5c75b0953935f15a81549825bc0fcff274efebedad0116fb484723acf21ef00f292189cf7fb7fd95c607331ce8163d98eca656a050e313d0c6c6b01327e0e2fc4674669466cdee6652485aa109174631fa688b85d6e03467e0ca4ac17d8e11aaa9a8694f65e91af6b9f32a4cc3333e1e6b00efd12e9b7ccf899d63141b72c092f22f0d61a19077b146a77d929864a18e667c332ef8783c5ce93e55530d5f00c1b0d21202e170d009b08aeee517acc2422c23535a920bf6c0ac423ef00c762227ee738ab5736520f77ef14dced495be5fe5e050ba5f732d5263ddce615f01a2499561eb221ba50f7f829c7640c27300a3d95fa3da0d05f22810c6f358ea9bc04d51a1041c4267595146c41723072f277714d2aefa4a24ed771cca0c6cae035246b9c4b7c3ced3338ca2f126815275c531f9991f757379286023733bc7226e6061fc89f33013eee2a9a6e46da673ae8d2b768db22fb3d19c5538a7e378a518502a7528efda5b359114b70fe88ec40ee48b7df7548951146d3726b944b6abbcb1e00f5465be285fc50a6257929d7197106c8f5bb94b7fad2ed848d987cb90d6b061541e69a35ee81aad42e8ffe42a7d55e0a54f67ace4f8a881b10e3f15b5f9005e9611b4f9cff3651e9da3922d8b166268dc70e920c1bd426250f391bd4a23d018e721f396dc4aa5926d36519269623e54634fbc568118cf8833b14bf2f0f9c2408ef297f5bd7529c9e199fdf843129e1709870e829f727f30c5323a92355d6031d7764a8c1059e6ee659de164d2f52a78c31364ae9badedba237ee8f84255705909bf520653973493924d598636ca89b7d541ace420ac4340d29cb4273b5d32de51b202c11bbdfd327f9a4938bc9b528780e9d55db14a4a49e25ec67851ae908c03a3bd6b5688b8fa80584971ea4a7a810101f0ce15609319ff637b638a57102b07336582f42861c05dc94f32398d0f89255e4934442f0b0d3c585f1bcfa512c1a2ca556fa3932883d32a3466836b393df44648d81374833f534e1484d779d14bf87ed0d5db60c426075474f0083cf5bc37395e28ff991b22ae5fd5d557ac7012d5c433edcda19b749861ab7931deb37a046bed34d32fe9065ae09682c5eb61b3efda55bccbfd7d25cfd3b80db5d69a5850670275b5818bc737a193fb3a9e9024760eb652d70eb3ab5f712a92b44265d57d8a4854ef9e55088ccf335e2f9040428aff91d34912db111388e6a3cbf301ae316363a9d9a2e36a64612c033367b244ca9c7ac21d13e47c2d883d23d803c470c038c682f10fe2405c9ea557de22c1ca92fffb3b0ea9411886a7338b51a183050fe97622a3e650248d0c228b4f98022f12daca4b4314980b9880fba7633fcb15be0a6394965e1945c7e8a3a99e80301d83ec98c932bb90daceee9387ef62cdb9da04cfc4e6501a4aca08b9f39ec0b2160ae2c2d8a07f07b3ccd792ca5f40903123fe6d299eab5377a3b6f5bd7eae3034d29284aeadeb4ff78da1cb8f349857059381a613324e45fe33951e1732ff126323082eb785850c626c60cc5b8a4384612b7ac0debda63779869af4a7ac9c32a23878fccefd2c5b944b923e7682a78bd970bf2b7bab3094a70a4d3da19cb2526bd654cd10fd2a0423c761fbfa0da080b547cff8d763bf7d8fcb811dfcd9b622bb3dfccab710ea0721519857102a66d31a900fa9f40ec5c793ccc33d0c8c33e2bf6362c665d695c88870fb36a87fefa6d52c1809a79d76a7ec90080bb4d4c1f0733bc18a85d5e6b67912ec5ee87af74e5ea0a42e68560046e956cd9ff9c0d672441ff72085faac7df73a19408fca81b68ef4674bccb2054c23db7fc123f901d2f7bbcc34a46b06efe0ceaa8865be8bc091ba28ac27bc165fc8ae8aa8e1844d8295fd0e24c586724197a6bba19537e6f616b2a7d77e67305fc9c634e999432eb25badd33c6863de00c63d0dc0def6e4849fd6e2b2df0014d4ab355e239870fbe2ecaeede9abfcfb7e314923aa3fb127698a3bb028b51c3645a52e464b81584d7169a2a83bf3e5133d06e1aaa879506964625e29c2f4cf0c78055a93e2091c3b415cdef36f794c8c1f7f9cfa9ad1c62880b767df5c07a7b54930fb6428048d48e25e662a0332ab1e6f0aecce9f6c4f1f3270edbe606a45bef508beefe9db7a2871fb91f1ef3fe9290f58143b81b21140d2ee9c155792cef559d8d0ab6556550cf01e96f289c21331f28096710f92057003b543b0ed7c34a31e6dd33ef8ed2bee102decee0c87f67b0f3d5c2b8451094bc0457042ebd95c506001787750e9d061e2b1e350ccf2a89b329d57c4780b006e297469b359729a8344336eb1b27ff1785247c5ae080cd0cc5b8f404959249a5a94c72f907ff7470f1b96d4b28f216b4302a264bf6671a6c6240847a9bf0f209d637902371d9bb702cf1ab61b2256522791990cfe77ee80f96f336cb9af05e9f13454108f9fa8a315c1753fffe47a7e46014c2168608d6c63e70112a3813559687fd6f986892a5391c35f2bc99a7d782db10ffaf1385dc8d8eea02e82f2259b27e18fe0f03d457272d25d0f4bed62cdd4b30067152881fa2c91394d7fd5577156ae826cdf3ff1080f8758776c605264bb10115e845d4735696d3ea96e14bae7a5c6ad95ad97ebd93bde67a62b6964963ff2ccbbe458f8bf252f10c3d39f820f0cfcdebb167d253cae57d42362eb6000e221e5ee7d0a4f1552fd4862e88e6de342fdbcac2e15f67543bb1d87124e01ecfc7195474dacbe1fe031a33f2fdeeb86639ec42fb42f0577c718686343e5e3a67b403e7c957eac1ea723e6843beaaea32b798c22c62858ba97cd71fca644b8ee5481d643fafa4911cfe3606bd36ddbcff8aa625615cf55045efe09c720b75b8da002a4a1edf1d2f1cd31f5b10df8f0511c3b10f55be14c31c6ca298129ce7a9cd3d1a741f98c2682ec2d45caf2074d6a156995405d03e56ea5e8b54b7deffc2ddeb0de075bfea7001090c584a2d3548d838ea3659e2197723f2a3b5bc15acf9c5f82d78d0ebbe7d05ce5d403609ef9b9c808ddb5afe59950074bf327d2a6e06e65a0ec4288f5d286b80e3c55f32d20f5367bf41fcecc92de57b76cb5ec4eef3ca312289f837e4918216a39f411f879a5d625a8934490d1d518ed96dbe5f1350e73d0fbbb31f50a74b73398ecc1ffe2569e09b39b5faea93850e3fb1d7ba62c4bb960902f1fc2ea763b223c0a2fba633657b9367a044b7fe5aff25a830886db7271d02402c90f0131b822bdd895731ed2ebcb41cacd436136e9733e5c2092a4712231bb7b467810ddbea4671a8bcbb9314b24f3a6f825f36f826320c723f1737e8ab2377dcdc1c018e8e128df26a1bfce1c72cd6a1366b28d2819da0fcae532c09771f82ce33a2548712e66fc60cec5772d302e69d1f2df6d60fe2a6383a98c44a3f2dd94ae12729dd3c3f4a7d5e64f9b934c639cc0a7ec642c135b983ad2adc336f14d9b20808c00bb40549a9e544eebd53d7949c990f9b0828e7de51b758a04f7d03001bdeee20777af07151ad8656d122694b9dd0e1bee7f3b2a3244056b5454a1898af35794759223c9347bc9f78bf8fe4b94e5977bc2ff5fa80a37def24da5b093ea1e7414bef1e418adbe7622ae9a81c0f40eeb94a6f06b7c7139530ce622015a8d0b35cc4a77ff97038e85382ea32409c3d7722cb104c9991609e6aa7f28c078cb0f8f8451b679a04431d0a7b35eb9e249acf659f02f115bdbfc3d97c162a1618ffe3eeccdce29bfd365c50ef925a9cdb6792273f2c5349d9e690e61feb170a7a8d828ef5e26703904ed3678a2e996e1fed6a094e8bb418bfa7c7166d43720f6dcdaebd42d290c2aa070762cf3667fef41235bfbce8c70d8bedd7c1749bee024f7f33bbc47cd9b7db07f4a3b45857582d77ea71acd4c604df900612be43fd1cfa3840cfaf1b0a9270b553a56d3c9bbb518bfb8dddced9a04787181d3212cd0b274d4f697ec304ce3a070d882713c71e078b8a71062b6ae5edc90827b1ada00532887071825f085481624d66b338c735e1afa78795d04bfa439b3d4f93fd4026ab28108d0d8ff1297721ae41514d3fa3b272b088e33a4c8878e6efcfb7a6ce1f80ebcf65a5eff98e95749c4f70b1968a96d8e057bdf3f1e60cd5c1830756b62daa2ccdf58c5f0a2f8534824bcb2463b0cb5709e2be340037a8313d9f09365c1bb52455c0389ed9b2052cb1d78d2fc5ef7236f2fd35ee9a91d592efe14b8f783021f01328fc18ece366589934704f227d8a7c7c282d084daa41d35ecd3aa8ec2e4673e29869e6e297522e4fdfb4904506935d533eb42a7ddbd49e6a0c816eb42eebcbe73dbea6b5930b0efe546834e89f1d6c63c64b3c28a530234483423964253045cb001a298bb6007785aa0a0ba3f86bc92495ee7977a0583db41178d9b607226c4552986cc353d78325112c844cbc184103b89d48474e07eb2da807e6701d05c6142154dca876d4aa16ef524cd435221e25e070eab4ec524fb11441c9a62e70c84621711975ef9e18e1707aaf27dcba0c7627c71a92d0776c3c4eccc0d41fcf98f7c2bfac75d69cce01d058be3f58e4a51249629d7eaa149dd69e68ea8f2b193e1e178af41ad154844c0ca3d543030ad385960e8fc7cb64f8a06625d0eb2d6a1b4cf1d13f5f3b6b5de9e0748df23d8d80245a89873515a5715896c9d8481dcf53d63a2fe893f3814de873b577a29c47baa36033c2df2518748e803a427622121f16170a7c5ab7c468564630def77f88bf5079ab89579a3666172e36a59e184a68538aa4a428345540f2e3e104574db2e5ac6e969adcf560474d7ab9042125d0a02aac77af0fd65cad3ac912515008fe3a5365340d5d1323fea34560319b2ca0a7d2cc4a4f1bb3a273e6493a8afc68d118497a0c9090bfe7832e914bb44f29bc63026dbeda84673be1dc2493df4fafb316fbd4bcbe872c12e258141f45a224a7aa37f1623202127a443b242df30be8c9e51cfa58981c108ba0d5e175749e0bb01a825c77a26345ae07c881f54f0cd312e69d84c47a6e35171d511480c7a623c0686555c3d16f732f51a6bb8310683af2a1b89c8de3f7ad7839a3299ea5c91fbbd780b436ad5822f8bb61a3cc9091e59bc458b37010ac2c26024cc52cb5ca2cda90b76ae1e0815d194c3f61a51a21edd361e236ddc58067c5ef28abce834c20b3b7bbc718400cf3f0f8641d0ff9f4790e08958bdb07e6f8c8f5ce0a9fe5fc10ab65eb491b589e3e3d5db8ee8ad35b24e796ed08d3c019493ce5cb8b9558190ddd4bce04d23ebad8d2b7e32f5ee142ac3be219e9c5d9c1af4cbf6096fbb01d01949b1a870272a624332f0c02ff857ea20aa761cd723ce6d6831b85df78f6fa0573a41def76f0cea5dfac64a6153d3d828207573f1f848a94f3124d814054c81da77050c122cb8320403cfd319ee805654250e69233929733053d984ef80ec02c39b2e8a227a81cd36cd62cc79efd8d82009b634d44a367be48652fe18e4dfb1cadf878d4a6e0055105ca2dc38b58e21ca07b8a2dfc857134d539d8ebfd8cc92d15ddd4e24f6456754f6ecdb00e85db62cc0742ed00409ef49aea1d5cfe539e0dde1bc03e991fb8c93fb96ebb190a4cef5b1a7b87f8895e37a200a5ecea805029f66fe3f696c6fc2ef1b60a377f7b3da9dc4ae8f786453548ed49867b43df3f080b10827db91f6bb2069912f0b907fdd194a1dcf76b1c1bd51227839df832b015eb7d8a71b5caf4b9dd13c61499c50df6800f788e09445da160fe68a52debf813950fe7b976dd58e77215cf615f1eb35b8445b821c6c318e8d194a132607d181a125a777def0dadd03854c88a4c3eb870c734e288d60844cb23cd906a658f6f2fdca70eead38cc483aefa8dfa409e7450b29a4f7c998dfb39be9a46848bb9410e26911139b211ef86278eea2f6af7ed6b9a502355c920b4cea607fd9f5227751e127df19b5636726b7673f28cd8475fb9d658e87d6193d27c1f1bac151d955806b940988d597cdda152be63e702af40ff2afac18ccb71365781ec8dcc84376b16bfdb6946840650156b02c0c99120db71b53828b582c36ec2ca96cd34f522df17f6e776b5fe1368982546833cfc95969f656a26ded12437c9fd0bf89ae540c216bb0cae2ef7f97b46db72a93eeb11930c955444611cc15876b1ea0f5e8fe6bf2b05b3fc0f2a6b93b7543e53dcb1c09156477f48f2ce61b2a0b6c24c2b86185b1cfce2c00966f876a7ad0d9d33cbf494c5c469bbe59f3a7bfc3f1ff57484091f0dbd377667ee30adc93888599dd36efd7943e63de39fca03441ceea9c6995fce1822808da97a302d5fe9b87bc89da33c2db970ca7efadce17d24a714ebdcf3bb27839ffb318141eca7f013af5f673715018f1bdeb04b71529f0ea46e702b24d32cd5d0e7e717439e1bea535901c535fedcb68e035a9bd934a2e3aa42effedd600d038c00c434af813d7ae3e81e1054ad8ebd3056aa885058101bb548c83f23b929ca029d14363e8b937de5c1689f723eca79f986dce6110a83a853c028bbf616103e4122f8c15d594fb8ffd2ec83b0d0ebf76136a1a2dfb25df6b2031961872319a4d909bb8b41a1ddf11a19175e1065244b8c439765de3420842fe0a26f693617ee1ff0add77c43a374a8e8ccc5986db941722c754816c44f686bfeebfa05a61835b59331aa8f8746ce1e597e567a86dda92dd37fb069e4c7f651c8e5eaff2526fc6b1af5d3f08ea03aa5ed0511600538de7f23da11bde04d9d4e861960a17321a3d8d7a2a6125e5d1d896c00c7c502f4ea433134599c1d0ec465b276c17a8902880131a292ecccf38beaf20b8d363589adee688b040b08812966c062854f061cc0a3111de4da97d2a95b6e0697a34af3b961c1468ea331e91e848b044b35522608c3eba0fed478ed7ad206cb0096971ff1d323564891e9776529aa1cddaa77126e4417de32dabe06141cfbbfa3921f613baedea2c163cdf6fa6612e8bbf36b29b6e6045f8ef8c9626754ecdd71d692237bf421469a7d35a5c766a2798a618d157ce05f74ec0ff68a292f6ec068ab05a1cb582a3494c750d5234d23474050c202b70d20b30a587bb023bdfdcbd03a85668cf85621429913770cd4a2213730e31d4cf90d501fd21243616a43830015378128eeead4d80d94aed7532994885afd0a67b8f015363abc354bbcc64c0c6cf38d0dfbe730ef61cbe8f721059287603406bb909455949a17212218a2054576e347bfbe41bde4abefd659c6681f8ee01e1c7b1917f5778c1b4a05867f5d7d3ffec2d545cf9d450b9631370bb8188ee95b151209d415f6f186c816516cb4d81f3e10e6ca17a8988775fba24b9c41c517b822e93b2f3631ee916d9cf099532ed9aae35734dc0e932e76f8cfb464fd21fc030b0a0bc9e8e967c73313f1ec276e26c178c0565863cd438684389ce6086161222b9b7d0944205b642e83aabaf88fab2027beb3223ceaf76cbe5f5a9d0367f7842582feda0d1dd7e4d9083fef75c35b505dfb1cd735a59921937fbe06e0032bba0078567034645c741772689758a3fe57ab5f78df30de943007a5a68791e2c4912a53f642121e984b3609a1536ff50352968c434ab8e94124f48e4ec5f56976af2212992b9406027a5783ea73c4003554f01dcf845efb0523a54e9ebb3436e6bf12ec81a92c3a60cfe4ae3ec4372b99123f0032bc39e5938fe1fd10f0bacaac9908374a6a5a7a7772b97dfe3ed854883a0ab3d8363d3879e6caef86f67ca16d87065be426730ae06ad1ce3a8b53c7fd2ccbb7ba4714f2eebcfa7f094822713ed52b684c8e80a6bf90d4a06e9f984df68a607e6e73aed098d19528ee0e2a2cdb3e08dbfbd5e8f4be8d58ab13541f43af3c44df16dae420ffb2c31eb88bf6a69010251956d0d6c04b50d14da8393fee7cc9bab7a83d195954f63ac9ba8dd23a76ba085d7ca28d17aabc1eaf183b2d29cd7037707137b3081c1f88f0c3dbe027cd3b24361b9b42e2d74e3d7ddc0deffae8284572e2d701f5b858556064cf6990534d103e4cac6729dd067f8b8e129fae2d48b1459535ed3af0cbabfef2f6437687601dc24cb6f3afec32975f0edbe7457a4eb601fd9b31f1884cfd71c63cf85428af098d92974449b398dbd3abd6ef1417000cbc96487d1c86d8e308fbb58c355b1a20b47390a257cc8cf26356f3dddcc3f86374f847b6f2fa92a2aabbd2933f555a2aaaf1aac262e2177dac30d537766e89511503a4c66e18767d424f7420820b3f037682fc0d1e17f264b37bd1675f616a13a96ba71e9fae85e335f9719f30631f2904e6448b9c0681de5893e8b8b707bc13eaef7a5987c4a978d9655a2148088117eed85fe8955714ae95e32d3f576ca0b488f24ded321a7fcbec2655bee6e67b0f76e8ed228785e68fde668b12506905f02378f933b203618faacb3a6d5bd1f8013f76cc464379353ec9eed3e754c2e2b6f8b21b8cfe7ecae33986653e464bcb3052be548815bf0b73d1613ad822847cc61e3e3a629855fa5f6cc67ef44898782ae2188052f05e0985bbe24ac528b506c6ae308c092b450c6d5e124dd3a4f73a2ff54a2cc7d3a9fcd6517d5455ac8307346c2747b6862428b29773042c3430a023e2176fe58e6abab972ee2fd51cf4f1d12341b393857d864462572cbe892c822ed55ef37abe0d55b5e094bba8be9bc15707d75f62f9d4d35dbcadbdf7f178472f458924487e86627522f2bcf9d9a432e6c481bae82ecdb4b11385df0e8e2bc92c39c8d59d441dc289dd6ae1f414f2a4daf9802fd44e962bf8ae29d8c7731edd1a44fb6aaaffd4daeed2abd97eb0a2154a93eeb0b3001f6ade26c3e2fd4dfb3616ed049cc776e5b93b9b0ea9cb2b4b2d98dcadb63526b00b9b465e3cf607c9eb0a508904be5c33fdc141dcded6cb8e15a9f5f9cf787336c199ad2e12c7077015218472e9b6221101ccc760cfce6239ab08a594d22ab0d8fc0340265f41fef1730b1c59c995735a75140606f2e7f0ba722567f2ba53750fea1915673f4a41bda11425d213acb84ab066795955d083151485c18615e9ec1423d8d1426752cd2d4b011ea1c41aef1f7911b2826210eb63440ddbfc404125d1295f0229489e40beb72cdf305854142ca6b985f3a6a3add75c316476adb6c49077151b92014886d047167c0b2cd68a15fa851bba38a3d2096a6370ec1be612914c42bb75d9a9531a3d0490829f224f9e23e2a5918b4c093d650da9e00c26761238908e65a07748d0a4239d5782c3b55f78591ec52d5265b2b3690668d8f8daf85e245aec06df52d5bb02ea4a1fc1724b83a2e5e10bb61c0f9f7e45392914c03a851206291cdde2421a0d67d99a279504a25fc2456fc513814853f38f3acf4a3de2f8ced7b974c3cafe1bafa3e5db4239ef4ab0887a397d1ac7d4089042aa0da14dbf69ab63cd8be3402dbde015c3accfc04388f54670271fc8a0abf607f694ab3fe308f1bce3a74c48050118178b3c952fdf0d3c32227b81377efffb94759da81ea4259dc4590fa1a30dfd1246bc14b754402ef8584da0f02073350efe9ac906ed8c9416a8e41c7e7a25573c26cfbae07a1484fdb072b7b9bb4b8f088338f24a15a056e828f3ca898f1cfadcf0bb38844a57ccf35bd832ea21d41b119d1c974a852484982820ba37d11bc6768972da0d4e5bb6da275417d1a4742899e2d5b9b258eb26399df9578700121148abd9c18a123399dc0dfc8a5c7e0d2a265e9a5346d8ce7df300d80252bb01ebdb1a01f3c18c183669c153a04a8d8679f500bc95fdbd6a556ba14d57a641234833b1b855ff632c6d7ebef1260aa2b0c5fa9443f5a0334f3ef1f98c619121216d3755343ede9097165dc12e15e32b140d52a0a4c17e9ba55ce8ec95f9e78b0e093afce59357457d7d34f90d5f7cbbbd2fdd5a12d718cf15675e49997f19ff1b238e407482be973e027a84cfd5095656887765ae6d9bcd619b959bff2d5dad1f7dcc2545e68ed7c4b3f380e8a534370c2e7346593f4c06f40d775005c23af704294a3cfec6b973d867d7853d943d1bbcf7b15649bdea6d1325260216cb91e017785fe8b1257580e4d82d6d09f83482322b3b70ab57c4fa8b4e1a919551cb250031084b29a0eadcfc494129f0e8670d12c9b27274e1500e1e76429bf5b424a619c8a4958459024e4859bdd69f96e07c02109ca93e63679440047e92e4e0161615e9d1332bc06b18d08d4526646b4e8cb5229325d75170396cb4c50cad3a6ab92aa9834dd538c528fdadac1ae6617bcc2d53cc6ea78762e325c68d58b6faebe22d949f507a1a9c9a379a3b7d553107f143ec98abeabfb16cbe6cb5f6cd7a039e2d9c547336699d6ca653b22e61dcbdf713b9b53020ed4a6da8dfee3ffef5f8b227b79ff0084ba475413a7dbece24fbe30aa85d9d2c916f14f6a8b4d0fa49c811155d77e55db88a21d46d18b38cfcf1d323901f4e449f8f5b7059ba53f0f8346d0ff2936114e8a530772045928793ab3b3fdaae3449a28e780f9c799c7bb26ab906a151f404a7022275bcd128e81f411a2363e07907c90d10a7b15186094860a420bb4122ddad2a55a2cf34ad69b2c28deb69db0a709a4d8242f248c79b648d0c1744c73fb0eb16b73e2697bd97f3989b7bc7796d5093b4e3fb68be145facd3c626fa4f14c54443a0094e97239c2b75bfdca5eefd2f596a75fd3db9a675f85afa2b9a3f81ac84d3afc834d4e59a0075c3df4d40d7935da3e8106a4c4e787f780c3014fdd09658ed6e107d656b858a79adfb1f89df218ba81b120ca2f8669d03ee008f365965325696051878d50c58ace4409d323d3bbb301fb846e51cb75de55c067dac000325021ea22bcb0ed5470977dca93f2f9e3d585f4c9fba53473123d61ff90243ee6925c8b8395c8174bdea515993c0be76a5c46c08e2bc465626f65a2e8c994229c40247ff05a3b9cf78c6c58663049b9f0151552d242cb998e76f0c10a7f482e6bd655d0694774852037f677163d095ccdfe90194df386bec988a0b057af032793f01b40dbe68ffb4c535233b12d7221a002d9cbf11ea23e4859540214b88576722c5f3b42b6e3e02c5005a75324cdf17ba37abe02335e35fa7725b1303fd3f4450a701b56f1938e2b1f467bdec6bed4295c9cc27ec9c58b10e3531162e00eb08d52bcc7c69f52645cecb2521e6ceebaeaf700f93d5785688a59f1e26556ede9f2af979effb30fdce03a9f4b005abe5570263acc1548f61634a97c91e66e5217cb5914c227efe1b94644fcf249048fce02a2d6cb547177987305c9d113159dd34770e5737eee4d47259f4b4f320d521dcff218e6dac7f31dcbc9e7927745d31c8ebe73ed8db274f3fbe894d97bf69b2d83bcf051f7494074e9dad7300665b8d469d4c14a10c996e4b46d2b4e42948d78910ab4d108b2d4bae9787800990cc67f5a027ada3e2a9158289fe3cf9a45e75bd97966806c45542350ab9ef124185f4aa972d51cdc7c0fbcf9e28d0ddbc34bef1457dc10084dcfee9ce59dd07ad285735f5f80dc502b3a58eafca9b7528bf7b3c7205806efdbb632fa410d12266e6cb1403986ac4d08d3ee6fe0070b03f87808ded440c9ef2f7d58af172c1", + "public_inputs_hex": "0x1a207628cc6936816ccb62a7b56fdbbf8e975293b677c988644e018fc402e44107940cf3c3a18e9c2b8af0fc91a18c91a709c00a8093bbe606a2e9fd472457bc000000000000000000000000000000005874be0dda5bf3cee7d33e2ac260833700000000000000000000000000000000c484d632fca06937651e18db1cebd2a60b3f37898c93078120c11921f007446ceef9867e6da4e341fb3bf8991edcbd630000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000214b346a1e0b88b78ee55229a563175a39a591790754460f52f2c62ba9209ec682c52b19c6d060045e45222e0d8e0b98f4ed39d1828106df7922a57e9dfb4e3612c171bec038f3c507bc03153950b824f23b8c9bee914c66ffffd81476e3d8274248698204cea2dcbfb2a3f50cad9df0ee2be785bc9d51b32240ff14a38e634700000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + } +} diff --git a/circuits/benchmarks/results_secure_agg/report.md b/circuits/benchmarks/results_secure_agg_micro/report.md similarity index 71% rename from circuits/benchmarks/results_secure_agg/report.md rename to circuits/benchmarks/results_secure_agg_micro/report.md index c9fac38a1b..ea8de0c137 100644 --- a/circuits/benchmarks/results_secure_agg/report.md +++ b/circuits/benchmarks/results_secure_agg_micro/report.md @@ -1,9 +1,9 @@ # Enclave ZK Circuit Benchmarks -**Generated:** 2026-05-23 16:20:50 UTC +**Generated:** 2026-05-27 15:42:56 UTC -**Git Branch:** `feat/1549` -**Git Commit:** `604ef9af71651ffae19546146b78a7940744741f` +**Git Branch:** `params/dyn-conf` +**Git Commit:** `b015a7ed6e5c7c989f2fd267cf14647865854100` **Committee Size:** `H=3`, `N=3`, `T=1` @@ -72,39 +72,39 @@ Single-circuit `bb prove` on the benchmark oracle witness (not the integration a | Circuit | Constraints | Prove (s) | Verify (ms) | Proof (KB) | | -------------------- | ----------- | --------- | ----------- | ---------- | -| C0 | 287764 | 1.46 | 26.25 | 15.88 | -| C1 | 2432074 | 9.41 | 26.79 | 15.88 | -| C2a | 1446348 | 5.33 | 26.99 | 15.88 | -| C2b | 2889001 | 10.00 | 27.27 | 15.88 | -| C3a | 3563512 | 11.07 | 27.07 | 15.88 | -| C3b | 3563512 | 11.07 | 27.07 | 15.88 | -| C4a | 1961956 | 5.96 | 26.32 | 15.88 | -| C4b | 1961956 | 5.96 | 26.32 | 15.88 | -| C5 | 3719555 | 10.99 | 26.81 | 15.88 | -| user_data_encryption | 1678200 | 5.81 | 26.25 | 15.88 | -| C6 | 3001847 | 10.43 | 27.26 | 15.88 | -| C7 | 109424 | 0.51 | 26.42 | 15.88 | +| C0 | 287764 | 1.71 | 28.61 | 15.88 | +| C1 | 2432074 | 9.68 | 25.89 | 15.88 | +| C2a | 1446348 | 5.54 | 32.30 | 15.88 | +| C2b | 2889001 | 10.24 | 26.92 | 15.88 | +| C3a | 3563512 | 11.18 | 24.78 | 15.88 | +| C3b | 3563512 | 11.18 | 24.78 | 15.88 | +| C4a | 1961956 | 5.92 | 25.28 | 15.88 | +| C4b | 1961956 | 5.92 | 25.28 | 15.88 | +| C5 | 3719555 | 11.25 | 26.59 | 15.88 | +| user_data_encryption | 1678200 | 5.92 | 26.34 | 15.88 | +| C6 | 3001847 | 11.55 | 27.82 | 15.88 | +| C7 | 109424 | 0.53 | 29.11 | 15.88 | ### Artifacts | Artifact | Proof size | Public input size | Verify gas | Calldata gas | Total gas | | -------- | ---------- | ----------------- | ---------- | ------------ | --------- | -| Π_DKG | 10.69 KB | 0.47 KB | 3125282 | 176136 | 3301418 | -| Π_user | 15.88 KB | 0.12 KB | 2973001 | 193312 | 3166313 | -| Π_dec | 10.69 KB | 3.47 KB | 3641070 | 187344 | 3828414 | +| Π_DKG | 10.69 KB | 0.47 KB | 3125318 | 176172 | 3301490 | +| Π_user | 15.88 KB | 0.12 KB | 2972965 | 193216 | 3166181 | +| Π_dec | 10.69 KB | 3.47 KB | 3640997 | 187272 | 3828269 | ### Role / Phase / Activity | Role | Phase | Activity | Metric | Duration | Proof size | Bandwidth | | --------------- | ----- | ----------------------------------------- | -------------- | -------- | ---------- | --------- | -| Each ciphernode | P1 | one-time DKG participation (test harness) | wall_clock | 616.80 s | 127.00 KB | 128.56 KB | -| Aggregator | P2 | C5 + Π_DKG fold (aggregator span) | wall_clock | 160.99 s | 10.69 KB | 11.16 KB | -| User | P3 | per user input | isolated_nargo | 11.18 s | 15.88 KB | 16.00 KB | -| Each ciphernode | P4 | per computation output (C6) | isolated_nargo | 10.43 s | 15.88 KB | 16.00 KB | -| Aggregator | P4 | C7 + Π_dec fold (full publish→aggregate) | wall_clock | 186.97 s | 10.69 KB | 14.16 KB | -| Aggregator | P4 | C7 + fold only (pending→plaintext span) | wall_clock | 50.52 s | 10.69 KB | 14.16 KB | - -_P2 **tracked_job_wall** sum (ZkDkgAggregation + ZkPkAggregation, parallelizable): **43.96 s** — not +| Each ciphernode | P1 | one-time DKG participation (test harness) | wall_clock | 646.10 s | 127.00 KB | 128.56 KB | +| Aggregator | P2 | C5 + Π_DKG fold (aggregator span) | wall_clock | 166.66 s | 10.69 KB | 11.16 KB | +| User | P3 | per user input | isolated_nargo | 11.52 s | 15.88 KB | 16.00 KB | +| Each ciphernode | P4 | per computation output (C6) | isolated_nargo | 11.55 s | 15.88 KB | 16.00 KB | +| Aggregator | P4 | C7 + Π_dec fold (full publish→aggregate) | wall_clock | 152.64 s | 10.69 KB | 14.16 KB | +| Aggregator | P4 | C7 + fold only (pending→plaintext span) | wall_clock | 51.08 s | 10.69 KB | 14.16 KB | + +_P2 **tracked_job_wall** sum (ZkDkgAggregation + ZkPkAggregation, parallelizable): **45.62 s** — not comparable to P2 wall_clock row above._ ## Integration test (`test_trbfv_actor`) @@ -114,17 +114,17 @@ comparable to P2 wall_clock row above._ | Phase | Metric | Duration (s) | | ------------------------------------------------------------------ | ------------ | ------------ | | Starting trbfv actor test | `wall_clock` | 0.00 | -| Setup completed | `wall_clock` | 2.79 | -| Committee Setup Completed | `wall_clock` | 20.37 | +| Setup completed | `wall_clock` | 3.00 | +| Committee Setup Completed | `wall_clock` | 20.10 | | Committee Finalization Complete | `wall_clock` | 0.00 | -| Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall) | `wall_clock` | 160.99 | -| ThresholdShares -> PublicKeyAggregated | `wall_clock` | 616.80 | -| E3Request -> PublicKeyAggregated | `wall_clock` | 617.32 | -| Application CT Gen | `wall_clock` | 0.35 | +| Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall) | `wall_clock` | 166.66 | +| ThresholdShares -> PublicKeyAggregated | `wall_clock` | 646.10 | +| E3Request -> PublicKeyAggregated | `wall_clock` | 646.66 | +| Application CT Gen | `wall_clock` | 0.32 | | Running FHE Application | `wall_clock` | 0.00 | -| Aggregator P4: Aggregation pending -> PlaintextAggregated (wall) | `wall_clock` | 50.52 | -| Ciphertext published -> PlaintextAggregated | `wall_clock` | 186.97 | -| Entire Test | `wall_clock` | 827.80 | +| Aggregator P4: Aggregation pending -> PlaintextAggregated (wall) | `wall_clock` | 51.08 | +| Ciphertext published -> PlaintextAggregated | `wall_clock` | 152.64 | +| Entire Test | `wall_clock` | 822.72 | ### Multithread job timings (`tracked_job_wall`) @@ -132,54 +132,54 @@ comparable to P2 wall_clock row above._ | ----------------------------- | ------- | ---- | --------- | | CalculateDecryptionKey | 0.04 | 3 | 0.12 | | CalculateDecryptionShare | 0.16 | 3 | 0.47 | -| CalculateThresholdDecryption | 0.23 | 1 | 0.23 | -| GenEsiSss | 0.08 | 3 | 0.23 | -| GenPkShareAndSkSss | 0.10 | 3 | 0.31 | -| NodeDkgFold/c2ab_fold | 7.16 | 3 | 21.48 | -| NodeDkgFold/c3a_fold | 57.61 | 3 | 172.82 | -| NodeDkgFold/c3ab_fold | 6.65 | 3 | 19.94 | -| NodeDkgFold/c3b_fold | 50.04 | 3 | 150.12 | -| NodeDkgFold/c4ab_fold | 8.45 | 3 | 25.35 | -| NodeDkgFold/node_fold | 14.89 | 3 | 44.67 | -| ZkDecryptedSharesAggregation | 2.91 | 1 | 2.91 | -| ZkDecryptionAggregation | 47.43 | 1 | 47.43 | -| ZkDkgAggregation | 19.53 | 1 | 19.53 | -| ZkDkgShareDecryption | 21.92 | 6 | 131.52 | -| ZkNodeDkgFold | 144.80 | 3 | 434.40 | -| ZkPkAggregation | 24.44 | 1 | 24.44 | -| ZkPkBfv | 3.56 | 3 | 10.68 | -| ZkPkGeneration | 55.11 | 3 | 165.34 | -| ZkShareComputation | 38.70 | 6 | 232.21 | -| ZkShareEncryption | 121.54 | 36 | 4375.30 | -| ZkThresholdShareDecryption | 99.20 | 3 | 297.59 | -| ZkVerifyShareDecryptionProofs | 0.13 | 3 | 0.38 | -| ZkVerifyShareProofs | 0.31 | 5 | 1.56 | - -Sum of tracked job wall time: **6179.03 s** — **not** end-to-end latency (jobs run in parallel up to +| CalculateThresholdDecryption | 0.24 | 1 | 0.24 | +| GenEsiSss | 0.06 | 3 | 0.18 | +| GenPkShareAndSkSss | 0.09 | 3 | 0.28 | +| NodeDkgFold/c2ab_fold | 7.48 | 3 | 22.44 | +| NodeDkgFold/c3a_fold | 59.44 | 3 | 178.33 | +| NodeDkgFold/c3ab_fold | 6.88 | 3 | 20.64 | +| NodeDkgFold/c3b_fold | 52.51 | 3 | 157.52 | +| NodeDkgFold/c4ab_fold | 8.78 | 3 | 26.34 | +| NodeDkgFold/node_fold | 15.67 | 3 | 47.02 | +| ZkDecryptedSharesAggregation | 2.76 | 1 | 2.76 | +| ZkDecryptionAggregation | 48.18 | 1 | 48.18 | +| ZkDkgAggregation | 20.01 | 1 | 20.01 | +| ZkDkgShareDecryption | 28.81 | 6 | 172.87 | +| ZkNodeDkgFold | 150.77 | 3 | 452.30 | +| ZkPkAggregation | 25.61 | 1 | 25.61 | +| ZkPkBfv | 3.61 | 3 | 10.82 | +| ZkPkGeneration | 108.80 | 3 | 326.40 | +| ZkShareComputation | 75.60 | 6 | 453.58 | +| ZkShareEncryption | 124.99 | 36 | 4499.53 | +| ZkThresholdShareDecryption | 98.95 | 3 | 296.84 | +| ZkVerifyShareDecryptionProofs | 0.12 | 3 | 0.36 | +| ZkVerifyShareProofs | 0.35 | 5 | 1.77 | + +Sum of tracked job wall time: **6764.60 s** — **not** end-to-end latency (jobs run in parallel up to `BENCHMARK_MULTITHREAD_JOBS`). ### NodeDkgFold sub-steps (`tracked_job_wall`, per fold prove) | Step | Avg (s) | Runs | Total (s) | | --------- | ------- | ---- | --------- | -| c2ab_fold | 7.16 | 3 | 21.48 | -| c3a_fold | 57.61 | 3 | 172.82 | -| c3ab_fold | 6.65 | 3 | 19.94 | -| c3b_fold | 50.04 | 3 | 150.12 | -| c4ab_fold | 8.45 | 3 | 25.35 | -| node_fold | 14.89 | 3 | 44.67 | +| c2ab_fold | 7.48 | 3 | 22.44 | +| c3a_fold | 59.44 | 3 | 178.33 | +| c3ab_fold | 6.88 | 3 | 20.64 | +| c3b_fold | 52.51 | 3 | 157.52 | +| c4ab_fold | 8.78 | 3 | 26.34 | +| node_fold | 15.67 | 3 | 47.02 | ### Aggregation jobs (`tracked_job_wall`) | Operation | Avg (s) | Runs | Total (s) | | ---------------------------- | ------- | ---- | --------- | -| ZkDecryptedSharesAggregation | 2.91 | 1 | 2.91 | -| ZkDecryptionAggregation | 47.43 | 1 | 47.43 | -| ZkDkgAggregation | 19.53 | 1 | 19.53 | -| ZkNodeDkgFold | 144.80 | 3 | 434.40 | -| ZkPkAggregation | 24.44 | 1 | 24.44 | +| ZkDecryptedSharesAggregation | 2.76 | 1 | 2.76 | +| ZkDecryptionAggregation | 48.18 | 1 | 48.18 | +| ZkDkgAggregation | 20.01 | 1 | 20.01 | +| ZkNodeDkgFold | 150.77 | 3 | 452.30 | +| ZkPkAggregation | 25.61 | 1 | 25.61 | -Sum of aggregation job tracked time: **528.70 s** (parallel CPU work; not P1/P2 wall clock). +Sum of aggregation job tracked time: **548.86 s** (parallel CPU work; not P1/P2 wall clock). ### Folded on-chain artifacts (exported for Π_DKG / Π_dec gas) diff --git a/circuits/benchmarks/results_secure_agg_small/benchmark_run_meta.json b/circuits/benchmarks/results_secure_agg_small/benchmark_run_meta.json new file mode 100644 index 0000000000..3c2d06ae3a --- /dev/null +++ b/circuits/benchmarks/results_secure_agg_small/benchmark_run_meta.json @@ -0,0 +1,14 @@ +{ + "benchmark_mode": "secure", + "bfv_preset_subdir": "secure-8192", + "committee": "small", + "proof_aggregation": true, + "multithread_jobs": 13, + "verbose": true, + "nodes_spawned": 20, + "committee_size_n": 5, + "committee_size_h": 5, + "committee_threshold_t": 2, + "network_model": "in_process_bus", + "testmode_harness": true +} diff --git a/circuits/benchmarks/results_secure_agg_small/crisp_verify_gas.json b/circuits/benchmarks/results_secure_agg_small/crisp_verify_gas.json new file mode 100644 index 0000000000..9150b2ce58 --- /dev/null +++ b/circuits/benchmarks/results_secure_agg_small/crisp_verify_gas.json @@ -0,0 +1,107 @@ +{ + "verify_gas": { + "dkg": 3136885, + "user": 2972977, + "dec": 3646908 + }, + "source": "folded_proof_export_plus_crisp_verify_test", + "artifact_sizes_bytes": { + "dkg": { + "proof": 10944, + "public_inputs": 672 + }, + "dec": { + "proof": 10944, + "public_inputs": 3648 + } + }, + "calldata_gas": { + "dkg": { + "proof": 169980, + "public_inputs": 8448, + "total": 178428 + }, + "dec": { + "proof": 170076, + "public_inputs": 18456, + "total": 188532 + } + }, + "integration_summary": { + "integration_test": "test_trbfv_actor", + "benchmark_config": { + "mode": "secure", + "bfv_preset_subdir": "secure-8192", + "bfv_preset": "SecureThreshold8192", + "lambda": 60, + "proof_aggregation_enabled": true, + "multithread_concurrent_jobs": 13, + "committee_h": 5, + "committee_n": 5, + "committee_t": 2, + "nodes_spawned": 20, + "network_model": "in_process_bus", + "testmode_harness": true + }, + "proof_aggregation_enabled": true, + "dkg_fold_attestation_verifier": "0x7969c5eD335650692Bc04293B07F5BF2e7A673C0", + "multithread": { "rayon_threads": 13, "max_simultaneous_rayon_tasks": 13, "cores_available": 14 }, + "operation_timings": [ + { "name": "CalculateDecryptionKey", "avg_seconds": 0.059818383, "runs": 5, "total_seconds": 0.299091917 }, + { "name": "CalculateDecryptionShare", "avg_seconds": 0.159473866, "runs": 5, "total_seconds": 0.797369333 }, + { "name": "CalculateThresholdDecryption", "avg_seconds": 0.231732417, "runs": 1, "total_seconds": 0.231732417 }, + { "name": "GenEsiSss", "avg_seconds": 0.156219799, "runs": 5, "total_seconds": 0.781098998 }, + { "name": "GenPkShareAndSkSss", "avg_seconds": 0.313501966, "runs": 5, "total_seconds": 1.567509833 }, + { "name": "NodeDkgFold/c2ab_fold", "avg_seconds": 11.847578675, "runs": 5, "total_seconds": 59.237893376 }, + { "name": "NodeDkgFold/c3a_fold", "avg_seconds": 169.184619283, "runs": 5, "total_seconds": 845.923096416 }, + { "name": "NodeDkgFold/c3ab_fold", "avg_seconds": 12.817567216, "runs": 5, "total_seconds": 64.087836083 }, + { "name": "NodeDkgFold/c3b_fold", "avg_seconds": 151.491728074, "runs": 5, "total_seconds": 757.458640373 }, + { "name": "NodeDkgFold/c4ab_fold", "avg_seconds": 10.847684408, "runs": 5, "total_seconds": 54.238422042 }, + { "name": "NodeDkgFold/node_fold", "avg_seconds": 23.955023783, "runs": 5, "total_seconds": 119.775118917 }, + { "name": "ZkDecryptedSharesAggregation", "avg_seconds": 3.327329542, "runs": 1, "total_seconds": 3.327329542 }, + { "name": "ZkDecryptionAggregation", "avg_seconds": 60.962331541, "runs": 1, "total_seconds": 60.962331541 }, + { "name": "ZkDkgAggregation", "avg_seconds": 28.085369792, "runs": 1, "total_seconds": 28.085369792 }, + { "name": "ZkDkgShareDecryption", "avg_seconds": 61.25314797, "runs": 10, "total_seconds": 612.531479708 }, + { "name": "ZkNodeDkgFold", "avg_seconds": 380.154250233, "runs": 5, "total_seconds": 1900.771251167 }, + { "name": "ZkPkAggregation", "avg_seconds": 49.192114, "runs": 1, "total_seconds": 49.192114 }, + { "name": "ZkPkBfv", "avg_seconds": 5.465944433, "runs": 5, "total_seconds": 27.329722166 }, + { "name": "ZkPkGeneration", "avg_seconds": 67.431268691, "runs": 5, "total_seconds": 337.156343458 }, + { "name": "ZkShareComputation", "avg_seconds": 50.505588075, "runs": 10, "total_seconds": 505.05588075 }, + { "name": "ZkShareEncryption", "avg_seconds": 112.371622883, "runs": 120, "total_seconds": 13484.594745965 }, + { "name": "ZkThresholdShareDecryption", "avg_seconds": 133.8429849, "runs": 5, "total_seconds": 669.2149245 }, + { "name": "ZkVerifyShareDecryptionProofs", "avg_seconds": 0.290990533, "runs": 5, "total_seconds": 1.454952667 }, + { "name": "ZkVerifyShareProofs", "avg_seconds": 1.076807577, "runs": 7, "total_seconds": 7.537653043 } + ], + "operation_timings_total_seconds": 19591.611908004, + "operation_timings_metric": "tracked_job_wall", + "phase_timings": [ + { "label": "Starting trbfv actor test", "seconds": 0e-9, "metric": "wall_clock" }, + { "label": "Setup completed", "seconds": 2.8164285, "metric": "wall_clock" }, + { "label": "Committee Setup Completed", "seconds": 20.127044, "metric": "wall_clock" }, + { "label": "Committee Finalization Complete", "seconds": 0.001253209, "metric": "wall_clock" }, + { "label": "Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall)", "seconds": 400.034844, "metric": "wall_clock" }, + { "label": "ThresholdShares -> PublicKeyAggregated", "seconds": 1669.469802042, "metric": "wall_clock" }, + { "label": "E3Request -> PublicKeyAggregated", "seconds": 1669.997398541, "metric": "wall_clock" }, + { "label": "Application CT Gen", "seconds": 0.304409375, "metric": "wall_clock" }, + { "label": "Running FHE Application", "seconds": 0.000809917, "metric": "wall_clock" }, + { "label": "Aggregator P4: Aggregation pending -> PlaintextAggregated (wall)", "seconds": 64.513878, "metric": "wall_clock" }, + { "label": "Ciphertext published -> PlaintextAggregated", "seconds": 205.700746333, "metric": "wall_clock" }, + { "label": "Entire Test", "seconds": 1898.949991209, "metric": "wall_clock" } + ], + "folded_artifacts": { + "dkg_aggregator": { + "proof_hex": "0x00000000000000000000000000000000000000000000000f8cf4eb44ea7bb973000000000000000000000000000000000000000000000002fe6a2e9f65b54987000000000000000000000000000000000000000000000004cb9cdf5f722d0d31000000000000000000000000000000000000000000000000000120dd7263dd0d00000000000000000000000000000000000000000000000a7c765c503af0ca8800000000000000000000000000000000000000000000000c438e0a1837d19462000000000000000000000000000000000000000000000000fe6a7967e27240350000000000000000000000000000000000000000000000000002ed1b06d5e46a00000000000000000000000000000000000000000000000073ae7e558975da6900000000000000000000000000000000000000000000000b40a9060c3659b72f00000000000000000000000000000000000000000000000271a38c15d43fed70000000000000000000000000000000000000000000000000000159384b1efd6c000000000000000000000000000000000000000000000004b79f2d04172cfb6b00000000000000000000000000000000000000000000000831e8bbaa05d116b400000000000000000000000000000000000000000000000942afbf6aa7e7798b0000000000000000000000000000000000000000000000000002332f302695aa1682b09c868798d9b80459f108450027d8b7e34032a713a8f0f5a51c1d3c161421ad456a75c6872dbc5ed9cc8562afc387b6d64df0218debb3d3bfd3c8a18b4d2dfe9df17302f9e5b42959bd451047d6e6d232e589db3b06a3184826472d70dc108bf072502ec19531b39949e5aa2cff83796033315791f2e3e9cec19d880aec1bf9af6dc3795931b567b91cd9187ffc1d59e2bbb0ea5963ea0192cc43bf3e710f41e632e8ea500c510870f4482962d448611d964d7c1017bd3893923b7fd4c2208ee98b855d511584781bdfd7bc7010a5c7c56a5a5b256bd052a906d81c48db175bb09885e5437fa9774c36e0ad5cfae43ffc9b0afcca6c68b0fbf991d9e9e30f14e2b1bac451200f190ea0417688be9e9e7326ba36aaf30cbf403cf7a3e36a033cd178d883aa7126af75245f5edb60b8077181b8f97a60d8f0268724c8a97e2a13d2f0b35513703c939ed6c63be19a4ad007a30b0f3ba65067f50664b364f018eb0329e6f2875a150d0142d7136d839186a4761906c494891a0b54021524ee2b8f9409866c5e0896f2f7b98c44aec8acf5299f4605d308e657301f0987109b114f608775844e74b54aad341abdd8b483a965b840eb8a09586605c74c9fcedc2fc3a34aee8e9b3ccf6d489dcfe2df004342a8111589cf1dcd23d828a059de700fde0b1012a7dc4912df91bcb908258a79c863141c092e2e7c871cdbe4ce658b178e3ed9471fbeda851d23cc5516b0c925106d1a96b03469c336af0d1c93dfb81d9f3c8e0e6b7d9877c0291f7063f4aff4767be58df30d0ba7cf6cd887fe62da0c35d308e50ef2b97b0c038fac5c962ca7b93eca3855eddbb47ab4da6f42e3ff0fefa9e4c64879b112311f2504b5800e961a4cd4d519f5dbfc751048376ed4d625b05663d489824178cf171a8001b084fd7a8cdc96870f1914ae35ec0525600b22086c87843a73afd95f57f3197e11e4f8b4aa1279ccedc39b19ce30e195bfa121e8cbb1c2253a644f3c40a08b34fb36aab9a6a4487371e0445647e2383d43d51df61b7fed26ac4468d0b09a5af2c0dd96be4d8b88eece6a840e69626ecc8c3e1f535e681d68f7e4db85d0b7836721660c53bb50ae39285454e13dce7eda5bca09e63b630ee447041e02022b66b6bb043923f20ff0160aae10e63910ab8497ae1f856fec2a2e5cd9f5a4665c808372dafe8a7b29cc542904228984c059241b5126a9d31a4b9bdc246d0d1d57e2bd2ba5a5aa64c6bdd85d15838f29188e4ff6fa0c677776b475721085d4811d1dfc89939ccc310d3737579be2c80beca9b7c8e427f1d24d1ec75fef9748e80e26731b09b708336826b274d44a87a77da07367d318cdd42c458484a1da9aa86f3a86d5712b5f760a75fe29d66a9e4a71c44552bf2b7c4b784097c3c4880a04b51b438b29f715f596b5e69843983d28ba16ef9e9a2ec90fa646ad8eef1b55a2a114199e3e5e33bd941c4196b654fe8b827654ce5321a89d763c7754c6234e4015d0a55d2ab9641614edb8395cd7ba18eb1b7dfe0f149ca7a39e880fc1a864daaf822f8b237f112d8d59eb993fb49ce75f12fc9a8f2b7b797b534986b38964f3c77bda62cc2f8cf329b457806fa5b0d9cf7aaabb2419161b4b8d4a35d3c609e1d0d45cb1cfa796ab1273ea177c577888b2f5ace9c204a5d4ae630b6885ad89cb3844d7860ff0423cf6cf8329c0d7f27c990db3fb882457b618471527753abd61adedfc6a068edc792c7c5d26661b5002e9bce6bef91fc14bd2149e1d8487dc51620c7ea7243f2ab729592f4ca595dc60c74426717a0226cb14a5021437c020ad312030fa0cf34beddd06e7ea342563dfe2ce64a1b11f28a59a53732754b62297ca0c280949393e00ebc1d9b5113490ab370062a3510b7c296fbe4d2e509ea850fdb0c50631ffce02b6362e00b8d363b3086dcc34c31dc69a97c93d2f5cd3cb491511d9eb8aa6d09edceed0a4aefd633a3cc4fb8cb602222d2d962062a89951027c580823f7a54236adf185a1a51a7716c6851378da0cdbeb52e7e08aed22fdc09e687e79d5101542088ce0d38a7e1d4c898a6b573c0ce3bf102237bd0d6178fdb1b7804915fae9aecdb5cd66a7b03e047de559412b2d38e49e554cb25993f7422f0876f7128c1e78244511656cf77af02a0cd9e91401aadfa2577e9c460e4f37818c5fd08fadf6d8feb5d186e0ce7fffe1e96282fc16f929180250cf6e04e756103cb11a94f527d10e7152d9dd898de648dae773f815f071be728e768086b8d8ddc3a24c6310b636db66b6edfaa79454f456f8a63b22efaa28d6079b861677ae63c9be81aa53f08cf522823dcf77b358a3e73be85417ab64897fff7840a3c81a375d17138b77597f8ba1de3fb81c04afdbdeb6c70e1d75741eab64ed54ac88a00c82fbb83509f53f211ec80a53c7f9f929d237546a1f04592e0ce043b501037fb064072351c7110a5354f882a5f3438beba7c818a80526b7287378b7b02bac41b8dbaa535a7ad36576a5dba5ddc8eb9a57952ce9a91181f80a457904433cb2f4735c2d56348fa8962fce5e030a021777799fc7a9db0600ab5818ca2a4157abd6cb9aafdfe1a76cf6f853e578885caed79b04d9dbd002b5e7aaef46d81adbf2c3f726371ff2dbbf2908656b28b54027174e0314fed21fdb1f9f4f5b721065972e8a15e21685a1e1a089bccdf1578ae75a26a4cd76d921d5f42ec9cacbd4d07535cac21e2fbd05433f9f3a18be2b6b01cfe96e8ec15b269bffdba83eabed4bea3eca373a402b2bea20065a6ce1880ff57d22a591249a1b488a56f4db4ac84a88cf6706981492618fe93c037c4d40b24ee5b151486fe821ab713f4e3eaa8a3f1af81d701bb75771d5434485562b8d38f236fe57ff1f9c104145d00e69eb57f7eab51e67bba351430240d039cb677bde6e6f2fa77642bc200319a8dea6735aca2d7a682003fe8150812aed472eeba46bcd8c0cae9aa9590da57b0d4271354277a1357bb93b8ed003a90cac91366a1561fb20fdc507a0360ae18d51eef2886db725890bad5ce1985018fdf064b72c6851119dca94aae60b1f28dee8ab6508311be986a3acfdd81422838e4a1b54ae7d85f73f2fdd7260471a8b6e012ecff6d3c51b52cabda738a0df4618b30b719d5f4fe8b258fea7589e28894748a5d6e0f6861e90b8e67866b055089c3e4b6602e1541537bc39c4509c18796a05a33ac38821d3fdf11540e1d3658384f45ce5438b05d720312b2f09ed2a4b9a8afa0b289cbb84df58c22e065fbafb6d7a1c00fa00dfded916976769f60f62d9e67524aa0388e220f1e93b5735c6a90aad57cb9ba38e7d88cc74137d38180c1a2df6459e7f0aa21562a68b91b825fcaedfe7463d19393094fc6c4ba6ec001bbf4b689dd55c592f244bc5bc7490360441f412a73b256def2164051539d6043e38cbff1cedc18a9aa2f8896b688671e9a7535fb5fa9ca2573b4d079c1e100e2b3f9b73e2a30ce84422bb96eaad707c461078f7531db516bcd027702c82a21c53fe5709550a1037abdbb0715eecfd8a71f64aa5dec3e7df1fd7074496534e0d077a0e6f2179e6c159600c0611dca8719901ba76150553546ca625122c96491ffc6e0372529455bb468f79b309f613b589576015b8e5df9091047ab3e9bbe407883a58019032c61a315109f7cfc60ca1b162a2129d2510a461140c48777ed42aac70d7a5d1564e92f8376c6631c68b53b942555db5af89d0683196029500ae21b9114997061d126a66d39f04a3207b7f979a5ed9a0e07153cb3b6999cfe39d18fb0bc43b87736d69768d162662dc5676ec6303c3bae7046bfb53aaa856353500d26528623ba1e2b96ca0b794636b19ae843b80674371543aa5bb5c9c12d9d624816dee09cea3ac10a450349dd556cfe0b6cb3aeb6bf3d0cfaf8e773346c83b1318851056d6d268c9ae3a7f81c15634283ae2c80a279a0654c66748caf0a3ff1fe384a9610f357139f9f10f50af50ae44566a66eeb779206d02b482775fca152db2bf3ff68b269bdce69272b7eaf203d957201e3f7a77cc6d082dd3155692292fbceb5ee42ecd18040607684cdc2a30df4647c3769b11f248118a9b16926c0225f2d136c04fa8aec89ace848062d98b2733ead5abbb86e47415eb7b706cbe172e445488a5921dcf7b00fde2957ca5985858ac613a3658c09b7f8c49855cbbf407972d2d7d02e77ba1af60ed4ca833ca94ae90d16b62ef16a0e16e92b515824a033dfda8cb5b472cb415b21fdaf0a68cb55fc957c4b170a588648f5af8947aa81640f89ebd26e164a95aa84b3ca629f5c852b7bf41032b3f50b100ba452945dd02d098f8cae107d21ac95c720cdfa34f68902deb208ddb631bf8ec45a4cdcb0d02c9b9f04629fa45e016f42ea1b7c114212f08eef69ee4cd9dae331f8bb370aa1b3845c84eed88741ec11ad341a8bd2749d2b13195d7c02d890938e10fec14e51564fd177aeded08e90323e208ad1267d50ad5ae493f416c43196dda4eea87b828a28e93703ac0ae95c8a8014ea151ec1471104b75b21351578dc7aad638c5412bd99a63b19b1da253bc2107f7e8b4eb7fc5dfc61457e8ac7381693c3e59567d2509211887cc1ba0b9f0497052e8a8662d2f3187dd2a0f96485c606e7dcbb2e413392610ad2440026831551fff760ece740c26af9f2c69c288a7a75f7107b56b2709867b0e96087e99336e0c3cbb27b6ee59112d541000bda27643a992bdb64722831b803aa8bfaa372e88fa3a6a1d2280dc5621acad38514a9d6fbbd1f7cc500fd872c5ec9d6ccd74b0f77013442f08abcc4cd3299e1cbf6d19a154e205b1620e34b6fe0705e7774fa60307d218defe6b489e8631e7e45b84fceeb0df0fcfae048bc55c1922199a0ea0365b83702fbdbbaaf68b8c5319c9265f630bc5353ffa162d02a4f75a0f05b25e65788dc00c393b8441b323fc74a8ab4c9d125f90457e180a59c842f6e1c2ac90698b07733b954724098342f1ca8bb6715576aea2defe08e98494d0bd897d1f630d5d0e3872ccec2f6357f8901017b352ee3637c4960306e502e2b781b17372b08827b3639076643aa83a754dfbdebe64e9e58d4203480e0877c3456b04f057d52d1caebf21a1c6efb523d9ce78aff2ec71c675504cee2cd77d623a9f09a241d38a26a3ca59a521a8dc22ee304838f97ae352a721fcf607b960758d2970f849b37aaba64d2795405570433bdc3693fdc791b4d25b837d2f3e1a611cdaebe5071905b723a70a9469edc5225484a806d2d1ad86df2758481b3d5a6ba262f76e0c42663ce543ea49eace1c0ae9a6a45f247a7c267ce2d2be2002337e07aef72d17a1594e7e27171f08017cc067e59dca287a61c7b37687f711ad81bdf74060145d2a4bbae427d2d2fbf8a4926338bf97afa40b87de4b1b3f04352c6e671783e41daf549156c01e95ec1c9e294770e34776f89f516ab590821dd34ece728c26fe3bf8d5758e3181a882b5847a8d49fba164bbae46849ea1ad096561db5c553a6b3b0581693ba295bf258be7fd47f7164f18ddd1626c9f2f012bc3cc3bad66bcc6e88436590edcbd82cd17d02800e664f5bb417935d5c96b561b2ffb65c5a9f8ec9d0e1792a95ac9220200d51be059d46f3b035b875f7ccc65178ff7b1198d38bbebccca0f7f7e8f3fedc27eda3948b47d8b54aee682f3b64617c9a4622543660da65201488ac25a30c756d3d7f9f1d0c5c80c4fffde42bef61090f6a01ef9e9ec31a1b724ba21192e1512fff832f6917d93f4cc7ac25bd32f24df54d405c3d87a41ac1a590ee40b1abf1f0de5834bb26256b68e048da10bfd001482c637ab4572e53b0e794a2f6908139ba237b81394bce3bc6afcb9c684ce279cc943938fcb26dde13ad80910537b1b5fe43c6d60bb339d40e5a40215739a0b1005f8bb6b0189d2fbe89a5b00b1b543238e7fbc7fcea521d0e1fae0f9116618b248d8d4e3072bbcdf0b2fe50607ced2b67f89bc5d046f837e3f2715e9775701da2355354f5c6ed2fabc49662208d7b7452a129b9ea299de46e0cd655453671c821652dcd2ab87ef2e61cb72293aa27b5fdf95017a94fdc4bb5e8bf8fc39f725fccfb818685ad276f5df10db5f3873b2f8562c79d977909e1b4743922866d902a652d8a3b57afa097b51b78ea574c466a13647e94d42c129d97ddcccb54b542a3ef4511ed8e06217823e2eae64ae32dadb252f676827e708f65da94bd622ca0cc97c714ca3905980a4f55e35f8559b0b376dc879bdb801b68c0dedc44e53682f78c7af9f48c5a3a4d936af5117eae715b5d9d0690a5946bb5f76dc226bd49b0a116f5d01e49f8f55d351b2e9cb60a96426985e48accb388fa1c884b011341415b2cb90265307152ace284bb397bc3d86146434d6814f68a36b61a05f7c5ed62a4c5c6fab4c22fad3d73d3cbc74f0ef00a513f7d9aca5635505bf82bfc6a70525bb597fc69e219b7d72dfc1f11daf52850c0f6f494373384c2995e74c518f7e0dd35dfe88b3febc99ecdb7a643c09bea95d8bb8e2c9c2483c4d7dd4c22a13f919f02b199b339fb250412c9eae6b785fe36cdf1c2805c5b8c9321720370aba270764a45048933ae256fce1790638eaa43073118e4947185020f11b01f592dd002aaff0025762ee2b02e665d7cabeca7cfec6a9a8c98e27993d878ed4f60dfafa2aada3b27025c0bace89da4d121353c04f1f31b4a5e27e548344ba501a95a19b1deb7337e7ace684065c4b7852ccaf33cd564080094058f840fd10af1fd46f2a1517e323a23c62f5b3fae6b841adb4ac330ba581fa047b3b842a2aa40089900b1404b57576a411243ab4b7d63a0c560bb3a9c37464c27037b5a3a94f288b33db2a1ba702b83cbc4e1c6673ac8e687416019f1fd156dfc5919d4da977becce88b026229566e127838c6ad037cbd46a8c3ae7295dd4a6a9ad307f0ce6bbe8003e915593cba42b17949940cd753cffee93ef1978aaa214eee88a7802d9168dce4772b022c0ad7ee08786899d13d958d311e9aca8ae0591f3dd21be472aab41db23115b775053084283bc5d8d0c88ed1bcba7ae6b389b001b6cdffb3fd4bb99e47702bf294f20eba8b2694d2626dc7e5e0aba944496988a669ef2b26300692a689d40bcb1efb3e396b2d75219e11b852d18a358f117413840e23cd68e99321fccb7a256b902e1acba57023b193f41fe5b16741034303534ff42547c3d6b366cd29ce110263c3d812fa8d4be863b63a245903347d9ae3278e5cd0d8391d9510ec96222e0a50840c6e02c3cd831731ede6929e3d2cd7301d9017be2775cf1307f4f81a14589f24b785cb8c80354f811a38c7d0dfbb175c1223b9394501bcf2701a98692004a787961c23bd5cc83ca31c6979df58eb2bf72bb5245acf6730427ddd9ce2078c798d75734619ee5fc01c550f8bc26c05ba9248fd21885874f8bf3959ebc012ba20af3955912889abfeacbb17efb14013cdd8e79b61152c9145ae7c1cfa2e2c847c046d2ad74eee19910ff6643faa6c5763a0d2ed0022f50b11aebe38d7ec0837446cdb3d84c7dfe4b153b3a2e6ed2e6c42cf57c0e5109581ae882ed7c9c804b85a3fb7468c9db5db232b17acc83bf928d3928ab67d0f71b673232ff50ff8140756140b6eacd949e5771d8482f5b26261b5df04f38b923f60d9ac9b6192d3136047faf725baf1408beb5ec71752f89f7330ee60a842ba372ea58f0f0c238d284fa9818fb94f0323be5dedee392b7d034e1322b90aac38a9eab3e4854d5af82efe40526d62eaf14028de72b50a2d5bdef706474c945f7ce29fc469121a982b0b27424460ba39bead9d9ab64ad650ea35d0d2da6479dc53d36771d5cefa65de00a8aed65fcba7eccc5bae30bff27b7accf17575147286beca6f8db5d32382611dfecae871564aeee4b8b82b3879508245d363c523fd54b460492a1733b998ec0c2c5b3eafb4ab51cc3a6641d7afd108767235107c5326cdd627fbaa7346685221323abeae65f40678a6320eb1db8b2fb6e719f22f42059f049095c46b00cd4602cb6d3f08602a61d96b35a318ab2031fa422edecddf04581779972c1473730417f60bc84942265911d86d6affb9621288585b5bddec0a0be9686bc651cf95eb17400cb285c35bd85d198dd9f5d8874544efaeae5cc9f27a03359aee1b1a1a4e0dda704fbdf9af9389fe21e342e995778a0134d0c4c348cdec8e0fc1d94377e51598b96a5f97fbb81ae4fa7a3cec37793cb59ece462e39f7f2d8c9f66392744012244b522c41207a0db8649da6e085a1b331857a8520166fceea86bab7a3ed9313fd0bad2a0dcc83fc7139b93787be412eade7af7c89259079037550a43778452cadb8c2d5ffa4afa1d73d0f9984c3c921b51964530e1d1a82f87b6310e054740f8c69aabf9a9392bb26efc05a7acc12c453517b25b8eca5e159b75b72f65d051807bcf35c918ec2601bc2e135b6596315f627aa75399b93643141e78a11ef4917097ba3a32f23a48ed55f7012b79a1ac54fc813c5875e32e7526483e3f06548143e7a553a396d2fbcbd28c83ff13522ef8462c1e7ebbcd52169fac9c474ab4804f7103581731d0332925b62674f496fcc3ee9dfe9ee25eb8d0ca6ab378a300e0b5250f2160baea730eaff92a27dac2f08f8d752be32e1077a3430180214d15b10059503004fc2da16b9179202b1afb4c15a288af31c364033c3234d451f70c40fd13a566fe5d11e54a3b9bd3446676330bbb6eddcf087f00384a5f16050e0fd27147a9aef6114df318e35163792ee8093c0887c73ab832f405b64e58a46c5b303d6c9dc4cafef1b5db5b98b188effe25a31b0a3449284bf268576cbb58af4260e990f595a7390946b64ab7af90903e83ad987ad7ce5a2adfb1731bcdb2d907d1160e18f81d234c75422830245afd17a155737e2866620f8dac2b7eba6fca8c600313a019a45e414a261fdc423ef6b6642fa8fd3d15a6700057e5a57b0dcc50a1f5f9d1cd1c01e4859bf98715370390f424bde2932afc1c98adcb237ee5fc08b0b8c5432e5c131d310833bafe8860abd0455d7de8679ebc90e2dd0609c0071572299808ccbe8064e08fa4e976ca970262869972fda098faa9b646c19021dedcc1f65955d1ad5da522b2fdcb142a0d2ef1e7a3a2cfe418edb958fb53f18241db92d465e20f6f851f9ae0a156c22c89d26d09075c4aac45e0ea0662f6a018b74c5159f08474fda3a9c7ee549318100b55bffc8dcec15a535ec62a688dddc6cbdad03e529bb9869497cc54d9e8e39f0fbec222b9ce84a36d9e58d05cf0adbaccfae272b3984053c38ca321a350b63482893b15ed5cb60a5b16e82572b3365db06a40797b2553322c5124325755745250d54928b6f089ab26967a32f19e4db2a951c1fba3bb3fb2150aaa39cc0d1a85389403a040eb628834779a649bc02539e1a912fe457b6c5787318b33f23ab78ea50b9923cd0f945f9263b28897ba8659c7cbe15c064eb89884c8921389b18069775c728866a1f61972cfd4c4c90e196a147c10b16cfd4a6967bf1aa06b1e7d083fa3c2a9e6a92b979a4862ef6afe578d985b1038e222d206f88d03ee1bed0b56b456e3b638c5fa335b273032af7a868262e012ccc5994daadef166712a114049499e2b6b2aec2581fb7d494d5918683a5007b0482cd1d4b1bc998b6151c299b62fc530faaf63ea54abdf345020b127ce53f912b1ad6c886d57f6c2a5ef0ab54f51103a998794859791cae76c1eb75269d4046277fa14eb7542eb03aed1a898a1bce9663fa930570a5dea6829990cc2e3ba8811be656c21e2dbaf61141e5bd746faf82a16705498e8d97479337a14147eae99900c8c7ca20fea54a4675f653dc880f7d8a72cd47329c5d448ff4df9925daa2bc2c2ddd7a98ca8799c8096758dd9ccaf66634f05cf391c6d05e9055eb159db94f29ce7e5fb6330e2afc8da4bda2f8ea401b099360cc7e7afc7e69054c008837250b87ca67aa7b8c34cd119ead62bde06d6ca2ab1362311e0ee5478aaaa417bc022ca6a91c85d4590d74ede6399cc3f4472cd2bfcacbf2fb6d418e4ca4e144d1fc07c207d8c753a5f9d3ddf3a0fd91bed472a460d857a80c8d4b4b80621a821fc6050084ea350b6aaad2080fd12ac01b78e21d6e83b49fb00a177e8730728f9109002d6e4faee663c76b3df3234fbdcd455d6634366b9d766aad9d15fe3eb84fa404fb261913768d1b9c20ef14a13104090c2a6e58500b09de45a44ef81a5ee3d8005251ec28110ef1aa5250e899c86efbb23c86479cd91ee628e31b30352a242a2c3e59104e63809d99634b58a363c7834ba5210d1841fbd8de5daafcfc2f9c890f91bc9c661dae903de8b646a122adc92a7e661d81e3f1e12b310c91b4a4e5f726a56a5261d3bcd4ce400d39f7ad167a63d04267fef7e4fe489e93e90a43f2680348b307e0bc58f24d6d4af797076dfa758726dc8e2c95631c39a002eb62388f2652b2b578befc62242acbc58c28859b2be225d3f3875bd10fa16bd857aa179021c0a999ead5003e0df2ddd90585ef1cd1b85e28d40a423c3141bd2260634b4e0494371e2d406c39895d2bc4ccf823a25ca2247c5e8dffe41addf4d40219043a0f8d3c338c53e68cb53b95231a9efab53fd6a3430ffb4633c1061e8a8abde34b1151c4e65bf3aecddf6e83c6a55b8acb37bd200b1db884d3c277f5cbf8573fbf098e4f23575d6d4e0ca088b718c592192c2b6a2eb2d78b9f773a3a476c0b110d25205bfdaecd530a971fc3fb229104c6e7259fed783694adadd557fedb4894ae0345b5b345a1ecd52ce7dff2b27eaf0c699aff68e1f06c1abb734daf81932d8816b43f3aea81b233ec33d0a0ab15bffa9d32240ebda4fd497344e55c35e56473133e41fcbbce8d172762281828ed8fed593ff1ea6eb711df35fb01d61cfdc2fe20faeee0134d91e60953e71151adf5e180b8ed5076779b63259a10b415976f9e2898bfcd129061351321d89760c0da2a56ab37e0025e0a83e4c251920c8b0ce61be4f8cd54792a512d193869c11c4e51f698207c1c80e507ecd3a05af9d56b6d26e77769c5fbafcf610255c2fb65c81887944d4d6db30e885fa87b1c4cd23a4715fe9965afe173636dc1724c6ddd7ee52901b6996e48188c555f7aef66bfc8411248015534059bfe3d6214ad93ab052d0c6cb72233c67f190be26e04d91b164c0249d109b4224a90a699583c104db3d9ee91061a71efa00f4b3caa5a3b77da472a2a87f50f6c2ae8a3f258449b62008474045806dcb3273031db418e079277a01e808b86c1e5eb913a504a9159ec365e56f8dc92425378f117d09f78caa81a792ea83e12ee7637fdbd98dd49f43916b143ad6c8b5acdc80ecd2fdb11ebe25acd0abc429231a8c1721cb2285de27f7d5efc412d195c7c038137b4ee460bb73f6126391658eb5c07447074a37ada33f388c3b6d3a97e7a1948cdcb456c972ece361820c2041c104108b9323864d7ab030ee8c81b4d7f7bfe13b72394dd1be3bc8227a3fa9c452a8599d24a10ca420a0722667d8fb5cb8f7035ee36a3f6e80ced5601c6c1babc095ded8f037bf6c49644dcb67dbf9dfe895aceb7a03d44faafc9ba180a4f13b44e01e41cbd911af18446ead17edaf20d95125f543f4ce384c56cbe099f42753e88b53ff2080c6a9a3bee8c1afedc2626612f092f1d5c6a7d38eecb1dac82b0725bd094f8bfc59a84d3d5e97813d2d8997c09b80b918dbbef0237f42ced7f609f50632afaba049397eeb8487baffca713fe54b66102790c801d5b40280c740f26d9b50a581ff91836ba7a6583f74cc2d01a99b908d9e869daa0c1cc2772966b46f4647a9b556fe5dcdf6b779191f6590a175c4ba4148aaf5126fe4d20495503aaa68c53fdec0db78b669ab31327d8d58efaa3624af26cf2ba298e1e0698c8d2bdd12df70932e3fcea5855d7595aa31d9aa3211e3b1a3a89002dbf7723e5b69005d825fff1f8d43390e5698327dec64e4963307d230ea41089cf77dd0313b52121b2235d2fc288d50a9914d3cc3cbd54ce4e41a0b1dddf9c8f86e61226bae62c6f0364778e9c037391a16c8a23cead8ed29a4fef2bf53fb3b3608fa218607dc97dbc236e3aaef81bfdb8eb516444cb361306411dab415f828c7a9c2b2918861b45136294dfe194a8789ffc0901255e214545a4ebcf4eea444996488e27eb9082d232bf4da14ce3d2d4e31c99f8e11854f31933e9e7b3e4feb81a338f04270a8aede63a8181e7415bf0d8959c97826aec25e182d940ffb7c728ede3e222370bd7f558924eed74cd1a1aa1d92124d5f7aba040d12889c3747511b73b08285e79ba795b70f2b47a1bf101af78f5682d315647e61af7563acd53cb01869521c788ba1b5726dae79205418d35ceb4e8bb9d6f488eea0734e71eff5fed92900c13c5306642f757a2ca9e5df619e000d84d2a3de52901f275ba2b481506ef2b24e027bfb5cf184d29fa7bf609a35f6f70d0b29df3c880c676b370c14c6e3e4c08e61d86bb5ddd3c57f3ab7d69a75f3fb3cb06918b65c356623c7ba763bb59c02121d2e7a834a53709b0b27d4da4420f645dcead8645d7c9c9f798c29fe6a58a007dfc5709a867a2c8d5c72522509fb497e5c1779bacd54b3daaa6ee3537d4c325b5b644f9d3738060485c5367fb1f313f9b325777cbf14b971bf2b18d2f3b0a16a10eeb72486b9ea42883440336269aa6f67b2345892c160d0952c18ea4f19217f6d1f45dd3bc180c1d95350e582795f6a489076769819737126cb2b9ba84912873231286c955d96d7bf607c0d40081ecc7a4373c4213313cb83c39a8c3fc61185a43ac96a7dacd144b2c3321841dcce6975b393511555887147a563c247343033f3bba0711fc94edd980ec770c77ee9e0c885adec6266e214e7397f8d0248f2bbbdc08ecc4f1affe4a0e37cdf4c5c348f6f69ebf873aa253daddb0ed03fc931698c76804072c87467734688d793a3a4bbe752b6e22e6865fa5146d7635dbd51f49efbe4f8ba41dcba1dcd126f17f0504c4217d7c9a162a2444021bfc5aa08118b38a728e2a965e2fd2c80bbe873ab5530f07aed1965066ba4847e462cef5f60a913a3c5167e9be7e5d3c4eb3c313e519438f2d3b0411c5d3c0141df3c505a12fd59b673a1f3bf65003f97caeb69e12c6f565b56a56e02eda5d9d89ddeb99c9087ff17454d49668a2644099452e814caa55fb0869f258396cd5199100525c3b05cfe82be0a62fac2afbd15f4b2b2978ffecb4977ab84926d5de6556bdc9816c0bcae0aba9e3b5904df14a520ea50d42a6bb2e26e53f94300795e2876f9859791d911b3789837e5480a0f7ae0afa612dfdba1b4df5e210adf7be6184fbb2383f14820c15259bdc8dfa1543626556ca55693ff7c4555b61adeab78896d2a9063b05c8659042106fc5931c63d71e476b13f06f9d98532ae17fe2bd3b110ece7ad700082e80e054e62040274fb5047fba7944cdca52ad452355a5146dcaee345b591625f9c39568c8d9af72c180eb3c4e74d9341dcee2a58b44d519a93f59b845180e4452741aa2c4670ec9806ac629c58183da2337b3b2daa732a2d5b17cb78f7815aeacae2f193df2bf1a4c19f80194db9995a681170c9d848a5d2ffc60d388761db857b06708f48cae537039ecdff66f6072ccb56a0714fd07f1b98cacb68bdb068db409a0458654641887a1fb759284db98f3bad52f9ac23eebc802fdccb5611b4fbfdf700992ac3028523ea9b4daf4f29ef45143aefa1253ce1c7b2989ee031469f406cbed78ababc15d42738cf03a69a848e17c78a435aa0fec644000fade113f1b196e500f213712754c4706f8dcd3bb322d4251b76d094dde2d29cf0d4a29b835a7fec34e06850b89a3f37b26a95ed6824181a384191467de119e390144268853925ecaa1bcf020103f1df03abf895c572299f56dd7d6bcf3cad24aa4fb25fa4d234ac8b74a430b77dc237233c8a34938a45d2dd8430014317d42447f740c475aef6a62da133f53afddc4147d651a69ee0ea69275305a527cc9213e539812dde358b128fa10a21317c2493b4ff02dff20f68a65f6507d873a79f930a4b921c1fa025cec11d426eb10edfc22024206c0f02f4e8cb99f17ae3912b112547c14d39d54ab1be07e9fe721a516ca526a401627728c001e111a3cf37f25e059901182996e5b44282112e23b9f464c6c3ba4cbe77500adc916acf1478ee9f74ec3052628afd8c41b85c4978caf9ec9b6b74472cb32ba4814bb63f67aa55c39b7c3230b726d3d8cdeea05f02d90c9411f85d35442669703d785d88e5b6a1f33689600babd6b741402d1a294754e33da00ea3703abb5e71a47905b6dbfede5ed1d5d2cd7608960386fad09e730c5afcad0441ca37de3751b6cbf42b17e2f7c2981c1015d74a71fddf10e7f87657ab424f0cbe33be68a75eabfc3d1553f5ed8a105fd2fea2cc9ff9b3ae99596fde121ceade67aaca0a51c3275b67642c1282a44a04e1e2449bc4310625b7c9fc5f1d0b4a0f14f5ac5e2a9baecd06ef9e636624a953318cb8a50078552f4fbf8a85f24b8fb02d5efd4b084fceb0a80b9afae437b14400e1eacf3e5c70a99de3b23dcdd9bb3b0a93810490e7464886d8829dbe31de580169cf11e68ad484fbabd1bf643846fd5deb3777be149c12d51a4466ab654c02b17d1c7f78cce8fa36c279d0e2492231473bd0c4e0719f692ec83eb7c900f1011", + "public_inputs_hex": "0x0f49557e21b4c1e191c610875aeb6702f871442427b85ffe7800672edea8c1d60b324b37de91c33f34ff507deaac47e46ac9414b19c85359cad868c69fd6e38b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000077117e59dd1feeaa796907ee32a6005e00000000000000000000000000000000eef1d7464190461ca1a8dd367f48f2691c4b3169d5138d89963b08a431685e575ed0dae5acf6924f1458f622166a0bee1ccd2641e1e9bba64242cefdf3aba968b556698db1967dd559f0b465375ed0e41a4f5a9fe72cf1cc5a1512597f770cebf0b305ebcf8253761101a5746bc6d44006de2cdb6761ecafb3a9875fe5f28694e7749e5733edecbe3b49a1a34903f4c22ff5a850b79b88858917917684517dffd3ed24b2aa5e274c405269ea13bbf06700ece9c8a24d22aad11d49040b0158cb07a4ef0975dc217e02e5781867add686033ff88e898ca0a5be229028e8fbf251abf458ec5f8d1ad7f5d6dcfbbd2d51d02a27c7b79209d048001b37b0c550f30837dd7d8b86cc16371235304c6bc2f9dd2b8ccac82963e057a58b2e299874d166843e4b273356423f5a4e25ea487d0ca81249c2f4e26761665140c88d1a0ddfacce3a75bd7c135214b95b701073f01b851f639e4a8567bdb7fbb16c1c024fae67efa5bbabcbb8071d51a65ba263648247289c5c3fb4e27fb6bf47d3355d5b73a486b026213dc9d8d45325fae14740177c" + }, + "decryption_aggregator": { + "proof_hex": "0x00000000000000000000000000000000000000000000000c89c6d537dc17c06800000000000000000000000000000000000000000000000abea37864d8d1a4bc00000000000000000000000000000000000000000000000e4cb9d9b55b3cc4440000000000000000000000000000000000000000000000000001d3f866ce9aca000000000000000000000000000000000000000000000006b7a8a9b76244e8e00000000000000000000000000000000000000000000000054804db9064a04ce500000000000000000000000000000000000000000000000a0cc0944ff2fd3b3a0000000000000000000000000000000000000000000000000001e3710e20776f00000000000000000000000000000000000000000000000af2374a1255cbb795000000000000000000000000000000000000000000000001f42106ae3c71e6060000000000000000000000000000000000000000000000093e40600e5880ac680000000000000000000000000000000000000000000000000000cfceacb62bc9000000000000000000000000000000000000000000000007006384dc97ba668800000000000000000000000000000000000000000000000e88607f6385664f96000000000000000000000000000000000000000000000004a95a2e0e0d8546d30000000000000000000000000000000000000000000000000002b9a55392ce9d20399faa4f45f0b5fd87663551d18cbc7e1e7bad5f2915d9a8c63b2bfc8bf16928177752a23de28d0af0ccc90d6ed411b66e9b1118c664d2cf694a04d7fb75db08671fe02dbe87691b8866298ca7325099594c113c1cd88938ed63018d65a32525ca353e36e25f50fcd403dbb31602da618db03b721dfb6b8ac68bad4b4ab1de1e3abf3b30a88ffa6ff867d426b8ccba06c56950e7d347a13f07c99f6c0441b02c294ead4ca0b1d62f3c192c6e040e68189d7ef936c05734cb759e946d4dd4e60bbe4692392ec64c98ae9bfb79676bc33892805afa7f201f277b54906713ce0b00211627a7aea8ec047dcf9ffb14cf724330ad3b489d1cf6d7f132495f85da1d1623643dbca86366658f114b3298ab73bef71bb6751ac6cc139f9beb8266ad1b080e3a38d3c12c60abf3fbb3d318308c6307b22a8b71bfc12d0c032595e362080494370b121569e8e2610dfe14e8aaa054ede111e30aea159918186bf2acd0a015e1d86a606b53484cb42f0a4ad9d18da5904d4ca189c5390f2e2188d048ed1208b7fbd3f62965fa0bb074ca8874602f31d2858f90acc480e2a06d521d53501001848dd16d21bc334654463586270607ad62a34a98913e56c670f5c223829a7d201bd4bde38d28cbd799099914a7788567562564a9902a2b318209d71d84f8982e03d5f68ef5a4427edfc0f2c4f2205defea40db91417c4b84e6edeb640154140c2dd440e2ad98b51f5cabdd687ad9c8928cbc02a51ec32acd5ab418ad441e181a546853ceb1e68df0713dce6a32ca5cefa7bda2dc1b12fb4ce27741b42e5da41e2eaf7a36c90126ad33023f64dd7e5813f0a4f1c26201e6c405b8f6bbec785008491423a4cb455b62534e676fd55c8c02cc5b918241039351d6d00e7b79a15e0a3241db4b42abf14fc6ed7a231c563b190eba472eee285438209400eae43c060e231ad2fe8b5d4a34d2619109e7cfa7b5d64af2f03af7b63e957c80e20db7000a70c24aa51af6ee2add7a06bde08c83dd8204bbc1c5255cd39ad602e13e6d9928c6b45e624a4935bc1eb76b8240b1c34d1cc605e486a7b53da04bcc4e1696400bf14ca73fd3a4df6dcef76dc88b24e20628ef9c38954bd2f4d0ad27493b69d71e53b5a2ddf3e1595732703159e3a4705d99aacc650d7ceeaebf013165cc728f0514a00179184d0fae94c1b2e40c315d47b6b17000e59030dd029318070c560d03cffad0aff9f24ab7ef3b75aa2d1ee2b65c35e6ca303cc49b25b5cc7a7e4af7238b08386ea58b1dc539e87dd2aa6f1858839625e45e24239222eaafa5a2a9a2209a59250c01aa9ff998ad22681e3d94367fdd3a6665d039e1a1ed3096d8b7cc23e56856817598477cbd49c345951f1992ce3ae8b7f8c3bd4ee4a57ac26663cf113a59f5907e4cf2aa2f6d7643b1fd08a8c6d730b2ff804a54477f326c6eead90453ffa88bd2e94099ee8c518e31937ac840df0eb3d9a37a56c126f00b48d58027d2406eb20dc4f83c7ee2938ad6ccd917cf64dcb7141c86c6923e37279ed09e10a84225bc6fe2ad5e1d15168aefb2e0a7fb67584081215595c020434741a3d82f3d39518bd7549c6411574228b6d50c5471ae0496cde505042f15d8fa0515f5121848aef65bc2b519fe97d669f0c7203db55a6bbfa6989a4e5772147e8d2c9d0fb07a6fd4a03af65fba4d42398c79948678ffede5a54b752ae0f13a39d316bc27dd4524c1b116537f44603fcd89e841715fc5ce79051d295815475761f0db7b2eb70a6d50e7f18ffc8553818cc0bfb56145dbba2c25070d3b186df877de01662956052fcae18b6b408214e2b0f55d473bcbef95a0dbc62aebf45ec1f5f056310b579c9982326609b818988dc83126b68675c351aff660541d2507a7efd2e0001ecaf16c9ed3112e1033aa70a8c13fc73c9d85fd09496626e439cb874479a3d421be2645fc870419c171e0cdc870af8d21b817d91d13a8e7aa78d91d18fca68728ef61abda744559114f6f496986d2cc8df0db894fc7d1bc327ff3c5849bc9f30ebb980ca907c6a26caa0595c78309b2b5f860617dff116f392b33214bedd3210c949c8962da611212662ef1a1198f6827186a5b9c2466c121228836541989c910d3aa1047884f46a7a63525ff069b6d02a2ae0383bb8d8ea8996a5579296665245390f605af2b34c8f459814940922c5ca726c4ed7144885fc959b43edd0f6515d7b70f4f6427f7e82980a71921ddfd9622a8d407a5d1fdb502f881b3de1dc70eed60b8ff4d4430268d71e2aaae46f474bf760df4779015375aebfec78240c427bd285a0a0a8cfcdc200a00f40811f554a8744463080dc26eba7434803f06192ff92016b363b6987cb8d3b7411ac47e07e668b45a9cd839a6a7b5b14a138ca925885e95a6f19c2e884f4b9a6a93788d629aee6ecf157274a514c18580ad785611c0910ddf81f8dbf1d3e57fbe4169fd6e59ac403662813a67dcc0da913117d30bc33121916704d31f9b972b432b9621fce608a1440f992bcce07641745c3fbf1718d0bfeb7d62ac55e0325a15a137307b0b1f97d2b205eb5d6b961669d7b986291c571a26dbe60ae868a0b2bd3c9daf91d2c384e0cc3d67453e5511d304ccf106102f18a6306ffe870df0e6d0473aca0010cb2aefcf29a9a8771b859f7db3cb2c42d250c35c0f74e3630537628961087188dbd94510d97b024e97fb6c26032201b4d76b354fef07d7b608f6e10f52b457d5beae97b43c323e4db538bdc26ed71af65c36e85ace2d80f79b138c010fd892a5051b0ab3ed55e535eaaeb293a58d2d8fba9edbdab3223a4a6d9c6aa64033e68bbdf51e6ff450bd6ebe5c13f43b23103a0ee17ea5a7cc61175e56c0c7ce50884f850825ee45a3e07edb0aba545f4129e7ad569d707fdd5353e8206c4f57dfb13e314e6b6cff00f8577b827e5ca560009d83b40420a631a51d16a12988202c3531221b5126d4eb6b45ba008919601d2c85139688273b7a912d9378cddd42cf4f9fe2c2591d775f65748dc64733a1281ee676b61b20d780b60770ac947f6958df183df76f61c861316aa1f90946c397270831e5927d3b2c3d172a5ad77654838c198cf28357cbfc2be906754b6478b31119346af4397662f1250d996820dda07aa1323329d6a067f1d9549aa01e688b30114ebaaeb319424615aacfe626f6ecc2847d7e9bf277ab232c205315b34f1e0b8506572704459c92bf13573f4ba64060c976b3255bf9cd99a2080e988197cf1b6f9249ac718607deac4ff9e11ae12367220d8f8d8dcabea4f0e7663c7f59b813094b4f4dce74b68461cf994770d6693fed5f8ec86d589719f134706e72b3de2f6273f9ca3170c7364ba64c627f679c706ffd9ac9e585a6931553bc32f38cc40a83feb406ae89a4a0d60ac2958d4166b1dc932477cb6e9594357e24d9e143c82906c5789bcfe0a99626170739be491a23cb48cf0d83da111b58991845915db019b9f5a9b851686bf22e2e7f703f5d646b90cf1ef39e8fc72b42e4112f1f4edd182f2bb6f3c86634ab973102e8c93a3843b0e0a337a70c6d7f060c71b2dedc6222c66a6871c742cdd3dd5c00633cfcc49bde2792c741a6e52ea4a1c33ab1aa480f2bc7afd5fb64009acf0c2f6bd318f9e91c705ab3247d3b290b6f414289798801a9553d74b13e457c54215a7a5206711946f76c240d3b93e98957301aeb0e97144f51cada9ad7206d5d684a4ed9ce5e28f8d8d0780ae0f1baeb6f324d26a98f294d8e4f06d7dc6abb5fedfa0294ddf410b43df8ae94a71e98c82b3579cfe92b1d5dd17f4aac660baeaa09646cfa4dc073c53081ab42c8932b1d5b13591619b60b6b527d5e6cbcf107faf382d3d96314c61cb3a822cc3022984600339609f24e28bdb3802e418d8dbdee8058a36fb20120817e83e59f744644e92757ebbc11b2286edd3d83956028c3f5d58dcea863db877dbaae40aea6dc4cf2b094e38017a70d54f771fe61acf6f2e4e09df6cc683ddaf0bc8f7a08c3838ebfa945a53d391e0a145204009ee574a99eb6c606623d7ed090dc3e074cd7152a7a423dc98abb4a116d04adb6203592009e92d070801878a6095dc68c222336389815d4245aed0d1d58149b353f2715514ec64bfda809e279802e804783942e7b4346a191486d602a6a74605f461c1c638f99e3ad0b377bc6cd95c110ae36bdc3902df86159ae91165da7bfa47cc52894712b9adf10276f5cc1c7eab31c0f2cc3e8f4fb0c2961c4142c9463aa263292a1ff073d4bbf5b2c1d7c0471997d757103ccd9fd904d6be71a8b13aebe660d0836600ece14bffab2e6e2f71756666aafc7aa07c62e3b1eec2497e0664fd9d726b753cd062d7a95ec2edcb0e152596fdb4c748bc97f25fa912174c8b49dc0bd751a11c96739f9144e529d711319524e989446e8a6f632a5df1a1df982d6e8741fa0ff391c04a1b1aeb794f6f78e2c4090d6afaeb0d45248d309a4de86b9c603f0b9be48cd9b3da994f3998ee76edffae2160ce10f9b100bfe280acf39ad339ec311925eed926024efbf2caf5ab442cb6412b65669dadd448906acf752f209ca42e906a204a2a1c2bd8e24267fdf62f7ea7b24a78f93fac69802eee7c25dc4c49ccbb410e55937787bd6ce5a42159b3441f548212cb7eda00f2ff88884c12b96a676d0154443159a1f6b72f01e08ba30fc03ceda9d4ca9f72d0895d29763a5e317a36e87747130090e2ea3f17cf3ba9f2f4c51ae18e32b5c8728a082be630596cf61ab1d3d6383f7a78d4148f1aaa348d26f7309c98cc3f3cb1e12947d0a21ba19b53d4e479b952b268dafac63352546791758a344c4b9ad4c042037903c3e972a4900bf220a21ee32d799589e635830a260839a97dc4f5a5508d43ceee2225bd217dcc4b8b853cc49d0f86da0b0a7d1ff25924041ecd8e48715c0f0f6b864470dbdbb63eac1975ca815db7a18799f7d3a02aec970c3ed3c4e158ddb8f649748e6e8dfa451f1ddf78fee322c6c50eba8c8bcc1e7ec64e2da640eb97c1cf3e9282911011ee95935e08db09ce3da4d7cd66a60d5a5178dfbb98e10625f5828fa3736f8654df927599d6a11fd019263d07e780fe58c25fb91911c2f9bbe551faad0e6aa4ff2e2d2878be45cc0fab413ef253b81fd186bc75ab69a2bc1cbb7f944fff72da778484c84de2496c525d757d9c6c5e273053d2fa4eb300041edcc8c15022c6b5b0268c58adf1284630ee5a064ad2d25c6426bae954a530a980d6a154ff0533ec9ef62a37ebb3addf1c6d3af97d7a5db0526ecbafcb32028d5af720af2661efa9abe7defc30699039784c7192ff1ff35e33132a16dff3d076d01884ed88148ce4515f829d7b11d79f71008a688229933e8c3b6ca8944722498d74aabfb9a7ef6ebe4ef83d9520b15dcf0be3c0789946f814cc9a2ce95341adc0cc2e042b151f08cb81cf13bc74690381e23ed2648be36fd1eed6a84eadb029c4aa9ffeec101b0f7ca9fa8a76ac1ab4a567821f58876fe0c7a540f0760b31354a067fbba520c30ad6a35666429fd210f93aa2e95f2c8b3b75bd6b68c506b019a973330f98e900cd1fdc7a44c8abfb4715274b57a4d17766d6944be602ceb0dbd3afbeedb8fc5eb12b443eef44ab6f6049446dbf0e228e6029a6e8a4655321d538a8ac2fe637eb8d7c2d3ea495fefbead174a503bbd80715cd9d914b0fa391b36f27d1ce2a46f43356f70e56c740ca47334d2569fb6f4a312367fc5efe34303a6ca94b9dd1e61dca11199549fb4d4a8b0c789e658250ba944053332ad461e2aeba9eb564bcdc0b44518cff46e9193a8ea344680e19144f8c798c67ef6e25f033a5f163e1221aa863ebb1e0d19dc9da8dcf641f4555b44bbe475ee6da738d4141ec8e7b098acb7b8f06f3280740690d52d31d5154e5d3ca19102ff1630e73a278236dff0334c674aea7b44981d0aa3f3316e0de17bcdd919b028e1fa2a745e010503791d46b9d277f533a4ff66004d93b7d67061f81f16da634eedaaa69bff0fb11f989e7acda3e19eb5a0164bdec36695ee787380b25e5054ab875eca29670e11bf0dfa5dc4fbe8168762b8ff6088998244b54f78f73358b3e09d79efcfff16131ba42806241a5d92b6681ebc8e2105a39e38eb7154c70620788d3791319802a301dccae44351b67c1dff95ef2c1280a8be53d4f630de77a56980c912de7625368cbcaf0616fc46972eea11c8837e693fb2050890f2ae61494b7328805e530313d033a56aee98ff24709e09fdae163b19bb8e5bd3478ab4fb1fdab6df7eea2d39c2439c7b762d641d7103384403443772756c7f4e474c461255fc78eef7502f2be6e196906c516d597d172d0b2b068f6df3b7e3452895952ac95363f2a0650d0e3b408a7b482df002b71a0428f19cfdd2081094b775ac9fc1d151e810313c03d6dbda32758fa2ae34f06bdd8de0f1a30e58259ab810124054c6fee1ddc7891669d12248e3e53b31132e6740873f2d60c1f6455914f70e21fc4d8a25765a2f026d93cf4dbe32a22173c09019f9cd25a27c52cb6b15a1eff5f3cdeb19a0dec406372614804cb4e1b4326d15ed3eb8f972c47280999028dbae6c5bafd757153c1eb447d9f1fc3b066a0b1e09d0fd18655e36c6081fceaa29c0029befddc2006609585113af587f61eb5fa1835cc892d40585bd1d5698f051564dd511f44f912c277b54c9af80e887198b9a94f8bc2d03b62b2272cef760a6687d0998196b1f5624bdb12c15974cd89cad11caa70428ea70c25470658c9f273c73c0a8ca2254712941d318b86be07221c1c996549d3dde7447d2a32cf2fa6a634a1db5c67cf31a03208e53ee766d564d0a6e8571b703ae063e4784718fa3522df36e9f437b986509fdd3a9cdf45154d66006b8618e385414711f57e946da0bf97667747e1db24b14d2fd3ebd7da3314e4ac46ac9b007713a744b5a216d248d07b6e95bf97cceed2c377fd627fa0e4d55d4d9ac7a0677d62311b36a331016e833442363ddca763e29d8ddd02aa806fc880d57b993fb91e95150699d121f2c919b44bbaa7da99f501c3753f981def7c102e19d480edda037efc0936a7ad9df50b1376b91292f72160f125ea8eff631272ae19157d8b22b143666108577ff3847d7b66ce4851827bb06ac08d872dd463b08e6b9fab8baee4718dd4d4176a41a1b212cdcc89a9cf3ae0b6f523d34a58363732b0002467da559b72b6648354ab640ed26ede6189e14dd244325f66e019776ab18755061be47e154ce39e4717bd3e82d41e33bb2a38f950f90fc2bbb2cefb2faf687791f677e9a2ced18135beb8a02e3c914c7f76f344d22be36bd30322545e47f9dfbe39ab444c127238629df49e04d4f2a78404c89262d9b6c14eacc5130dfca23eac58a8b9c1239f809e521851610b2bebeb87eb6ed10722e1eb4ee99afc987f656e28fa4c94ce00f450c2252e8b0bcb63d7f4b1daf189d4fec6a0eff27cd720199233bfdc79bea4c91989e9babefb5b5ad1a5777a120bb989820521753144cd511c9d37afa24d25398e945fd1c10510876d909a0d414d6abb1dc6f08decff25e2751b27bcd485d210f08738c533ef2f4283c2f25490e92d5edfdab7dbf61f89c1e255138aed746b4aa831c90c6b204480ea92331c61357a9aa02a6dd527aacf387400b323e7bc7516dc54cd1822917b7bed12ae2510ea4bc05b01193fad22ce67752a0e96fe5f015d0575c68676cd786b97a1cbb4729191e9e6636e17a18e0ab7a83427a2beaa701bac17d8f3c421fe9fbf1421eaa2f9cbdf7adcd5ba37fd5bd11362397abb015d6d28e66bdc3b94a147223a06f633044145a0bd28815fb92b515573d51d9b5c5baab513e8c4128c994f4d11871f4279cacce2e914c5d1edd41a9a1b83151e037f5cc223c89a04495484717f0d019294103222f7219fa5aac902a925bd3d07495581ac613c82c4979960bf3b17a2b1abf55a0c3a193f4359594c466125a9f97a7fc2dc51650872ae7554ce37969cc148cc2cc447107b4aab04902ea7699e868c333863d75bdcb64136dd680f474f62d4dc965082959f0a127201846c843f1aef4ae044f80e41e74c39d51b6c8ba9502d7bb4c2e9dc0c7872c11ea07da7ff3635c4ac8ccfbfff8489cd8d09ccea02b04f74bd235a6bac2f501a6721a5d202168b828d6b106b141400cb39a5d5ed77d13b87d15fd1efaacbb24ae5eeb854c3263dd2aa28c3ed98afcfe9c087811af0a1a17107671953e3431780da900b4f917bdc92027263da96b4d60f542cc2c82e509be2e2b97e4bffa9c3cd204d3d2cc19c8960078e8e74ade1a3cf15fe27ef6b20172e772a3dc884bf612a80ab2eace1e48cf3648f3adca4abc3214b8955003cc003e578536d2ec7331b59490ece686e352e8b85c7ecf37b685d668480a3a17ca0170ed17ef491496e42584995fe4a3374f222e01026d8ab67436113c264aca1c19c8f2d8e0297a873069fc76c743766555556f26f56e9b64584ab29012ddd9270ce0e65ee8da15e3197f0e0ba16c0289f55542ffabd7b3760ad0528a60ca332400cdcb19bb3820fafa568c51b192fd3242446efe7f297bb539165932d989d1000e8c197a075b68ce08d92b47d4859cbf75060202b7d5a8bdfbd8f3f4b026796104a4501d6b9b0ac4d0c288e4b3bf14cd043909750b54dd89dfba0af1883702ee0648207f313993b9a8669bdc97b6f8e1d880f27e9638b8b919b3f35df0d4a4cb13e79388eb6e11206cf680d0665efafcfb6f7a634cbaded364b22224a971aa3e2bf89dca518517c860d8dbf455865efbae865648cba9e8bdc7cd32e9af0bc7c32aa25fc0b0c35493c8bd144b55dd8dea0db112ce0b11bcdbaa266abba170df3e1b862f038b5fafc43e249434b4868df74be6d0010aa4d44c09b91bf8bfbae3e7276b73347df76d954af4a210c94bc03315190f6a90b988e210fd37ab1cf8b5352625dd786537207de459105e02ceae54571c391fa25a2ea3ce38c7c48bf3965d291af2670efc172e2b9ad90128146162e705eec643aeca5f1a0209c9230d1cf61e9c39bbfc9e9219da275aa1cbe22147fe193ac2330830130e66c3e7eb9b6c4f0c67062f5204a407aa1ef69fd65e88c7212ce545c52c8c66ffcc82487f8594b629f87ee67617f9bfa157b9e98450938cc8ceeb548aafb27731a6db910c2f3d202c63540025366f9d89c39cb0b686d936d2e3836e6c341d7e276069b8601b299a1d19cf2ed96cf7769dad1f6d0848456e758a130e2b5a71346ceedd076dc2500d115e52496919ec8b4a9c90a1256d0921d71c46e69e2742af220d959e7737ebae17952950241397ec0766e7922f06b2942a0fcaf9e31dd2fad3e223612da6a91e121135039f1def7539c63dfc5ca99614f13e97e5c1445c6b76610686fb720d9e228c8b3894d56b4509e39c2c7b15062cf197a7f6b7d97afc08a4612495107fe706b8c5cdbb040dd23f8c9cb732dbd224d178e16aa554b8301e485b59e74121a802db623780ff63442de371fb5a77fa649994d37abdd8f37e9e5c4d1b2d0f42c320ac1c7061ad7ff3396f338966e21b0d7bbd2aa165cdd6f2a279934a7ef1ea0b145f8116afa4921473eeac90f43e6751baa607563814d97d8e5981f4e08663d60aaa136b5252b7b6407974decf3a4a709bb9ec0d95e0ccba44e7eaadd58a5a7414d88abdabb208b20f7ea49b3bcad4770757644454769f27946e9e289c7d582d0e8d351c17bdef0985b3d1eab178d114d350e118515b0f2017a2d173dbd0f9d105977b281e273e7a0161c0a7d98da4fa432edb214d0f373336a89cabb9baa08920e60b0b53760d0428dd28a57e05eac32380fd9e160e19daa8891ca35395014f16ed8d012d33f22e7d41d5201d12dd7939c49bb6361c1bdda7fbaf6bce7550fc014123f6a31e0b82d529a6d0f54bfbc364c60c911f486321236091e7f01e77b31dcb3f844b13078b75de943429987d5ce353a7f6ebd892272d0b16b04d34cac31253abd9d1ed6c38c78d38c15e5d8840190f45b718b4025ce35b79fa5edb416a1c8a2b6da3049ad2756f045aa9b8fdc8e370ee37bfcbb64940783912d98d00222badf84f989b1694925c313f2079e6b4e785ece0bb6ecf9d308bd4eb07ad0b7010da33e4046baba11da3706c8654284da3fc40e944342bbf8b9ddda67974a5082e92e98c8872e2892da7cfc7eec88f12edf372ec6c62aab4d853ffe00f8829071fcbd437983e196a54d1ebc802d2e07004e53ff074e776bada1eb9c7c95dbd511bb89d20bfc0e563e85165bbb8820ec35ddccd3a181a7d8dcb1cb930830b64f307a2e001b1931cfeb11744c8b5d5e4ba316462158381a48272cf70c85474a3c6257448805443e1fbb464f1d59f6c9e7c73c3faf9e7c49cef4725e22e85a314cb1a81f6a8d20dadb4d7656d51157e400462aafc88f0821ac59174b614f0cb4b1d1fb2b54961adbe66a6e3c633c8ebeb09e82366f2f8ad9cc12a03097a6c62462e22525c15fa397556d997133dc53dfe32553453c422d55a842dbe6a01f4f368481dcad44cc429803caf6b140ff493ead1d4fce834b73c12ac73489c5c82d1d0091833e95b095c84a052b0e5b66b3e3b276360db86276ed736d39c65a04dada032291b3237ea5cdd8f9ab325f169b2866ac990754405562f9831ce895ff2d0df961800f3af75ec1ed1cf38b93303e81552ff284447d2ea46166f94027431376d6f1a847fb254374aac9f9ece3e0b383cafa1b6c224c8eb3a96b017e52a8cb4a93611b26156e338d9365c02fdabaee829613cffc2b5a0c5cb95757f45f28c94bd7f2457bb006461ce518ff3801a7e382db239c999acf8ca898e67d17d72ecb696780208aae8938d49205be2d4a5d2094ae8912c57d8e9232196f15ba1f459b035fe12f00d11d33bddcb331bc867e6f1c4c2a52c2c30acae767a1d6c265606607a55084f33e47aae6fd9f6e79503f5697161a40fc994c7bf0146496b9dc41c408fa202514b2d4c7f04f6961eca1fe17391846d7fc84757bdf4f4a6060cd4f98ed4f7098ec5bc944178ef9c49b88b1a2e53de1d99237336b4c0b6973f234964305a1808e6e0c1858df2daa7b1877d90afdb028c3c89a43ef7042fe9c38904360fbc262d69c32b05e446110ee2d8603bffbc0fdb4481f33e517698dcd54bbd48de06b70f07b23c65850c68063ca8557ebbc7e796cc7306d755cf701b7f7cf896007f2f0fc38e421e1a38efde29e2a129ca309f8980e1d4896a061e7d6d963b9fc6a52830144780fae450fc3957fdfb39bc2ec75cefe759f393c866e341ffbb8a2b60c4188df90bf20e1bf41235141b8a259b56009a5c716379288b75a4fa9006fc3185113f52b0c20e5686598d2d281fb35235151c959549a0cedc08d51634bfffa0392f3d72d923acd03d487baca86d252c8da92dee59605a742ac030c9a89b9867f8033d91040102dc0f1b3517fd43144bacc5ae8ca9ee36e0fbd0dbfeac61b1b36e154ca49951e1338ba2f92487a6aa36fb47927431a24a69d337cd8ea5e680958322312add93ad09b6885953ad9003ae124afa391981037c10aabed8118bc04b98162524c11dc8cb722db3ac6803cbee486cdf8c33513c22cd41251988a251e96419c6be87356bc9621efae31b1896e931301e2229ec61e93d4db5b41077f5fc7b188a9751200bd4e58032e702b45ef22e0af05fc05123b333a7a121725a9c61fd02575e449d694602ed596b1b335040f388de51a2452e9ff83e213e3e38c6f52a1b046f24e07e265515112c56ea29bf39253c9a86c9f57dca7345a00a4cdf775706f1e95b16799e4ba12038fbcc2e08709bf658ccfbd1483b4069d0db57f6376a2b31e619856943621b9729d6a6e74dbaa22485792ac25154f65e60ec5acf0c430659c71f52cb233f0448e5e68581abb5582f04d9768b01a55f32b5e9ce141ea51cb4edd9362ff5cfab9c62c22130bd7a02f5c81fd23e2fd3739606558c7e0fb40192e09d0084c6a2710c59d820ded9b0dfb52e305756e0c61edb1ae25a70ea800dd31c9e48109b517c961fe9acfde7071ae40ff98cc4121bc322256f9ab36d6d108e72d7dae149a54ab46cfe8f241861e3485334f33da713ab44fcc3d01966a905ccbd32a363d22fe2781d4c08e0e1fac22f78bca526c0133a72c236eb8a765513d0dbde4270cc3ec7baeed504e673ba128b5b01abb64b2602a4c6ad85634b19110de95ae4ee45349b57ee12c10ed2362836c4fd24a5831b8216cebdc8a43af22bbaffa79dcedf5476c38a0c0f6256efe1f149225568dcd0773b66a0f5591a9c05c20af8d94c7d25aaacbf83f94c21882788bbc3e4b39c28b4ee8a996bb1f10821695e01a394c003d10daecd0d4dbbc07b583d27cc13f37000921f3af89c7a3a19459449376c83ab8ff2dd441343709b2a8b289f21efcb73ffcabaf7c0510d370fbb0248aaee14e17980e4d275c88789cd31a4d6cd2087dd53530365d448714b1789bae49ff1dbd36fa3eca86cb86406a1426453279f8877a9ef3c02afd141b60444570d61f15c5762a79891f438ff47136a11efe3cea777a50fc3aa052abc500a9c6aca82b30a6e8813a8f4374b74f7f55726f93c329917f8b30e1ab59c98801b143d1bb0f80574d08726efb0b1f21f480b56de8c8b115b06c64297e58f936b2cc18773b7c21b694442b8617e4417a1531464ad91e901db9e348f50350f4c3f216d1e25b6584b9d33dab2c84cb0d6e684f6a0eed67bad450c575efc4c0d594e206887a1573529b89fc2631f98a4ec17f03733fa0ff5e67d600f480f5610955b146b73ec0b092980f0d33c0045bf95a8eaab0f0a421a261992b0db14f8778be101f6b0ef437b0890cc015c63fdeb518f4fc8235c5bc445f76fa70474c34ca5b8248fc167187c38a539762a5b0e3dab0b6d69b5fcea61d187d53a882119b9eab118a7f09c3955d823e048c83be5b6b71dff45ad8690a0fb2a510ecf3c37e54ae31b48215c527f02d9b013fb0138c7e2f9d370ea123012bd03fe1e925f469cae5903ea70b93dfae0911b49a1f3e7878ec80d333a557003aefbb777c2c1341a61322d45b23e319beb981b89d42d6d28500672ce4a244e357d0be894af6fd6c3691311610518f1764098418a910a498ac6b8978e4432b79f5f7a60376458c1b593ca2fe4563bfb08a32688623dfd3b861bb0aa45fb8f9cd3b48f268088155ac9112205bc557c7931c1e37d018ef027384710268e5a91a7ff7301b4dd5534f9130ae20df0927c7fad23ea0a0270660946c46ad6ce067cbbbd7bdca6afc18614fbe2f2098158b1111f78af9afc775df64cb81d2bfa5a59ceaa3b52b091216bf6d8facd118aa56c8c098b4da0926502cafe647aa42cea8f7dfe592d03662b335a456d4419fc9e76413861f02caf52a4f4489c24649b317472983e5dd984f81a17d81d89227676376516733962432d1167e2d1663c3035369c5d9edd006ab5a9b34d5c670c64f32218f939710b9107a5bfbe4dc3b378c9a4941a98fb8a78632150d02e13174d118c62e479cc5df24825f4013e21a06b282813668ad425634728d622c7942dbfa145133ad697c75789c89a5507331bf91a05bd83a91a7403f91e2f8c279d2700a3f990b809827fc5b8b44c2a63d289d3de4cb742aea0c3547c278bda86490783ef2164e4be77de089f9aca8c96bdd0f4025ec1b28c46b23b63ef246f6fe9112c9770df978d0b1e1c49c839454ec4b5d2e56a3fa1e666743a89aca491a86d084555685085b93a82aa0b80bf0dc52cbc6b69995f398e3ec9a439bda8f3e71d16ba82a35c75ef65f8e7136ad53d95cb1987ad134d0e01829b382651dfe2d08b2b10f4725cd179cb2edeaad869bebf0d2479bf66f50a23e413249486e0db8a0016d65db73ba629a925c5fbad59b0b91c4081d1290868064b2bf615afbbc9048f01658fb240208041c3e282c7cf6c433a4defd52989300104b975661ca620abee10fabe7ef8fc6a53325afbffba8dd31053389f1db562dfe1a4471510d02cb6bd2d6f47af21e48047838eab00bf0d30b7bb22e68c5e477cf7e6876a05dcd85f4029302348ab9dd41f3385055edc3621db38543d9e9bee69633f504d39a21e10990617fb839efe0c159e8d66eb0d79bf3bde28b5cf5ad8e59d7d2c95205ab7aff62e055183a5aa5fbf7a87d3eeac44971fbc79afbed69007d01ef3838b3b859125220413f9cbbea087d0c890980915ec1860fc7c0d190babdbcc6a92b96d235ed426c0334dd23410c81279726e388a829d6bd677eb2d678cefb2ac120ca725b1e32f9fae15667a3d8e0b2cc51df7ae0512c26b87daa571de0d6645f230f0e6747c225bc2d01348dedc4f2e3a8789c3a20d552ef06ff669a0f44c834ca2aee3034d05ce81e93d3ae5e1b71de9f0e3f5f003e1dffe2fd8f4b0c447dcfa4f7aed18fa17945e0d4cf92deed799619f0a09acb6ae81046f0047dd510493a56cb1498e712d37e585731a65c80f4653abb50f5f5f855a5e3b504aff482443df1d44ddf40408d651d48b444aadc22b5b49687122e1147e4a50f3578b891520f53c62f225c42e0490eb430ae8e33ffe09f0e39d300ced42067da91fc6cd02e311fac20b172b1dec4a4c5c5019d5a1482f38df0876f89ad2734571416300ebd8572beda8e05f1a31d972f9aa895ff52c782404c739333b8c4d65a0da7562c1effd99cf0376050666893ad9320ccb9873c574dc1f61940c5300f58f7b6471295825ce3cc53447", + "public_inputs_hex": "0x0ce1b376e5479afb4df722f877c26647f4e29e254ece539a333093ef73fac2e711cbf664e6e1ab436d8227ba889283c5b88c37545dfcc186a393533996b7bdc90000000000000000000000000000000077117e59dd1feeaa796907ee32a6005e00000000000000000000000000000000eef1d7464190461ca1a8dd367f48f2690da5935cc20672e95aa834ee487f402f7598651b4db414611358e24d7afc7f9e0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000031ccd2641e1e9bba64242cefdf3aba968b556698db1967dd559f0b465375ed0e41a4f5a9fe72cf1cc5a1512597f770cebf0b305ebcf8253761101a5746bc6d44006de2cdb6761ecafb3a9875fe5f28694e7749e5733edecbe3b49a1a34903f4c2033ff88e898ca0a5be229028e8fbf251abf458ec5f8d1ad7f5d6dcfbbd2d51d02a27c7b79209d048001b37b0c550f30837dd7d8b86cc16371235304c6bc2f9dd2b8ccac82963e057a58b2e299874d166843e4b273356423f5a4e25ea487d0ca8000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + } + }, + "test_exit_code": { + "crisp": 0, + "folded_export": 0, + "enclave_contracts": 0 + } +} diff --git a/circuits/benchmarks/results_secure_agg_small/integration_summary.json b/circuits/benchmarks/results_secure_agg_small/integration_summary.json new file mode 100644 index 0000000000..8053fffe52 --- /dev/null +++ b/circuits/benchmarks/results_secure_agg_small/integration_summary.json @@ -0,0 +1,244 @@ +{ + "integration_test": "test_trbfv_actor", + "benchmark_config": { + "mode": "secure", + "bfv_preset_subdir": "secure-8192", + "bfv_preset": "SecureThreshold8192", + "lambda": 60, + "proof_aggregation_enabled": true, + "multithread_concurrent_jobs": 13, + "committee_h": 5, + "committee_n": 5, + "committee_t": 2, + "nodes_spawned": 20, + "network_model": "in_process_bus", + "testmode_harness": true + }, + "proof_aggregation_enabled": true, + "dkg_fold_attestation_verifier": "0x7969c5eD335650692Bc04293B07F5BF2e7A673C0", + "multithread": { + "rayon_threads": 13, + "max_simultaneous_rayon_tasks": 13, + "cores_available": 14 + }, + "operation_timings": [ + { + "name": "CalculateDecryptionKey", + "avg_seconds": 0.059818383, + "runs": 5, + "total_seconds": 0.299091917 + }, + { + "name": "CalculateDecryptionShare", + "avg_seconds": 0.159473866, + "runs": 5, + "total_seconds": 0.797369333 + }, + { + "name": "CalculateThresholdDecryption", + "avg_seconds": 0.231732417, + "runs": 1, + "total_seconds": 0.231732417 + }, + { + "name": "GenEsiSss", + "avg_seconds": 0.156219799, + "runs": 5, + "total_seconds": 0.781098998 + }, + { + "name": "GenPkShareAndSkSss", + "avg_seconds": 0.313501966, + "runs": 5, + "total_seconds": 1.567509833 + }, + { + "name": "NodeDkgFold/c2ab_fold", + "avg_seconds": 11.847578675, + "runs": 5, + "total_seconds": 59.237893376 + }, + { + "name": "NodeDkgFold/c3a_fold", + "avg_seconds": 169.184619283, + "runs": 5, + "total_seconds": 845.923096416 + }, + { + "name": "NodeDkgFold/c3ab_fold", + "avg_seconds": 12.817567216, + "runs": 5, + "total_seconds": 64.087836083 + }, + { + "name": "NodeDkgFold/c3b_fold", + "avg_seconds": 151.491728074, + "runs": 5, + "total_seconds": 757.458640373 + }, + { + "name": "NodeDkgFold/c4ab_fold", + "avg_seconds": 10.847684408, + "runs": 5, + "total_seconds": 54.238422042 + }, + { + "name": "NodeDkgFold/node_fold", + "avg_seconds": 23.955023783, + "runs": 5, + "total_seconds": 119.775118917 + }, + { + "name": "ZkDecryptedSharesAggregation", + "avg_seconds": 3.327329542, + "runs": 1, + "total_seconds": 3.327329542 + }, + { + "name": "ZkDecryptionAggregation", + "avg_seconds": 60.962331541, + "runs": 1, + "total_seconds": 60.962331541 + }, + { + "name": "ZkDkgAggregation", + "avg_seconds": 28.085369792, + "runs": 1, + "total_seconds": 28.085369792 + }, + { + "name": "ZkDkgShareDecryption", + "avg_seconds": 61.25314797, + "runs": 10, + "total_seconds": 612.531479708 + }, + { + "name": "ZkNodeDkgFold", + "avg_seconds": 380.154250233, + "runs": 5, + "total_seconds": 1900.771251167 + }, + { + "name": "ZkPkAggregation", + "avg_seconds": 49.192114, + "runs": 1, + "total_seconds": 49.192114 + }, + { + "name": "ZkPkBfv", + "avg_seconds": 5.465944433, + "runs": 5, + "total_seconds": 27.329722166 + }, + { + "name": "ZkPkGeneration", + "avg_seconds": 67.431268691, + "runs": 5, + "total_seconds": 337.156343458 + }, + { + "name": "ZkShareComputation", + "avg_seconds": 50.505588075, + "runs": 10, + "total_seconds": 505.05588075 + }, + { + "name": "ZkShareEncryption", + "avg_seconds": 112.371622883, + "runs": 120, + "total_seconds": 13484.594745965 + }, + { + "name": "ZkThresholdShareDecryption", + "avg_seconds": 133.8429849, + "runs": 5, + "total_seconds": 669.2149245 + }, + { + "name": "ZkVerifyShareDecryptionProofs", + "avg_seconds": 0.290990533, + "runs": 5, + "total_seconds": 1.454952667 + }, + { + "name": "ZkVerifyShareProofs", + "avg_seconds": 1.076807577, + "runs": 7, + "total_seconds": 7.537653043 + } + ], + "operation_timings_total_seconds": 19591.611908004, + "operation_timings_metric": "tracked_job_wall", + "phase_timings": [ + { + "label": "Starting trbfv actor test", + "seconds": 0e-9, + "metric": "wall_clock" + }, + { + "label": "Setup completed", + "seconds": 2.8164285, + "metric": "wall_clock" + }, + { + "label": "Committee Setup Completed", + "seconds": 20.127044, + "metric": "wall_clock" + }, + { + "label": "Committee Finalization Complete", + "seconds": 0.001253209, + "metric": "wall_clock" + }, + { + "label": "Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall)", + "seconds": 400.034844, + "metric": "wall_clock" + }, + { + "label": "ThresholdShares -> PublicKeyAggregated", + "seconds": 1669.469802042, + "metric": "wall_clock" + }, + { + "label": "E3Request -> PublicKeyAggregated", + "seconds": 1669.997398541, + "metric": "wall_clock" + }, + { + "label": "Application CT Gen", + "seconds": 0.304409375, + "metric": "wall_clock" + }, + { + "label": "Running FHE Application", + "seconds": 0.000809917, + "metric": "wall_clock" + }, + { + "label": "Aggregator P4: Aggregation pending -> PlaintextAggregated (wall)", + "seconds": 64.513878, + "metric": "wall_clock" + }, + { + "label": "Ciphertext published -> PlaintextAggregated", + "seconds": 205.700746333, + "metric": "wall_clock" + }, + { + "label": "Entire Test", + "seconds": 1898.949991209, + "metric": "wall_clock" + } + ], + "folded_artifacts": { + "dkg_aggregator": { + "proof_hex": "0x00000000000000000000000000000000000000000000000f8cf4eb44ea7bb973000000000000000000000000000000000000000000000002fe6a2e9f65b54987000000000000000000000000000000000000000000000004cb9cdf5f722d0d31000000000000000000000000000000000000000000000000000120dd7263dd0d00000000000000000000000000000000000000000000000a7c765c503af0ca8800000000000000000000000000000000000000000000000c438e0a1837d19462000000000000000000000000000000000000000000000000fe6a7967e27240350000000000000000000000000000000000000000000000000002ed1b06d5e46a00000000000000000000000000000000000000000000000073ae7e558975da6900000000000000000000000000000000000000000000000b40a9060c3659b72f00000000000000000000000000000000000000000000000271a38c15d43fed70000000000000000000000000000000000000000000000000000159384b1efd6c000000000000000000000000000000000000000000000004b79f2d04172cfb6b00000000000000000000000000000000000000000000000831e8bbaa05d116b400000000000000000000000000000000000000000000000942afbf6aa7e7798b0000000000000000000000000000000000000000000000000002332f302695aa1682b09c868798d9b80459f108450027d8b7e34032a713a8f0f5a51c1d3c161421ad456a75c6872dbc5ed9cc8562afc387b6d64df0218debb3d3bfd3c8a18b4d2dfe9df17302f9e5b42959bd451047d6e6d232e589db3b06a3184826472d70dc108bf072502ec19531b39949e5aa2cff83796033315791f2e3e9cec19d880aec1bf9af6dc3795931b567b91cd9187ffc1d59e2bbb0ea5963ea0192cc43bf3e710f41e632e8ea500c510870f4482962d448611d964d7c1017bd3893923b7fd4c2208ee98b855d511584781bdfd7bc7010a5c7c56a5a5b256bd052a906d81c48db175bb09885e5437fa9774c36e0ad5cfae43ffc9b0afcca6c68b0fbf991d9e9e30f14e2b1bac451200f190ea0417688be9e9e7326ba36aaf30cbf403cf7a3e36a033cd178d883aa7126af75245f5edb60b8077181b8f97a60d8f0268724c8a97e2a13d2f0b35513703c939ed6c63be19a4ad007a30b0f3ba65067f50664b364f018eb0329e6f2875a150d0142d7136d839186a4761906c494891a0b54021524ee2b8f9409866c5e0896f2f7b98c44aec8acf5299f4605d308e657301f0987109b114f608775844e74b54aad341abdd8b483a965b840eb8a09586605c74c9fcedc2fc3a34aee8e9b3ccf6d489dcfe2df004342a8111589cf1dcd23d828a059de700fde0b1012a7dc4912df91bcb908258a79c863141c092e2e7c871cdbe4ce658b178e3ed9471fbeda851d23cc5516b0c925106d1a96b03469c336af0d1c93dfb81d9f3c8e0e6b7d9877c0291f7063f4aff4767be58df30d0ba7cf6cd887fe62da0c35d308e50ef2b97b0c038fac5c962ca7b93eca3855eddbb47ab4da6f42e3ff0fefa9e4c64879b112311f2504b5800e961a4cd4d519f5dbfc751048376ed4d625b05663d489824178cf171a8001b084fd7a8cdc96870f1914ae35ec0525600b22086c87843a73afd95f57f3197e11e4f8b4aa1279ccedc39b19ce30e195bfa121e8cbb1c2253a644f3c40a08b34fb36aab9a6a4487371e0445647e2383d43d51df61b7fed26ac4468d0b09a5af2c0dd96be4d8b88eece6a840e69626ecc8c3e1f535e681d68f7e4db85d0b7836721660c53bb50ae39285454e13dce7eda5bca09e63b630ee447041e02022b66b6bb043923f20ff0160aae10e63910ab8497ae1f856fec2a2e5cd9f5a4665c808372dafe8a7b29cc542904228984c059241b5126a9d31a4b9bdc246d0d1d57e2bd2ba5a5aa64c6bdd85d15838f29188e4ff6fa0c677776b475721085d4811d1dfc89939ccc310d3737579be2c80beca9b7c8e427f1d24d1ec75fef9748e80e26731b09b708336826b274d44a87a77da07367d318cdd42c458484a1da9aa86f3a86d5712b5f760a75fe29d66a9e4a71c44552bf2b7c4b784097c3c4880a04b51b438b29f715f596b5e69843983d28ba16ef9e9a2ec90fa646ad8eef1b55a2a114199e3e5e33bd941c4196b654fe8b827654ce5321a89d763c7754c6234e4015d0a55d2ab9641614edb8395cd7ba18eb1b7dfe0f149ca7a39e880fc1a864daaf822f8b237f112d8d59eb993fb49ce75f12fc9a8f2b7b797b534986b38964f3c77bda62cc2f8cf329b457806fa5b0d9cf7aaabb2419161b4b8d4a35d3c609e1d0d45cb1cfa796ab1273ea177c577888b2f5ace9c204a5d4ae630b6885ad89cb3844d7860ff0423cf6cf8329c0d7f27c990db3fb882457b618471527753abd61adedfc6a068edc792c7c5d26661b5002e9bce6bef91fc14bd2149e1d8487dc51620c7ea7243f2ab729592f4ca595dc60c74426717a0226cb14a5021437c020ad312030fa0cf34beddd06e7ea342563dfe2ce64a1b11f28a59a53732754b62297ca0c280949393e00ebc1d9b5113490ab370062a3510b7c296fbe4d2e509ea850fdb0c50631ffce02b6362e00b8d363b3086dcc34c31dc69a97c93d2f5cd3cb491511d9eb8aa6d09edceed0a4aefd633a3cc4fb8cb602222d2d962062a89951027c580823f7a54236adf185a1a51a7716c6851378da0cdbeb52e7e08aed22fdc09e687e79d5101542088ce0d38a7e1d4c898a6b573c0ce3bf102237bd0d6178fdb1b7804915fae9aecdb5cd66a7b03e047de559412b2d38e49e554cb25993f7422f0876f7128c1e78244511656cf77af02a0cd9e91401aadfa2577e9c460e4f37818c5fd08fadf6d8feb5d186e0ce7fffe1e96282fc16f929180250cf6e04e756103cb11a94f527d10e7152d9dd898de648dae773f815f071be728e768086b8d8ddc3a24c6310b636db66b6edfaa79454f456f8a63b22efaa28d6079b861677ae63c9be81aa53f08cf522823dcf77b358a3e73be85417ab64897fff7840a3c81a375d17138b77597f8ba1de3fb81c04afdbdeb6c70e1d75741eab64ed54ac88a00c82fbb83509f53f211ec80a53c7f9f929d237546a1f04592e0ce043b501037fb064072351c7110a5354f882a5f3438beba7c818a80526b7287378b7b02bac41b8dbaa535a7ad36576a5dba5ddc8eb9a57952ce9a91181f80a457904433cb2f4735c2d56348fa8962fce5e030a021777799fc7a9db0600ab5818ca2a4157abd6cb9aafdfe1a76cf6f853e578885caed79b04d9dbd002b5e7aaef46d81adbf2c3f726371ff2dbbf2908656b28b54027174e0314fed21fdb1f9f4f5b721065972e8a15e21685a1e1a089bccdf1578ae75a26a4cd76d921d5f42ec9cacbd4d07535cac21e2fbd05433f9f3a18be2b6b01cfe96e8ec15b269bffdba83eabed4bea3eca373a402b2bea20065a6ce1880ff57d22a591249a1b488a56f4db4ac84a88cf6706981492618fe93c037c4d40b24ee5b151486fe821ab713f4e3eaa8a3f1af81d701bb75771d5434485562b8d38f236fe57ff1f9c104145d00e69eb57f7eab51e67bba351430240d039cb677bde6e6f2fa77642bc200319a8dea6735aca2d7a682003fe8150812aed472eeba46bcd8c0cae9aa9590da57b0d4271354277a1357bb93b8ed003a90cac91366a1561fb20fdc507a0360ae18d51eef2886db725890bad5ce1985018fdf064b72c6851119dca94aae60b1f28dee8ab6508311be986a3acfdd81422838e4a1b54ae7d85f73f2fdd7260471a8b6e012ecff6d3c51b52cabda738a0df4618b30b719d5f4fe8b258fea7589e28894748a5d6e0f6861e90b8e67866b055089c3e4b6602e1541537bc39c4509c18796a05a33ac38821d3fdf11540e1d3658384f45ce5438b05d720312b2f09ed2a4b9a8afa0b289cbb84df58c22e065fbafb6d7a1c00fa00dfded916976769f60f62d9e67524aa0388e220f1e93b5735c6a90aad57cb9ba38e7d88cc74137d38180c1a2df6459e7f0aa21562a68b91b825fcaedfe7463d19393094fc6c4ba6ec001bbf4b689dd55c592f244bc5bc7490360441f412a73b256def2164051539d6043e38cbff1cedc18a9aa2f8896b688671e9a7535fb5fa9ca2573b4d079c1e100e2b3f9b73e2a30ce84422bb96eaad707c461078f7531db516bcd027702c82a21c53fe5709550a1037abdbb0715eecfd8a71f64aa5dec3e7df1fd7074496534e0d077a0e6f2179e6c159600c0611dca8719901ba76150553546ca625122c96491ffc6e0372529455bb468f79b309f613b589576015b8e5df9091047ab3e9bbe407883a58019032c61a315109f7cfc60ca1b162a2129d2510a461140c48777ed42aac70d7a5d1564e92f8376c6631c68b53b942555db5af89d0683196029500ae21b9114997061d126a66d39f04a3207b7f979a5ed9a0e07153cb3b6999cfe39d18fb0bc43b87736d69768d162662dc5676ec6303c3bae7046bfb53aaa856353500d26528623ba1e2b96ca0b794636b19ae843b80674371543aa5bb5c9c12d9d624816dee09cea3ac10a450349dd556cfe0b6cb3aeb6bf3d0cfaf8e773346c83b1318851056d6d268c9ae3a7f81c15634283ae2c80a279a0654c66748caf0a3ff1fe384a9610f357139f9f10f50af50ae44566a66eeb779206d02b482775fca152db2bf3ff68b269bdce69272b7eaf203d957201e3f7a77cc6d082dd3155692292fbceb5ee42ecd18040607684cdc2a30df4647c3769b11f248118a9b16926c0225f2d136c04fa8aec89ace848062d98b2733ead5abbb86e47415eb7b706cbe172e445488a5921dcf7b00fde2957ca5985858ac613a3658c09b7f8c49855cbbf407972d2d7d02e77ba1af60ed4ca833ca94ae90d16b62ef16a0e16e92b515824a033dfda8cb5b472cb415b21fdaf0a68cb55fc957c4b170a588648f5af8947aa81640f89ebd26e164a95aa84b3ca629f5c852b7bf41032b3f50b100ba452945dd02d098f8cae107d21ac95c720cdfa34f68902deb208ddb631bf8ec45a4cdcb0d02c9b9f04629fa45e016f42ea1b7c114212f08eef69ee4cd9dae331f8bb370aa1b3845c84eed88741ec11ad341a8bd2749d2b13195d7c02d890938e10fec14e51564fd177aeded08e90323e208ad1267d50ad5ae493f416c43196dda4eea87b828a28e93703ac0ae95c8a8014ea151ec1471104b75b21351578dc7aad638c5412bd99a63b19b1da253bc2107f7e8b4eb7fc5dfc61457e8ac7381693c3e59567d2509211887cc1ba0b9f0497052e8a8662d2f3187dd2a0f96485c606e7dcbb2e413392610ad2440026831551fff760ece740c26af9f2c69c288a7a75f7107b56b2709867b0e96087e99336e0c3cbb27b6ee59112d541000bda27643a992bdb64722831b803aa8bfaa372e88fa3a6a1d2280dc5621acad38514a9d6fbbd1f7cc500fd872c5ec9d6ccd74b0f77013442f08abcc4cd3299e1cbf6d19a154e205b1620e34b6fe0705e7774fa60307d218defe6b489e8631e7e45b84fceeb0df0fcfae048bc55c1922199a0ea0365b83702fbdbbaaf68b8c5319c9265f630bc5353ffa162d02a4f75a0f05b25e65788dc00c393b8441b323fc74a8ab4c9d125f90457e180a59c842f6e1c2ac90698b07733b954724098342f1ca8bb6715576aea2defe08e98494d0bd897d1f630d5d0e3872ccec2f6357f8901017b352ee3637c4960306e502e2b781b17372b08827b3639076643aa83a754dfbdebe64e9e58d4203480e0877c3456b04f057d52d1caebf21a1c6efb523d9ce78aff2ec71c675504cee2cd77d623a9f09a241d38a26a3ca59a521a8dc22ee304838f97ae352a721fcf607b960758d2970f849b37aaba64d2795405570433bdc3693fdc791b4d25b837d2f3e1a611cdaebe5071905b723a70a9469edc5225484a806d2d1ad86df2758481b3d5a6ba262f76e0c42663ce543ea49eace1c0ae9a6a45f247a7c267ce2d2be2002337e07aef72d17a1594e7e27171f08017cc067e59dca287a61c7b37687f711ad81bdf74060145d2a4bbae427d2d2fbf8a4926338bf97afa40b87de4b1b3f04352c6e671783e41daf549156c01e95ec1c9e294770e34776f89f516ab590821dd34ece728c26fe3bf8d5758e3181a882b5847a8d49fba164bbae46849ea1ad096561db5c553a6b3b0581693ba295bf258be7fd47f7164f18ddd1626c9f2f012bc3cc3bad66bcc6e88436590edcbd82cd17d02800e664f5bb417935d5c96b561b2ffb65c5a9f8ec9d0e1792a95ac9220200d51be059d46f3b035b875f7ccc65178ff7b1198d38bbebccca0f7f7e8f3fedc27eda3948b47d8b54aee682f3b64617c9a4622543660da65201488ac25a30c756d3d7f9f1d0c5c80c4fffde42bef61090f6a01ef9e9ec31a1b724ba21192e1512fff832f6917d93f4cc7ac25bd32f24df54d405c3d87a41ac1a590ee40b1abf1f0de5834bb26256b68e048da10bfd001482c637ab4572e53b0e794a2f6908139ba237b81394bce3bc6afcb9c684ce279cc943938fcb26dde13ad80910537b1b5fe43c6d60bb339d40e5a40215739a0b1005f8bb6b0189d2fbe89a5b00b1b543238e7fbc7fcea521d0e1fae0f9116618b248d8d4e3072bbcdf0b2fe50607ced2b67f89bc5d046f837e3f2715e9775701da2355354f5c6ed2fabc49662208d7b7452a129b9ea299de46e0cd655453671c821652dcd2ab87ef2e61cb72293aa27b5fdf95017a94fdc4bb5e8bf8fc39f725fccfb818685ad276f5df10db5f3873b2f8562c79d977909e1b4743922866d902a652d8a3b57afa097b51b78ea574c466a13647e94d42c129d97ddcccb54b542a3ef4511ed8e06217823e2eae64ae32dadb252f676827e708f65da94bd622ca0cc97c714ca3905980a4f55e35f8559b0b376dc879bdb801b68c0dedc44e53682f78c7af9f48c5a3a4d936af5117eae715b5d9d0690a5946bb5f76dc226bd49b0a116f5d01e49f8f55d351b2e9cb60a96426985e48accb388fa1c884b011341415b2cb90265307152ace284bb397bc3d86146434d6814f68a36b61a05f7c5ed62a4c5c6fab4c22fad3d73d3cbc74f0ef00a513f7d9aca5635505bf82bfc6a70525bb597fc69e219b7d72dfc1f11daf52850c0f6f494373384c2995e74c518f7e0dd35dfe88b3febc99ecdb7a643c09bea95d8bb8e2c9c2483c4d7dd4c22a13f919f02b199b339fb250412c9eae6b785fe36cdf1c2805c5b8c9321720370aba270764a45048933ae256fce1790638eaa43073118e4947185020f11b01f592dd002aaff0025762ee2b02e665d7cabeca7cfec6a9a8c98e27993d878ed4f60dfafa2aada3b27025c0bace89da4d121353c04f1f31b4a5e27e548344ba501a95a19b1deb7337e7ace684065c4b7852ccaf33cd564080094058f840fd10af1fd46f2a1517e323a23c62f5b3fae6b841adb4ac330ba581fa047b3b842a2aa40089900b1404b57576a411243ab4b7d63a0c560bb3a9c37464c27037b5a3a94f288b33db2a1ba702b83cbc4e1c6673ac8e687416019f1fd156dfc5919d4da977becce88b026229566e127838c6ad037cbd46a8c3ae7295dd4a6a9ad307f0ce6bbe8003e915593cba42b17949940cd753cffee93ef1978aaa214eee88a7802d9168dce4772b022c0ad7ee08786899d13d958d311e9aca8ae0591f3dd21be472aab41db23115b775053084283bc5d8d0c88ed1bcba7ae6b389b001b6cdffb3fd4bb99e47702bf294f20eba8b2694d2626dc7e5e0aba944496988a669ef2b26300692a689d40bcb1efb3e396b2d75219e11b852d18a358f117413840e23cd68e99321fccb7a256b902e1acba57023b193f41fe5b16741034303534ff42547c3d6b366cd29ce110263c3d812fa8d4be863b63a245903347d9ae3278e5cd0d8391d9510ec96222e0a50840c6e02c3cd831731ede6929e3d2cd7301d9017be2775cf1307f4f81a14589f24b785cb8c80354f811a38c7d0dfbb175c1223b9394501bcf2701a98692004a787961c23bd5cc83ca31c6979df58eb2bf72bb5245acf6730427ddd9ce2078c798d75734619ee5fc01c550f8bc26c05ba9248fd21885874f8bf3959ebc012ba20af3955912889abfeacbb17efb14013cdd8e79b61152c9145ae7c1cfa2e2c847c046d2ad74eee19910ff6643faa6c5763a0d2ed0022f50b11aebe38d7ec0837446cdb3d84c7dfe4b153b3a2e6ed2e6c42cf57c0e5109581ae882ed7c9c804b85a3fb7468c9db5db232b17acc83bf928d3928ab67d0f71b673232ff50ff8140756140b6eacd949e5771d8482f5b26261b5df04f38b923f60d9ac9b6192d3136047faf725baf1408beb5ec71752f89f7330ee60a842ba372ea58f0f0c238d284fa9818fb94f0323be5dedee392b7d034e1322b90aac38a9eab3e4854d5af82efe40526d62eaf14028de72b50a2d5bdef706474c945f7ce29fc469121a982b0b27424460ba39bead9d9ab64ad650ea35d0d2da6479dc53d36771d5cefa65de00a8aed65fcba7eccc5bae30bff27b7accf17575147286beca6f8db5d32382611dfecae871564aeee4b8b82b3879508245d363c523fd54b460492a1733b998ec0c2c5b3eafb4ab51cc3a6641d7afd108767235107c5326cdd627fbaa7346685221323abeae65f40678a6320eb1db8b2fb6e719f22f42059f049095c46b00cd4602cb6d3f08602a61d96b35a318ab2031fa422edecddf04581779972c1473730417f60bc84942265911d86d6affb9621288585b5bddec0a0be9686bc651cf95eb17400cb285c35bd85d198dd9f5d8874544efaeae5cc9f27a03359aee1b1a1a4e0dda704fbdf9af9389fe21e342e995778a0134d0c4c348cdec8e0fc1d94377e51598b96a5f97fbb81ae4fa7a3cec37793cb59ece462e39f7f2d8c9f66392744012244b522c41207a0db8649da6e085a1b331857a8520166fceea86bab7a3ed9313fd0bad2a0dcc83fc7139b93787be412eade7af7c89259079037550a43778452cadb8c2d5ffa4afa1d73d0f9984c3c921b51964530e1d1a82f87b6310e054740f8c69aabf9a9392bb26efc05a7acc12c453517b25b8eca5e159b75b72f65d051807bcf35c918ec2601bc2e135b6596315f627aa75399b93643141e78a11ef4917097ba3a32f23a48ed55f7012b79a1ac54fc813c5875e32e7526483e3f06548143e7a553a396d2fbcbd28c83ff13522ef8462c1e7ebbcd52169fac9c474ab4804f7103581731d0332925b62674f496fcc3ee9dfe9ee25eb8d0ca6ab378a300e0b5250f2160baea730eaff92a27dac2f08f8d752be32e1077a3430180214d15b10059503004fc2da16b9179202b1afb4c15a288af31c364033c3234d451f70c40fd13a566fe5d11e54a3b9bd3446676330bbb6eddcf087f00384a5f16050e0fd27147a9aef6114df318e35163792ee8093c0887c73ab832f405b64e58a46c5b303d6c9dc4cafef1b5db5b98b188effe25a31b0a3449284bf268576cbb58af4260e990f595a7390946b64ab7af90903e83ad987ad7ce5a2adfb1731bcdb2d907d1160e18f81d234c75422830245afd17a155737e2866620f8dac2b7eba6fca8c600313a019a45e414a261fdc423ef6b6642fa8fd3d15a6700057e5a57b0dcc50a1f5f9d1cd1c01e4859bf98715370390f424bde2932afc1c98adcb237ee5fc08b0b8c5432e5c131d310833bafe8860abd0455d7de8679ebc90e2dd0609c0071572299808ccbe8064e08fa4e976ca970262869972fda098faa9b646c19021dedcc1f65955d1ad5da522b2fdcb142a0d2ef1e7a3a2cfe418edb958fb53f18241db92d465e20f6f851f9ae0a156c22c89d26d09075c4aac45e0ea0662f6a018b74c5159f08474fda3a9c7ee549318100b55bffc8dcec15a535ec62a688dddc6cbdad03e529bb9869497cc54d9e8e39f0fbec222b9ce84a36d9e58d05cf0adbaccfae272b3984053c38ca321a350b63482893b15ed5cb60a5b16e82572b3365db06a40797b2553322c5124325755745250d54928b6f089ab26967a32f19e4db2a951c1fba3bb3fb2150aaa39cc0d1a85389403a040eb628834779a649bc02539e1a912fe457b6c5787318b33f23ab78ea50b9923cd0f945f9263b28897ba8659c7cbe15c064eb89884c8921389b18069775c728866a1f61972cfd4c4c90e196a147c10b16cfd4a6967bf1aa06b1e7d083fa3c2a9e6a92b979a4862ef6afe578d985b1038e222d206f88d03ee1bed0b56b456e3b638c5fa335b273032af7a868262e012ccc5994daadef166712a114049499e2b6b2aec2581fb7d494d5918683a5007b0482cd1d4b1bc998b6151c299b62fc530faaf63ea54abdf345020b127ce53f912b1ad6c886d57f6c2a5ef0ab54f51103a998794859791cae76c1eb75269d4046277fa14eb7542eb03aed1a898a1bce9663fa930570a5dea6829990cc2e3ba8811be656c21e2dbaf61141e5bd746faf82a16705498e8d97479337a14147eae99900c8c7ca20fea54a4675f653dc880f7d8a72cd47329c5d448ff4df9925daa2bc2c2ddd7a98ca8799c8096758dd9ccaf66634f05cf391c6d05e9055eb159db94f29ce7e5fb6330e2afc8da4bda2f8ea401b099360cc7e7afc7e69054c008837250b87ca67aa7b8c34cd119ead62bde06d6ca2ab1362311e0ee5478aaaa417bc022ca6a91c85d4590d74ede6399cc3f4472cd2bfcacbf2fb6d418e4ca4e144d1fc07c207d8c753a5f9d3ddf3a0fd91bed472a460d857a80c8d4b4b80621a821fc6050084ea350b6aaad2080fd12ac01b78e21d6e83b49fb00a177e8730728f9109002d6e4faee663c76b3df3234fbdcd455d6634366b9d766aad9d15fe3eb84fa404fb261913768d1b9c20ef14a13104090c2a6e58500b09de45a44ef81a5ee3d8005251ec28110ef1aa5250e899c86efbb23c86479cd91ee628e31b30352a242a2c3e59104e63809d99634b58a363c7834ba5210d1841fbd8de5daafcfc2f9c890f91bc9c661dae903de8b646a122adc92a7e661d81e3f1e12b310c91b4a4e5f726a56a5261d3bcd4ce400d39f7ad167a63d04267fef7e4fe489e93e90a43f2680348b307e0bc58f24d6d4af797076dfa758726dc8e2c95631c39a002eb62388f2652b2b578befc62242acbc58c28859b2be225d3f3875bd10fa16bd857aa179021c0a999ead5003e0df2ddd90585ef1cd1b85e28d40a423c3141bd2260634b4e0494371e2d406c39895d2bc4ccf823a25ca2247c5e8dffe41addf4d40219043a0f8d3c338c53e68cb53b95231a9efab53fd6a3430ffb4633c1061e8a8abde34b1151c4e65bf3aecddf6e83c6a55b8acb37bd200b1db884d3c277f5cbf8573fbf098e4f23575d6d4e0ca088b718c592192c2b6a2eb2d78b9f773a3a476c0b110d25205bfdaecd530a971fc3fb229104c6e7259fed783694adadd557fedb4894ae0345b5b345a1ecd52ce7dff2b27eaf0c699aff68e1f06c1abb734daf81932d8816b43f3aea81b233ec33d0a0ab15bffa9d32240ebda4fd497344e55c35e56473133e41fcbbce8d172762281828ed8fed593ff1ea6eb711df35fb01d61cfdc2fe20faeee0134d91e60953e71151adf5e180b8ed5076779b63259a10b415976f9e2898bfcd129061351321d89760c0da2a56ab37e0025e0a83e4c251920c8b0ce61be4f8cd54792a512d193869c11c4e51f698207c1c80e507ecd3a05af9d56b6d26e77769c5fbafcf610255c2fb65c81887944d4d6db30e885fa87b1c4cd23a4715fe9965afe173636dc1724c6ddd7ee52901b6996e48188c555f7aef66bfc8411248015534059bfe3d6214ad93ab052d0c6cb72233c67f190be26e04d91b164c0249d109b4224a90a699583c104db3d9ee91061a71efa00f4b3caa5a3b77da472a2a87f50f6c2ae8a3f258449b62008474045806dcb3273031db418e079277a01e808b86c1e5eb913a504a9159ec365e56f8dc92425378f117d09f78caa81a792ea83e12ee7637fdbd98dd49f43916b143ad6c8b5acdc80ecd2fdb11ebe25acd0abc429231a8c1721cb2285de27f7d5efc412d195c7c038137b4ee460bb73f6126391658eb5c07447074a37ada33f388c3b6d3a97e7a1948cdcb456c972ece361820c2041c104108b9323864d7ab030ee8c81b4d7f7bfe13b72394dd1be3bc8227a3fa9c452a8599d24a10ca420a0722667d8fb5cb8f7035ee36a3f6e80ced5601c6c1babc095ded8f037bf6c49644dcb67dbf9dfe895aceb7a03d44faafc9ba180a4f13b44e01e41cbd911af18446ead17edaf20d95125f543f4ce384c56cbe099f42753e88b53ff2080c6a9a3bee8c1afedc2626612f092f1d5c6a7d38eecb1dac82b0725bd094f8bfc59a84d3d5e97813d2d8997c09b80b918dbbef0237f42ced7f609f50632afaba049397eeb8487baffca713fe54b66102790c801d5b40280c740f26d9b50a581ff91836ba7a6583f74cc2d01a99b908d9e869daa0c1cc2772966b46f4647a9b556fe5dcdf6b779191f6590a175c4ba4148aaf5126fe4d20495503aaa68c53fdec0db78b669ab31327d8d58efaa3624af26cf2ba298e1e0698c8d2bdd12df70932e3fcea5855d7595aa31d9aa3211e3b1a3a89002dbf7723e5b69005d825fff1f8d43390e5698327dec64e4963307d230ea41089cf77dd0313b52121b2235d2fc288d50a9914d3cc3cbd54ce4e41a0b1dddf9c8f86e61226bae62c6f0364778e9c037391a16c8a23cead8ed29a4fef2bf53fb3b3608fa218607dc97dbc236e3aaef81bfdb8eb516444cb361306411dab415f828c7a9c2b2918861b45136294dfe194a8789ffc0901255e214545a4ebcf4eea444996488e27eb9082d232bf4da14ce3d2d4e31c99f8e11854f31933e9e7b3e4feb81a338f04270a8aede63a8181e7415bf0d8959c97826aec25e182d940ffb7c728ede3e222370bd7f558924eed74cd1a1aa1d92124d5f7aba040d12889c3747511b73b08285e79ba795b70f2b47a1bf101af78f5682d315647e61af7563acd53cb01869521c788ba1b5726dae79205418d35ceb4e8bb9d6f488eea0734e71eff5fed92900c13c5306642f757a2ca9e5df619e000d84d2a3de52901f275ba2b481506ef2b24e027bfb5cf184d29fa7bf609a35f6f70d0b29df3c880c676b370c14c6e3e4c08e61d86bb5ddd3c57f3ab7d69a75f3fb3cb06918b65c356623c7ba763bb59c02121d2e7a834a53709b0b27d4da4420f645dcead8645d7c9c9f798c29fe6a58a007dfc5709a867a2c8d5c72522509fb497e5c1779bacd54b3daaa6ee3537d4c325b5b644f9d3738060485c5367fb1f313f9b325777cbf14b971bf2b18d2f3b0a16a10eeb72486b9ea42883440336269aa6f67b2345892c160d0952c18ea4f19217f6d1f45dd3bc180c1d95350e582795f6a489076769819737126cb2b9ba84912873231286c955d96d7bf607c0d40081ecc7a4373c4213313cb83c39a8c3fc61185a43ac96a7dacd144b2c3321841dcce6975b393511555887147a563c247343033f3bba0711fc94edd980ec770c77ee9e0c885adec6266e214e7397f8d0248f2bbbdc08ecc4f1affe4a0e37cdf4c5c348f6f69ebf873aa253daddb0ed03fc931698c76804072c87467734688d793a3a4bbe752b6e22e6865fa5146d7635dbd51f49efbe4f8ba41dcba1dcd126f17f0504c4217d7c9a162a2444021bfc5aa08118b38a728e2a965e2fd2c80bbe873ab5530f07aed1965066ba4847e462cef5f60a913a3c5167e9be7e5d3c4eb3c313e519438f2d3b0411c5d3c0141df3c505a12fd59b673a1f3bf65003f97caeb69e12c6f565b56a56e02eda5d9d89ddeb99c9087ff17454d49668a2644099452e814caa55fb0869f258396cd5199100525c3b05cfe82be0a62fac2afbd15f4b2b2978ffecb4977ab84926d5de6556bdc9816c0bcae0aba9e3b5904df14a520ea50d42a6bb2e26e53f94300795e2876f9859791d911b3789837e5480a0f7ae0afa612dfdba1b4df5e210adf7be6184fbb2383f14820c15259bdc8dfa1543626556ca55693ff7c4555b61adeab78896d2a9063b05c8659042106fc5931c63d71e476b13f06f9d98532ae17fe2bd3b110ece7ad700082e80e054e62040274fb5047fba7944cdca52ad452355a5146dcaee345b591625f9c39568c8d9af72c180eb3c4e74d9341dcee2a58b44d519a93f59b845180e4452741aa2c4670ec9806ac629c58183da2337b3b2daa732a2d5b17cb78f7815aeacae2f193df2bf1a4c19f80194db9995a681170c9d848a5d2ffc60d388761db857b06708f48cae537039ecdff66f6072ccb56a0714fd07f1b98cacb68bdb068db409a0458654641887a1fb759284db98f3bad52f9ac23eebc802fdccb5611b4fbfdf700992ac3028523ea9b4daf4f29ef45143aefa1253ce1c7b2989ee031469f406cbed78ababc15d42738cf03a69a848e17c78a435aa0fec644000fade113f1b196e500f213712754c4706f8dcd3bb322d4251b76d094dde2d29cf0d4a29b835a7fec34e06850b89a3f37b26a95ed6824181a384191467de119e390144268853925ecaa1bcf020103f1df03abf895c572299f56dd7d6bcf3cad24aa4fb25fa4d234ac8b74a430b77dc237233c8a34938a45d2dd8430014317d42447f740c475aef6a62da133f53afddc4147d651a69ee0ea69275305a527cc9213e539812dde358b128fa10a21317c2493b4ff02dff20f68a65f6507d873a79f930a4b921c1fa025cec11d426eb10edfc22024206c0f02f4e8cb99f17ae3912b112547c14d39d54ab1be07e9fe721a516ca526a401627728c001e111a3cf37f25e059901182996e5b44282112e23b9f464c6c3ba4cbe77500adc916acf1478ee9f74ec3052628afd8c41b85c4978caf9ec9b6b74472cb32ba4814bb63f67aa55c39b7c3230b726d3d8cdeea05f02d90c9411f85d35442669703d785d88e5b6a1f33689600babd6b741402d1a294754e33da00ea3703abb5e71a47905b6dbfede5ed1d5d2cd7608960386fad09e730c5afcad0441ca37de3751b6cbf42b17e2f7c2981c1015d74a71fddf10e7f87657ab424f0cbe33be68a75eabfc3d1553f5ed8a105fd2fea2cc9ff9b3ae99596fde121ceade67aaca0a51c3275b67642c1282a44a04e1e2449bc4310625b7c9fc5f1d0b4a0f14f5ac5e2a9baecd06ef9e636624a953318cb8a50078552f4fbf8a85f24b8fb02d5efd4b084fceb0a80b9afae437b14400e1eacf3e5c70a99de3b23dcdd9bb3b0a93810490e7464886d8829dbe31de580169cf11e68ad484fbabd1bf643846fd5deb3777be149c12d51a4466ab654c02b17d1c7f78cce8fa36c279d0e2492231473bd0c4e0719f692ec83eb7c900f1011", + "public_inputs_hex": "0x0f49557e21b4c1e191c610875aeb6702f871442427b85ffe7800672edea8c1d60b324b37de91c33f34ff507deaac47e46ac9414b19c85359cad868c69fd6e38b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000077117e59dd1feeaa796907ee32a6005e00000000000000000000000000000000eef1d7464190461ca1a8dd367f48f2691c4b3169d5138d89963b08a431685e575ed0dae5acf6924f1458f622166a0bee1ccd2641e1e9bba64242cefdf3aba968b556698db1967dd559f0b465375ed0e41a4f5a9fe72cf1cc5a1512597f770cebf0b305ebcf8253761101a5746bc6d44006de2cdb6761ecafb3a9875fe5f28694e7749e5733edecbe3b49a1a34903f4c22ff5a850b79b88858917917684517dffd3ed24b2aa5e274c405269ea13bbf06700ece9c8a24d22aad11d49040b0158cb07a4ef0975dc217e02e5781867add686033ff88e898ca0a5be229028e8fbf251abf458ec5f8d1ad7f5d6dcfbbd2d51d02a27c7b79209d048001b37b0c550f30837dd7d8b86cc16371235304c6bc2f9dd2b8ccac82963e057a58b2e299874d166843e4b273356423f5a4e25ea487d0ca81249c2f4e26761665140c88d1a0ddfacce3a75bd7c135214b95b701073f01b851f639e4a8567bdb7fbb16c1c024fae67efa5bbabcbb8071d51a65ba263648247289c5c3fb4e27fb6bf47d3355d5b73a486b026213dc9d8d45325fae14740177c" + }, + "decryption_aggregator": { + "proof_hex": "0x00000000000000000000000000000000000000000000000c89c6d537dc17c06800000000000000000000000000000000000000000000000abea37864d8d1a4bc00000000000000000000000000000000000000000000000e4cb9d9b55b3cc4440000000000000000000000000000000000000000000000000001d3f866ce9aca000000000000000000000000000000000000000000000006b7a8a9b76244e8e00000000000000000000000000000000000000000000000054804db9064a04ce500000000000000000000000000000000000000000000000a0cc0944ff2fd3b3a0000000000000000000000000000000000000000000000000001e3710e20776f00000000000000000000000000000000000000000000000af2374a1255cbb795000000000000000000000000000000000000000000000001f42106ae3c71e6060000000000000000000000000000000000000000000000093e40600e5880ac680000000000000000000000000000000000000000000000000000cfceacb62bc9000000000000000000000000000000000000000000000007006384dc97ba668800000000000000000000000000000000000000000000000e88607f6385664f96000000000000000000000000000000000000000000000004a95a2e0e0d8546d30000000000000000000000000000000000000000000000000002b9a55392ce9d20399faa4f45f0b5fd87663551d18cbc7e1e7bad5f2915d9a8c63b2bfc8bf16928177752a23de28d0af0ccc90d6ed411b66e9b1118c664d2cf694a04d7fb75db08671fe02dbe87691b8866298ca7325099594c113c1cd88938ed63018d65a32525ca353e36e25f50fcd403dbb31602da618db03b721dfb6b8ac68bad4b4ab1de1e3abf3b30a88ffa6ff867d426b8ccba06c56950e7d347a13f07c99f6c0441b02c294ead4ca0b1d62f3c192c6e040e68189d7ef936c05734cb759e946d4dd4e60bbe4692392ec64c98ae9bfb79676bc33892805afa7f201f277b54906713ce0b00211627a7aea8ec047dcf9ffb14cf724330ad3b489d1cf6d7f132495f85da1d1623643dbca86366658f114b3298ab73bef71bb6751ac6cc139f9beb8266ad1b080e3a38d3c12c60abf3fbb3d318308c6307b22a8b71bfc12d0c032595e362080494370b121569e8e2610dfe14e8aaa054ede111e30aea159918186bf2acd0a015e1d86a606b53484cb42f0a4ad9d18da5904d4ca189c5390f2e2188d048ed1208b7fbd3f62965fa0bb074ca8874602f31d2858f90acc480e2a06d521d53501001848dd16d21bc334654463586270607ad62a34a98913e56c670f5c223829a7d201bd4bde38d28cbd799099914a7788567562564a9902a2b318209d71d84f8982e03d5f68ef5a4427edfc0f2c4f2205defea40db91417c4b84e6edeb640154140c2dd440e2ad98b51f5cabdd687ad9c8928cbc02a51ec32acd5ab418ad441e181a546853ceb1e68df0713dce6a32ca5cefa7bda2dc1b12fb4ce27741b42e5da41e2eaf7a36c90126ad33023f64dd7e5813f0a4f1c26201e6c405b8f6bbec785008491423a4cb455b62534e676fd55c8c02cc5b918241039351d6d00e7b79a15e0a3241db4b42abf14fc6ed7a231c563b190eba472eee285438209400eae43c060e231ad2fe8b5d4a34d2619109e7cfa7b5d64af2f03af7b63e957c80e20db7000a70c24aa51af6ee2add7a06bde08c83dd8204bbc1c5255cd39ad602e13e6d9928c6b45e624a4935bc1eb76b8240b1c34d1cc605e486a7b53da04bcc4e1696400bf14ca73fd3a4df6dcef76dc88b24e20628ef9c38954bd2f4d0ad27493b69d71e53b5a2ddf3e1595732703159e3a4705d99aacc650d7ceeaebf013165cc728f0514a00179184d0fae94c1b2e40c315d47b6b17000e59030dd029318070c560d03cffad0aff9f24ab7ef3b75aa2d1ee2b65c35e6ca303cc49b25b5cc7a7e4af7238b08386ea58b1dc539e87dd2aa6f1858839625e45e24239222eaafa5a2a9a2209a59250c01aa9ff998ad22681e3d94367fdd3a6665d039e1a1ed3096d8b7cc23e56856817598477cbd49c345951f1992ce3ae8b7f8c3bd4ee4a57ac26663cf113a59f5907e4cf2aa2f6d7643b1fd08a8c6d730b2ff804a54477f326c6eead90453ffa88bd2e94099ee8c518e31937ac840df0eb3d9a37a56c126f00b48d58027d2406eb20dc4f83c7ee2938ad6ccd917cf64dcb7141c86c6923e37279ed09e10a84225bc6fe2ad5e1d15168aefb2e0a7fb67584081215595c020434741a3d82f3d39518bd7549c6411574228b6d50c5471ae0496cde505042f15d8fa0515f5121848aef65bc2b519fe97d669f0c7203db55a6bbfa6989a4e5772147e8d2c9d0fb07a6fd4a03af65fba4d42398c79948678ffede5a54b752ae0f13a39d316bc27dd4524c1b116537f44603fcd89e841715fc5ce79051d295815475761f0db7b2eb70a6d50e7f18ffc8553818cc0bfb56145dbba2c25070d3b186df877de01662956052fcae18b6b408214e2b0f55d473bcbef95a0dbc62aebf45ec1f5f056310b579c9982326609b818988dc83126b68675c351aff660541d2507a7efd2e0001ecaf16c9ed3112e1033aa70a8c13fc73c9d85fd09496626e439cb874479a3d421be2645fc870419c171e0cdc870af8d21b817d91d13a8e7aa78d91d18fca68728ef61abda744559114f6f496986d2cc8df0db894fc7d1bc327ff3c5849bc9f30ebb980ca907c6a26caa0595c78309b2b5f860617dff116f392b33214bedd3210c949c8962da611212662ef1a1198f6827186a5b9c2466c121228836541989c910d3aa1047884f46a7a63525ff069b6d02a2ae0383bb8d8ea8996a5579296665245390f605af2b34c8f459814940922c5ca726c4ed7144885fc959b43edd0f6515d7b70f4f6427f7e82980a71921ddfd9622a8d407a5d1fdb502f881b3de1dc70eed60b8ff4d4430268d71e2aaae46f474bf760df4779015375aebfec78240c427bd285a0a0a8cfcdc200a00f40811f554a8744463080dc26eba7434803f06192ff92016b363b6987cb8d3b7411ac47e07e668b45a9cd839a6a7b5b14a138ca925885e95a6f19c2e884f4b9a6a93788d629aee6ecf157274a514c18580ad785611c0910ddf81f8dbf1d3e57fbe4169fd6e59ac403662813a67dcc0da913117d30bc33121916704d31f9b972b432b9621fce608a1440f992bcce07641745c3fbf1718d0bfeb7d62ac55e0325a15a137307b0b1f97d2b205eb5d6b961669d7b986291c571a26dbe60ae868a0b2bd3c9daf91d2c384e0cc3d67453e5511d304ccf106102f18a6306ffe870df0e6d0473aca0010cb2aefcf29a9a8771b859f7db3cb2c42d250c35c0f74e3630537628961087188dbd94510d97b024e97fb6c26032201b4d76b354fef07d7b608f6e10f52b457d5beae97b43c323e4db538bdc26ed71af65c36e85ace2d80f79b138c010fd892a5051b0ab3ed55e535eaaeb293a58d2d8fba9edbdab3223a4a6d9c6aa64033e68bbdf51e6ff450bd6ebe5c13f43b23103a0ee17ea5a7cc61175e56c0c7ce50884f850825ee45a3e07edb0aba545f4129e7ad569d707fdd5353e8206c4f57dfb13e314e6b6cff00f8577b827e5ca560009d83b40420a631a51d16a12988202c3531221b5126d4eb6b45ba008919601d2c85139688273b7a912d9378cddd42cf4f9fe2c2591d775f65748dc64733a1281ee676b61b20d780b60770ac947f6958df183df76f61c861316aa1f90946c397270831e5927d3b2c3d172a5ad77654838c198cf28357cbfc2be906754b6478b31119346af4397662f1250d996820dda07aa1323329d6a067f1d9549aa01e688b30114ebaaeb319424615aacfe626f6ecc2847d7e9bf277ab232c205315b34f1e0b8506572704459c92bf13573f4ba64060c976b3255bf9cd99a2080e988197cf1b6f9249ac718607deac4ff9e11ae12367220d8f8d8dcabea4f0e7663c7f59b813094b4f4dce74b68461cf994770d6693fed5f8ec86d589719f134706e72b3de2f6273f9ca3170c7364ba64c627f679c706ffd9ac9e585a6931553bc32f38cc40a83feb406ae89a4a0d60ac2958d4166b1dc932477cb6e9594357e24d9e143c82906c5789bcfe0a99626170739be491a23cb48cf0d83da111b58991845915db019b9f5a9b851686bf22e2e7f703f5d646b90cf1ef39e8fc72b42e4112f1f4edd182f2bb6f3c86634ab973102e8c93a3843b0e0a337a70c6d7f060c71b2dedc6222c66a6871c742cdd3dd5c00633cfcc49bde2792c741a6e52ea4a1c33ab1aa480f2bc7afd5fb64009acf0c2f6bd318f9e91c705ab3247d3b290b6f414289798801a9553d74b13e457c54215a7a5206711946f76c240d3b93e98957301aeb0e97144f51cada9ad7206d5d684a4ed9ce5e28f8d8d0780ae0f1baeb6f324d26a98f294d8e4f06d7dc6abb5fedfa0294ddf410b43df8ae94a71e98c82b3579cfe92b1d5dd17f4aac660baeaa09646cfa4dc073c53081ab42c8932b1d5b13591619b60b6b527d5e6cbcf107faf382d3d96314c61cb3a822cc3022984600339609f24e28bdb3802e418d8dbdee8058a36fb20120817e83e59f744644e92757ebbc11b2286edd3d83956028c3f5d58dcea863db877dbaae40aea6dc4cf2b094e38017a70d54f771fe61acf6f2e4e09df6cc683ddaf0bc8f7a08c3838ebfa945a53d391e0a145204009ee574a99eb6c606623d7ed090dc3e074cd7152a7a423dc98abb4a116d04adb6203592009e92d070801878a6095dc68c222336389815d4245aed0d1d58149b353f2715514ec64bfda809e279802e804783942e7b4346a191486d602a6a74605f461c1c638f99e3ad0b377bc6cd95c110ae36bdc3902df86159ae91165da7bfa47cc52894712b9adf10276f5cc1c7eab31c0f2cc3e8f4fb0c2961c4142c9463aa263292a1ff073d4bbf5b2c1d7c0471997d757103ccd9fd904d6be71a8b13aebe660d0836600ece14bffab2e6e2f71756666aafc7aa07c62e3b1eec2497e0664fd9d726b753cd062d7a95ec2edcb0e152596fdb4c748bc97f25fa912174c8b49dc0bd751a11c96739f9144e529d711319524e989446e8a6f632a5df1a1df982d6e8741fa0ff391c04a1b1aeb794f6f78e2c4090d6afaeb0d45248d309a4de86b9c603f0b9be48cd9b3da994f3998ee76edffae2160ce10f9b100bfe280acf39ad339ec311925eed926024efbf2caf5ab442cb6412b65669dadd448906acf752f209ca42e906a204a2a1c2bd8e24267fdf62f7ea7b24a78f93fac69802eee7c25dc4c49ccbb410e55937787bd6ce5a42159b3441f548212cb7eda00f2ff88884c12b96a676d0154443159a1f6b72f01e08ba30fc03ceda9d4ca9f72d0895d29763a5e317a36e87747130090e2ea3f17cf3ba9f2f4c51ae18e32b5c8728a082be630596cf61ab1d3d6383f7a78d4148f1aaa348d26f7309c98cc3f3cb1e12947d0a21ba19b53d4e479b952b268dafac63352546791758a344c4b9ad4c042037903c3e972a4900bf220a21ee32d799589e635830a260839a97dc4f5a5508d43ceee2225bd217dcc4b8b853cc49d0f86da0b0a7d1ff25924041ecd8e48715c0f0f6b864470dbdbb63eac1975ca815db7a18799f7d3a02aec970c3ed3c4e158ddb8f649748e6e8dfa451f1ddf78fee322c6c50eba8c8bcc1e7ec64e2da640eb97c1cf3e9282911011ee95935e08db09ce3da4d7cd66a60d5a5178dfbb98e10625f5828fa3736f8654df927599d6a11fd019263d07e780fe58c25fb91911c2f9bbe551faad0e6aa4ff2e2d2878be45cc0fab413ef253b81fd186bc75ab69a2bc1cbb7f944fff72da778484c84de2496c525d757d9c6c5e273053d2fa4eb300041edcc8c15022c6b5b0268c58adf1284630ee5a064ad2d25c6426bae954a530a980d6a154ff0533ec9ef62a37ebb3addf1c6d3af97d7a5db0526ecbafcb32028d5af720af2661efa9abe7defc30699039784c7192ff1ff35e33132a16dff3d076d01884ed88148ce4515f829d7b11d79f71008a688229933e8c3b6ca8944722498d74aabfb9a7ef6ebe4ef83d9520b15dcf0be3c0789946f814cc9a2ce95341adc0cc2e042b151f08cb81cf13bc74690381e23ed2648be36fd1eed6a84eadb029c4aa9ffeec101b0f7ca9fa8a76ac1ab4a567821f58876fe0c7a540f0760b31354a067fbba520c30ad6a35666429fd210f93aa2e95f2c8b3b75bd6b68c506b019a973330f98e900cd1fdc7a44c8abfb4715274b57a4d17766d6944be602ceb0dbd3afbeedb8fc5eb12b443eef44ab6f6049446dbf0e228e6029a6e8a4655321d538a8ac2fe637eb8d7c2d3ea495fefbead174a503bbd80715cd9d914b0fa391b36f27d1ce2a46f43356f70e56c740ca47334d2569fb6f4a312367fc5efe34303a6ca94b9dd1e61dca11199549fb4d4a8b0c789e658250ba944053332ad461e2aeba9eb564bcdc0b44518cff46e9193a8ea344680e19144f8c798c67ef6e25f033a5f163e1221aa863ebb1e0d19dc9da8dcf641f4555b44bbe475ee6da738d4141ec8e7b098acb7b8f06f3280740690d52d31d5154e5d3ca19102ff1630e73a278236dff0334c674aea7b44981d0aa3f3316e0de17bcdd919b028e1fa2a745e010503791d46b9d277f533a4ff66004d93b7d67061f81f16da634eedaaa69bff0fb11f989e7acda3e19eb5a0164bdec36695ee787380b25e5054ab875eca29670e11bf0dfa5dc4fbe8168762b8ff6088998244b54f78f73358b3e09d79efcfff16131ba42806241a5d92b6681ebc8e2105a39e38eb7154c70620788d3791319802a301dccae44351b67c1dff95ef2c1280a8be53d4f630de77a56980c912de7625368cbcaf0616fc46972eea11c8837e693fb2050890f2ae61494b7328805e530313d033a56aee98ff24709e09fdae163b19bb8e5bd3478ab4fb1fdab6df7eea2d39c2439c7b762d641d7103384403443772756c7f4e474c461255fc78eef7502f2be6e196906c516d597d172d0b2b068f6df3b7e3452895952ac95363f2a0650d0e3b408a7b482df002b71a0428f19cfdd2081094b775ac9fc1d151e810313c03d6dbda32758fa2ae34f06bdd8de0f1a30e58259ab810124054c6fee1ddc7891669d12248e3e53b31132e6740873f2d60c1f6455914f70e21fc4d8a25765a2f026d93cf4dbe32a22173c09019f9cd25a27c52cb6b15a1eff5f3cdeb19a0dec406372614804cb4e1b4326d15ed3eb8f972c47280999028dbae6c5bafd757153c1eb447d9f1fc3b066a0b1e09d0fd18655e36c6081fceaa29c0029befddc2006609585113af587f61eb5fa1835cc892d40585bd1d5698f051564dd511f44f912c277b54c9af80e887198b9a94f8bc2d03b62b2272cef760a6687d0998196b1f5624bdb12c15974cd89cad11caa70428ea70c25470658c9f273c73c0a8ca2254712941d318b86be07221c1c996549d3dde7447d2a32cf2fa6a634a1db5c67cf31a03208e53ee766d564d0a6e8571b703ae063e4784718fa3522df36e9f437b986509fdd3a9cdf45154d66006b8618e385414711f57e946da0bf97667747e1db24b14d2fd3ebd7da3314e4ac46ac9b007713a744b5a216d248d07b6e95bf97cceed2c377fd627fa0e4d55d4d9ac7a0677d62311b36a331016e833442363ddca763e29d8ddd02aa806fc880d57b993fb91e95150699d121f2c919b44bbaa7da99f501c3753f981def7c102e19d480edda037efc0936a7ad9df50b1376b91292f72160f125ea8eff631272ae19157d8b22b143666108577ff3847d7b66ce4851827bb06ac08d872dd463b08e6b9fab8baee4718dd4d4176a41a1b212cdcc89a9cf3ae0b6f523d34a58363732b0002467da559b72b6648354ab640ed26ede6189e14dd244325f66e019776ab18755061be47e154ce39e4717bd3e82d41e33bb2a38f950f90fc2bbb2cefb2faf687791f677e9a2ced18135beb8a02e3c914c7f76f344d22be36bd30322545e47f9dfbe39ab444c127238629df49e04d4f2a78404c89262d9b6c14eacc5130dfca23eac58a8b9c1239f809e521851610b2bebeb87eb6ed10722e1eb4ee99afc987f656e28fa4c94ce00f450c2252e8b0bcb63d7f4b1daf189d4fec6a0eff27cd720199233bfdc79bea4c91989e9babefb5b5ad1a5777a120bb989820521753144cd511c9d37afa24d25398e945fd1c10510876d909a0d414d6abb1dc6f08decff25e2751b27bcd485d210f08738c533ef2f4283c2f25490e92d5edfdab7dbf61f89c1e255138aed746b4aa831c90c6b204480ea92331c61357a9aa02a6dd527aacf387400b323e7bc7516dc54cd1822917b7bed12ae2510ea4bc05b01193fad22ce67752a0e96fe5f015d0575c68676cd786b97a1cbb4729191e9e6636e17a18e0ab7a83427a2beaa701bac17d8f3c421fe9fbf1421eaa2f9cbdf7adcd5ba37fd5bd11362397abb015d6d28e66bdc3b94a147223a06f633044145a0bd28815fb92b515573d51d9b5c5baab513e8c4128c994f4d11871f4279cacce2e914c5d1edd41a9a1b83151e037f5cc223c89a04495484717f0d019294103222f7219fa5aac902a925bd3d07495581ac613c82c4979960bf3b17a2b1abf55a0c3a193f4359594c466125a9f97a7fc2dc51650872ae7554ce37969cc148cc2cc447107b4aab04902ea7699e868c333863d75bdcb64136dd680f474f62d4dc965082959f0a127201846c843f1aef4ae044f80e41e74c39d51b6c8ba9502d7bb4c2e9dc0c7872c11ea07da7ff3635c4ac8ccfbfff8489cd8d09ccea02b04f74bd235a6bac2f501a6721a5d202168b828d6b106b141400cb39a5d5ed77d13b87d15fd1efaacbb24ae5eeb854c3263dd2aa28c3ed98afcfe9c087811af0a1a17107671953e3431780da900b4f917bdc92027263da96b4d60f542cc2c82e509be2e2b97e4bffa9c3cd204d3d2cc19c8960078e8e74ade1a3cf15fe27ef6b20172e772a3dc884bf612a80ab2eace1e48cf3648f3adca4abc3214b8955003cc003e578536d2ec7331b59490ece686e352e8b85c7ecf37b685d668480a3a17ca0170ed17ef491496e42584995fe4a3374f222e01026d8ab67436113c264aca1c19c8f2d8e0297a873069fc76c743766555556f26f56e9b64584ab29012ddd9270ce0e65ee8da15e3197f0e0ba16c0289f55542ffabd7b3760ad0528a60ca332400cdcb19bb3820fafa568c51b192fd3242446efe7f297bb539165932d989d1000e8c197a075b68ce08d92b47d4859cbf75060202b7d5a8bdfbd8f3f4b026796104a4501d6b9b0ac4d0c288e4b3bf14cd043909750b54dd89dfba0af1883702ee0648207f313993b9a8669bdc97b6f8e1d880f27e9638b8b919b3f35df0d4a4cb13e79388eb6e11206cf680d0665efafcfb6f7a634cbaded364b22224a971aa3e2bf89dca518517c860d8dbf455865efbae865648cba9e8bdc7cd32e9af0bc7c32aa25fc0b0c35493c8bd144b55dd8dea0db112ce0b11bcdbaa266abba170df3e1b862f038b5fafc43e249434b4868df74be6d0010aa4d44c09b91bf8bfbae3e7276b73347df76d954af4a210c94bc03315190f6a90b988e210fd37ab1cf8b5352625dd786537207de459105e02ceae54571c391fa25a2ea3ce38c7c48bf3965d291af2670efc172e2b9ad90128146162e705eec643aeca5f1a0209c9230d1cf61e9c39bbfc9e9219da275aa1cbe22147fe193ac2330830130e66c3e7eb9b6c4f0c67062f5204a407aa1ef69fd65e88c7212ce545c52c8c66ffcc82487f8594b629f87ee67617f9bfa157b9e98450938cc8ceeb548aafb27731a6db910c2f3d202c63540025366f9d89c39cb0b686d936d2e3836e6c341d7e276069b8601b299a1d19cf2ed96cf7769dad1f6d0848456e758a130e2b5a71346ceedd076dc2500d115e52496919ec8b4a9c90a1256d0921d71c46e69e2742af220d959e7737ebae17952950241397ec0766e7922f06b2942a0fcaf9e31dd2fad3e223612da6a91e121135039f1def7539c63dfc5ca99614f13e97e5c1445c6b76610686fb720d9e228c8b3894d56b4509e39c2c7b15062cf197a7f6b7d97afc08a4612495107fe706b8c5cdbb040dd23f8c9cb732dbd224d178e16aa554b8301e485b59e74121a802db623780ff63442de371fb5a77fa649994d37abdd8f37e9e5c4d1b2d0f42c320ac1c7061ad7ff3396f338966e21b0d7bbd2aa165cdd6f2a279934a7ef1ea0b145f8116afa4921473eeac90f43e6751baa607563814d97d8e5981f4e08663d60aaa136b5252b7b6407974decf3a4a709bb9ec0d95e0ccba44e7eaadd58a5a7414d88abdabb208b20f7ea49b3bcad4770757644454769f27946e9e289c7d582d0e8d351c17bdef0985b3d1eab178d114d350e118515b0f2017a2d173dbd0f9d105977b281e273e7a0161c0a7d98da4fa432edb214d0f373336a89cabb9baa08920e60b0b53760d0428dd28a57e05eac32380fd9e160e19daa8891ca35395014f16ed8d012d33f22e7d41d5201d12dd7939c49bb6361c1bdda7fbaf6bce7550fc014123f6a31e0b82d529a6d0f54bfbc364c60c911f486321236091e7f01e77b31dcb3f844b13078b75de943429987d5ce353a7f6ebd892272d0b16b04d34cac31253abd9d1ed6c38c78d38c15e5d8840190f45b718b4025ce35b79fa5edb416a1c8a2b6da3049ad2756f045aa9b8fdc8e370ee37bfcbb64940783912d98d00222badf84f989b1694925c313f2079e6b4e785ece0bb6ecf9d308bd4eb07ad0b7010da33e4046baba11da3706c8654284da3fc40e944342bbf8b9ddda67974a5082e92e98c8872e2892da7cfc7eec88f12edf372ec6c62aab4d853ffe00f8829071fcbd437983e196a54d1ebc802d2e07004e53ff074e776bada1eb9c7c95dbd511bb89d20bfc0e563e85165bbb8820ec35ddccd3a181a7d8dcb1cb930830b64f307a2e001b1931cfeb11744c8b5d5e4ba316462158381a48272cf70c85474a3c6257448805443e1fbb464f1d59f6c9e7c73c3faf9e7c49cef4725e22e85a314cb1a81f6a8d20dadb4d7656d51157e400462aafc88f0821ac59174b614f0cb4b1d1fb2b54961adbe66a6e3c633c8ebeb09e82366f2f8ad9cc12a03097a6c62462e22525c15fa397556d997133dc53dfe32553453c422d55a842dbe6a01f4f368481dcad44cc429803caf6b140ff493ead1d4fce834b73c12ac73489c5c82d1d0091833e95b095c84a052b0e5b66b3e3b276360db86276ed736d39c65a04dada032291b3237ea5cdd8f9ab325f169b2866ac990754405562f9831ce895ff2d0df961800f3af75ec1ed1cf38b93303e81552ff284447d2ea46166f94027431376d6f1a847fb254374aac9f9ece3e0b383cafa1b6c224c8eb3a96b017e52a8cb4a93611b26156e338d9365c02fdabaee829613cffc2b5a0c5cb95757f45f28c94bd7f2457bb006461ce518ff3801a7e382db239c999acf8ca898e67d17d72ecb696780208aae8938d49205be2d4a5d2094ae8912c57d8e9232196f15ba1f459b035fe12f00d11d33bddcb331bc867e6f1c4c2a52c2c30acae767a1d6c265606607a55084f33e47aae6fd9f6e79503f5697161a40fc994c7bf0146496b9dc41c408fa202514b2d4c7f04f6961eca1fe17391846d7fc84757bdf4f4a6060cd4f98ed4f7098ec5bc944178ef9c49b88b1a2e53de1d99237336b4c0b6973f234964305a1808e6e0c1858df2daa7b1877d90afdb028c3c89a43ef7042fe9c38904360fbc262d69c32b05e446110ee2d8603bffbc0fdb4481f33e517698dcd54bbd48de06b70f07b23c65850c68063ca8557ebbc7e796cc7306d755cf701b7f7cf896007f2f0fc38e421e1a38efde29e2a129ca309f8980e1d4896a061e7d6d963b9fc6a52830144780fae450fc3957fdfb39bc2ec75cefe759f393c866e341ffbb8a2b60c4188df90bf20e1bf41235141b8a259b56009a5c716379288b75a4fa9006fc3185113f52b0c20e5686598d2d281fb35235151c959549a0cedc08d51634bfffa0392f3d72d923acd03d487baca86d252c8da92dee59605a742ac030c9a89b9867f8033d91040102dc0f1b3517fd43144bacc5ae8ca9ee36e0fbd0dbfeac61b1b36e154ca49951e1338ba2f92487a6aa36fb47927431a24a69d337cd8ea5e680958322312add93ad09b6885953ad9003ae124afa391981037c10aabed8118bc04b98162524c11dc8cb722db3ac6803cbee486cdf8c33513c22cd41251988a251e96419c6be87356bc9621efae31b1896e931301e2229ec61e93d4db5b41077f5fc7b188a9751200bd4e58032e702b45ef22e0af05fc05123b333a7a121725a9c61fd02575e449d694602ed596b1b335040f388de51a2452e9ff83e213e3e38c6f52a1b046f24e07e265515112c56ea29bf39253c9a86c9f57dca7345a00a4cdf775706f1e95b16799e4ba12038fbcc2e08709bf658ccfbd1483b4069d0db57f6376a2b31e619856943621b9729d6a6e74dbaa22485792ac25154f65e60ec5acf0c430659c71f52cb233f0448e5e68581abb5582f04d9768b01a55f32b5e9ce141ea51cb4edd9362ff5cfab9c62c22130bd7a02f5c81fd23e2fd3739606558c7e0fb40192e09d0084c6a2710c59d820ded9b0dfb52e305756e0c61edb1ae25a70ea800dd31c9e48109b517c961fe9acfde7071ae40ff98cc4121bc322256f9ab36d6d108e72d7dae149a54ab46cfe8f241861e3485334f33da713ab44fcc3d01966a905ccbd32a363d22fe2781d4c08e0e1fac22f78bca526c0133a72c236eb8a765513d0dbde4270cc3ec7baeed504e673ba128b5b01abb64b2602a4c6ad85634b19110de95ae4ee45349b57ee12c10ed2362836c4fd24a5831b8216cebdc8a43af22bbaffa79dcedf5476c38a0c0f6256efe1f149225568dcd0773b66a0f5591a9c05c20af8d94c7d25aaacbf83f94c21882788bbc3e4b39c28b4ee8a996bb1f10821695e01a394c003d10daecd0d4dbbc07b583d27cc13f37000921f3af89c7a3a19459449376c83ab8ff2dd441343709b2a8b289f21efcb73ffcabaf7c0510d370fbb0248aaee14e17980e4d275c88789cd31a4d6cd2087dd53530365d448714b1789bae49ff1dbd36fa3eca86cb86406a1426453279f8877a9ef3c02afd141b60444570d61f15c5762a79891f438ff47136a11efe3cea777a50fc3aa052abc500a9c6aca82b30a6e8813a8f4374b74f7f55726f93c329917f8b30e1ab59c98801b143d1bb0f80574d08726efb0b1f21f480b56de8c8b115b06c64297e58f936b2cc18773b7c21b694442b8617e4417a1531464ad91e901db9e348f50350f4c3f216d1e25b6584b9d33dab2c84cb0d6e684f6a0eed67bad450c575efc4c0d594e206887a1573529b89fc2631f98a4ec17f03733fa0ff5e67d600f480f5610955b146b73ec0b092980f0d33c0045bf95a8eaab0f0a421a261992b0db14f8778be101f6b0ef437b0890cc015c63fdeb518f4fc8235c5bc445f76fa70474c34ca5b8248fc167187c38a539762a5b0e3dab0b6d69b5fcea61d187d53a882119b9eab118a7f09c3955d823e048c83be5b6b71dff45ad8690a0fb2a510ecf3c37e54ae31b48215c527f02d9b013fb0138c7e2f9d370ea123012bd03fe1e925f469cae5903ea70b93dfae0911b49a1f3e7878ec80d333a557003aefbb777c2c1341a61322d45b23e319beb981b89d42d6d28500672ce4a244e357d0be894af6fd6c3691311610518f1764098418a910a498ac6b8978e4432b79f5f7a60376458c1b593ca2fe4563bfb08a32688623dfd3b861bb0aa45fb8f9cd3b48f268088155ac9112205bc557c7931c1e37d018ef027384710268e5a91a7ff7301b4dd5534f9130ae20df0927c7fad23ea0a0270660946c46ad6ce067cbbbd7bdca6afc18614fbe2f2098158b1111f78af9afc775df64cb81d2bfa5a59ceaa3b52b091216bf6d8facd118aa56c8c098b4da0926502cafe647aa42cea8f7dfe592d03662b335a456d4419fc9e76413861f02caf52a4f4489c24649b317472983e5dd984f81a17d81d89227676376516733962432d1167e2d1663c3035369c5d9edd006ab5a9b34d5c670c64f32218f939710b9107a5bfbe4dc3b378c9a4941a98fb8a78632150d02e13174d118c62e479cc5df24825f4013e21a06b282813668ad425634728d622c7942dbfa145133ad697c75789c89a5507331bf91a05bd83a91a7403f91e2f8c279d2700a3f990b809827fc5b8b44c2a63d289d3de4cb742aea0c3547c278bda86490783ef2164e4be77de089f9aca8c96bdd0f4025ec1b28c46b23b63ef246f6fe9112c9770df978d0b1e1c49c839454ec4b5d2e56a3fa1e666743a89aca491a86d084555685085b93a82aa0b80bf0dc52cbc6b69995f398e3ec9a439bda8f3e71d16ba82a35c75ef65f8e7136ad53d95cb1987ad134d0e01829b382651dfe2d08b2b10f4725cd179cb2edeaad869bebf0d2479bf66f50a23e413249486e0db8a0016d65db73ba629a925c5fbad59b0b91c4081d1290868064b2bf615afbbc9048f01658fb240208041c3e282c7cf6c433a4defd52989300104b975661ca620abee10fabe7ef8fc6a53325afbffba8dd31053389f1db562dfe1a4471510d02cb6bd2d6f47af21e48047838eab00bf0d30b7bb22e68c5e477cf7e6876a05dcd85f4029302348ab9dd41f3385055edc3621db38543d9e9bee69633f504d39a21e10990617fb839efe0c159e8d66eb0d79bf3bde28b5cf5ad8e59d7d2c95205ab7aff62e055183a5aa5fbf7a87d3eeac44971fbc79afbed69007d01ef3838b3b859125220413f9cbbea087d0c890980915ec1860fc7c0d190babdbcc6a92b96d235ed426c0334dd23410c81279726e388a829d6bd677eb2d678cefb2ac120ca725b1e32f9fae15667a3d8e0b2cc51df7ae0512c26b87daa571de0d6645f230f0e6747c225bc2d01348dedc4f2e3a8789c3a20d552ef06ff669a0f44c834ca2aee3034d05ce81e93d3ae5e1b71de9f0e3f5f003e1dffe2fd8f4b0c447dcfa4f7aed18fa17945e0d4cf92deed799619f0a09acb6ae81046f0047dd510493a56cb1498e712d37e585731a65c80f4653abb50f5f5f855a5e3b504aff482443df1d44ddf40408d651d48b444aadc22b5b49687122e1147e4a50f3578b891520f53c62f225c42e0490eb430ae8e33ffe09f0e39d300ced42067da91fc6cd02e311fac20b172b1dec4a4c5c5019d5a1482f38df0876f89ad2734571416300ebd8572beda8e05f1a31d972f9aa895ff52c782404c739333b8c4d65a0da7562c1effd99cf0376050666893ad9320ccb9873c574dc1f61940c5300f58f7b6471295825ce3cc53447", + "public_inputs_hex": "0x0ce1b376e5479afb4df722f877c26647f4e29e254ece539a333093ef73fac2e711cbf664e6e1ab436d8227ba889283c5b88c37545dfcc186a393533996b7bdc90000000000000000000000000000000077117e59dd1feeaa796907ee32a6005e00000000000000000000000000000000eef1d7464190461ca1a8dd367f48f2690da5935cc20672e95aa834ee487f402f7598651b4db414611358e24d7afc7f9e0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000031ccd2641e1e9bba64242cefdf3aba968b556698db1967dd559f0b465375ed0e41a4f5a9fe72cf1cc5a1512597f770cebf0b305ebcf8253761101a5746bc6d44006de2cdb6761ecafb3a9875fe5f28694e7749e5733edecbe3b49a1a34903f4c2033ff88e898ca0a5be229028e8fbf251abf458ec5f8d1ad7f5d6dcfbbd2d51d02a27c7b79209d048001b37b0c550f30837dd7d8b86cc16371235304c6bc2f9dd2b8ccac82963e057a58b2e299874d166843e4b273356423f5a4e25ea487d0ca8000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + } +} diff --git a/circuits/benchmarks/results_secure_agg_small/report.md b/circuits/benchmarks/results_secure_agg_small/report.md new file mode 100644 index 0000000000..d76a004a3c --- /dev/null +++ b/circuits/benchmarks/results_secure_agg_small/report.md @@ -0,0 +1,215 @@ +# Enclave ZK Circuit Benchmarks + +**Generated:** 2026-05-27 18:28:14 UTC + +**Git Branch:** `params/dyn-conf` +**Git Commit:** `de480d631ab48f652be8ca1c8c136a80262c0c19` + +**Committee Size:** `H=5`, `N=5`, `T=2` + +## Run configuration + +Settings for this benchmark run (integration test + Nargo circuit benches on the same host). + +### Integration test (`test_trbfv_actor`) + +| Setting | Value | +| ----------------------------------------------------- | -------------------------------------------- | +| Benchmark mode | `secure` | +| BFV preset (artifacts) | `secure-8192` | +| BFV preset (enum) | `SecureThreshold8192` | +| λ (smudging / error) | 60 | +| Nodes spawned (builder) | 20 | +| Network model | `in_process_bus` | +| Testmode harness | true | +| `proof_aggregation_enabled` | true | +| `BENCHMARK_MULTITHREAD_JOBS` (max concurrent ZK jobs) | 13 | +| Rayon worker threads | 13 | +| CPU cores (host) | 14 | +| `dkg_fold_attestation_verifier` (EIP-712) | `0x7969c5eD335650692Bc04293B07F5BF2e7A673C0` | +| Verbose logging (`run_benchmarks.sh --verbose`) | true | + +### Hardware & software (Nargo / Barretenberg host) + +| | | +| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **CPU** | Apple M4 Pro | +| **CPU cores** | 14 | +| **RAM** | 48.00 GB | +| **OS** | Darwin | +| **Architecture** | arm64 | +| **Nargo** | nargo version = 1.0.0-beta.16 noirc version = 1.0.0-beta.16+2d46fca7203545cbbfb31a0d0328de6c10a8db95 (git version hash: 2d46fca7203545cbbfb31a0d0328de6c10a8db95, is dirty: false) | +| **Barretenberg** | 3.0.0-nightly.20260102 | + +--- + +## Audit status + +On-chain verify gas: **complete** (CRISP Π_user + Enclave Π_DKG / Π_dec replay). + +--- + +## Measurement methodology + +| Metric kind | Source | Meaning | Do **not** use for | +| -------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------ | -------------------------------------------------------------- | +| **wall_clock** | `test_trbfv_actor` phase timers / HLC event span | End-to-end wait in the in-process test harness | Production WAN latency; per-node deployment cost | +| **isolated_nargo** | `benchmark_circuit.sh` per circuit | Single `bb prove` on oracle witness, one circuit at a time | Full protocol pipeline (different witness path) | +| **tracked_job_wall** | `MultithreadReport` per `ComputeRequest` | Wall time of each job on the shared Rayon pool (≤ `BENCHMARK_MULTITHREAD_JOBS` concurrent) | End-to-end time — **sums exceed wall clock** when jobs overlap | + +**Harness limits (integration):** all ciphernodes share one process and bus +(`network_model: in_process_bus`); sortition registers extra nodes; `testmode_*` enabled. Compare +runs only with the same `benchmark_mode`, proof-aggregation flag, `BENCHMARK_MULTITHREAD_JOBS`, +commit, and hardware. + +--- + +## Protocol Summary + +### Circuit Benchmarks (isolated Nargo + Barretenberg) + +Single-circuit `bb prove` on the benchmark oracle witness (not the integration actor pipeline). + +| Circuit | Constraints | Prove (s) | Verify (ms) | Proof (KB) | +| -------------------- | ----------- | --------- | ----------- | ---------- | +| C0 | 287764 | 1.42 | 25.93 | 15.88 | +| C1 | 2432074 | 9.16 | 25.45 | 15.88 | +| C2a | 2424942 | 9.17 | 24.93 | 15.88 | +| C2b | 3867595 | 10.90 | 24.73 | 15.88 | +| C3a | 3563512 | 10.76 | 25.30 | 15.88 | +| C3b | 3563512 | 10.76 | 25.30 | 15.88 | +| C4a | 2418310 | 9.14 | 25.53 | 15.88 | +| C4b | 2418310 | 9.14 | 25.53 | 15.88 | +| C5 | 4656265 | 18.41 | 25.33 | 15.88 | +| user_data_encryption | 1678200 | 5.59 | 25.44 | 15.88 | +| C6 | 3001847 | 10.18 | 25.04 | 15.88 | +| C7 | 136374 | 0.74 | 24.68 | 15.88 | + +### Artifacts + +| Artifact | Proof size | Public input size | Verify gas | Calldata gas | Total gas | +| -------- | ---------- | ----------------- | ---------- | ------------ | --------- | +| Π_DKG | 10.69 KB | 0.66 KB | 3136885 | 178428 | 3315313 | +| Π_user | 15.88 KB | 0.12 KB | 2972977 | 193300 | 3166277 | +| Π_dec | 10.69 KB | 3.56 KB | 3646908 | 188532 | 3835440 | + +### Role / Phase / Activity + +| Role | Phase | Activity | Metric | Duration | Proof size | Bandwidth | +| --------------- | ----- | ----------------------------------------- | -------------- | --------- | ---------- | --------- | +| Each ciphernode | P1 | one-time DKG participation (test harness) | wall_clock | 1669.47 s | 127.00 KB | 129.31 KB | +| Aggregator | P2 | C5 + Π_DKG fold (aggregator span) | wall_clock | 400.03 s | 10.69 KB | 11.34 KB | +| User | P3 | per user input | isolated_nargo | 10.75 s | 15.88 KB | 16.00 KB | +| Each ciphernode | P4 | per computation output (C6) | isolated_nargo | 10.18 s | 15.88 KB | 16.00 KB | +| Aggregator | P4 | C7 + Π_dec fold (full publish→aggregate) | wall_clock | 205.70 s | 10.69 KB | 14.25 KB | +| Aggregator | P4 | C7 + fold only (pending→plaintext span) | wall_clock | 64.51 s | 10.69 KB | 14.25 KB | + +_P2 **tracked_job_wall** sum (ZkDkgAggregation + ZkPkAggregation, parallelizable): **77.28 s** — not +comparable to P2 wall_clock row above._ + +## Integration test (`test_trbfv_actor`) + +### End-to-end phase timings (integration test) + +| Phase | Metric | Duration (s) | +| ------------------------------------------------------------------ | ------------ | ------------ | +| Starting trbfv actor test | `wall_clock` | 0.00 | +| Setup completed | `wall_clock` | 2.82 | +| Committee Setup Completed | `wall_clock` | 20.13 | +| Committee Finalization Complete | `wall_clock` | 0.00 | +| Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall) | `wall_clock` | 400.03 | +| ThresholdShares -> PublicKeyAggregated | `wall_clock` | 1669.47 | +| E3Request -> PublicKeyAggregated | `wall_clock` | 1670.00 | +| Application CT Gen | `wall_clock` | 0.30 | +| Running FHE Application | `wall_clock` | 0.00 | +| Aggregator P4: Aggregation pending -> PlaintextAggregated (wall) | `wall_clock` | 64.51 | +| Ciphertext published -> PlaintextAggregated | `wall_clock` | 205.70 | +| Entire Test | `wall_clock` | 1898.95 | + +### Multithread job timings (`tracked_job_wall`) + +| Name | Avg (s) | Runs | Total (s) | +| ----------------------------- | ------- | ---- | --------- | +| CalculateDecryptionKey | 0.06 | 5 | 0.30 | +| CalculateDecryptionShare | 0.16 | 5 | 0.80 | +| CalculateThresholdDecryption | 0.23 | 1 | 0.23 | +| GenEsiSss | 0.16 | 5 | 0.78 | +| GenPkShareAndSkSss | 0.31 | 5 | 1.57 | +| NodeDkgFold/c2ab_fold | 11.85 | 5 | 59.24 | +| NodeDkgFold/c3a_fold | 169.18 | 5 | 845.92 | +| NodeDkgFold/c3ab_fold | 12.82 | 5 | 64.09 | +| NodeDkgFold/c3b_fold | 151.49 | 5 | 757.46 | +| NodeDkgFold/c4ab_fold | 10.85 | 5 | 54.24 | +| NodeDkgFold/node_fold | 23.96 | 5 | 119.78 | +| ZkDecryptedSharesAggregation | 3.33 | 1 | 3.33 | +| ZkDecryptionAggregation | 60.96 | 1 | 60.96 | +| ZkDkgAggregation | 28.09 | 1 | 28.09 | +| ZkDkgShareDecryption | 61.25 | 10 | 612.53 | +| ZkNodeDkgFold | 380.15 | 5 | 1900.77 | +| ZkPkAggregation | 49.19 | 1 | 49.19 | +| ZkPkBfv | 5.47 | 5 | 27.33 | +| ZkPkGeneration | 67.43 | 5 | 337.16 | +| ZkShareComputation | 50.51 | 10 | 505.06 | +| ZkShareEncryption | 112.37 | 120 | 13484.59 | +| ZkThresholdShareDecryption | 133.84 | 5 | 669.21 | +| ZkVerifyShareDecryptionProofs | 0.29 | 5 | 1.45 | +| ZkVerifyShareProofs | 1.08 | 7 | 7.54 | + +Sum of tracked job wall time: **19591.61 s** — **not** end-to-end latency (jobs run in parallel up +to `BENCHMARK_MULTITHREAD_JOBS`). + +### NodeDkgFold sub-steps (`tracked_job_wall`, per fold prove) + +| Step | Avg (s) | Runs | Total (s) | +| --------- | ------- | ---- | --------- | +| c2ab_fold | 11.85 | 5 | 59.24 | +| c3a_fold | 169.18 | 5 | 845.92 | +| c3ab_fold | 12.82 | 5 | 64.09 | +| c3b_fold | 151.49 | 5 | 757.46 | +| c4ab_fold | 10.85 | 5 | 54.24 | +| node_fold | 23.96 | 5 | 119.78 | + +### Aggregation jobs (`tracked_job_wall`) + +| Operation | Avg (s) | Runs | Total (s) | +| ---------------------------- | ------- | ---- | --------- | +| ZkDecryptedSharesAggregation | 3.33 | 1 | 3.33 | +| ZkDecryptionAggregation | 60.96 | 1 | 60.96 | +| ZkDkgAggregation | 28.09 | 1 | 28.09 | +| ZkNodeDkgFold | 380.15 | 5 | 1900.77 | +| ZkPkAggregation | 49.19 | 1 | 49.19 | + +Sum of aggregation job tracked time: **2042.34 s** (parallel CPU work; not P1/P2 wall clock). + +### Folded on-chain artifacts (exported for Π_DKG / Π_dec gas) + +| Artifact | Proof (bytes) | Public inputs (bytes) | +| --------------------- | ------------- | --------------------- | +| dkg_aggregator | 10944 | 672 | +| decryption_aggregator | 10944 | 3648 | + +## Raw circuit benchmark JSON (Nargo) + +Source files for the **Circuit Benchmarks** table. Persist this directory with +`crisp_verify_gas.json` (and optional `integration_summary.json`) to regenerate the report without +re-running the integration test. + +| File | +| ----------------------------------------------------- | +| `config_default.json` | +| `dkg_e_sm_share_computation_default.json` | +| `dkg_pk_default.json` | +| `dkg_share_decryption_default.json` | +| `dkg_share_encryption_default.json` | +| `dkg_sk_share_computation_default.json` | +| `threshold_decrypted_shares_aggregation_default.json` | +| `threshold_pk_aggregation_default.json` | +| `threshold_pk_generation_default.json` | +| `threshold_share_decryption_default.json` | +| `threshold_user_data_encryption_ct0_default.json` | +| `threshold_user_data_encryption_ct1_default.json` | + +## Notes + +- All nodes are executed on the same machine in this benchmark run, so inter-node network latency is + effectively 0. diff --git a/circuits/benchmarks/results_secure_no_agg/crisp_verify_gas.json b/circuits/benchmarks/results_secure_no_agg/crisp_verify_gas.json deleted file mode 100644 index 5014f0c4f9..0000000000 --- a/circuits/benchmarks/results_secure_no_agg/crisp_verify_gas.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "verify_gas": { - "dkg": null, - "user": 2972977, - "dec": null - }, - "source": "folded_proof_export_plus_crisp_verify_test", - "artifact_sizes_bytes": { - "dkg": { - "proof": 0, - "public_inputs": 0 - }, - "dec": { - "proof": 0, - "public_inputs": 0 - } - }, - "calldata_gas": { - "dkg": { - "proof": 0, - "public_inputs": 0, - "total": 0 - }, - "dec": { - "proof": 0, - "public_inputs": 0, - "total": 0 - } - }, - "integration_summary": { - "integration_test": "test_trbfv_actor", - "benchmark_config": { - "mode": "secure", - "bfv_preset_subdir": "secure-8192", - "bfv_preset": "SecureThreshold8192", - "lambda": 60, - "proof_aggregation_enabled": false, - "multithread_concurrent_jobs": 13, - "committee_h": 3, - "committee_n": 3, - "committee_t": 1, - "nodes_spawned": 20, - "network_model": "in_process_bus", - "testmode_harness": true - }, - "proof_aggregation_enabled": false, - "multithread": { "rayon_threads": 13, "max_simultaneous_rayon_tasks": 13, "cores_available": 14 }, - "operation_timings": [ - { "name": "CalculateDecryptionKey", "avg_seconds": 0.036104014, "runs": 3, "total_seconds": 0.108312043 }, - { "name": "CalculateDecryptionShare", "avg_seconds": 0.155666888, "runs": 3, "total_seconds": 0.467000666 }, - { "name": "CalculateThresholdDecryption", "avg_seconds": 0.234273375, "runs": 1, "total_seconds": 0.234273375 }, - { "name": "GenEsiSss", "avg_seconds": 0.088555027, "runs": 3, "total_seconds": 0.265665083 }, - { "name": "GenPkShareAndSkSss", "avg_seconds": 0.120120347, "runs": 3, "total_seconds": 0.360361042 }, - { "name": "ZkDecryptedSharesAggregation", "avg_seconds": 2.90879575, "runs": 1, "total_seconds": 2.90879575 }, - { "name": "ZkDkgShareDecryption", "avg_seconds": 20.727147222, "runs": 6, "total_seconds": 124.362883334 }, - { "name": "ZkPkAggregation", "avg_seconds": 11.371170708, "runs": 1, "total_seconds": 11.371170708 }, - { "name": "ZkPkBfv", "avg_seconds": 3.53991425, "runs": 3, "total_seconds": 10.61974275 }, - { "name": "ZkPkGeneration", "avg_seconds": 96.487730153, "runs": 3, "total_seconds": 289.463190459 }, - { "name": "ZkShareComputation", "avg_seconds": 50.543073166, "runs": 6, "total_seconds": 303.258439 }, - { "name": "ZkShareEncryption", "avg_seconds": 115.255456694, "runs": 36, "total_seconds": 4149.196440999 }, - { "name": "ZkThresholdShareDecryption", "avg_seconds": 102.677723166, "runs": 3, "total_seconds": 308.0331695 }, - { "name": "ZkVerifyShareDecryptionProofs", "avg_seconds": 0.103283111, "runs": 3, "total_seconds": 0.309849333 }, - { "name": "ZkVerifyShareProofs", "avg_seconds": 0.313393508, "runs": 5, "total_seconds": 1.566967541 } - ], - "operation_timings_total_seconds": 5202.526261583, - "operation_timings_metric": "tracked_job_wall", - "phase_timings": [ - { "label": "Starting trbfv actor test", "seconds": 0e-9, "metric": "wall_clock" }, - { "label": "Setup completed", "seconds": 2.6577995, "metric": "wall_clock" }, - { "label": "Committee Setup Completed", "seconds": 20.181663416, "metric": "wall_clock" }, - { "label": "Committee Finalization Complete", "seconds": 0.001112875, "metric": "wall_clock" }, - { "label": "Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall)", "seconds": 11.43493, "metric": "wall_clock" }, - { "label": "ThresholdShares -> PublicKeyAggregated", "seconds": 461.185495792, "metric": "wall_clock" }, - { "label": "E3Request -> PublicKeyAggregated", "seconds": 461.7008915, "metric": "wall_clock" }, - { "label": "Application CT Gen", "seconds": 0.357493625, "metric": "wall_clock" }, - { "label": "Running FHE Application", "seconds": 0.000820875, "metric": "wall_clock" }, - { "label": "Aggregator P4: Aggregation pending -> PlaintextAggregated (wall)", "seconds": 3.068546, "metric": "wall_clock" }, - { "label": "Ciphertext published -> PlaintextAggregated", "seconds": 144.435938625, "metric": "wall_clock" }, - { "label": "Entire Test", "seconds": 629.335317291, "metric": "wall_clock" } - ], - "folded_artifacts": null - }, - "test_exit_code": { - "crisp": 0, - "folded_export": 0, - "enclave_contracts": 0 - } -} diff --git a/circuits/benchmarks/results_secure_no_agg/benchmark_run_meta.json b/circuits/benchmarks/results_secure_no_agg_micro/benchmark_run_meta.json similarity index 100% rename from circuits/benchmarks/results_secure_no_agg/benchmark_run_meta.json rename to circuits/benchmarks/results_secure_no_agg_micro/benchmark_run_meta.json diff --git a/circuits/benchmarks/results_secure_no_agg_micro/crisp_verify_gas.json b/circuits/benchmarks/results_secure_no_agg_micro/crisp_verify_gas.json new file mode 100644 index 0000000000..5b5d500dcd --- /dev/null +++ b/circuits/benchmarks/results_secure_no_agg_micro/crisp_verify_gas.json @@ -0,0 +1,88 @@ +{ + "verify_gas": { + "dkg": null, + "user": 2972869, + "dec": null + }, + "source": "folded_proof_export_plus_crisp_verify_test", + "artifact_sizes_bytes": { + "dkg": { + "proof": 0, + "public_inputs": 0 + }, + "dec": { + "proof": 0, + "public_inputs": 0 + } + }, + "calldata_gas": { + "dkg": { + "proof": 0, + "public_inputs": 0, + "total": 0 + }, + "dec": { + "proof": 0, + "public_inputs": 0, + "total": 0 + } + }, + "integration_summary": { + "integration_test": "test_trbfv_actor", + "benchmark_config": { + "mode": "secure", + "bfv_preset_subdir": "secure-8192", + "bfv_preset": "SecureThreshold8192", + "lambda": 60, + "proof_aggregation_enabled": false, + "multithread_concurrent_jobs": 13, + "committee_h": 3, + "committee_n": 3, + "committee_t": 1, + "nodes_spawned": 20, + "network_model": "in_process_bus", + "testmode_harness": true + }, + "proof_aggregation_enabled": false, + "multithread": { "rayon_threads": 13, "max_simultaneous_rayon_tasks": 13, "cores_available": 14 }, + "operation_timings": [ + { "name": "CalculateDecryptionKey", "avg_seconds": 0.051704847, "runs": 3, "total_seconds": 0.155114542 }, + { "name": "CalculateDecryptionShare", "avg_seconds": 0.157532861, "runs": 3, "total_seconds": 0.472598583 }, + { "name": "CalculateThresholdDecryption", "avg_seconds": 0.241033167, "runs": 1, "total_seconds": 0.241033167 }, + { "name": "GenEsiSss", "avg_seconds": 0.068493249, "runs": 3, "total_seconds": 0.205479749 }, + { "name": "GenPkShareAndSkSss", "avg_seconds": 0.096295819, "runs": 3, "total_seconds": 0.288887458 }, + { "name": "ZkDecryptedSharesAggregation", "avg_seconds": 2.804543209, "runs": 1, "total_seconds": 2.804543209 }, + { "name": "ZkDkgShareDecryption", "avg_seconds": 21.82194018, "runs": 6, "total_seconds": 130.931641083 }, + { "name": "ZkPkAggregation", "avg_seconds": 12.009726, "runs": 1, "total_seconds": 12.009726 }, + { "name": "ZkPkBfv", "avg_seconds": 3.528275806, "runs": 3, "total_seconds": 10.584827418 }, + { "name": "ZkPkGeneration", "avg_seconds": 82.938874222, "runs": 3, "total_seconds": 248.816622668 }, + { "name": "ZkShareComputation", "avg_seconds": 70.235628104, "runs": 6, "total_seconds": 421.413768625 }, + { "name": "ZkShareEncryption", "avg_seconds": 120.769739194, "runs": 36, "total_seconds": 4347.710611001 }, + { "name": "ZkThresholdShareDecryption", "avg_seconds": 95.062077694, "runs": 3, "total_seconds": 285.186233082 }, + { "name": "ZkVerifyShareDecryptionProofs", "avg_seconds": 0.099425374, "runs": 3, "total_seconds": 0.298276124 }, + { "name": "ZkVerifyShareProofs", "avg_seconds": 0.321428608, "runs": 5, "total_seconds": 1.607143041 } + ], + "operation_timings_total_seconds": 5462.72650575, + "operation_timings_metric": "tracked_job_wall", + "phase_timings": [ + { "label": "Starting trbfv actor test", "seconds": 0e-9, "metric": "wall_clock" }, + { "label": "Setup completed", "seconds": 3.034527042, "metric": "wall_clock" }, + { "label": "Committee Setup Completed", "seconds": 20.111298625, "metric": "wall_clock" }, + { "label": "Committee Finalization Complete", "seconds": 0.001936125, "metric": "wall_clock" }, + { "label": "Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall)", "seconds": 12.061739, "metric": "wall_clock" }, + { "label": "ThresholdShares -> PublicKeyAggregated", "seconds": 466.548189375, "metric": "wall_clock" }, + { "label": "E3Request -> PublicKeyAggregated", "seconds": 467.102610875, "metric": "wall_clock" }, + { "label": "Application CT Gen", "seconds": 0.316549625, "metric": "wall_clock" }, + { "label": "Running FHE Application", "seconds": 0.000933208, "metric": "wall_clock" }, + { "label": "Aggregator P4: Aggregation pending -> PlaintextAggregated (wall)", "seconds": 2.934427, "metric": "wall_clock" }, + { "label": "Ciphertext published -> PlaintextAggregated", "seconds": 100.616335584, "metric": "wall_clock" }, + { "label": "Entire Test", "seconds": 591.18516725, "metric": "wall_clock" } + ], + "folded_artifacts": null + }, + "test_exit_code": { + "crisp": 0, + "folded_export": 0, + "enclave_contracts": 0 + } +} diff --git a/circuits/benchmarks/results_secure_no_agg/integration_summary.json b/circuits/benchmarks/results_secure_no_agg_micro/integration_summary.json similarity index 66% rename from circuits/benchmarks/results_secure_no_agg/integration_summary.json rename to circuits/benchmarks/results_secure_no_agg_micro/integration_summary.json index 57b3f5eb94..7f7c574c69 100644 --- a/circuits/benchmarks/results_secure_no_agg/integration_summary.json +++ b/circuits/benchmarks/results_secure_no_agg_micro/integration_summary.json @@ -23,96 +23,96 @@ "operation_timings": [ { "name": "CalculateDecryptionKey", - "avg_seconds": 0.036104014, + "avg_seconds": 0.051704847, "runs": 3, - "total_seconds": 0.108312043 + "total_seconds": 0.155114542 }, { "name": "CalculateDecryptionShare", - "avg_seconds": 0.155666888, + "avg_seconds": 0.157532861, "runs": 3, - "total_seconds": 0.467000666 + "total_seconds": 0.472598583 }, { "name": "CalculateThresholdDecryption", - "avg_seconds": 0.234273375, + "avg_seconds": 0.241033167, "runs": 1, - "total_seconds": 0.234273375 + "total_seconds": 0.241033167 }, { "name": "GenEsiSss", - "avg_seconds": 0.088555027, + "avg_seconds": 0.068493249, "runs": 3, - "total_seconds": 0.265665083 + "total_seconds": 0.205479749 }, { "name": "GenPkShareAndSkSss", - "avg_seconds": 0.120120347, + "avg_seconds": 0.096295819, "runs": 3, - "total_seconds": 0.360361042 + "total_seconds": 0.288887458 }, { "name": "ZkDecryptedSharesAggregation", - "avg_seconds": 2.90879575, + "avg_seconds": 2.804543209, "runs": 1, - "total_seconds": 2.90879575 + "total_seconds": 2.804543209 }, { "name": "ZkDkgShareDecryption", - "avg_seconds": 20.727147222, + "avg_seconds": 21.82194018, "runs": 6, - "total_seconds": 124.362883334 + "total_seconds": 130.931641083 }, { "name": "ZkPkAggregation", - "avg_seconds": 11.371170708, + "avg_seconds": 12.009726, "runs": 1, - "total_seconds": 11.371170708 + "total_seconds": 12.009726 }, { "name": "ZkPkBfv", - "avg_seconds": 3.53991425, + "avg_seconds": 3.528275806, "runs": 3, - "total_seconds": 10.61974275 + "total_seconds": 10.584827418 }, { "name": "ZkPkGeneration", - "avg_seconds": 96.487730153, + "avg_seconds": 82.938874222, "runs": 3, - "total_seconds": 289.463190459 + "total_seconds": 248.816622668 }, { "name": "ZkShareComputation", - "avg_seconds": 50.543073166, + "avg_seconds": 70.235628104, "runs": 6, - "total_seconds": 303.258439 + "total_seconds": 421.413768625 }, { "name": "ZkShareEncryption", - "avg_seconds": 115.255456694, + "avg_seconds": 120.769739194, "runs": 36, - "total_seconds": 4149.196440999 + "total_seconds": 4347.710611001 }, { "name": "ZkThresholdShareDecryption", - "avg_seconds": 102.677723166, + "avg_seconds": 95.062077694, "runs": 3, - "total_seconds": 308.0331695 + "total_seconds": 285.186233082 }, { "name": "ZkVerifyShareDecryptionProofs", - "avg_seconds": 0.103283111, + "avg_seconds": 0.099425374, "runs": 3, - "total_seconds": 0.309849333 + "total_seconds": 0.298276124 }, { "name": "ZkVerifyShareProofs", - "avg_seconds": 0.313393508, + "avg_seconds": 0.321428608, "runs": 5, - "total_seconds": 1.566967541 + "total_seconds": 1.607143041 } ], - "operation_timings_total_seconds": 5202.526261583, + "operation_timings_total_seconds": 5462.72650575, "operation_timings_metric": "tracked_job_wall", "phase_timings": [ { @@ -122,57 +122,57 @@ }, { "label": "Setup completed", - "seconds": 2.6577995, + "seconds": 3.034527042, "metric": "wall_clock" }, { "label": "Committee Setup Completed", - "seconds": 20.181663416, + "seconds": 20.111298625, "metric": "wall_clock" }, { "label": "Committee Finalization Complete", - "seconds": 0.001112875, + "seconds": 0.001936125, "metric": "wall_clock" }, { "label": "Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall)", - "seconds": 11.43493, + "seconds": 12.061739, "metric": "wall_clock" }, { "label": "ThresholdShares -> PublicKeyAggregated", - "seconds": 461.185495792, + "seconds": 466.548189375, "metric": "wall_clock" }, { "label": "E3Request -> PublicKeyAggregated", - "seconds": 461.7008915, + "seconds": 467.102610875, "metric": "wall_clock" }, { "label": "Application CT Gen", - "seconds": 0.357493625, + "seconds": 0.316549625, "metric": "wall_clock" }, { "label": "Running FHE Application", - "seconds": 0.000820875, + "seconds": 0.000933208, "metric": "wall_clock" }, { "label": "Aggregator P4: Aggregation pending -> PlaintextAggregated (wall)", - "seconds": 3.068546, + "seconds": 2.934427, "metric": "wall_clock" }, { "label": "Ciphertext published -> PlaintextAggregated", - "seconds": 144.435938625, + "seconds": 100.616335584, "metric": "wall_clock" }, { "label": "Entire Test", - "seconds": 629.335317291, + "seconds": 591.18516725, "metric": "wall_clock" } ], diff --git a/circuits/benchmarks/results_secure_no_agg/report.md b/circuits/benchmarks/results_secure_no_agg_micro/report.md similarity index 74% rename from circuits/benchmarks/results_secure_no_agg/report.md rename to circuits/benchmarks/results_secure_no_agg_micro/report.md index b3d22c5270..76cc79b6ed 100644 --- a/circuits/benchmarks/results_secure_no_agg/report.md +++ b/circuits/benchmarks/results_secure_no_agg_micro/report.md @@ -1,9 +1,9 @@ # Enclave ZK Circuit Benchmarks -**Generated:** 2026-05-23 15:56:04 UTC +**Generated:** 2026-05-27 15:16:58 UTC -**Git Branch:** `feat/1549` -**Git Commit:** `604ef9af71651ffae19546146b78a7940744741f` +**Git Branch:** `params/dyn-conf` +**Git Commit:** `b015a7ed6e5c7c989f2fd267cf14647865854100` **Committee Size:** `H=3`, `N=3`, `T=1` @@ -74,39 +74,39 @@ Single-circuit `bb prove` on the benchmark oracle witness (not the integration a | Circuit | Constraints | Prove (s) | Verify (ms) | Proof (KB) | | -------------------- | ----------- | --------- | ----------- | ---------- | -| C0 | 287764 | 1.43 | 25.44 | 15.88 | -| C1 | 2432074 | 9.38 | 26.85 | 15.88 | -| C2a | 1446348 | 5.27 | 25.40 | 15.88 | -| C2b | 2889001 | 9.76 | 26.04 | 15.88 | -| C3a | 3563512 | 11.04 | 26.42 | 15.88 | -| C3b | 3563512 | 11.04 | 26.42 | 15.88 | -| C4a | 1961956 | 5.97 | 26.68 | 15.88 | -| C4b | 1961956 | 5.97 | 26.68 | 15.88 | -| C5 | 3719555 | 11.05 | 26.65 | 15.88 | -| user_data_encryption | 1678200 | 5.79 | 26.44 | 15.88 | -| C6 | 3001847 | 10.72 | 26.87 | 15.88 | -| C7 | 109424 | 0.52 | 26.65 | 15.88 | +| C0 | 287764 | 1.53 | 27.12 | 15.88 | +| C1 | 2432074 | 9.73 | 28.71 | 15.88 | +| C2a | 1446348 | 5.60 | 26.71 | 15.88 | +| C2b | 2889001 | 10.88 | 26.18 | 15.88 | +| C3a | 3563512 | 11.08 | 25.14 | 15.88 | +| C3b | 3563512 | 11.08 | 25.14 | 15.88 | +| C4a | 1961956 | 6.03 | 26.05 | 15.88 | +| C4b | 1961956 | 6.03 | 26.05 | 15.88 | +| C5 | 3719555 | 11.47 | 28.81 | 15.88 | +| user_data_encryption | 1678200 | 5.78 | 26.54 | 15.88 | +| C6 | 3001847 | 10.38 | 26.76 | 15.88 | +| C7 | 109424 | 0.52 | 26.43 | 15.88 | ### Artifacts | Artifact | Proof size | Public input size | Verify gas | Calldata gas | Total gas | | -------- | ---------- | ----------------- | ---------- | ------------ | --------- | -| Π_DKG | 15.88 KB | 0.12 KB | N/A | 197956 | N/A | -| Π_user | 15.88 KB | 0.12 KB | 2972977 | 193300 | 3166277 | -| Π_dec | 15.88 KB | 3.25 KB | N/A | 188136 | N/A | +| Π_DKG | 15.88 KB | 0.12 KB | N/A | 198016 | N/A | +| Π_user | 15.88 KB | 0.12 KB | 2972869 | 193264 | 3166133 | +| Π_dec | 15.88 KB | 3.25 KB | N/A | 188220 | N/A | ### Role / Phase / Activity -| Role | Phase | Activity | Metric | Duration | Proof size | Bandwidth | -| --------------- | ----- | ----------------------------------------- | -------------- | --------- | ---------- | --------- | -| Each ciphernode | P1 | one-time DKG participation (test harness) | wall_clock | 1226.64 s | 127.00 KB | 128.56 KB | -| Aggregator | P2 | C5 + Π_DKG fold (aggregator span) | wall_clock | 49.16 s | 15.88 KB | 16.00 KB | -| User | P3 | per user input | isolated_nargo | 11.17 s | 15.88 KB | 16.00 KB | -| Each ciphernode | P4 | per computation output (C6) | isolated_nargo | 10.72 s | 15.88 KB | 16.00 KB | -| Aggregator | P4 | C7 + Π_dec fold (full publish→aggregate) | wall_clock | 331.86 s | 15.88 KB | 19.12 KB | -| Aggregator | P4 | C7 + fold only (pending→plaintext span) | wall_clock | 19.35 s | 15.88 KB | 19.12 KB | +| Role | Phase | Activity | Metric | Duration | Proof size | Bandwidth | +| --------------- | ----- | ----------------------------------------- | -------------- | -------- | ---------- | --------- | +| Each ciphernode | P1 | one-time DKG participation (test harness) | wall_clock | 466.55 s | 127.00 KB | 128.56 KB | +| Aggregator | P2 | C5 + Π_DKG fold (aggregator span) | wall_clock | 12.06 s | 15.88 KB | 16.00 KB | +| User | P3 | per user input | isolated_nargo | 11.29 s | 15.88 KB | 16.00 KB | +| Each ciphernode | P4 | per computation output (C6) | isolated_nargo | 10.38 s | 15.88 KB | 16.00 KB | +| Aggregator | P4 | C7 + Π_dec fold (full publish→aggregate) | wall_clock | 100.62 s | 15.88 KB | 19.12 KB | +| Aggregator | P4 | C7 + fold only (pending→plaintext span) | wall_clock | 2.93 s | 15.88 KB | 19.12 KB | -_P2 **tracked_job_wall** sum (ZkDkgAggregation + ZkPkAggregation, parallelizable): **49.00 s** — not +_P2 **tracked_job_wall** sum (ZkDkgAggregation + ZkPkAggregation, parallelizable): **12.01 s** — not comparable to P2 wall_clock row above._ ## Integration test (`test_trbfv_actor`) @@ -116,40 +116,40 @@ comparable to P2 wall_clock row above._ | Phase | Metric | Duration (s) | | ------------------------------------------------------------------ | ------------ | ------------ | | Starting trbfv actor test | `wall_clock` | 0.00 | -| Setup completed | `wall_clock` | 3.29 | -| Committee Setup Completed | `wall_clock` | 20.25 | +| Setup completed | `wall_clock` | 3.03 | +| Committee Setup Completed | `wall_clock` | 20.11 | | Committee Finalization Complete | `wall_clock` | 0.00 | -| Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall) | `wall_clock` | 49.16 | -| ThresholdShares -> PublicKeyAggregated | `wall_clock` | 1226.64 | -| E3Request -> PublicKeyAggregated | `wall_clock` | 1233.99 | -| Application CT Gen | `wall_clock` | 7.69 | -| Running FHE Application | `wall_clock` | 0.08 | -| Aggregator P4: Aggregation pending -> PlaintextAggregated (wall) | `wall_clock` | 19.35 | -| Ciphertext published -> PlaintextAggregated | `wall_clock` | 331.86 | -| Entire Test | `wall_clock` | 1597.16 | +| Aggregator P2: PkAggregation pending -> PublicKeyAggregated (wall) | `wall_clock` | 12.06 | +| ThresholdShares -> PublicKeyAggregated | `wall_clock` | 466.55 | +| E3Request -> PublicKeyAggregated | `wall_clock` | 467.10 | +| Application CT Gen | `wall_clock` | 0.32 | +| Running FHE Application | `wall_clock` | 0.00 | +| Aggregator P4: Aggregation pending -> PlaintextAggregated (wall) | `wall_clock` | 2.93 | +| Ciphertext published -> PlaintextAggregated | `wall_clock` | 100.62 | +| Entire Test | `wall_clock` | 591.19 | ### Multithread job timings (`tracked_job_wall`) | Name | Avg (s) | Runs | Total (s) | | ----------------------------- | ------- | ---- | --------- | -| CalculateDecryptionKey | 0.62 | 3 | 1.87 | -| CalculateDecryptionShare | 2.17 | 3 | 6.52 | -| CalculateThresholdDecryption | 1.95 | 1 | 1.95 | -| GenEsiSss | 0.75 | 3 | 2.25 | -| GenPkShareAndSkSss | 1.55 | 3 | 4.65 | -| ZkDecryptedSharesAggregation | 18.93 | 1 | 18.93 | -| ZkDkgShareDecryption | 55.89 | 6 | 335.31 | -| ZkPkAggregation | 49.00 | 1 | 49.00 | -| ZkPkBfv | 6.07 | 3 | 18.22 | -| ZkPkGeneration | 380.69 | 3 | 1142.08 | -| ZkShareComputation | 118.56 | 6 | 711.37 | -| ZkShareEncryption | 297.63 | 36 | 10714.67 | -| ZkThresholdShareDecryption | 299.47 | 3 | 898.41 | -| ZkVerifyShareDecryptionProofs | 0.10 | 3 | 0.29 | -| ZkVerifyShareProofs | 0.30 | 5 | 1.48 | - -Sum of tracked job wall time: **13907.01 s** — **not** end-to-end latency (jobs run in parallel up -to `BENCHMARK_MULTITHREAD_JOBS`). +| CalculateDecryptionKey | 0.05 | 3 | 0.16 | +| CalculateDecryptionShare | 0.16 | 3 | 0.47 | +| CalculateThresholdDecryption | 0.24 | 1 | 0.24 | +| GenEsiSss | 0.07 | 3 | 0.21 | +| GenPkShareAndSkSss | 0.10 | 3 | 0.29 | +| ZkDecryptedSharesAggregation | 2.80 | 1 | 2.80 | +| ZkDkgShareDecryption | 21.82 | 6 | 130.93 | +| ZkPkAggregation | 12.01 | 1 | 12.01 | +| ZkPkBfv | 3.53 | 3 | 10.58 | +| ZkPkGeneration | 82.94 | 3 | 248.82 | +| ZkShareComputation | 70.24 | 6 | 421.41 | +| ZkShareEncryption | 120.77 | 36 | 4347.71 | +| ZkThresholdShareDecryption | 95.06 | 3 | 285.19 | +| ZkVerifyShareDecryptionProofs | 0.10 | 3 | 0.30 | +| ZkVerifyShareProofs | 0.32 | 5 | 1.61 | + +Sum of tracked job wall time: **5462.73 s** — **not** end-to-end latency (jobs run in parallel up to +`BENCHMARK_MULTITHREAD_JOBS`). _Baseline run: node DKG folds and folded Π_DKG / Π_dec export are disabled. Compare with `BENCHMARK_PROOF_AGGREGATION=true` (default)._ @@ -158,10 +158,10 @@ _Baseline run: node DKG folds and folded Π_DKG / Π_dec export are disabled. Co | Operation | Avg (s) | Runs | Total (s) | | ---------------------------- | ------- | ---- | --------- | -| ZkDecryptedSharesAggregation | 18.93 | 1 | 18.93 | -| ZkPkAggregation | 49.00 | 1 | 49.00 | +| ZkDecryptedSharesAggregation | 2.80 | 1 | 2.80 | +| ZkPkAggregation | 12.01 | 1 | 12.01 | -Sum of aggregation job tracked time: **67.94 s** (parallel CPU work; not P1/P2 wall clock). +Sum of aggregation job tracked time: **14.81 s** (parallel CPU work; not P1/P2 wall clock). ## Raw circuit benchmark JSON (Nargo) diff --git a/circuits/benchmarks/scripts/benchmark_output_dir.sh b/circuits/benchmarks/scripts/benchmark_output_dir.sh index fd94af1b87..2310106239 100644 --- a/circuits/benchmarks/scripts/benchmark_output_dir.sh +++ b/circuits/benchmarks/scripts/benchmark_output_dir.sh @@ -2,20 +2,29 @@ # Shared output directory naming for benchmark runs. # Sourced by run_benchmarks.sh and regenerate_report.sh. # -# Four default layouts (under circuits/benchmarks/): -# results_insecure_agg | results_insecure_no_agg -# results_secure_agg | results_secure_no_agg +# Layout (under circuits/benchmarks/) — three axes, hyphen-separated: +# results___ +# +# Examples: +# results_insecure_agg_micro +# results_insecure_no_agg_micro +# results_insecure_agg_medium +# results_secure_agg_micro +# +# Three layouts (mode, proof aggregation, committee) so micro/small/medium runs coexist on +# disk for direct A/B comparison without manual renames. -# Args: +# Args: [committee] benchmark_results_dir_basename() { local mode="$1" local proof_agg="${2:-true}" + local committee="${3:-micro}" local base="${BENCHMARK_OUTPUT_DIR_BASE:-results}" local suffix="agg" case "$(echo "$proof_agg" | tr '[:upper:]' '[:lower:]')" in 0|false|no|off) suffix="no_agg" ;; esac - echo "${base}_${mode}_${suffix}" + echo "${base}_${mode}_${suffix}_${committee}" } # Full path under BENCHMARKS_DIR (set by caller). @@ -23,10 +32,28 @@ benchmark_results_dir_path() { local benchmarks_dir="$1" local mode="$2" local proof_agg="${3:-true}" - echo "${benchmarks_dir}/$(benchmark_results_dir_basename "$mode" "$proof_agg")" + local committee="${4:-micro}" + echo "${benchmarks_dir}/$(benchmark_results_dir_basename "$mode" "$proof_agg" "$committee")" +} + +# Legacy basenames the regenerator falls back to when no committee-aware dir exists: +# 1. results__ — committee-less layout (pre-committee axis) +# 2. results_ — pre-suffix layout (oldest) +# Returns each candidate on its own line; callers iterate and pick the first that exists. +benchmark_results_dir_legacy_basenames() { + local mode="$1" + local proof_agg="${2:-true}" + local base="${BENCHMARK_OUTPUT_DIR_BASE:-results}" + local suffix="agg" + case "$(echo "$proof_agg" | tr '[:upper:]' '[:lower:]')" in + 0|false|no|off) suffix="no_agg" ;; + esac + echo "${base}_${mode}_${suffix}" + echo "${base}_${mode}" } -# Legacy: results_ (no agg suffix). Used as fallback when regenerating old runs. +# Backward compat: single-string version (oldest legacy only). Kept so older external scripts +# that source this file don't break. benchmark_results_dir_legacy_basename() { local mode="$1" local base="${BENCHMARK_OUTPUT_DIR_BASE:-results}" diff --git a/circuits/benchmarks/scripts/ensure_circuit_preset_built.sh b/circuits/benchmarks/scripts/ensure_circuit_preset_built.sh index 8def1bf787..d256cc1b00 100755 --- a/circuits/benchmarks/scripts/ensure_circuit_preset_built.sh +++ b/circuits/benchmarks/scripts/ensure_circuit_preset_built.sh @@ -2,7 +2,7 @@ # Ensure Noir circuit artifacts exist for a benchmark preset (insecure-512 | secure-8192). # # Usage (from repo root): -# ./circuits/benchmarks/scripts/ensure_circuit_preset_built.sh [--force-build] [--verbose] +# ./circuits/benchmarks/scripts/ensure_circuit_preset_built.sh [--committee micro|small|medium] [--force-build] [--verbose] # # Default: pnpm build:circuits --skip-if-built --no-clean --no-clean-targets (fast re-runs). # --force-build: full rebuild (wipes dist/circuits and circuits/bin targets via build:circuits). @@ -10,11 +10,39 @@ set -e PRESET="" +COMMITTEE="" FORCE_BUILD=false VERBOSE=false +usage() { + echo "Usage: $0 [--committee micro|small|medium] [--force-build] [--verbose]" +} + +require_arg_value() { + local flag="$1" + local value="${2:-}" + if [ -z "$value" ] || [[ "$value" == -* ]]; then + echo "Error: $flag requires a value" + usage + exit 1 + fi +} + while [[ $# -gt 0 ]]; do case $1 in + --committee) + require_arg_value "$1" "${2:-}" + COMMITTEE="$2" + case "$COMMITTEE" in + micro|small|medium) ;; + *) + echo "Error: --committee must be micro|small|medium (got: $COMMITTEE)" + usage + exit 1 + ;; + esac + shift 2 + ;; --force-build) FORCE_BUILD=true shift @@ -25,7 +53,7 @@ while [[ $# -gt 0 ]]; do ;; -*) echo "Unknown option: $1" - echo "Usage: $0 [--force-build] [--verbose]" + usage exit 1 ;; *) @@ -33,6 +61,7 @@ while [[ $# -gt 0 ]]; do PRESET="$1" else echo "Unexpected argument: $1" + usage exit 1 fi shift @@ -41,7 +70,7 @@ while [[ $# -gt 0 ]]; do done if [ -z "$PRESET" ]; then - echo "Usage: $0 [--force-build] [--verbose]" + usage exit 1 fi if [ "$PRESET" != "insecure-512" ] && [ "$PRESET" != "secure-8192" ]; then @@ -52,12 +81,21 @@ fi SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)" -BUILD_ARGS=(--preset "$PRESET") +if [ -z "$COMMITTEE" ]; then + # shellcheck source=load_default_committee.sh + source "${SCRIPT_DIR}/load_default_committee.sh" + load_default_committee "" "$REPO_ROOT" + COMMITTEE="$COMMITTEE_NAME" +fi + +BUILD_ARGS=(--preset "$PRESET" --committee "$COMMITTEE") if [ "$FORCE_BUILD" = true ]; then - echo " [circuits] Full rebuild: pnpm build:circuits --preset ${PRESET}" + echo " [circuits] Full rebuild: pnpm build:circuits ${BUILD_ARGS[*]}" else + # Committee changes invalidate the source hash, so --skip-if-built still recompiles + # when the committee changed since the last build. BUILD_ARGS+=(--skip-if-built --no-clean --no-clean-targets) - echo " [circuits] Ensuring preset ${PRESET} (skip-if-built; use --force-build to recompile)..." + echo " [circuits] Ensuring (${PRESET}${COMMITTEE:+, committee=$COMMITTEE}) (skip-if-built; use --force-build to recompile)..." fi if [ "$VERBOSE" = true ]; then diff --git a/circuits/benchmarks/scripts/extract_crisp_verify_gas.sh b/circuits/benchmarks/scripts/extract_crisp_verify_gas.sh index 7cbdd8a9a6..f5922f77aa 100755 --- a/circuits/benchmarks/scripts/extract_crisp_verify_gas.sh +++ b/circuits/benchmarks/scripts/extract_crisp_verify_gas.sh @@ -1,8 +1,8 @@ #!/bin/bash # extract_crisp_verify_gas.sh - Runs CRISP verifier test with gas reporter and emits JSON. -# Usage: ./extract_crisp_verify_gas.sh --output [--mode insecure|secure] [--verbose] -# [--skip-build] [--force-build] +# Usage: ./extract_crisp_verify_gas.sh --output [--mode insecure|secure] +# [--committee micro|small|medium] [--verbose] [--skip-build] [--force-build] # # Integration test env (also set by run_benchmarks.sh): # BENCHMARK_PROOF_AGGREGATION=true|false — recursive fold + folded Π_DKG/Π_dec (default: true) @@ -13,6 +13,7 @@ set -e OUTPUT_JSON="" MODE="insecure" +COMMITTEE="" VERBOSE=false SKIP_BUILD=false FORCE_BUILD=false @@ -27,6 +28,17 @@ while [[ $# -gt 0 ]]; do MODE="$2" shift 2 ;; + --committee) + COMMITTEE="$2" + case "$COMMITTEE" in + micro|small|medium) ;; + *) + echo "Error: --committee must be micro|small|medium (got: $COMMITTEE)" + exit 1 + ;; + esac + shift 2 + ;; --verbose|-v) VERBOSE=true shift @@ -41,14 +53,14 @@ while [[ $# -gt 0 ]]; do ;; *) echo "Unknown option: $1" - echo "Usage: $0 --output [--mode insecure|secure] [--verbose] [--skip-build] [--force-build]" + echo "Usage: $0 --output [--mode insecure|secure] [--committee micro|small|medium] [--verbose] [--skip-build] [--force-build]" exit 1 ;; esac done if [ -z "$OUTPUT_JSON" ]; then - echo "Usage: $0 --output [--mode insecure|secure] [--verbose] [--skip-build] [--force-build]" + echo "Usage: $0 --output [--mode insecure|secure] [--committee micro|small|medium] [--verbose] [--skip-build] [--force-build]" exit 1 fi if [ "$SKIP_BUILD" = true ] && [ "$FORCE_BUILD" = true ]; then @@ -62,6 +74,12 @@ fi SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)" +# shellcheck source=load_default_committee.sh +source "${SCRIPT_DIR}/load_default_committee.sh" +if [ -z "$COMMITTEE" ]; then + load_default_committee "" "$REPO_ROOT" + COMMITTEE="$COMMITTEE_NAME" +fi CRISP_CONTRACTS_DIR="${REPO_ROOT}/examples/CRISP/packages/crisp-contracts" TMP_LOG_CRISP="$(mktemp)" TMP_LOG_FOLDED="$(mktemp)" @@ -108,7 +126,7 @@ if [ "$SKIP_BUILD" = true ]; then echo " [gas] Skipping circuit build and Honk verifier generation (--skip-build)." require_preset_artifacts else - ENSURE_ARGS=("$PRESET_NAME") + ENSURE_ARGS=("$PRESET_NAME" --committee "$COMMITTEE") if [ "$FORCE_BUILD" = true ]; then ENSURE_ARGS+=(--force-build) fi diff --git a/circuits/benchmarks/scripts/generate_prover_toml.sh b/circuits/benchmarks/scripts/generate_prover_toml.sh index 2b7be187df..3ace7bea4b 100755 --- a/circuits/benchmarks/scripts/generate_prover_toml.sh +++ b/circuits/benchmarks/scripts/generate_prover_toml.sh @@ -28,6 +28,23 @@ fi PRESET="insecure" [ "$MODE" = "secure" ] && PRESET="secure" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=load_default_committee.sh +source "${SCRIPT_DIR}/load_default_committee.sh" +DEFAULT_MOD_NR="${REPO_ROOT}/circuits/lib/src/configs/default/mod.nr" +# Generate Prover.toml using the benchmark run's committee (set by run_benchmarks.sh when invoked +# from the suite; otherwise falls back to the on-disk active committee). +if [ -z "${BENCHMARK_COMMITTEE:-}" ]; then + load_default_committee "$DEFAULT_MOD_NR" "$REPO_ROOT" +else + load_committee_by_name "$BENCHMARK_COMMITTEE" "$REPO_ROOT" +fi + +if [ -z "$COMMITTEE_NAME" ]; then + echo "Error: COMMITTEE_NAME not set by load_default_committee.sh" + exit 1 +fi + OUTPUT_DIR="${REPO_ROOT}/circuits/bin/${CIRCUIT_PATH}" # Map circuit path to zk_cli --circuit and optional --inputs @@ -105,12 +122,12 @@ if [ "$ZK_CIRCUIT" = "_no_zk_cli" ]; then exit 0 fi -CMD=(cargo run -p e3-zk-helpers --bin zk_cli -- --circuit "$ZK_CIRCUIT" --preset "$PRESET" --output "$OUTPUT_DIR" --toml --no-configs) +CMD=(cargo run -p e3-zk-helpers --bin zk_cli -- --circuit "$ZK_CIRCUIT" --preset "$PRESET" --committee "$COMMITTEE_NAME" --output "$OUTPUT_DIR" --toml --no-configs) if [ -n "$ZK_INPUTS" ]; then CMD+=(--inputs "$ZK_INPUTS") fi -echo " Generating Prover.toml: zk_cli --circuit $ZK_CIRCUIT --preset $PRESET ${ZK_INPUTS:+--inputs $ZK_INPUTS}" +echo " Generating Prover.toml: zk_cli --circuit $ZK_CIRCUIT --preset $PRESET --committee $COMMITTEE_NAME ${ZK_INPUTS:+--inputs $ZK_INPUTS}" if ! "${CMD[@]}" 2>&1; then echo "Error: zk_cli failed for $CIRCUIT_PATH" exit 1 diff --git a/circuits/benchmarks/scripts/generate_report.sh b/circuits/benchmarks/scripts/generate_report.sh index e11948dac1..c886423959 100755 --- a/circuits/benchmarks/scripts/generate_report.sh +++ b/circuits/benchmarks/scripts/generate_report.sh @@ -402,30 +402,10 @@ artifact_size_pair_from_gas() { } load_protocol_params() { - local default_mod="${REPO_ROOT}/circuits/lib/src/configs/default/mod.nr" - local committee_name - committee_name=$(python3 - "$default_mod" <<'PY' -import re, sys -p = sys.argv[1] -try: - txt = open(p, "r", encoding="utf-8").read() -except Exception: - print("") - raise SystemExit(0) -m = re.search(r"committee::([a-zA-Z0-9_]+)::\{H,\s*N_PARTIES,\s*T\}", txt) -print(m.group(1) if m else "") -PY -) - [ -z "$committee_name" ] && committee_name="micro" - local committee_file="${REPO_ROOT}/circuits/lib/src/configs/committee/${committee_name}.nr" - local n t h - n=$(rg -N "N_PARTIES: u32 = " "$committee_file" | sed -E 's/.*= ([0-9]+);/\1/' | head -1) - t=$(rg -N "T: u32 = " "$committee_file" | sed -E 's/.*= ([0-9]+);/\1/' | head -1) - h=$(rg -N "H: u32 = " "$committee_file" | sed -E 's/.*= ([0-9]+);/\1/' | head -1) - [ -z "$n" ] && n="N/A" - [ -z "$t" ] && t="N/A" - [ -z "$h" ] && h="N/A" - echo "$h|$n|$t" + # shellcheck source=load_default_committee.sh + source "${SCRIPT_DIR}/load_default_committee.sh" + load_default_committee "${REPO_ROOT}/circuits/lib/src/configs/default/mod.nr" "${REPO_ROOT}" + echo "${COMMITTEE_H}|${COMMITTEE_N}|${COMMITTEE_T}" } load_system_info_from_raw() { diff --git a/circuits/benchmarks/scripts/load_default_committee.sh b/circuits/benchmarks/scripts/load_default_committee.sh new file mode 100644 index 0000000000..d6454f669d --- /dev/null +++ b/circuits/benchmarks/scripts/load_default_committee.sh @@ -0,0 +1,77 @@ +#!/bin/bash +# Resolve the active committee size (matches the active committee written by +# `pnpm build:circuits --committee `). Reads in priority order: +# +# 1. circuits/bin/.active-preset.json::committee (canonical, written by build-circuits) +# 2. circuits/lib/src/configs/committee/active.nr (fallback for stamp-less builds) +# 3. "micro" (final fallback so a fresh clone has sane defaults) +# +# Sets: COMMITTEE_NAME, COMMITTEE_N, COMMITTEE_T, COMMITTEE_H + +_load_committee_nt_h() { + local repo_root="$1" + local committee_file="${repo_root}/circuits/lib/src/configs/committee/${COMMITTEE_NAME}/mod.nr" + if [ ! -f "$committee_file" ]; then + echo "Error: committee config not found: $committee_file" >&2 + return 1 + fi + + COMMITTEE_N=$(rg -N "N_PARTIES: u32 = " "$committee_file" | sed -E 's/.*= ([0-9]+);/\1/' | head -1) + COMMITTEE_T=$(rg -N "T: u32 = " "$committee_file" | sed -E 's/.*= ([0-9]+);/\1/' | head -1) + COMMITTEE_H=$(rg -N "H: u32 = " "$committee_file" | sed -E 's/.*= ([0-9]+);/\1/' | head -1) + + if [ -z "$COMMITTEE_N" ] || [ -z "$COMMITTEE_T" ] || [ -z "$COMMITTEE_H" ]; then + echo "Error: failed to parse N/T/H from $committee_file" >&2 + return 1 + fi + + export COMMITTEE_NAME COMMITTEE_N COMMITTEE_T COMMITTEE_H +} + +# Load N/T/H for an explicit committee name (independent of on-disk active selection). +load_committee_by_name() { + local name="$1" + local repo_root="${2:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}" + COMMITTEE_NAME="$name" + _load_committee_nt_h "$repo_root" +} + +load_default_committee() { + # First positional arg is legacy (path to default/mod.nr) and is ignored — committee is + # now plumbed through active.nr / the stamp, not default/mod.nr. Kept so existing callers + # don't break. + local _legacy_default_mod="${1:-}" + local repo_root="${2:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}" + + local stamp="${repo_root}/circuits/bin/.active-preset.json" + local active_nr="${repo_root}/circuits/lib/src/configs/committee/active.nr" + + COMMITTEE_NAME="" + if [ -f "$stamp" ]; then + COMMITTEE_NAME=$(python3 - "$stamp" <<'PY' +import json, sys +try: + v = json.load(open(sys.argv[1])) + print(v.get("committee") or "") +except Exception: + print("") +PY +) + fi + if [ -z "$COMMITTEE_NAME" ] && [ -f "$active_nr" ]; then + COMMITTEE_NAME=$(python3 - "$active_nr" <<'PY' +import re, sys +try: + txt = open(sys.argv[1], encoding="utf-8").read() +except Exception: + print("") + raise SystemExit(0) +m = re.search(r"crate::configs::committee::([a-zA-Z0-9_]+)::N_PARTIES", txt) +print(m.group(1) if m else "") +PY +) + fi + [ -z "$COMMITTEE_NAME" ] && COMMITTEE_NAME="micro" + + _load_committee_nt_h "$repo_root" +} diff --git a/circuits/benchmarks/scripts/regenerate_report.sh b/circuits/benchmarks/scripts/regenerate_report.sh index 417f45d27c..f567804d43 100755 --- a/circuits/benchmarks/scripts/regenerate_report.sh +++ b/circuits/benchmarks/scripts/regenerate_report.sh @@ -13,15 +13,22 @@ BENCHMARKS_DIR="$(dirname "$SCRIPT_DIR")" REPO_ROOT="$(cd "${BENCHMARKS_DIR}/../.." && pwd)" # shellcheck source=benchmark_output_dir.sh source "${SCRIPT_DIR}/benchmark_output_dir.sh" +# shellcheck source=load_default_committee.sh +source "${SCRIPT_DIR}/load_default_committee.sh" MODE="${MODE:-secure}" PROOF_AGGREGATION="${BENCHMARK_PROOF_AGGREGATION:-true}" +COMMITTEE_OVERRIDE="" while [[ $# -gt 0 ]]; do case $1 in --mode) MODE="$2" shift 2 ;; + --committee) + COMMITTEE_OVERRIDE="$2" + shift 2 + ;; --proof-aggregation) PROOF_AGGREGATION="$2" shift 2 @@ -32,7 +39,7 @@ while [[ $# -gt 0 ]]; do ;; *) echo "Unknown option: $1" - echo "Usage: $0 [--mode insecure|secure] [--proof-aggregation on|off] [--no-proof-aggregation]" + echo "Usage: $0 [--mode insecure|secure] [--committee micro|small|medium] [--proof-aggregation on|off] [--no-proof-aggregation]" exit 1 ;; esac @@ -48,14 +55,31 @@ if [ "$MODE" != "insecure" ] && [ "$MODE" != "secure" ]; then exit 1 fi -OUTPUT_DIR="$(benchmark_results_dir_path "$BENCHMARKS_DIR" "$MODE" "$PROOF_AGGREGATION")" -# Backward compatibility: pre-suffix layout results_/ +if [ -n "$COMMITTEE_OVERRIDE" ]; then + case "$COMMITTEE_OVERRIDE" in + micro|small|medium) ;; + *) + echo "Error: --committee must be one of micro|small|medium" + exit 1 + ;; + esac + OUTPUT_COMMITTEE="$COMMITTEE_OVERRIDE" +else + load_default_committee "" "$REPO_ROOT" + OUTPUT_COMMITTEE="$COMMITTEE_NAME" +fi +OUTPUT_DIR="$(benchmark_results_dir_path "$BENCHMARKS_DIR" "$MODE" "$PROOF_AGGREGATION" "$OUTPUT_COMMITTEE")" +# Backward compatibility: walk through legacy layouts (newest-first) if the committee-aware +# dir doesn't exist on disk. if [ ! -d "${OUTPUT_DIR}/raw" ] && [ ! -f "${OUTPUT_DIR}/crisp_verify_gas.json" ]; then - LEGACY="${BENCHMARKS_DIR}/$(benchmark_results_dir_legacy_basename "$MODE")" - if [ -d "${LEGACY}/raw" ] || [ -f "${LEGACY}/crisp_verify_gas.json" ]; then - echo "Note: using legacy output dir ${LEGACY} (rename to $(basename "$OUTPUT_DIR") to match new layout)" - OUTPUT_DIR="$LEGACY" - fi + while IFS= read -r legacy_base; do + LEGACY="${BENCHMARKS_DIR}/${legacy_base}" + if [ -d "${LEGACY}/raw" ] || [ -f "${LEGACY}/crisp_verify_gas.json" ]; then + echo "Note: using legacy output dir ${LEGACY} (rename to $(basename "$OUTPUT_DIR") to match new layout)" + OUTPUT_DIR="$LEGACY" + break + fi + done < <(benchmark_results_dir_legacy_basenames "$MODE" "$PROOF_AGGREGATION") fi GIT_COMMIT=$(git -C "$REPO_ROOT" rev-parse HEAD 2>/dev/null || echo "unknown") GIT_BRANCH=$(git -C "$REPO_ROOT" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown") diff --git a/circuits/benchmarks/scripts/replay_folded_verify_gas.sh b/circuits/benchmarks/scripts/replay_folded_verify_gas.sh index 68cff81f0d..fe9fdd4ba8 100755 --- a/circuits/benchmarks/scripts/replay_folded_verify_gas.sh +++ b/circuits/benchmarks/scripts/replay_folded_verify_gas.sh @@ -17,6 +17,7 @@ set -e SUMMARY_JSON="" GAS_JSON="" BUILD_PRESET="" +COMMITTEE="" FORCE_BUILD=false SKIP_BUILD=false SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" @@ -31,6 +32,17 @@ while [[ $# -gt 0 ]]; do BUILD_PRESET="$2" shift 2 ;; + --committee) + COMMITTEE="$2" + case "$COMMITTEE" in + micro|small|medium) ;; + *) + echo "Error: --committee must be micro|small|medium (got: $COMMITTEE)" + exit 1 + ;; + esac + shift 2 + ;; --force-build) FORCE_BUILD=true shift @@ -83,6 +95,9 @@ if [ -n "$BUILD_PRESET" ]; then "${SCRIPT_DIR}/check_circuit_preset_artifacts.sh" "$BUILD_PRESET" else ENSURE_ARGS=("$BUILD_PRESET") + if [ -n "$COMMITTEE" ]; then + ENSURE_ARGS+=(--committee "$COMMITTEE") + fi if [ "$FORCE_BUILD" = true ]; then ENSURE_ARGS+=(--force-build) fi diff --git a/circuits/benchmarks/scripts/run_benchmarks.sh b/circuits/benchmarks/scripts/run_benchmarks.sh index a99939275f..e595b0f79d 100755 --- a/circuits/benchmarks/scripts/run_benchmarks.sh +++ b/circuits/benchmarks/scripts/run_benchmarks.sh @@ -14,6 +14,7 @@ source "${SCRIPT_DIR}/benchmark_output_dir.sh" CONFIG_FILE="${BENCHMARKS_DIR}/config.json" CLEAN_ARTIFACTS=false MODE_OVERRIDE="" +COMMITTEE_OVERRIDE="" SKIP_COMPILE=false BENCH_COMPILE=false CIRCUIT_FILTER="" @@ -37,6 +38,17 @@ while [[ $# -gt 0 ]]; do fi shift 2 ;; + --committee) + COMMITTEE_OVERRIDE="$2" + case "$COMMITTEE_OVERRIDE" in + micro|small|medium) ;; + *) + echo "Error: --committee must be micro|small|medium (got: $COMMITTEE_OVERRIDE)" + exit 1 + ;; + esac + shift 2 + ;; --circuit) CIRCUIT_FILTER="$2" shift 2 @@ -71,7 +83,7 @@ while [[ $# -gt 0 ]]; do ;; *) echo "Unknown option: $1" - echo "Usage: $0 [--config ] [--mode insecure|secure] [--circuit ] [--skip-compile] [--bench-compile] [--clean] [--verbose] [--proof-aggregation on|off] [--no-proof-aggregation] [--multithread-jobs N]" + echo "Usage: $0 [--config ] [--mode insecure|secure] [--committee micro|small|medium] [--circuit ] [--skip-compile] [--bench-compile] [--clean] [--verbose] [--proof-aggregation on|off] [--no-proof-aggregation] [--multithread-jobs N]" exit 1 ;; esac @@ -138,9 +150,36 @@ REPO_ROOT="$(cd "${BENCHMARKS_DIR}/../.." && pwd)" # Circuits live under circuits/bin (bin_dir is relative to benchmarks dir, e.g. ../bin) CIRCUITS_BASE_DIR="$(cd "${BENCHMARKS_DIR}/${BIN_DIR}" && pwd)" -# results__agg | results__no_agg (see benchmark_output_dir.sh) +# Resolve the committee for the output dir name. Explicit --committee wins; otherwise we +# read what's currently on disk (the build step below will respect that selection). Sourced +# here so OUTPUT_DIR can include the committee axis (`results___`). +# shellcheck source=load_default_committee.sh +source "${SCRIPT_DIR}/load_default_committee.sh" + +assert_skip_compile_committee_matches_disk() { + load_default_committee "" "$REPO_ROOT" + if [ "$COMMITTEE_NAME" != "$OUTPUT_COMMITTEE" ]; then + echo "Error: --skip-compile with --committee $OUTPUT_COMMITTEE but on-disk circuits are built for committee '$COMMITTEE_NAME'." + echo " Rebuild: pnpm build:circuits --committee $OUTPUT_COMMITTEE" + echo " Or omit --committee to benchmark the on-disk selection." + exit 1 + fi +} + +if [ -n "$COMMITTEE_OVERRIDE" ]; then + OUTPUT_COMMITTEE="$COMMITTEE_OVERRIDE" +else + load_default_committee "" "$REPO_ROOT" + OUTPUT_COMMITTEE="$COMMITTEE_NAME" +fi + +if [ "$SKIP_COMPILE" = true ] && [ -n "$COMMITTEE_OVERRIDE" ]; then + assert_skip_compile_committee_matches_disk +fi + +# results___ (see benchmark_output_dir.sh) BENCHMARK_OUTPUT_DIR_BASE="$OUTPUT_DIR_BASE" -OUTPUT_DIR="$(benchmark_results_dir_basename "$MODE" "$BENCHMARK_PROOF_AGGREGATION")" +OUTPUT_DIR="$(benchmark_results_dir_basename "$MODE" "$BENCHMARK_PROOF_AGGREGATION" "$OUTPUT_COMMITTEE")" mkdir -p "${BENCHMARKS_DIR}/${OUTPUT_DIR}/raw" # For secure mode, patch lib to use secure configs (restored at end) @@ -161,8 +200,11 @@ fi GIT_COMMIT=$(git rev-parse HEAD 2>/dev/null || echo "unknown") GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown") +load_committee_by_name "$OUTPUT_COMMITTEE" "$REPO_ROOT" + echo "Configuration:" echo " Mode: $MODE" +echo " Committee: $OUTPUT_COMMITTEE (N=$COMMITTEE_N, T=$COMMITTEE_T, H=$COMMITTEE_H)" if [ -n "$CIRCUIT_FILTER" ]; then echo " Circuit: $CIRCUIT_FILTER (single)" fi @@ -196,7 +238,7 @@ if [ "$SKIP_COMPILE" = false ]; then else PRESET_NAME="insecure-512" fi - ENSURE_ARGS=("$PRESET_NAME") + ENSURE_ARGS=("$PRESET_NAME" --committee "$OUTPUT_COMMITTEE") if [ "$VERBOSE" = true ]; then ENSURE_ARGS+=(--verbose) fi @@ -270,7 +312,7 @@ for CIRCUIT in $RUN_CIRCUITS; do # Generate Prover.toml (and configs.nr) via zk_cli so nargo execute has witness echo " Generating Prover.toml..." - if ! "${SCRIPT_DIR}/generate_prover_toml.sh" "$CIRCUIT" "$MODE" "$REPO_ROOT" 2>&1; then + if ! BENCHMARK_COMMITTEE="$OUTPUT_COMMITTEE" "${SCRIPT_DIR}/generate_prover_toml.sh" "$CIRCUIT" "$MODE" "$REPO_ROOT" 2>&1; then echo "⚠️ Prover.toml generation failed for $CIRCUIT, skipping benchmark" echo "" continue @@ -299,10 +341,14 @@ echo "Stage 1/3: Running gas extraction pipeline (CRISP test + integration + EVM GAS_JSON_FILE="${BENCHMARKS_DIR}/${OUTPUT_DIR}/crisp_verify_gas.json" # Remove any previous gas artifact so failures cannot leak stale values. rm -f "${GAS_JSON_FILE}" -EXTRACT_ARGS=(--output "${GAS_JSON_FILE}" --mode "$MODE") +EXTRACT_ARGS=(--output "${GAS_JSON_FILE}" --mode "$MODE" --committee "$OUTPUT_COMMITTEE") if [ "$VERBOSE" = true ]; then EXTRACT_ARGS+=(--verbose) fi +# Benches already validated preset+committee artifacts; gas stage only checks + runs tests. +if [ "$SKIP_COMPILE" = true ] || [ "$PRESET_ARTIFACTS_READY" = true ]; then + EXTRACT_ARGS+=(--skip-build) +fi if "${SCRIPT_DIR}/extract_crisp_verify_gas.sh" "${EXTRACT_ARGS[@]}"; then echo "✓ CRISP verify gas extracted: ${GAS_JSON_FILE}" else @@ -312,20 +358,28 @@ fi # Persist CLI flags for report regeneration (see generate_report.sh → Run configuration). RUN_META_FILE="${BENCHMARKS_DIR}/${OUTPUT_DIR}/benchmark_run_meta.json" MT_JOBS_JSON="${BENCHMARK_MULTITHREAD_JOBS:-1}" +load_committee_by_name "$OUTPUT_COMMITTEE" "$REPO_ROOT" jq -n \ --arg mode "$MODE" \ --arg preset "$([ "$MODE" = "secure" ] && echo "secure-8192" || echo "insecure-512")" \ + --arg committee "$OUTPUT_COMMITTEE" \ --argjson proof_agg "$( [ "$BENCHMARK_PROOF_AGGREGATION" = "false" ] && echo false || echo true )" \ --argjson multithread_jobs "$MT_JOBS_JSON" \ --argjson verbose "$([ "$VERBOSE" = true ] && echo true || echo false)" \ + --argjson committee_size_n "$COMMITTEE_N" \ + --argjson committee_size_h "$COMMITTEE_H" \ + --argjson committee_threshold_t "$COMMITTEE_T" \ '{ benchmark_mode: $mode, bfv_preset_subdir: $preset, + committee: $committee, proof_aggregation: $proof_agg, multithread_jobs: $multithread_jobs, verbose: $verbose, nodes_spawned: 20, - committee_size_n: 3, + committee_size_n: $committee_size_n, + committee_size_h: $committee_size_h, + committee_threshold_t: $committee_threshold_t, network_model: "in_process_bus", testmode_harness: true }' > "${RUN_META_FILE}" diff --git a/circuits/lib/src/configs/committee/active.nr b/circuits/lib/src/configs/committee/active.nr new file mode 100644 index 0000000000..a839e5beff --- /dev/null +++ b/circuits/lib/src/configs/committee/active.nr @@ -0,0 +1,28 @@ +// 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. +// +// Auto-generated by scripts/build-circuits.ts for committee: micro +// Single source of truth for the active committee size in the Noir codebase. +// +// Importing modules MUST NOT reach into `committee::{micro,small,medium}` directly; +// always go through `committee::active` so that switching committee is a one-file edit. +// +// This module also breaks the import cycle that would arise from +// `math::committee_hash` -> `configs::default` -> `configs::insecure::threshold` -> `math`: +// `committee_hash` imports `N_PARTIES` from here (which only depends on the leaf +// committee module), not from `configs::default`. + +/// Number of registered parties (matches on-chain `topNodes` length). +pub global N_PARTIES: u32 = crate::configs::committee::micro::N_PARTIES; +/// Secret-sharing reconstruction threshold. +pub global T: u32 = crate::configs::committee::micro::T; +/// Honest-party count expected during the DKG (`H <= N_PARTIES`). +pub global H: u32 = crate::configs::committee::micro::H; + +/// Parity matrices for the secret-sharing scheme, sized for the active committee. +/// `configs::{insecure,secure}::dkg` re-exports the relevant one as `PARITY_MATRIX`. +pub use crate::configs::committee::micro::parity_insecure::PARITY_MATRIX as PARITY_MATRIX_INSECURE; +pub use crate::configs::committee::micro::parity_secure::PARITY_MATRIX as PARITY_MATRIX_SECURE; diff --git a/circuits/lib/src/configs/committee/medium/mod.nr b/circuits/lib/src/configs/committee/medium/mod.nr new file mode 100644 index 0000000000..4ddb506263 --- /dev/null +++ b/circuits/lib/src/configs/committee/medium/mod.nr @@ -0,0 +1,19 @@ +// 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. + +//! Medium committee size: N=10, T=4, H=8. First committee where H is less than N. +//! +//! Has been validated end-to-end (DKG + decryption + EVM verifier) when +//! `parity_insecure.nr` is populated. Switching `committee::active` to `medium` +//! requires regenerating that file (and `parity_secure.nr` for the secure-8192 +//! preset) from the matrix generator. + +pub global N_PARTIES: u32 = 10; +pub global T: u32 = 4; +pub global H: u32 = 8; + +pub mod parity_insecure; +pub mod parity_secure; diff --git a/circuits/lib/src/configs/committee/medium/parity_insecure.nr b/circuits/lib/src/configs/committee/medium/parity_insecure.nr new file mode 100644 index 0000000000..015224fc17 --- /dev/null +++ b/circuits/lib/src/configs/committee/medium/parity_insecure.nr @@ -0,0 +1,33 @@ +// 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. +// +// AUTO-GENERATED by `generate_parity_matrices`. DO NOT EDIT BY HAND. +// Regenerate with `pnpm build:circuits --committee medium`. +// +// Reed-Solomon parity matrix for the medium committee under the +// insecure-512 (L_THRESHOLD=2) preset. Dimensions: [L_THRESHOLD][N_PARTIES - T][N_PARTIES + 1]. + +use crate::configs::committee::medium::{N_PARTIES, T}; +pub use crate::configs::insecure::threshold::L as L_THRESHOLD; + +pub global PARITY_MATRIX: [[[Field; N_PARTIES + 1]; N_PARTIES - T]; L_THRESHOLD] = [ + [ + [68719403008, 5, 68719402999, 10, 68719403004, 1, 0, 0, 0, 0, 0], + [68719403004, 24, 68719402964, 40, 68719402994, 0, 1, 0, 0, 0, 0], + [68719402994, 70, 68719402883, 105, 68719402974, 0, 0, 1, 0, 0, 0], + [68719402974, 160, 68719402729, 224, 68719402939, 0, 0, 0, 1, 0, 0], + [68719402939, 315, 68719402469, 420, 68719402883, 0, 0, 0, 0, 1, 0], + [68719402883, 560, 68719402064, 720, 68719402799, 0, 0, 0, 0, 0, 1], + ], + [ + [68719230976, 5, 68719230967, 10, 68719230972, 1, 0, 0, 0, 0, 0], + [68719230972, 24, 68719230932, 40, 68719230962, 0, 1, 0, 0, 0, 0], + [68719230962, 70, 68719230851, 105, 68719230942, 0, 0, 1, 0, 0, 0], + [68719230942, 160, 68719230697, 224, 68719230907, 0, 0, 0, 1, 0, 0], + [68719230907, 315, 68719230437, 420, 68719230851, 0, 0, 0, 0, 1, 0], + [68719230851, 560, 68719230032, 720, 68719230767, 0, 0, 0, 0, 0, 1], + ], +]; diff --git a/circuits/lib/src/configs/committee/medium/parity_secure.nr b/circuits/lib/src/configs/committee/medium/parity_secure.nr new file mode 100644 index 0000000000..f6761dc195 --- /dev/null +++ b/circuits/lib/src/configs/committee/medium/parity_secure.nr @@ -0,0 +1,41 @@ +// 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. +// +// AUTO-GENERATED by `generate_parity_matrices`. DO NOT EDIT BY HAND. +// Regenerate with `pnpm build:circuits --committee medium`. +// +// Reed-Solomon parity matrix for the medium committee under the +// secure-8192 (L_THRESHOLD=3) preset. Dimensions: [L_THRESHOLD][N_PARTIES - T][N_PARTIES + 1]. + +use crate::configs::committee::medium::{N_PARTIES, T}; +pub use crate::configs::secure::threshold::L as L_THRESHOLD; + +pub global PARITY_MATRIX: [[[Field; N_PARTIES + 1]; N_PARTIES - T]; L_THRESHOLD] = [ + [ + [288230376173076480, 5, 288230376173076471, 10, 288230376173076476, 1, 0, 0, 0, 0, 0], + [288230376173076476, 24, 288230376173076436, 40, 288230376173076466, 0, 1, 0, 0, 0, 0], + [288230376173076466, 70, 288230376173076355, 105, 288230376173076446, 0, 0, 1, 0, 0, 0], + [288230376173076446, 160, 288230376173076201, 224, 288230376173076411, 0, 0, 0, 1, 0, 0], + [288230376173076411, 315, 288230376173075941, 420, 288230376173076355, 0, 0, 0, 0, 1, 0], + [288230376173076355, 560, 288230376173075536, 720, 288230376173076271, 0, 0, 0, 0, 0, 1], + ], + [ + [288230376167047168, 5, 288230376167047159, 10, 288230376167047164, 1, 0, 0, 0, 0, 0], + [288230376167047164, 24, 288230376167047124, 40, 288230376167047154, 0, 1, 0, 0, 0, 0], + [288230376167047154, 70, 288230376167047043, 105, 288230376167047134, 0, 0, 1, 0, 0, 0], + [288230376167047134, 160, 288230376167046889, 224, 288230376167047099, 0, 0, 0, 1, 0, 0], + [288230376167047099, 315, 288230376167046629, 420, 288230376167047043, 0, 0, 0, 0, 1, 0], + [288230376167047043, 560, 288230376167046224, 720, 288230376167046959, 0, 0, 0, 0, 0, 1], + ], + [ + [288230376161280000, 5, 288230376161279991, 10, 288230376161279996, 1, 0, 0, 0, 0, 0], + [288230376161279996, 24, 288230376161279956, 40, 288230376161279986, 0, 1, 0, 0, 0, 0], + [288230376161279986, 70, 288230376161279875, 105, 288230376161279966, 0, 0, 1, 0, 0, 0], + [288230376161279966, 160, 288230376161279721, 224, 288230376161279931, 0, 0, 0, 1, 0, 0], + [288230376161279931, 315, 288230376161279461, 420, 288230376161279875, 0, 0, 0, 0, 1, 0], + [288230376161279875, 560, 288230376161279056, 720, 288230376161279791, 0, 0, 0, 0, 0, 1], + ], +]; diff --git a/circuits/lib/src/configs/committee/micro.nr b/circuits/lib/src/configs/committee/micro.nr deleted file mode 100644 index 1c1dacb6af..0000000000 --- a/circuits/lib/src/configs/committee/micro.nr +++ /dev/null @@ -1,15 +0,0 @@ -// 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. - -/// Currently defaults to just small committee size. -/// In the future, we will add more committee sizes. - -/// Number of parties. -pub global N_PARTIES: u32 = 3; -/// Threshold. -pub global T: u32 = 1; -/// Number of honest parties. -pub global H: u32 = 3; diff --git a/circuits/lib/src/configs/committee/micro/mod.nr b/circuits/lib/src/configs/committee/micro/mod.nr new file mode 100644 index 0000000000..c412cdd309 --- /dev/null +++ b/circuits/lib/src/configs/committee/micro/mod.nr @@ -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. + +//! Micro committee size: N=3 parties, T=1 reconstruction threshold, H=3 honest. +//! Used as the default in CI / local dev for fast circuit-compile times. + +/// Number of registered parties (matches on-chain `topNodes` length). +pub global N_PARTIES: u32 = 3; +/// Secret-sharing reconstruction threshold. +pub global T: u32 = 1; +/// Honest-party count expected during the DKG (`H <= N_PARTIES`). +pub global H: u32 = 3; + +pub mod parity_insecure; +pub mod parity_secure; diff --git a/circuits/lib/src/configs/committee/micro/parity_insecure.nr b/circuits/lib/src/configs/committee/micro/parity_insecure.nr new file mode 100644 index 0000000000..5b9862549b --- /dev/null +++ b/circuits/lib/src/configs/committee/micro/parity_insecure.nr @@ -0,0 +1,19 @@ +// 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. +// +// AUTO-GENERATED by `generate_parity_matrices`. DO NOT EDIT BY HAND. +// Regenerate with `pnpm build:circuits --committee micro`. +// +// Reed-Solomon parity matrix for the micro committee under the +// insecure-512 (L_THRESHOLD=2) preset. Dimensions: [L_THRESHOLD][N_PARTIES - T][N_PARTIES + 1]. + +use crate::configs::committee::micro::{N_PARTIES, T}; +pub use crate::configs::insecure::threshold::L as L_THRESHOLD; + +pub global PARITY_MATRIX: [[[Field; N_PARTIES + 1]; N_PARTIES - T]; L_THRESHOLD] = [ + [[1, 68719403007, 1, 0], [2, 68719403006, 0, 1]], + [[1, 68719230975, 1, 0], [2, 68719230974, 0, 1]], +]; diff --git a/circuits/lib/src/configs/committee/micro/parity_secure.nr b/circuits/lib/src/configs/committee/micro/parity_secure.nr new file mode 100644 index 0000000000..f3ffc970ac --- /dev/null +++ b/circuits/lib/src/configs/committee/micro/parity_secure.nr @@ -0,0 +1,20 @@ +// 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. +// +// AUTO-GENERATED by `generate_parity_matrices`. DO NOT EDIT BY HAND. +// Regenerate with `pnpm build:circuits --committee micro`. +// +// Reed-Solomon parity matrix for the micro committee under the +// secure-8192 (L_THRESHOLD=3) preset. Dimensions: [L_THRESHOLD][N_PARTIES - T][N_PARTIES + 1]. + +use crate::configs::committee::micro::{N_PARTIES, T}; +pub use crate::configs::secure::threshold::L as L_THRESHOLD; + +pub global PARITY_MATRIX: [[[Field; N_PARTIES + 1]; N_PARTIES - T]; L_THRESHOLD] = [ + [[1, 288230376173076479, 1, 0], [2, 288230376173076478, 0, 1]], + [[1, 288230376167047167, 1, 0], [2, 288230376167047166, 0, 1]], + [[1, 288230376161279999, 1, 0], [2, 288230376161279998, 0, 1]], +]; diff --git a/circuits/lib/src/configs/committee/mod.nr b/circuits/lib/src/configs/committee/mod.nr index 3bfb590e50..e4e5dca6cd 100644 --- a/circuits/lib/src/configs/committee/mod.nr +++ b/circuits/lib/src/configs/committee/mod.nr @@ -4,5 +4,12 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -pub mod small; +//! Committee size definitions. Downstream code MUST import from +//! `committee::active` rather than the leaf modules directly; `active` is +//! regenerated by `scripts/build-circuits.ts` and is the single source of truth +//! for the currently selected committee. + +pub mod active; pub mod micro; +pub mod small; +pub mod medium; diff --git a/circuits/lib/src/configs/committee/small.nr b/circuits/lib/src/configs/committee/small/mod.nr similarity index 54% rename from circuits/lib/src/configs/committee/small.nr rename to circuits/lib/src/configs/committee/small/mod.nr index 9d037d65f7..c852834757 100644 --- a/circuits/lib/src/configs/committee/small.nr +++ b/circuits/lib/src/configs/committee/small/mod.nr @@ -4,12 +4,12 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -/// Currently defaults to just small committee size. -/// In the future, we will add more committee sizes. +//! Small committee size: N=5, T=2, H=5 (all parties expected honest during DKG). +//! Parity matrices are auto-generated; switch with `pnpm build:circuits --committee small`. -/// Number of parties. pub global N_PARTIES: u32 = 5; -/// Threshold. pub global T: u32 = 2; -/// Number of honest parties. pub global H: u32 = 5; + +pub mod parity_insecure; +pub mod parity_secure; diff --git a/circuits/lib/src/configs/committee/small/parity_insecure.nr b/circuits/lib/src/configs/committee/small/parity_insecure.nr new file mode 100644 index 0000000000..14de4ba6bf --- /dev/null +++ b/circuits/lib/src/configs/committee/small/parity_insecure.nr @@ -0,0 +1,27 @@ +// 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. +// +// AUTO-GENERATED by `generate_parity_matrices`. DO NOT EDIT BY HAND. +// Regenerate with `pnpm build:circuits --committee small`. +// +// Reed-Solomon parity matrix for the small committee under the +// insecure-512 (L_THRESHOLD=2) preset. Dimensions: [L_THRESHOLD][N_PARTIES - T][N_PARTIES + 1]. + +use crate::configs::committee::small::{N_PARTIES, T}; +pub use crate::configs::insecure::threshold::L as L_THRESHOLD; + +pub global PARITY_MATRIX: [[[Field; N_PARTIES + 1]; N_PARTIES - T]; L_THRESHOLD] = [ + [ + [68719403008, 3, 68719403006, 1, 0, 0], + [68719403006, 8, 68719403003, 0, 1, 0], + [68719403003, 15, 68719402999, 0, 0, 1], + ], + [ + [68719230976, 3, 68719230974, 1, 0, 0], + [68719230974, 8, 68719230971, 0, 1, 0], + [68719230971, 15, 68719230967, 0, 0, 1], + ], +]; diff --git a/circuits/lib/src/configs/committee/small/parity_secure.nr b/circuits/lib/src/configs/committee/small/parity_secure.nr new file mode 100644 index 0000000000..2894d7afd4 --- /dev/null +++ b/circuits/lib/src/configs/committee/small/parity_secure.nr @@ -0,0 +1,32 @@ +// 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. +// +// AUTO-GENERATED by `generate_parity_matrices`. DO NOT EDIT BY HAND. +// Regenerate with `pnpm build:circuits --committee small`. +// +// Reed-Solomon parity matrix for the small committee under the +// secure-8192 (L_THRESHOLD=3) preset. Dimensions: [L_THRESHOLD][N_PARTIES - T][N_PARTIES + 1]. + +use crate::configs::committee::small::{N_PARTIES, T}; +pub use crate::configs::secure::threshold::L as L_THRESHOLD; + +pub global PARITY_MATRIX: [[[Field; N_PARTIES + 1]; N_PARTIES - T]; L_THRESHOLD] = [ + [ + [288230376173076480, 3, 288230376173076478, 1, 0, 0], + [288230376173076478, 8, 288230376173076475, 0, 1, 0], + [288230376173076475, 15, 288230376173076471, 0, 0, 1], + ], + [ + [288230376167047168, 3, 288230376167047166, 1, 0, 0], + [288230376167047166, 8, 288230376167047163, 0, 1, 0], + [288230376167047163, 15, 288230376167047159, 0, 0, 1], + ], + [ + [288230376161280000, 3, 288230376161279998, 1, 0, 0], + [288230376161279998, 8, 288230376161279995, 0, 1, 0], + [288230376161279995, 15, 288230376161279991, 0, 0, 1], + ], +]; diff --git a/circuits/lib/src/configs/default/mod.nr b/circuits/lib/src/configs/default/mod.nr index f29df7cd84..76bfde2334 100644 --- a/circuits/lib/src/configs/default/mod.nr +++ b/circuits/lib/src/configs/default/mod.nr @@ -6,7 +6,9 @@ // // Auto-generated by build-circuits.ts for preset: insecure-512 -pub use super::committee::micro::{H, N_PARTIES, T}; +// Committee size (N_PARTIES / T / H) is routed through `committee::active`, +// which `build-circuits.ts` regenerates atomically with this file. +pub use super::committee::active::{H, N_PARTIES, T}; pub use super::insecure::dkg; pub use super::insecure::threshold; diff --git a/circuits/lib/src/configs/insecure/dkg.nr b/circuits/lib/src/configs/insecure/dkg.nr index 87dada5bff..2f2dc95c1a 100644 --- a/circuits/lib/src/configs/insecure/dkg.nr +++ b/circuits/lib/src/configs/insecure/dkg.nr @@ -4,7 +4,6 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -use crate::configs::default::{N_PARTIES, T}; pub use crate::configs::insecure::threshold::{ L as L_THRESHOLD, QIS as QIS_THRESHOLD, THRESHOLD_SHARE_DECRYPTION_BIT_SK as SHARE_DECRYPTION_BIT_AGG, @@ -20,10 +19,9 @@ pub global PLAINTEXT_MODULUS: Field = 68719403009; pub global Q_MOD_T: Field = 2415755265; pub global Q_MOD_T_CENTERED: Field = 2415755265; -pub global PARITY_MATRIX: [[[Field; N_PARTIES + 1]; N_PARTIES - T]; L_THRESHOLD] = [ - [[1, 68719403007, 1, 0], [2, 68719403006, 0, 1]], - [[1, 68719230975, 1, 0], [2, 68719230974, 0, 1]], -]; +// Parity matrix is sized for the active committee and the insecure-512 threshold QIS; +// see `committee/{name}/parity_insecure.nr`. Re-exported via `committee::active`. +pub use crate::configs::committee::active::PARITY_MATRIX_INSECURE as PARITY_MATRIX; /************************************ ------------------------------------- diff --git a/circuits/lib/src/configs/secure/dkg.nr b/circuits/lib/src/configs/secure/dkg.nr index 022ed7b530..49745a2d09 100644 --- a/circuits/lib/src/configs/secure/dkg.nr +++ b/circuits/lib/src/configs/secure/dkg.nr @@ -4,7 +4,6 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -use crate::configs::default::{N_PARTIES, T}; pub use crate::configs::secure::threshold::{ L as L_THRESHOLD, QIS as QIS_THRESHOLD, THRESHOLD_SHARE_DECRYPTION_BIT_SK as SHARE_DECRYPTION_BIT_AGG, @@ -20,11 +19,9 @@ pub global PLAINTEXT_MODULUS: Field = 1152921504606846976; pub global Q_MOD_T: Field = 777715553927169; pub global Q_MOD_T_CENTERED: Field = 777715553927169; -pub global PARITY_MATRIX: [[[Field; N_PARTIES + 1]; N_PARTIES - T]; L_THRESHOLD] = [ - [[1, 288230376173076479, 1, 0], [2, 288230376173076478, 0, 1]], - [[1, 288230376167047167, 1, 0], [2, 288230376167047166, 0, 1]], - [[1, 288230376161279999, 1, 0], [2, 288230376161279998, 0, 1]], -]; +// Parity matrix is sized for the active committee and the secure-8192 threshold QIS; +// see `committee/{name}/parity_secure.nr`. Re-exported via `committee::active`. +pub use crate::configs::committee::active::PARITY_MATRIX_SECURE as PARITY_MATRIX; /************************************ ------------------------------------- diff --git a/circuits/lib/src/math/committee_hash.nr b/circuits/lib/src/math/committee_hash.nr index c4b6b7f88f..6c3bc08229 100644 --- a/circuits/lib/src/math/committee_hash.nr +++ b/circuits/lib/src/math/committee_hash.nr @@ -11,9 +11,10 @@ //! (matches `topNodes` on-chain). It is not parameterised by `H` (the //! folded honest-set size) because `topNodes` always carries the full committee. -// Same value as `configs::default::N_PARTIES` (`committee::micro`, via build-circuits). -// `default::N_PARTIES` is not importable here: math -> default -> insecure::threshold -> math. -use crate::configs::committee::micro::N_PARTIES; +// Same value as `configs::default::N_PARTIES`, but pulled from `committee::active` to +// break the cycle math -> default -> insecure::threshold -> math. `committee::active` +// is regenerated atomically with `default/mod.nr` by `scripts/build-circuits.ts`. +use crate::configs::committee::active::N_PARTIES; use keccak256::keccak256; global ADDRESS_BYTES: u32 = 20; diff --git a/crates/aggregator/src/ext.rs b/crates/aggregator/src/ext.rs index b1886f12d8..dbdaceca9c 100644 --- a/crates/aggregator/src/ext.rs +++ b/crates/aggregator/src/ext.rs @@ -27,9 +27,15 @@ use e3_fhe_params::BfvPreset; use e3_request::{E3Context, E3ContextSnapshot, E3Extension, TypedKey, META_KEY}; use e3_sortition::Sortition; -/// Finalized committee (`PublicKeyAggregated.nodes`) parsed once for downstream ZK requests. +/// Full finalized committee (`PublicKeyAggregated.committee_addresses`, length `N`) +/// for `committee_hash_*` binding in downstream ZK requests. pub const COMMITTEE_ADDRESSES_KEY: TypedKey> = TypedKey::new("committee_addresses"); +/// Honest subset of the committee (`PublicKeyAggregated.honest_committee_addresses`, length `H`) +/// for decryption-share collection gating. +pub const HONEST_COMMITTEE_ADDRESSES_KEY: TypedKey> = + TypedKey::new("honest_committee_addresses"); + pub struct PublicKeyAggregatorExtension { bus: BusHandle, } @@ -175,6 +181,8 @@ impl ThresholdPlaintextAggregatorExtension { const ERROR_TRBFV_PLAINTEXT_META_MISSING:&str = "Could not create ThresholdPlaintextAggregator because the meta instance it depends on was not set on the context."; const ERROR_TRBFV_PLAINTEXT_COMMITTEE_MISSING: &str = "Could not create ThresholdPlaintextAggregator because committee addresses were not set (expected PublicKeyAggregated before CiphertextOutputPublished)."; +const ERROR_TRBFV_PLAINTEXT_HONEST_COMMITTEE_MISSING: &str = + "Could not create ThresholdPlaintextAggregator because honest committee addresses were not set (expected non-empty PublicKeyAggregated.honest_committee_addresses)."; fn load_committee_addresses(ctx: &E3Context, e3_id: &E3id) -> Result> { if let Some(addrs) = ctx.get_dependency(COMMITTEE_ADDRESSES_KEY) { @@ -195,6 +203,26 @@ fn load_committee_addresses(ctx: &E3Context, e3_id: &E3id) -> Result Result> { + if let Some(addrs) = ctx.get_dependency(HONEST_COMMITTEE_ADDRESSES_KEY) { + if addrs.is_empty() { + return Err(anyhow!(ERROR_TRBFV_PLAINTEXT_HONEST_COMMITTEE_MISSING)); + } + return Ok(addrs.clone()); + } + let repo = ctx.repositories().publickey(e3_id); + let state = futures::executor::block_on(repo.read())?; + let Some(state) = state else { + return Err(anyhow!(ERROR_TRBFV_PLAINTEXT_HONEST_COMMITTEE_MISSING)); + }; + if let Some(addrs) = state.honest_committee_addresses() { + if addrs.is_empty() { + return Err(anyhow!(ERROR_TRBFV_PLAINTEXT_HONEST_COMMITTEE_MISSING)); + } + } + Err(anyhow!(ERROR_TRBFV_PLAINTEXT_HONEST_COMMITTEE_MISSING)) +} + #[async_trait] impl E3Extension for ThresholdPlaintextAggregatorExtension { fn on_event(&self, ctx: &mut E3Context, evt: &EnclaveEvent) { @@ -207,6 +235,17 @@ impl E3Extension for ThresholdPlaintextAggregatorExtension { match addrs { Ok(addrs) => { let _ = ctx.set_dependency(COMMITTEE_ADDRESSES_KEY, addrs); + if data.honest_committee_addresses.is_empty() { + self.bus.err( + EType::PlaintextAggregation, + anyhow!(ERROR_TRBFV_PLAINTEXT_HONEST_COMMITTEE_MISSING), + ); + return; + } + let _ = ctx.set_dependency( + HONEST_COMMITTEE_ADDRESSES_KEY, + data.honest_committee_addresses.clone(), + ); } Err(e) => { self.bus.err(EType::PlaintextAggregation, e); @@ -244,6 +283,13 @@ impl E3Extension for ThresholdPlaintextAggregatorExtension { return; } }; + let honest_committee_addresses = match load_honest_committee_addresses(ctx, &e3_id) { + Ok(addrs) => addrs, + Err(e) => { + self.bus.err(EType::PlaintextAggregation, e); + return; + } + }; let repo = ctx.repositories().trbfv_plaintext(&e3_id); let sync_state = repo.send(Some(ThresholdPlaintextAggregatorState::init( @@ -266,6 +312,7 @@ impl E3Extension for ThresholdPlaintextAggregatorExtension { params_preset: meta.params_preset, proof_aggregation_enabled: meta.proof_aggregation_enabled, committee_addresses, + honest_committee_addresses, }, sync_state, ) @@ -301,6 +348,7 @@ impl E3Extension for ThresholdPlaintextAggregatorExtension { }; let committee_addresses = load_committee_addresses(ctx, &ctx.e3_id)?; + let honest_committee_addresses = load_honest_committee_addresses(ctx, &ctx.e3_id)?; let value = ThresholdPlaintextAggregator::new( ThresholdPlaintextAggregatorParams { @@ -310,6 +358,7 @@ impl E3Extension for ThresholdPlaintextAggregatorExtension { params_preset: meta.params_preset, proof_aggregation_enabled: meta.proof_aggregation_enabled, committee_addresses, + honest_committee_addresses, }, sync_state, ) diff --git a/crates/aggregator/src/publickey_aggregator.rs b/crates/aggregator/src/publickey_aggregator.rs index c32c3bdf4c..1ddf1a4535 100644 --- a/crates/aggregator/src/publickey_aggregator.rs +++ b/crates/aggregator/src/publickey_aggregator.rs @@ -24,11 +24,25 @@ use e3_fhe::{Fhe, GetAggregatePublicKey}; use e3_fhe_params::BfvPreset; use e3_utils::NotifySync; use e3_utils::{ArcBytes, MAILBOX_LIMIT}; +use e3_zk_helpers::cap_honest_party_ids; +use e3_zk_helpers::CiphernodesCommitteeSize; use e3_zk_prover::extract_node_fold_agg_commits; use std::collections::{BTreeSet, HashMap}; use std::sync::Arc; use tracing::{error, info, warn}; +/// Circuit honest-party count `H` for the committee `(threshold_m, threshold_n)`. +fn committee_h_for(threshold_m: usize, threshold_n: usize) -> Result { + Ok( + CiphernodesCommitteeSize::from_threshold(threshold_m, threshold_n) + .with_context(|| { + format!("unknown committee for threshold_m={threshold_m} threshold_n={threshold_n}") + })? + .values() + .h, + ) +} + /// Public-signal key for the aggregated PK commitment in `CircuitName::PkAggregation` (C5). /// Must stay in lock-step with the Noir circuit's output ABI declaration. const C5_PK_COMMITMENT_FIELD: &str = "commitment"; @@ -108,6 +122,9 @@ pub enum PublicKeyAggregatorState { /// Insertion-ordered (party_id, node, keyshare) triples from Collecting. submission_order: Vec<(u64, String, ArcBytes)>, threshold_m: usize, + /// On-chain committee size N (for `committee_h` lookup). + #[serde(default)] + threshold_n: usize, /// C1 proofs in the same insertion order as `submission_order`. c1_proofs: Vec>, /// Real party_ids that submitted no C1 proof — treated as dishonest. @@ -117,7 +134,9 @@ pub enum PublicKeyAggregatorState { public_key: ArcBytes, keyshare_bytes: Vec, nodes: OrderedSet, - /// Registered node address per sortition `party_id` (for fold attestation checks). + /// Registered node address per sortition `party_id` for the **full** committee + /// (all `N` parties that submitted a keyshare, honest or not). Honest-only lookups + /// must intersect with `honest_party_ids`. party_nodes: HashMap, /// DKG recursive proofs per party (restart-critical). dkg_node_proofs: HashMap>, @@ -126,6 +145,12 @@ pub enum PublicKeyAggregatorState { dkg_fold_attestations: HashMap, honest_party_ids: BTreeSet, dishonest_parties: BTreeSet, + /// Circuit committee size N (NodeFold / DKG public IO layout). + #[serde(default)] + circuit_committee_n: usize, + /// Circuit honest-party count H (NodeFold / DKG public IO layout). + #[serde(default)] + circuit_committee_h: usize, /// In-flight [`ZkRequest::DkgAggregation`], if any. dkg_aggregation_correlation: Option, /// Result from [`ZkResponse::DkgAggregation`] (replaces pairwise `FoldProofs`). @@ -140,6 +165,9 @@ pub enum PublicKeyAggregatorState { /// Ascending `party_id` order (matches on-chain `topNodes` after finalize sort). #[serde(default)] committee_addresses: Vec
, + /// Honest subset (H entries) for decryption-share gating after restart. + #[serde(default)] + honest_committee_addresses: Vec
, }, } @@ -164,6 +192,18 @@ impl PublicKeyAggregatorState { } } + pub fn honest_committee_addresses(&self) -> Option<&[Address]> { + match self { + PublicKeyAggregatorState::Complete { + honest_committee_addresses, + .. + } if !honest_committee_addresses.is_empty() => { + Some(honest_committee_addresses.as_slice()) + } + _ => None, + } + } + pub fn init(threshold_n: usize, threshold_m: usize, seed: Seed) -> Self { PublicKeyAggregatorState::Collecting { threshold_n, @@ -234,28 +274,38 @@ impl PublicKeyAggregator { return Err(anyhow::anyhow!("Can only add keyshare in Collecting state")); }; + if submission_order + .iter() + .any(|(pid, _, _)| *pid == party_id) + { + return Ok(state); + } + keyshares.insert(keyshare.clone()); c1_proofs.push(c1_proof); nodes.insert(node.clone()); info!( - "add_keyshare: node={} party_id={} (arrival slot={})", - node, - party_id, + "add_keyshare: node={node} party_id={party_id} (arrival slot={})", submission_order.len() ); submission_order.push((party_id, node, keyshare)); let n = *threshold_n; let m = *threshold_m; + let committee_h = committee_h_for(m, n)?; + let unique_parties = submission_order.len(); info!( - "PublicKeyAggregator got keyshares {}/{}", - keyshares.len(), - n + "PublicKeyAggregator got keyshares {unique_parties}/{n} distinct parties (committee_h={committee_h})" ); - if keyshares.len() == n { - info!("All keyshares collected, transitioning to VerifyingC1..."); + // Collect all N committee keyshares before C1. C5 then requires exactly H honest + // proofs afterward (micro had N=H so waiting for H was equivalent). + if unique_parties >= n { + info!( + "Collected keyshares from {unique_parties} distinct parties (>= committee_n={n}), transitioning to VerifyingC1..." + ); return Ok(PublicKeyAggregatorState::VerifyingC1 { submission_order: std::mem::take(submission_order), threshold_m: m, + threshold_n: n, c1_proofs: std::mem::take(c1_proofs), no_proof_parties: Vec::new(), }); @@ -349,6 +399,7 @@ impl PublicKeyAggregator { let PublicKeyAggregatorState::VerifyingC1 { submission_order, threshold_m, + threshold_n, c1_proofs, .. } = self @@ -362,7 +413,12 @@ impl PublicKeyAggregator { }; let mut dishonest_parties = msg.dishonest_parties.clone(); - let committee_n = submission_order.len(); + let collected = submission_order.len(); + let circuit_h = committee_h_for(threshold_m, threshold_n)?; + + // Retain full N committee roster (party_id → node address) for the DKG aggregator + // `committee_members` input, which must cover all `topNodes` regardless of honesty. + let full_submission_order: Vec<(u64, String, ArcBytes)> = submission_order.clone(); // Filter out parties that failed C1 ZK verification. Keyed by the real // sortition party_id carried in `submission_order`, not arrival index. @@ -453,11 +509,6 @@ impl PublicKeyAggregator { // and by the circuit's slot indexing in `dkg_aggregator.nr`. honest_entries.sort_by_key(|(pid, _, _, _)| *pid); - let (honest_keyshares, honest_nodes): (Vec, Vec) = honest_entries - .iter() - .map(|(_, node, ks, _)| (ks.clone(), node.clone())) - .unzip(); - if !dishonest_parties.is_empty() { warn!( "Total dishonest parties (ZK + commitment): {:?}", @@ -465,15 +516,12 @@ impl PublicKeyAggregator { ); } - let honest_party_ids: BTreeSet = - honest_entries.iter().map(|(pid, _, _, _)| *pid).collect(); - - // Need at least threshold + 1 honest parties for aggregation - if honest_keyshares.len() <= threshold_m { + // Fail closed when fewer than H parties cleared C1 — C5 cannot be witnessed. + if honest_entries.len() < circuit_h { error!( - "Not enough honest parties after filtering: {} (need > {})", - honest_keyshares.len(), - threshold_m + "C5 requires {circuit_h} honest parties with valid C1 proofs; only {} honest after verification (collected {collected}, dishonest: {:?})", + honest_entries.len(), + dishonest_parties ); self.bus.publish( E3Failed { @@ -486,12 +534,39 @@ impl PublicKeyAggregator { return Ok(()); } - // C5 (PkAggregation) is compiled for a fixed committee size H; partial committees fail witness encoding. - if honest_keyshares.len() != committee_n { + // The C5 PkAggregation circuit is parameterised by a fixed honest-party count H. + // When more than H parties cleared C1, select the H lowest party_ids as the + // canonical honest set; the remainder stay in the full committee + // (so committee_hash still covers all N) but their keyshares are not consumed + // by C5 and they are not asked to publish a NodeFold proof. + let pre_cap_len = honest_entries.len(); + let honest_party_ids = + cap_honest_party_ids(circuit_h, honest_entries.iter().map(|(pid, _, _, _)| *pid)); + if pre_cap_len > circuit_h { + info!( + "Capping honest set from {pre_cap_len} to circuit_h={circuit_h} for E3 {} (extras remain in full committee)", + self.e3_id + ); + honest_entries.retain(|(pid, _, _, _)| honest_party_ids.contains(pid)); + } + + let (honest_keyshares, honest_nodes): (Vec, Vec) = honest_entries + .iter() + .map(|(_, node, ks, _)| (ks.clone(), node.clone())) + .unzip(); + + debug_assert_eq!( + honest_party_ids.len(), + honest_keyshares.len(), + "honest roster and keyshare payload lengths must match" + ); + + // Defensive: should hold after truncation above; guard against future refactors. + if honest_keyshares.len() <= threshold_m { error!( - "C5 requires all {committee_n} committee parties with valid C1 proofs; only {} honest after verification (dishonest: {:?})", + "Not enough honest parties after filtering: {} (need > {})", honest_keyshares.len(), - dishonest_parties + threshold_m ); self.bus.publish( E3Failed { @@ -532,6 +607,9 @@ impl PublicKeyAggregator { keyshare_bytes: keyshare_bytes.clone(), aggregated_pk_bytes: pubkey.clone(), params_preset: self.params_preset.clone(), + // C5 aggregates the H honest keyshares only; the circuit witness and prover + // path use `committee_h` (see pk_aggregation/computation.rs). N is not needed + // here — set both fields to H so downstream validation stays consistent. committee_n: committee_h, committee_h, committee_threshold: 0, @@ -542,11 +620,19 @@ impl PublicKeyAggregator { ec.clone(), )?; - let party_nodes: HashMap = honest_entries + // `party_nodes` covers the FULL registered committee (all N keyshare submitters), + // not just the H honest set. The DKG aggregator circuit binds `committee_members` + // to on-chain `topNodes` which always carries the full committee — so we must keep + // the dishonest addresses available here to build the N-sized address vector. + // `submission_order` here is the unfiltered list captured pre–C1 verification + // (the original `VerifyingC1.submission_order`); `honest_entries` is the H subset. + let party_nodes: HashMap = full_submission_order .iter() - .map(|(pid, node, _, _)| (*pid, node.clone())) + .map(|(pid, node, _)| (*pid, node.clone())) .collect(); + let circuit_committee_n = threshold_n; + let circuit_committee_h = circuit_h; self.state.try_mutate(&ec, |_| { Ok(PublicKeyAggregatorState::GeneratingC5Proof { public_key: pubkey.clone(), @@ -557,6 +643,8 @@ impl PublicKeyAggregator { dkg_fold_attestations: HashMap::new(), honest_party_ids: honest_party_ids.clone(), dishonest_parties: dishonest_parties.clone(), + circuit_committee_n, + circuit_committee_h, dkg_aggregation_correlation: None, dkg_aggregated_proof: None, c5_proof_pending: None, @@ -607,6 +695,8 @@ impl PublicKeyAggregator { dkg_fold_attestations, honest_party_ids, dishonest_parties, + circuit_committee_n, + circuit_committee_h, dkg_aggregation_correlation, dkg_aggregated_proof, .. @@ -623,6 +713,8 @@ impl PublicKeyAggregator { dkg_fold_attestations, honest_party_ids, dishonest_parties, + circuit_committee_n, + circuit_committee_h, dkg_aggregation_correlation, dkg_aggregated_proof, c5_proof_pending: Some(c5_proof), @@ -649,6 +741,8 @@ impl PublicKeyAggregator { party_nodes, dkg_node_proofs, honest_party_ids, + circuit_committee_n, + circuit_committee_h, .. }) = state.as_ref() else { @@ -685,9 +779,16 @@ impl PublicKeyAggregator { } (Some(proof), Some(attestation)) => { let meta = self.params_preset.metadata(); - let committee_n = party_nodes.len(); - let committee_h = committee_n; + let committee_n = *circuit_committee_n; + let committee_h = *circuit_committee_h; let n_moduli = meta.num_moduli as usize; + if committee_n == 0 || committee_h == 0 { + warn!( + party_id = msg.party_id, + "DKG fold attestation verify skipped — circuit committee dims unset" + ); + return Ok(()); + } if let Err(e) = verify_dkg_fold_attestation( &self.e3_id, msg.party_id, @@ -739,6 +840,8 @@ impl PublicKeyAggregator { mut dkg_fold_attestations, honest_party_ids, dishonest_parties, + circuit_committee_n, + circuit_committee_h, dkg_aggregation_correlation, dkg_aggregated_proof, c5_proof_pending, @@ -760,6 +863,8 @@ impl PublicKeyAggregator { dkg_fold_attestations, honest_party_ids, dishonest_parties, + circuit_committee_n, + circuit_committee_h, dkg_aggregation_correlation, dkg_aggregated_proof, c5_proof_pending, @@ -780,6 +885,8 @@ impl PublicKeyAggregator { c5_proof_pending, dkg_aggregation_correlation, dkg_aggregated_proof, + circuit_committee_n, + circuit_committee_h, .. }) = state.as_ref() else { @@ -838,6 +945,8 @@ impl PublicKeyAggregator { dkg_fold_attestations, honest_party_ids, dishonest_parties, + circuit_committee_n, + circuit_committee_h, dkg_aggregation_correlation: _, dkg_aggregated_proof, c5_proof_pending: _, @@ -856,6 +965,8 @@ impl PublicKeyAggregator { dkg_fold_attestations, honest_party_ids, dishonest_parties, + circuit_committee_n, + circuit_committee_h, dkg_aggregation_correlation: None, dkg_aggregated_proof, c5_proof_pending: None, @@ -894,13 +1005,25 @@ impl PublicKeyAggregator { return Ok(()); } - let committee_addresses = committee_addresses_in_party_order(&party_ids, party_nodes)?; + // Build the FULL committee address vector (length N) in ascending party_id order. + // The DKG aggregator circuit's `committee_members: [Field; N_PARTIES]` is the + // committee-hash preimage; passing only the H honest subset would silently + // hash a shorter array and diverge from on-chain `keccak(topNodes)`. + let mut full_committee_party_ids: Vec = party_nodes.keys().copied().collect(); + full_committee_party_ids.sort(); + let committee_addresses = + committee_addresses_in_party_order(&full_committee_party_ids, party_nodes)?; #[cfg(debug_assertions)] { debug_assert_eq!( - party_ids.len(), committee_addresses.len(), - "honest NodeFold count must equal registered committee size until expulsion enables H < N" + *circuit_committee_n, + "DkgAggregator committee_addresses must have N entries (full topNodes)" + ); + debug_assert_eq!( + party_ids.len(), + *circuit_committee_h, + "DkgAggregator party_ids must have H entries (honest set)" ); } @@ -930,6 +1053,8 @@ impl PublicKeyAggregator { dkg_fold_attestations, honest_party_ids, dishonest_parties, + circuit_committee_n, + circuit_committee_h, dkg_aggregation_correlation: _, dkg_aggregated_proof, c5_proof_pending, @@ -947,6 +1072,8 @@ impl PublicKeyAggregator { dkg_fold_attestations, honest_party_ids, dishonest_parties, + circuit_committee_n, + circuit_committee_h, dkg_aggregation_correlation: Some(corr), dkg_aggregated_proof, c5_proof_pending, @@ -1030,8 +1157,16 @@ impl PublicKeyAggregator { let pk_commitment = extract_pk_commitment(c5_proof)?; - let party_ids: Vec = honest_party_ids.iter().copied().collect(); - let committee_addresses = committee_addresses_in_party_order(&party_ids, &party_nodes)?; + // Full committee (N entries) — used by on-chain `committee_hash` binding. + let mut full_committee_party_ids: Vec = party_nodes.keys().copied().collect(); + full_committee_party_ids.sort(); + let committee_addresses = + committee_addresses_in_party_order(&full_committee_party_ids, &party_nodes)?; + + // Honest subset (H entries) — used by downstream actors for share-collection gating. + let honest_party_ids_vec: Vec = honest_party_ids.iter().copied().collect(); + let honest_committee_addresses = + committee_addresses_in_party_order(&honest_party_ids_vec, &party_nodes)?; let dkg_attestation_bundle = match dkg_aggregated_proof.as_ref() { Some(_) => { @@ -1050,6 +1185,7 @@ impl PublicKeyAggregator { e3_id: self.e3_id.clone(), nodes: nodes.clone(), committee_addresses: committee_addresses.clone(), + honest_committee_addresses: honest_committee_addresses.clone(), pk_commitment, dkg_aggregator_proof: dkg_aggregated_proof.clone(), dkg_attestation_bundle, @@ -1062,6 +1198,7 @@ impl PublicKeyAggregator { keyshares: OrderedSet::new(), nodes, committee_addresses, + honest_committee_addresses, }) })?; @@ -1094,6 +1231,8 @@ impl PublicKeyAggregator { dkg_fold_attestations, honest_party_ids, dishonest_parties, + circuit_committee_n, + circuit_committee_h, dkg_aggregation_correlation, dkg_aggregated_proof, c5_proof_pending, @@ -1112,6 +1251,8 @@ impl PublicKeyAggregator { dkg_fold_attestations, honest_party_ids, dishonest_parties, + circuit_committee_n, + circuit_committee_h, dkg_aggregation_correlation, dkg_aggregated_proof, c5_proof_pending, @@ -1127,6 +1268,8 @@ impl PublicKeyAggregator { dkg_fold_attestations, honest_party_ids, dishonest_parties, + circuit_committee_n, + circuit_committee_h, dkg_aggregation_correlation: None, dkg_aggregated_proof: Some(resp.proof.clone()), c5_proof_pending, @@ -1181,6 +1324,8 @@ impl PublicKeyAggregator { dkg_fold_attestations, honest_party_ids, dishonest_parties, + circuit_committee_n, + circuit_committee_h, dkg_aggregation_correlation: _, dkg_aggregated_proof, c5_proof_pending: _, @@ -1199,6 +1344,8 @@ impl PublicKeyAggregator { dkg_fold_attestations, honest_party_ids, dishonest_parties, + circuit_committee_n, + circuit_committee_h, dkg_aggregation_correlation: None, dkg_aggregated_proof, c5_proof_pending: None, @@ -1258,10 +1405,12 @@ impl PublicKeyAggregator { if keyshares.len() == *threshold_n && *threshold_n > 0 { let m = *threshold_m; + let n = *threshold_n; info!("PublicKeyAggregator: enough keyshares after expulsion, transitioning to VerifyingC1"); return Ok(PublicKeyAggregatorState::VerifyingC1 { submission_order: std::mem::take(submission_order), threshold_m: m, + threshold_n: n, c1_proofs: std::mem::take(c1_proofs), no_proof_parties: Vec::new(), }); @@ -1517,6 +1666,8 @@ mod tests { dkg_fold_attestations: HashMap::new(), honest_party_ids: BTreeSet::new(), dishonest_parties: BTreeSet::new(), + circuit_committee_n: 3, + circuit_committee_h: 3, dkg_aggregation_correlation: Some(correlation_id), dkg_aggregated_proof: None, c5_proof_pending: Some(dummy_proof(CircuitName::PkAggregation)), diff --git a/crates/aggregator/src/threshold_plaintext_aggregator.rs b/crates/aggregator/src/threshold_plaintext_aggregator.rs index a2bd99f044..cdbbdead4d 100644 --- a/crates/aggregator/src/threshold_plaintext_aggregator.rs +++ b/crates/aggregator/src/threshold_plaintext_aggregator.rs @@ -5,6 +5,7 @@ // or FITNESS FOR A PARTICULAR PURPOSE. use std::collections::{BTreeMap, BTreeSet}; +use std::str::FromStr; use actix::prelude::*; use alloy::primitives::Address; @@ -187,8 +188,13 @@ pub struct ThresholdPlaintextAggregator { decryption_aggregator_proofs: Option>, /// Last event context, reused for ZK and final publish. last_ec: Option>, - /// Ordered committee (`topNodes`) for decryption-aggregator `committee_hash_*` inputs. + /// Full registered committee (`topNodes`, length `N`) for decryption-aggregator + /// `committee_hash_*` inputs. Same value as `PublicKeyAggregated.committee_addresses`. committee_addresses: Vec
, + /// Canonical honest subset from DKG (length `H ≤ N`, from + /// `PublicKeyAggregated.honest_committee_addresses`). Drives share-collection + /// gating (expects one share from each H party) and sender checks after sortition. + honest_committee_addresses: Vec
, } pub struct ThresholdPlaintextAggregatorParams { @@ -197,8 +203,12 @@ pub struct ThresholdPlaintextAggregatorParams { pub e3_id: E3id, pub params_preset: BfvPreset, pub proof_aggregation_enabled: bool, - /// Finalized committee from `PublicKeyAggregated.nodes` (parsed once at construction). + /// Full committee from `PublicKeyAggregated.committee_addresses` (length `N`). + /// Used for `committee_hash_*` payload binding to on-chain `topNodes`. pub committee_addresses: Vec
, + /// Honest committee from `PublicKeyAggregated.honest_committee_addresses` + /// (length `H`). Roster for decryption-share collection and sender gating. + pub honest_committee_addresses: Vec
, } impl ThresholdPlaintextAggregator { @@ -220,9 +230,24 @@ impl ThresholdPlaintextAggregator { decryption_aggregator_proofs: None, last_ec: None, committee_addresses: params.committee_addresses, + honest_committee_addresses: params.honest_committee_addresses, } } + /// Length of the canonical honest subset (`H`), not on-chain committee size `N`. + /// Share collection waits for one decryption share from each address in + /// `honest_committee_addresses` (sortition membership is checked separately). + fn aggregated_committee_n(&self) -> u64 { + self.honest_committee_addresses.len() as u64 + } + + /// True when `node` is in `PublicKeyAggregated.honest_committee_addresses`. + fn node_in_aggregated_pk_committee(&self, node: &str) -> bool { + Address::from_str(node) + .ok() + .is_some_and(|addr| self.honest_committee_addresses.contains(&addr)) + } + pub fn add_share( &mut self, party_id: u64, @@ -230,6 +255,11 @@ impl ThresholdPlaintextAggregator { signed_decryption_proofs: Vec, ec: &EventContext, ) -> Result<()> { + let required_shares = self.aggregated_committee_n(); + ensure!( + required_shares > 0, + "honest committee addresses must not be empty before collecting decryption shares" + ); self.state.try_mutate(ec, |state| { info!("Adding share for party_id={}", party_id); let current: Collecting = state.clone().try_into()?; @@ -244,7 +274,7 @@ impl ThresholdPlaintextAggregator { shares.insert(party_id, share); c6_proofs.insert(party_id, signed_decryption_proofs); - if (shares.len() as u64) < threshold_n { + if (shares.len() as u64) < required_shares { return Ok(ThresholdPlaintextAggregatorState::Collecting(Collecting { params, threshold_n, @@ -257,8 +287,7 @@ impl ThresholdPlaintextAggregator { } info!( - "Changing state to VerifyingC6 because received all {} shares...", - threshold_n + "Changing state to VerifyingC6 because received all {required_shares} honest-committee shares..." ); Ok(ThresholdPlaintextAggregatorState::VerifyingC6( @@ -279,6 +308,7 @@ impl ThresholdPlaintextAggregator { party_id: u64, ec: &EventContext, ) -> Result<()> { + let required_shares = self.aggregated_committee_n(); self.state.try_mutate(ec, |state| { let ThresholdPlaintextAggregatorState::Collecting(current) = state else { return Ok(state); @@ -286,19 +316,15 @@ impl ThresholdPlaintextAggregator { let mut shares = current.shares; let mut c6_proofs = current.c6_proofs; - let mut threshold_n = current.threshold_n; + let threshold_n = current.threshold_n; shares.remove(&party_id); c6_proofs.remove(&party_id); - if threshold_n > 0 { - threshold_n -= 1; - } - - if threshold_n < current.threshold_m { + if required_shares < current.threshold_m { warn!( - "ThresholdPlaintextAggregator: threshold_n ({}) < threshold_m ({}) after expulsion", - threshold_n, current.threshold_m + "ThresholdPlaintextAggregator: honest committee size H ({required_shares}) < threshold_m ({}) after expulsion", + current.threshold_m ); return Ok(ThresholdPlaintextAggregatorState::Collecting(Collecting { threshold_m: current.threshold_m, @@ -311,7 +337,7 @@ impl ThresholdPlaintextAggregator { })); } - if (shares.len() as u64) < threshold_n || threshold_n == 0 { + if (shares.len() as u64) < required_shares { return Ok(ThresholdPlaintextAggregatorState::Collecting(Collecting { threshold_m: current.threshold_m, threshold_n, @@ -457,6 +483,8 @@ impl ThresholdPlaintextAggregator { // Publish ComputeRequest before transitioning state so a publish // failure leaves us in VerifyingC6 (retryable) rather than // Computing (no retry path). + // TrBFV scheme size stays N (`threshold_n`); only the share roster is restricted to the + // H canonical honest parties in `PublicKeyAggregated` (see `node_in_aggregated_pk_committee`). let trbfv_config = TrBFVConfig::new(state.params.clone(), state.threshold_n, state.threshold_m); @@ -1045,6 +1073,13 @@ impl Handler>> trace!("Node {} not found in finalized committee", &msg.node); return Ok(()); }; + if !self.node_in_aggregated_pk_committee(&msg.node) { + trace!( + "Node {} not in PublicKeyAggregated honest subset — ignoring decryption share", + &msg.node + ); + return Ok(()); + } // Trust the party_id from the event - it's based on CommitteeFinalized order // which is the authoritative source of truth for party IDs @@ -1288,6 +1323,7 @@ mod tests { params_preset: BfvPreset::InsecureThreshold512, proof_aggregation_enabled, committee_addresses: vec![test_committee_address()], + honest_committee_addresses: vec![test_committee_address()], }, test_persistable(initial_state), ); diff --git a/crates/data/src/data_store.rs b/crates/data/src/data_store.rs index 49578a335f..366d4aa6ad 100644 --- a/crates/data/src/data_store.rs +++ b/crates/data/src/data_store.rs @@ -127,24 +127,8 @@ impl DataStore { } /// Changes the scope for the data store. - /// Note that if the scope does not start with a slash one is appended. - /// ``` - /// use e3_data::DataStore; - /// use e3_data::InMemStore; - /// use actix::Actor; - /// use anyhow::Result; - /// - /// #[actix::main] - /// async fn main() -> Result<()>{ - /// let addr = InMemStore::new(false).start(); - /// let store = DataStore::from(&addr); - /// assert_eq!(store.base("//foo") - /// .scope("bar") - /// .scope("/baz") - /// .get_scope()?, "//foo/bar/baz"); - /// Ok(()) - /// } - /// ``` + /// Non-leading segments get a `/` separator; leading `/` on a segment is preserved. + /// Example: `base("//foo").scope("bar").scope("/baz")` → `"//foo/bar/baz"`. pub fn scope(&self, key: K) -> Self { let mut scope = self.scope.clone(); let encoded_key = key.into_key(); @@ -258,3 +242,20 @@ impl From<&Addr> for DataStore { } } } + +#[cfg(test)] +mod tests { + use super::*; + use actix::Actor; + + #[test] + fn scope_normalizes_slashes() { + actix::System::new().block_on(async { + let addr = InMemStore::new(false).start(); + let store = DataStore::from(&addr); + let scoped = store.base("//foo").scope("bar").scope("/baz"); + let scope = scoped.get_scope().expect("scope"); + assert_eq!(scope, "//foo/bar/baz"); + }); + } +} diff --git a/crates/events/src/enclave_event/publickey_aggregated.rs b/crates/events/src/enclave_event/publickey_aggregated.rs index aa31923724..c2b3ce30ec 100644 --- a/crates/events/src/enclave_event/publickey_aggregated.rs +++ b/crates/events/src/enclave_event/publickey_aggregated.rs @@ -20,9 +20,15 @@ pub struct PublicKeyAggregated { pub pubkey: ArcBytes, // TODO: ArcBytes ? pub e3_id: E3id, pub nodes: OrderedSet, - /// Committee addresses in ascending `party_id` (score) order for hash binding. + /// Full registered committee (`topNodes`) addresses in ascending `party_id` (score) order. + /// Length `N`. Used by `DecryptionAggregator` for `committee_hash_*` public-input binding. #[serde(default)] pub committee_addresses: Vec
, + /// Honest subset of the committee (size `H ≤ N`) in ascending `party_id` order. + /// These are the parties whose C1/NodeFold proofs were accepted; downstream actors + /// must gate decryption-share collection on this set rather than full `topNodes`. + #[serde(default)] + pub honest_committee_addresses: Vec
, /// Hash-based aggregated PK commitment (last public signal of the C5 proof). /// Passed as `pkCommitment` to `publishCommittee`. pub pk_commitment: [u8; 32], diff --git a/crates/keyshare/src/threshold_keyshare.rs b/crates/keyshare/src/threshold_keyshare.rs index de9057edb0..76b542cfd0 100644 --- a/crates/keyshare/src/threshold_keyshare.rs +++ b/crates/keyshare/src/threshold_keyshare.rs @@ -38,7 +38,7 @@ use e3_trbfv::{ use e3_utils::utility_types::ArcBytes; use e3_utils::{NotifySync, MAILBOX_LIMIT}; use e3_zk_helpers::computation::DkgInputType; -use e3_zk_helpers::CiphernodesCommitteeSize; +use e3_zk_helpers::{canonical_honest_party_ids_with_own, CiphernodesCommitteeSize}; use fhe::bfv::{PublicKey, SecretKey}; use fhe_traits::{DeserializeParametrized, Serialize}; use ndarray::Array2; @@ -1212,6 +1212,17 @@ impl ThresholdKeyshare { .map_err(|e| anyhow!("Failed to deserialize BFV public key: {:?}", e)) }) .collect::>()?; + // Share-encryption fan-out targets every registered party (`N`); `own_idx` is then + // skipped in `encrypt_all_extended_for_share_indices`, producing N-1 ciphertexts. + // The C3a/C3b NodeFold slots are sized for `N`, so any drift between the collected + // encryption-key roster and the configured committee would corrupt the fold witness. + if recipient_pks.len() != derived_committee_size.values().n as usize { + bail!( + "share-encryption recipients ({}) do not match committee N ({}); C3 fan-out would mis-size the NodeFold slots", + recipient_pks.len(), + derived_committee_size.values().n + ); + } let recipient_party_ids: Vec = encryption_keys.iter().map(|k| k.party_id).collect(); let recipient_share_indices: Vec = recipient_party_ids .iter() @@ -1775,7 +1786,7 @@ impl ThresholdKeyshare { // Validate per-party dimensions and exclude mismatched parties. let mut dimension_excluded: Vec = Vec::new(); - let honest_shares: Vec<_> = honest_shares + let mut honest_shares: Vec<_> = honest_shares .into_iter() .filter(|ts| { if ts.esi_sss.len() != expected_num_esi { @@ -1854,10 +1865,24 @@ impl ThresholdKeyshare { } } - // Honest party IDs include self (signing/aggregation treats own party as honest). - let mut honest_party_ids: BTreeSet = - honest_shares.iter().map(|s| s.party_id).collect(); - honest_party_ids.insert(own_party_id); + // Noir C4 is parameterized by `H` (honest-set size), not full committee `N`. + // Use the same lowest-`H` roster rule as the public-key aggregator (C5 / NodeFold). + let committee = CiphernodesCommitteeSize::from_threshold( + state.threshold_m as usize, + state.threshold_n as usize, + )?; + let committee_h = committee.values().h; + let external_party_ids: Vec = honest_shares.iter().map(|s| s.party_id).collect(); + if external_party_ids.len().saturating_add(1) > committee_h { + warn!( + "Capping honest roster to committee H={committee_h} for E3 {} (had {} external honest shares)", + e3_id, + external_party_ids.len() + ); + } + let honest_party_ids = + canonical_honest_party_ids_with_own(committee_h, external_party_ids, own_party_id); + honest_shares.retain(|s| honest_party_ids.contains(&s.party_id)); debug_assert!( honest_shares @@ -1866,23 +1891,36 @@ impl ThresholdKeyshare { "honest_shares must be strictly ascending by party_id" ); - // Position of own party within sorted {own} ∪ external honest set. - let own_plaintext_idx = honest_shares - .iter() - .position(|ts| ts.party_id > own_party_id) - .unwrap_or(honest_shares.len()); + let canonical_sorted: Vec = honest_party_ids.iter().copied().collect(); + let own_in_canonical = honest_party_ids.contains(&own_party_id); + let own_plaintext_idx = if let Some(idx) = + canonical_sorted.iter().position(|&pid| pid == own_party_id) + { + idx + } else { + warn!( + "Party {own_party_id} is outside the canonical honest roster (H={committee_h}, roster={honest_party_ids:?}) for E3 {e3_id}; \ + NodeFold/C5 on the aggregator will not include this party" + ); + canonical_sorted.len().saturating_sub(1) + }; + let num_honest = honest_party_ids.len(); + let external_for_c4: &[&Arc] = if own_in_canonical { + &honest_shares + } else { + &honest_shares[..num_honest.saturating_sub(1).min(honest_shares.len())] + }; - let num_honest = honest_shares.len() + 1; info!( - "Decrypting shares from {} honest parties (incl. self) for E3 {}", - num_honest, e3_id + "Decrypting shares from {} honest parties (canonical roster size H={}) for E3 {}", + num_honest, committee_h, e3_id ); // External ciphertexts for C4: own slot omitted from wire (rides as `own_share_raw`). // C4a: sk_sss external ciphertexts [(H-1) * L] let num_moduli_sk = expected_num_moduli_sk; let mut sk_ciphertexts_raw = Vec::new(); - for ts in &honest_shares { + for ts in external_for_c4 { let idx = if ts.sk_sss.len() == 1 { 0 } else { party_id }; let share = ts .sk_sss @@ -1897,7 +1935,7 @@ impl ThresholdKeyshare { let num_esi = expected_num_esi; let num_moduli_esi = expected_num_moduli_esi; let mut esi_ciphertexts_raw: Vec> = vec![Vec::new(); num_esi]; - for ts in &honest_shares { + for ts in external_for_c4 { for (esi_idx, esi_shares) in ts.esi_sss.iter().enumerate() { let idx = if esi_shares.len() == 1 { 0 } else { party_id }; let share = esi_shares @@ -1910,7 +1948,7 @@ impl ThresholdKeyshare { } // Decrypt our share row from each external honest sender using BFV. - let mut sk_sss_collected: Vec = honest_shares + let mut sk_sss_collected: Vec = external_for_c4 .iter() .map(|ts| { let idx = if ts.sk_sss.len() == 1 { 0 } else { party_id }; @@ -1922,12 +1960,16 @@ impl ThresholdKeyshare { }) .collect::>()?; - // Splice own sk share at the sorted-party position. + // Splice own sk share at the sorted-party position (when in the canonical roster). let own_sk_shamir = vec_of_rows_to_shamir_share(&own_sk_rows, degree)?; - sk_sss_collected.insert(own_plaintext_idx, own_sk_shamir); + if own_in_canonical { + sk_sss_collected.insert(own_plaintext_idx, own_sk_shamir); + } else { + sk_sss_collected.push(own_sk_shamir); + } // Decrypt per-party ESI shares: shape [external_party][esm_idx] - let mut per_party_esi: Vec> = honest_shares + let mut per_party_esi: Vec> = external_for_c4 .iter() .map(|ts| { ts.esi_sss @@ -1948,7 +1990,11 @@ impl ThresholdKeyshare { .iter() .map(|rows| vec_of_rows_to_shamir_share(rows, degree)) .collect::>()?; - per_party_esi.insert(own_plaintext_idx, own_esi_shamirs); + if own_in_canonical { + per_party_esi.insert(own_plaintext_idx, own_esi_shamirs); + } else { + per_party_esi.push(own_esi_shamirs); + } // Transpose to [esm_idx][party] — CalculateDecryptionKey aggregates per smudging noise let esi_sss_collected: Vec> = (0..num_esi) diff --git a/crates/test-helpers/src/ciphernode_system.rs b/crates/test-helpers/src/ciphernode_system.rs index 86c810c3f1..949414a1e6 100644 --- a/crates/test-helpers/src/ciphernode_system.rs +++ b/crates/test-helpers/src/ciphernode_system.rs @@ -237,6 +237,51 @@ impl CiphernodeSystem { ); Ok(CiphernodeHistory(history.events)) } + + /// Collect events until one whose [`EnclaveEvent::event_type`] equals `last_event_type` + /// (inclusive). Use when the pubkey flow ends with `PublicKeyAggregated` but a fixed + /// `take_history` count can stop too early while gossip duplicates inflate the multiset. + pub async fn take_history_until_last_event( + &self, + index: usize, + last_event_type: &str, + total_to: Option, + event_to: Option, + ) -> Result { + let start = Instant::now(); + let total_to = total_to.unwrap_or(Duration::from_secs(u64::MAX)); + let event_to = event_to.unwrap_or(Duration::from_secs(u64::MAX)); + let mut collected = Vec::new(); + + loop { + let remaining = total_to.saturating_sub(start.elapsed()); + if remaining.is_zero() { + bail!( + "take_history_until_last_event({last_event_type}) timed out after {:?}; got {} events: {:?}", + start.elapsed(), + collected.len(), + CiphernodeHistory(collected.clone()).event_types() + ); + } + let call_to = event_to.min(remaining); + let batch = self + .take_history_with_timeouts(index, 1, Some(call_to), Some(call_to)) + .await?; + for event in batch.0 { + let is_last = event.event_type() == last_event_type; + collected.push(event); + if is_last { + info!( + "take_history_until_last_event({last_event_type}) took {:?} ({} events)", + start.elapsed(), + collected.len() + ); + return Ok(CiphernodeHistory(collected)); + } + } + } + } + pub async fn flush_all_history(&self, millis: u64) -> Result<()> { let nodes = &self.0; for node in nodes.iter() { diff --git a/crates/tests/Cargo.toml b/crates/tests/Cargo.toml index 9856129b97..d138dbe080 100644 --- a/crates/tests/Cargo.toml +++ b/crates/tests/Cargo.toml @@ -44,6 +44,7 @@ fhe = { workspace = true } num-bigint = { workspace = true } rand = { workspace = true } rand_chacha = { workspace = true } +serde_json = { workspace = true } serial_test = { workspace = true } tempfile = { workspace = true } tokio = { workspace = true } diff --git a/crates/tests/tests/integration.rs b/crates/tests/tests/integration.rs index 8eebca8393..27e3d5c3c9 100644 --- a/crates/tests/tests/integration.rs +++ b/crates/tests/tests/integration.rs @@ -49,6 +49,7 @@ use num_bigint::BigUint; use rand::rngs::OsRng; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; +use std::collections::HashSet; use std::ffi::OsString; use std::sync::atomic::{AtomicU64, Ordering}; use std::time::{Duration, Instant}; @@ -162,6 +163,79 @@ fn benchmark_dkg_fold_attestation_verifier_address() -> Option
{ .or_else(|| "0x7969c5eD335650692Bc04293B07F5BF2e7A673C0".parse().ok()) } +/// Monorepo root (`crates/tests` → `../..`). +fn repo_root() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("..") + .join("..") +} + +/// Whether `setup_test_zk_backend` copies from `dist/circuits//` (same marker as below). +fn uses_dist_preset_artifacts(preset_subdir: &str) -> bool { + repo_root() + .join("dist/circuits") + .join(preset_subdir) + .join("recursive/dkg/pk/pk.json") + .exists() +} + +/// Preset stamp for committee/metadata — aligned with `setup_test_zk_backend` artifact source: +/// dist tree when present, otherwise `circuits/bin/.active-preset.json`. +fn resolve_preset_stamp_path(preset_subdir: &str) -> PathBuf { + let dist_preset = repo_root().join("dist/circuits").join(preset_subdir); + if uses_dist_preset_artifacts(preset_subdir) { + dist_preset.join(".build-stamp.json") + } else { + repo_root() + .join("circuits") + .join("bin") + .join(".active-preset.json") + } +} + +/// Reads the active committee from the preset stamp that matches the circuit artifacts in use. +/// Uses `resolve_preset_stamp_path` so committee metadata stays aligned with +/// `setup_test_zk_backend` (dist vs `circuits/bin`). +/// +/// Falls back to `Micro` (and warns) when the stamp is missing or pre-dates the `committee` +/// field — same default as the build script, so a freshly cloned repo's micro circuits work +/// out of the box. +fn active_committee(preset_subdir: &str) -> e3_zk_helpers::CiphernodesCommitteeSize { + use std::str::FromStr; + let stamp_path = resolve_preset_stamp_path(preset_subdir); + let fallback = e3_zk_helpers::CiphernodesCommitteeSize::Micro; + + let Ok(raw) = std::fs::read_to_string(&stamp_path) else { + eprintln!( + "⚠️ {} not found; defaulting to {fallback}. \ + Run `pnpm build:circuits --committee ` to make this deterministic.", + stamp_path.display(), + ); + return fallback; + }; + let Ok(stamp) = serde_json::from_str::(&raw) else { + eprintln!( + "⚠️ {} is not valid JSON; defaulting to {fallback}.", + stamp_path.display() + ); + return fallback; + }; + let Some(active) = stamp.get("committee").and_then(|v| v.as_str()) else { + eprintln!( + "⚠️ {} has no `committee` field (older build); defaulting to {fallback}.", + stamp_path.display(), + ); + return fallback; + }; + e3_zk_helpers::CiphernodesCommitteeSize::from_str(active).unwrap_or_else(|e| { + panic!( + "{} has unknown committee=\"{active}\": {e}. \ + Expected micro|small|medium|large.", + stamp_path.display() + ) + }) +} + /// Slashing manager address for benchmarks (no live RPC; used as EIP-712 /// `verifyingContract` for accusation vote signatures). fn benchmark_slashing_manager_address() -> Address { @@ -267,9 +341,7 @@ async fn setup_test_zk_backend( let bb_binary = noir_dir.join("bin").join("bb"); let circuits_dir = noir_dir.join("circuits"); let work_dir = noir_dir.join("work").join("test_node"); - let repo_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("..") - .join(".."); + let repo_root = repo_root(); let dist_preset = repo_root.join("dist/circuits").join(preset_subdir); if let Some(bb) = find_bb().await { @@ -285,7 +357,6 @@ async fn setup_test_zk_backend( compile_error!("Integration tests require unix symlink support"); let preset_out = circuits_dir.join(preset_subdir); - let dist_marker = dist_preset.join("recursive/dkg/pk/pk.json"); let circuits_bin_marker = repo_root.join("circuits/bin/dkg/target/pk.json"); // `circuits/bin` is preset-agnostic on disk — only `dist/circuits//.build-stamp.json` // (written by `pnpm build:circuits --preset `) records which preset the @@ -294,7 +365,7 @@ async fn setup_test_zk_backend( // produce invalid proofs. let preset_build_stamp = dist_preset.join(".build-stamp.json"); - if dist_marker.exists() { + if uses_dist_preset_artifacts(preset_subdir) { copy_dir_recursive(&dist_preset, &preset_out).await?; } else if !circuits_bin_marker.exists() || !preset_build_stamp.exists() { // Either no local build exists, or the local build cannot be proven to match @@ -1162,8 +1233,14 @@ async fn test_trbfv_actor() -> Result<()> { let params = ArcBytes::from_bytes(&encode_bfv_params(¶ms_raw.clone())); // round information - let threshold_m = 1; - let threshold_n = 3; + // Committee comes from the build stamp — the test always runs against whatever the circuits + // in `circuits/bin/` were compiled for, so switching committee is a single + // `pnpm build:circuits --committee ` away with no env var to remember. + let committee_size = active_committee(benchmark_params.preset_subdir); + let benchmark_committee = committee_size.values(); + let threshold_m = benchmark_committee.threshold; + let threshold_n = benchmark_committee.n; + let committee_h = benchmark_committee.h; let esi_per_ct = 1; // Statistical security parameter λ used for smudging bound / error_size. @@ -1384,53 +1461,47 @@ async fn test_trbfv_actor() -> Result<()> { // Node 0 is a non-committee observer. It only sees bus-global events and the forwardable // gossip events from the active aggregator flow. let shares_to_pubkey_agg_timer = Instant::now(); - const KS3: [&str; 3] = ["KeyshareCreated"; 3]; - const DKG3: [&str; 3] = ["DKGRecursiveAggregationComplete"; 3]; - const ACTIVE_AGGREGATOR_C1_C5: [&str; 9] = [ + // KeyshareCreated is gossiped by each committee member (N). The aggregator folds H honest + // keyshares into PublicKeyAggregated; DKGRecursiveAggregationComplete is one per member (N). + let ks_n: Vec<&'static str> = vec!["KeyshareCreated"; threshold_n]; + let dkg_n: Vec<&'static str> = vec!["DKGRecursiveAggregationComplete"; threshold_n]; + let mut active_aggregator_c1_c5: Vec<&'static str> = vec![ "ShareVerificationDispatched", "CommitmentConsistencyCheckRequested", "CommitmentConsistencyCheckComplete", - "ProofVerificationPassed", - "ProofVerificationPassed", - "ProofVerificationPassed", + ]; + // C1 verification dispatches ALL N submitted keyshare proofs (the protocol needs to know + // who's dishonest before it can pick the H honest set), so N ProofVerificationPassed events + // fire. The aggregator subsequently truncates to H for C5 input only. + active_aggregator_c1_c5.extend(std::iter::repeat("ProofVerificationPassed").take(threshold_n)); + active_aggregator_c1_c5.extend_from_slice(&[ "ShareVerificationComplete", "PkAggregationProofPending", "PkAggregationProofSigned", - ]; + ]); let mut expected_events: Vec<&'static str> = vec!["AggregatorChanged"]; if proof_aggregation_enabled { - expected_events.extend_from_slice(&KS3); - expected_events.extend_from_slice(&DKG3); + expected_events.extend_from_slice(&ks_n); + expected_events.extend_from_slice(&dkg_n); } else { - expected_events.extend_from_slice(&DKG3); - expected_events.extend_from_slice(&KS3); + expected_events.extend_from_slice(&dkg_n); + expected_events.extend_from_slice(&ks_n); } expected_events.push("PublicKeyAggregated"); - // KeyshareCreated and DKGRecursiveAggregationComplete are gossiped independently - // by different committee members, so at a non-committee observer they can interleave - // in any order. Assert the multiset matches and the boundary events are in place, - // rather than a strict sequence. + // Gossip can duplicate KeyshareCreated; wait until PublicKeyAggregated rather than a fixed take count. let h = nodes - .take_history_with_timeouts( + .take_history_until_last_event( 0, - expected_events.len(), + "PublicKeyAggregated", Some(pubkey_flow_timeout), Some(pubkey_flow_timeout), ) .await - .map_err(|e| anyhow::anyhow!("FAILURE on node 0: {expected_events:?} : {e}"))?; + .map_err(|e| anyhow::anyhow!("FAILURE on node 0 pubkey flow: {e}"))?; let actual_types = h.event_types(); - println!("node 0 >> {:?} =~ {:?}", actual_types, expected_events); - let mut actual_sorted = actual_types.clone(); - let mut expected_sorted: Vec = - expected_events.iter().map(|s| (*s).to_string()).collect(); - actual_sorted.sort(); - expected_sorted.sort(); - assert_eq!( - actual_sorted, expected_sorted, - "node 0 event multiset mismatch" - ); + println!("node 0 >> {:?}", actual_types); + assert_eq!( actual_types.first().map(String::as_str), Some("AggregatorChanged"), @@ -1442,6 +1513,44 @@ async fn test_trbfv_actor() -> Result<()> { "node 0: last event must be PublicKeyAggregated" ); + let dkg_parties: HashSet = h + .iter() + .filter_map(|e| match e.get_data() { + EnclaveEventData::DKGRecursiveAggregationComplete(d) => Some(d.party_id), + _ => None, + }) + .collect(); + let ks_parties: HashSet = h + .iter() + .filter_map(|e| match e.get_data() { + EnclaveEventData::KeyshareCreated(d) => Some(d.party_id), + _ => None, + }) + .collect(); + assert_eq!( + dkg_parties.len(), + threshold_n, + "node 0: expected one DKGRecursiveAggregationComplete per committee member (N={threshold_n}), got parties {dkg_parties:?}" + ); + assert_eq!( + ks_parties.len(), + threshold_n, + "node 0: expected KeyshareCreated from each committee member (N={threshold_n}), got parties {ks_parties:?}" + ); + let pk_agg = h + .iter() + .rev() + .find_map(|e| match e.get_data() { + EnclaveEventData::PublicKeyAggregated(d) => Some(d), + _ => None, + }) + .expect("PublicKeyAggregated in history"); + assert_eq!( + pk_agg.nodes.len(), + committee_h, + "PublicKeyAggregated must list H={committee_h} honest nodes" + ); + let active_aggregator_history = nodes.get_history(active_aggregator_index).await?; let active_aggregator_pubkey_history_len = active_aggregator_history.len(); let mut expected_active_aggregator_pubkey_events = vec![ @@ -1450,14 +1559,14 @@ async fn test_trbfv_actor() -> Result<()> { "AggregatorChanged", ]; if proof_aggregation_enabled { - expected_active_aggregator_pubkey_events.extend_from_slice(&KS3); + expected_active_aggregator_pubkey_events.extend_from_slice(&ks_n); } else { - expected_active_aggregator_pubkey_events.extend_from_slice(&DKG3); - expected_active_aggregator_pubkey_events.extend_from_slice(&KS3); + expected_active_aggregator_pubkey_events.extend_from_slice(&dkg_n); + expected_active_aggregator_pubkey_events.extend_from_slice(&ks_n); } - expected_active_aggregator_pubkey_events.extend_from_slice(&ACTIVE_AGGREGATOR_C1_C5); + expected_active_aggregator_pubkey_events.extend_from_slice(&active_aggregator_c1_c5); if proof_aggregation_enabled { - expected_active_aggregator_pubkey_events.extend_from_slice(&DKG3); + expected_active_aggregator_pubkey_events.extend_from_slice(&dkg_n); } expected_active_aggregator_pubkey_events.push("PublicKeyAggregated"); @@ -1577,62 +1686,137 @@ async fn test_trbfv_actor() -> Result<()> { // The collector only sees the shared ciphertext event, gossiped decryption shares, and the // final gossiped plaintext output. - const DS3: [&str; 3] = ["DecryptionshareCreated"; 3]; + // Only the H honest parties decrypt and gossip a share; the (N - H) extras stay in the + // full committee but do not participate in decryption. + let ds_n: Vec<&'static str> = vec!["DecryptionshareCreated"; committee_h]; let mut expected_events: Vec<&'static str> = vec!["CiphertextOutputPublished"]; - expected_events.extend_from_slice(&DS3); + expected_events.extend_from_slice(&ds_n); expected_events.push("PlaintextAggregated"); println!( "[bench-progress] waiting for PlaintextAggregated flow on observer node (expected events: {})", expected_events.len() ); - let h = expect_node_events_with_timeouts( - &nodes, - 0, - &expected_events, - plaintext_flow_timeout, - plaintext_flow_timeout, - ) - .await?; + // Gossip can duplicate DecryptionshareCreated on the collector path (same as KeyshareCreated + // in the pubkey flow); wait until `PlaintextAggregated` rather than a fixed take count, then + // assert the multiset matches with duplicates removed. + let h = nodes + .take_history_until_last_event( + 0, + "PlaintextAggregated", + Some(plaintext_flow_timeout), + Some(plaintext_flow_timeout), + ) + .await + .map_err(|e| anyhow::anyhow!("FAILURE on node 0 plaintext flow: {e}"))?; + let actual_types = h.event_types(); + println!("node 0 >> {:?}", actual_types); + assert_eq!( + actual_types.first().map(String::as_str), + Some("CiphertextOutputPublished"), + "collector: first plaintext-flow event must be CiphertextOutputPublished" + ); + assert_eq!( + actual_types.last().map(String::as_str), + Some("PlaintextAggregated"), + "collector: last plaintext-flow event must be PlaintextAggregated" + ); + let unique_ds_parties: HashSet = h + .iter() + .filter_map(|e| match e.get_data() { + EnclaveEventData::DecryptionshareCreated(d) => Some(d.party_id), + _ => None, + }) + .collect(); + // All N committee members that received share material attempt decryption and gossip; the + // aggregator consumes only H. So the number of distinct senders observed at the collector + // sits in [H, N]. + assert!( + unique_ds_parties.len() >= committee_h && unique_ds_parties.len() <= threshold_n, + "collector: expected DecryptionshareCreated from {committee_h}..={threshold_n} distinct parties, got {} parties {unique_ds_parties:?}", + unique_ds_parties.len() + ); println!("[bench-progress] PlaintextAggregated observed on collector path"); let active_aggregator_history = nodes.get_history(active_aggregator_index).await?; - const C6_VERIFY_PREFIX: [&str; 19] = [ - "CiphertextOutputPublished", - "DecryptionshareCreated", - "DecryptionshareCreated", - "DecryptionshareCreated", - "ShareVerificationDispatched", - "CommitmentConsistencyCheckRequested", - "CommitmentConsistencyCheckComplete", - "ComputeRequest", - "ComputeResponse", - "ProofVerificationPassed", - "ProofVerificationPassed", - "ProofVerificationPassed", - "ProofVerificationPassed", - "ProofVerificationPassed", - "ProofVerificationPassed", - "ProofVerificationPassed", - "ProofVerificationPassed", - "ProofVerificationPassed", - "ShareVerificationComplete", - ]; let active_aggregator_plaintext_events = project_history( &active_aggregator_history[active_aggregator_pubkey_history_len..], |data| plaintext_aggregator_marker(data, &e3_id), ); + + // C6 head layout: + // CiphertextOutputPublished, DecryptionshareCreated × K, ShareVerificationDispatched, + // CommitmentConsistencyCheckRequested, CommitmentConsistencyCheckComplete + // where K is in [H, N] plus possible gossip duplicates — every committee member that received + // share material gossips one, the aggregator selects H. Locate boundaries by name rather than + // by fixed offset. assert_eq!( - &active_aggregator_plaintext_events[..C6_VERIFY_PREFIX.len()], - C6_VERIFY_PREFIX, - "Unexpected active aggregator C6 verification prefix" + active_aggregator_plaintext_events.first().copied(), + Some("CiphertextOutputPublished"), + "active aggregator: first plaintext-flow event must be CiphertextOutputPublished" + ); + let svd_index = active_aggregator_plaintext_events + .iter() + .position(|e| *e == "ShareVerificationDispatched") + .expect("ShareVerificationDispatched should be present in plaintext flow"); + let pre_svd = &active_aggregator_plaintext_events[1..svd_index]; + assert!( + pre_svd.iter().all(|e| *e == "DecryptionshareCreated"), + "active aggregator: only DecryptionshareCreated allowed between CiphertextOutputPublished and ShareVerificationDispatched, got {pre_svd:?}" ); + let unique_ds_parties_agg: HashSet = active_aggregator_history + [active_aggregator_pubkey_history_len..] + .iter() + .take_while(|e| { + !matches!( + e.get_data(), + EnclaveEventData::ShareVerificationDispatched(_) + ) + }) + .filter_map(|e| match e.get_data() { + EnclaveEventData::DecryptionshareCreated(d) if d.e3_id == e3_id => Some(d.party_id), + _ => None, + }) + .collect(); + assert!( + unique_ds_parties_agg.len() >= committee_h && unique_ds_parties_agg.len() <= threshold_n, + "active aggregator: expected DecryptionshareCreated from {committee_h}..={threshold_n} distinct parties before ShareVerificationDispatched, got {} parties {unique_ds_parties_agg:?}", + unique_ds_parties_agg.len() + ); + assert_eq!( + &active_aggregator_plaintext_events[svd_index..svd_index + 3], + &[ + "ShareVerificationDispatched", + "CommitmentConsistencyCheckRequested", + "CommitmentConsistencyCheckComplete", + ][..], + "Unexpected active aggregator C6 head after ShareVerificationDispatched" + ); + let c6_head_end = svd_index + 3; - let completion_events = &active_aggregator_plaintext_events[C6_VERIFY_PREFIX.len()..]; + let aggregation_pending_index = active_aggregator_plaintext_events + .iter() + .position(|event| *event == "AggregationProofPending") + .expect("AggregationProofPending should be present"); + let c6_body = &active_aggregator_plaintext_events[c6_head_end..aggregation_pending_index]; + assert_eq!( + count_projected_events(c6_body, "ShareVerificationComplete"), + 1, + "expected one C6 ShareVerificationComplete before aggregation" + ); + assert!( + count_projected_events(c6_body, "ProofVerificationPassed") >= committee_h, + "expected >= {committee_h} C6 ProofVerificationPassed events before aggregation" + ); + let c6_compute_requests = count_projected_events(c6_body, "ComputeRequest"); + let c6_compute_responses = count_projected_events(c6_body, "ComputeResponse"); + assert!( + c6_compute_requests >= 1 && c6_compute_requests == c6_compute_responses, + "expected paired C6-phase ComputeRequest/ComputeResponse (got {c6_compute_requests} requests, {c6_compute_responses} responses)" + ); - let mut expected_plaintext_completion = vec![ - "ComputeRequest", - "ComputeResponse", + let aggregation_flow = &active_aggregator_plaintext_events[aggregation_pending_index..]; + let mut expected_aggregation_flow = vec![ "AggregationProofPending", "ComputeRequest", "ComputeResponse", @@ -1640,47 +1824,39 @@ async fn test_trbfv_actor() -> Result<()> { ]; if proof_aggregation_enabled { // `DecryptionAggregation`: one compute pair (C6 fold + C7 checked inside the worker). - expected_plaintext_completion.push("ComputeRequest"); - expected_plaintext_completion.push("ComputeResponse"); + expected_aggregation_flow.push("ComputeRequest"); + expected_aggregation_flow.push("ComputeResponse"); } - expected_plaintext_completion.push("PlaintextAggregated"); + expected_aggregation_flow.push("PlaintextAggregated"); assert_eq!( - completion_events, - expected_plaintext_completion.as_slice(), - "Unexpected active aggregator plaintext completion flow" + aggregation_flow, + expected_aggregation_flow.as_slice(), + "Unexpected active aggregator C7/aggregation flow" ); assert_eq!( - count_projected_events(completion_events, "AggregationProofPending"), + count_projected_events(aggregation_flow, "AggregationProofSigned"), 1 ); assert_eq!( - count_projected_events(completion_events, "AggregationProofSigned"), + count_projected_events(aggregation_flow, "PlaintextAggregated"), 1 ); - assert_eq!( - count_projected_events(completion_events, "PlaintextAggregated"), - 1 - ); - let aggregation_pending_index = completion_events - .iter() - .position(|event| *event == "AggregationProofPending") - .expect("AggregationProofPending should be present"); - let aggregation_signed_index = completion_events + let aggregation_signed_index = aggregation_flow .iter() .position(|event| *event == "AggregationProofSigned") .expect("AggregationProofSigned should be present"); - let plaintext_aggregated_index = completion_events + let plaintext_aggregated_index = aggregation_flow .iter() .position(|event| *event == "PlaintextAggregated") .expect("PlaintextAggregated should be present"); assert!( - aggregation_pending_index < aggregation_signed_index, - "AggregationProofPending must precede AggregationProofSigned" + aggregation_signed_index < plaintext_aggregated_index, + "AggregationProofSigned must precede PlaintextAggregated" ); assert_eq!( plaintext_aggregated_index, - completion_events.len() - 1, + aggregation_flow.len() - 1, "PlaintextAggregated must be the last active aggregator completion event" ); @@ -1884,7 +2060,7 @@ async fn test_trbfv_actor() -> Result<()> { benchmark_params.lambda, proof_aggregation_enabled, concurrent_jobs, - threshold_n, // micro committee: H == N_PARTIES + committee_h, threshold_n, threshold_m, 20usize, @@ -2454,7 +2630,8 @@ async fn test_duplicate_e3_id_with_different_chain_id() -> Result<()> { pubkey: ArcBytes::from_bytes(&test_pubkey.to_bytes()), e3_id: E3id::new("1234", 1), nodes: OrderedSet::from(eth_addrs.clone()), - committee_addresses: actual_pubkey_agg_1.committee_addresses, + committee_addresses: actual_pubkey_agg_1.committee_addresses.clone(), + honest_committee_addresses: actual_pubkey_agg_1.honest_committee_addresses.clone(), pk_commitment: actual_pubkey_agg_1.pk_commitment, dkg_aggregator_proof: None, dkg_attestation_bundle: None, @@ -2497,7 +2674,8 @@ async fn test_duplicate_e3_id_with_different_chain_id() -> Result<()> { pubkey: ArcBytes::from_bytes(&test_pubkey.to_bytes()), e3_id: E3id::new("1234", 2), nodes: OrderedSet::from(eth_addrs.clone()), - committee_addresses: actual_pubkey_agg_2.committee_addresses, + committee_addresses: actual_pubkey_agg_2.committee_addresses.clone(), + honest_committee_addresses: actual_pubkey_agg_2.honest_committee_addresses.clone(), pk_commitment: actual_pubkey_agg_2.pk_commitment, dkg_aggregator_proof: None, dkg_attestation_bundle: None, diff --git a/crates/zk-helpers/src/bin/generate_parity_matrices.rs b/crates/zk-helpers/src/bin/generate_parity_matrices.rs new file mode 100644 index 0000000000..e4211b057b --- /dev/null +++ b/crates/zk-helpers/src/bin/generate_parity_matrices.rs @@ -0,0 +1,156 @@ +// 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. + +//! Regenerates `circuits/lib/src/configs/committee//parity_{insecure,secure}.nr` +//! for the given committee. Invoked by `scripts/build-circuits.ts` whenever the active +//! committee is set, so the Reed-Solomon parity matrices stay in lockstep with `(N, T)` +//! and the threshold `QIS` of each preset. +//! +//! Usage: +//! cargo run --release --bin generate_parity_matrices -- \ +//! --committee \ +//! [--output-root ] +//! +//! The Noir literal is produced by +//! `e3_zk_helpers::circuits::dkg::share_computation::utils::parity_matrix_constant_string`, +//! which is the same function the C2 codegen uses — so the values here match what the +//! prover would compute at witness time. + +use std::path::{Path, PathBuf}; +use std::str::FromStr; + +use anyhow::{Context, Result}; +use clap::Parser; +use e3_fhe_params::{build_pair_for_preset, BfvPreset}; +use e3_zk_helpers::ciphernodes_committee::CiphernodesCommitteeSize; +use e3_zk_helpers::circuits::dkg::share_computation::utils::parity_matrix_constant_string; + +#[derive(Parser, Debug)] +#[command( + name = "generate_parity_matrices", + about = "Regenerate parity_{insecure,secure}.nr for a committee." +)] +struct Args { + /// Committee name (`micro`, `small`, `medium`, `large`). Determines `(N, T)`. + #[arg(long)] + committee: String, + + /// Root directory containing the per-committee modules. Defaults to + /// `/circuits/lib/src/configs/committee` relative to the workspace. + #[arg(long)] + output_root: Option, +} + +fn workspace_root() -> Result { + // CARGO_MANIFEST_DIR resolves to crates/zk-helpers at build time. + let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + manifest + .parent() + .and_then(|p| p.parent()) + .map(Path::to_path_buf) + .context("could not locate workspace root from CARGO_MANIFEST_DIR") +} + +fn output_root(args: &Args) -> Result { + if let Some(p) = &args.output_root { + return Ok(p.clone()); + } + Ok(workspace_root()? + .join("circuits") + .join("lib") + .join("src") + .join("configs") + .join("committee")) +} + +/// Maps a `(preset, committee)` pair to the path of the file that holds its +/// `PARITY_MATRIX` literal. The `_insecure` / `_secure` suffix is the same naming +/// that `committee::active::PARITY_MATRIX_INSECURE / _SECURE` re-export from. +fn file_for(root: &Path, committee: &str, preset: BfvPreset) -> PathBuf { + let suffix = match preset { + BfvPreset::InsecureThreshold512 => "insecure", + BfvPreset::SecureThreshold8192 => "secure", + // Codegen runs against the threshold side of each preset family. + // DKG-only variants don't need their own file. + BfvPreset::InsecureDkg512 => "insecure", + BfvPreset::SecureDkg8192 => "secure", + }; + root.join(committee).join(format!("parity_{suffix}.nr")) +} + +/// File template. Threading `committee` / `preset` / `matrix` keeps the on-disk format +/// stable across regenerations (so the lefthook check can diff against a fresh run). +fn render(committee: &str, preset_suffix: &str, l_module: &str, matrix_literal: &str) -> String { + let preset_label = match preset_suffix { + "insecure" => "insecure-512 (L_THRESHOLD=2)", + "secure" => "secure-8192 (L_THRESHOLD=3)", + other => other, + }; + format!( + "// SPDX-License-Identifier: LGPL-3.0-only\n\ +//\n\ +// This file is provided WITHOUT ANY WARRANTY;\n\ +// without even the implied warranty of MERCHANTABILITY\n\ +// or FITNESS FOR A PARTICULAR PURPOSE.\n\ +//\n\ +// AUTO-GENERATED by `generate_parity_matrices`. DO NOT EDIT BY HAND.\n\ +// Regenerate with `pnpm build:circuits --committee {committee}`.\n\ +//\n\ +// Reed-Solomon parity matrix for the {committee} committee under the\n\ +// {preset_label} preset. Dimensions: [L_THRESHOLD][N_PARTIES - T][N_PARTIES + 1].\n\ +\n\ +use crate::configs::committee::{committee}::{{N_PARTIES, T}};\n\ +pub use crate::configs::{l_module}::threshold::L as L_THRESHOLD;\n\ +\n\ +{matrix_literal}\n" + ) +} + +fn main() -> Result<()> { + let args = Args::parse(); + let size = CiphernodesCommitteeSize::from_str(&args.committee) + .with_context(|| format!("unknown committee: {}", args.committee))?; + let params = size.values(); + let root = output_root(&args)?; + + if !root.join(&args.committee).is_dir() { + anyhow::bail!( + "expected committee module dir at {}; \ + does {} exist as `pub mod {}` under committee/mod.nr?", + root.join(&args.committee).display(), + args.committee, + args.committee + ); + } + + for preset in BfvPreset::PAIR_PRESETS { + let (threshold_params, _) = build_pair_for_preset(preset) + .with_context(|| format!("build_pair_for_preset({preset:?}) failed"))?; + let literal = parity_matrix_constant_string(&threshold_params, params.n, params.threshold) + .with_context(|| { + format!( + "parity_matrix_constant_string(committee={}, preset={preset:?}) failed", + args.committee + ) + })?; + let (suffix, l_module) = match preset { + BfvPreset::InsecureThreshold512 => ("insecure", "insecure"), + BfvPreset::SecureThreshold8192 => ("secure", "secure"), + _ => continue, // PAIR_PRESETS only carries the threshold variants + }; + let path = file_for(&root, &args.committee, preset); + let content = render(&args.committee, suffix, l_module, &literal); + std::fs::write(&path, content).with_context(|| format!("writing {}", path.display()))?; + println!( + "✓ {} ({} rows × {} cols)", + path.display(), + params.n - params.threshold, + params.n + 1 + ); + } + + Ok(()) +} diff --git a/crates/zk-helpers/src/bin/zk_cli.rs b/crates/zk-helpers/src/bin/zk_cli.rs index e240f0ae1b..506561b1e6 100644 --- a/crates/zk-helpers/src/bin/zk_cli.rs +++ b/crates/zk-helpers/src/bin/zk_cli.rs @@ -64,15 +64,8 @@ enum DkgInputTypeArg { } fn parse_committee(s: &str) -> Result { - match s.trim().to_lowercase().as_str() { - "micro" => Ok(CiphernodesCommitteeSize::Micro), - "small" => Ok(CiphernodesCommitteeSize::Small), - "medium" => Ok(CiphernodesCommitteeSize::Medium), - "large" => Ok(CiphernodesCommitteeSize::Large), - _ => Err(anyhow!( - "unknown committee: {s}. Use \"micro\", \"small\", \"medium\", or \"large\"" - )), - } + use std::str::FromStr; + CiphernodesCommitteeSize::from_str(s.trim()) } fn parse_input_type(s: &str) -> Result { @@ -182,7 +175,7 @@ struct Cli { /// Select the witness family when sample generation depends on it. #[arg(long)] inputs: Option, - /// Committee size: "micro" or "small". + /// Committee size: micro, small, medium, or large (must match circuits lib default). #[arg(long, default_value = "micro")] committee: String, /// Output directory for generated artifacts. diff --git a/crates/zk-helpers/src/ciphernodes_committee.rs b/crates/zk-helpers/src/ciphernodes_committee.rs index b3096b686a..dd3de585e1 100644 --- a/crates/zk-helpers/src/ciphernodes_committee.rs +++ b/crates/zk-helpers/src/ciphernodes_committee.rs @@ -4,6 +4,10 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. +use std::collections::BTreeSet; +use std::fmt; +use std::str::FromStr; + use anyhow::{bail, Result}; use serde::{Deserialize, Serialize}; @@ -48,6 +52,17 @@ impl CiphernodesCommitteeSize { } } + /// Lower-case name as written into `circuits/bin/.active-preset.json` and the + /// `--committee` flag of `scripts/build-circuits.ts`. Use this for stamp/env cross-checks. + pub fn as_str(self) -> &'static str { + match self { + Self::Micro => "micro", + Self::Small => "small", + Self::Medium => "medium", + Self::Large => "large", + } + } + /// Returns `(num_parties, num_honest_parties, threshold)` for this size. pub fn values(self) -> CiphernodesCommittee { match self { @@ -74,3 +89,141 @@ impl CiphernodesCommitteeSize { } } } + +/// Validate `(T, N, H)` against the canonical committee table used by compiled Noir circuits. +/// +/// Returns the canonical row on success. Callers must pass the same `(threshold_m, threshold_n, +/// h)` the active `committee/*/mod.nr` was built with — smudging bounds and C1 public IO depend on +/// `N_PARTIES` (= `n`), not BFV preset degree. +pub fn canonical_committee_for_circuit( + committee: &CiphernodesCommittee, +) -> Result { + let expected = + CiphernodesCommitteeSize::from_threshold(committee.threshold, committee.n)?.values(); + if committee.h != expected.h { + anyhow::bail!( + "committee.h={} does not match canonical h={} for (T={}, N={})", + committee.h, + expected.h, + committee.threshold, + committee.n + ); + } + if committee.n != expected.n || committee.threshold != expected.threshold { + anyhow::bail!( + "committee (T={}, N={}, H={}) is not a canonical committee size", + committee.threshold, + committee.n, + committee.h + ); + } + Ok(expected) +} + +impl FromStr for CiphernodesCommitteeSize { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "micro" => Ok(Self::Micro), + "small" => Ok(Self::Small), + "medium" => Ok(Self::Medium), + "large" => Ok(Self::Large), + _ => bail!("Unknown committee size '{s}'. Expected micro|small|medium|large"), + } + } +} + +impl fmt::Display for CiphernodesCommitteeSize { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +/// Select the canonical honest roster of size at most `committee_h`: ascending `party_id`, +/// truncated to the lowest `H` when the candidate set is larger. +/// +/// Used by the public-key aggregator (C5 / NodeFold) and threshold keyshare (C4) so both sides +/// agree on which parties occupy the circuit's `H` slots when `H < N`. +pub fn cap_honest_party_ids( + committee_h: usize, + party_ids: impl IntoIterator, +) -> BTreeSet { + let mut ids: Vec = party_ids.into_iter().collect(); + ids.sort_unstable(); + ids.dedup(); + if ids.len() > committee_h { + ids.truncate(committee_h); + } + ids.into_iter().collect() +} + +/// Merge external honest `party_id`s with `own_party_id`, then [`cap_honest_party_ids`]. +pub fn canonical_honest_party_ids_with_own( + committee_h: usize, + external_honest_party_ids: impl IntoIterator, + own_party_id: u64, +) -> BTreeSet { + cap_honest_party_ids( + committee_h, + external_honest_party_ids + .into_iter() + .chain(std::iter::once(own_party_id)), + ) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn canonical_committee_for_circuit_accepts_medium_row() { + let committee = CiphernodesCommitteeSize::Medium.values(); + assert_eq!( + canonical_committee_for_circuit(&committee).unwrap(), + committee + ); + } + + #[test] + fn cap_honest_party_ids_keeps_lowest_h() { + let capped = cap_honest_party_ids(8, 0..10); + assert_eq!(capped, BTreeSet::from([0, 1, 2, 3, 4, 5, 6, 7])); + } + + #[test] + fn cap_honest_party_ids_noop_when_at_most_h() { + let capped = cap_honest_party_ids(8, [2u64, 0, 1]); + assert_eq!(capped, BTreeSet::from([0, 1, 2])); + } + + #[test] + fn canonical_with_own_matches_global_lowest_h_when_own_is_high() { + // Medium-style: N=10, H=8, all external 0..8 honest, own=9. + let external: Vec = (0..9).collect(); + let canonical = canonical_honest_party_ids_with_own(8, external, 9); + assert_eq!(canonical, BTreeSet::from([0, 1, 2, 3, 4, 5, 6, 7])); + assert!(!canonical.contains(&9)); + } + + #[test] + fn canonical_with_own_includes_own_when_in_lowest_h() { + let external: Vec = (0..9).collect(); + let canonical = canonical_honest_party_ids_with_own(8, external, 7); + assert_eq!(canonical, BTreeSet::from([0, 1, 2, 3, 4, 5, 6, 7])); + assert!(canonical.contains(&7)); + } + + #[test] + fn old_keyshare_cap_rule_diverges_from_canonical() { + let external: Vec = (0..9).collect(); + let committee_h = 8usize; + let own = 9u64; + let mut old_external = external.clone(); + old_external.truncate(committee_h.saturating_sub(1)); + let mut old = BTreeSet::from_iter(old_external); + old.insert(own); + let canonical = canonical_honest_party_ids_with_own(committee_h, external, own); + assert_ne!(old, canonical); + } +} diff --git a/crates/zk-helpers/src/circuits/dkg/share_computation/computation.rs b/crates/zk-helpers/src/circuits/dkg/share_computation/computation.rs index b80e5bb3a2..fe7117a98a 100644 --- a/crates/zk-helpers/src/circuits/dkg/share_computation/computation.rs +++ b/crates/zk-helpers/src/circuits/dkg/share_computation/computation.rs @@ -150,7 +150,7 @@ impl Computation for Bounds { type Data = ShareComputationCircuitData; type Error = CircuitsErrors; - fn compute(preset: Self::Preset, _data: &Self::Data) -> Result { + fn compute(preset: Self::Preset, data: &Self::Data) -> Result { let (threshold_params, _) = build_pair_for_preset(preset).map_err(|e| CircuitsErrors::Sample(e.to_string()))?; let defaults = preset @@ -159,12 +159,11 @@ impl Computation for Bounds { let num_ciphertexts = defaults.z; let lambda = defaults.lambda; - // Use search_defaults.n (same as C1/PkGeneration) so the smudging bound and - // resulting bit width match C1's PK_GENERATION_BIT_E_SM. This ensures - // C1.e_sm_commitment == C2b.expected_secret_commitment for the same e_sm. + // Use the same committee size as C1 (pk_generation) so smudging bounds and + // bit widths match PK_GENERATION_BIT_E_SM / SHARE_COMPUTATION_E_SM_BIT_SECRET. let e_sm_config = SmudgingBoundCalculatorConfig::new( threshold_params, - defaults.n as usize, + data.n_parties as usize, num_ciphertexts as usize, lambda as usize, ); diff --git a/crates/zk-helpers/src/circuits/threshold/pk_generation/codegen.rs b/crates/zk-helpers/src/circuits/threshold/pk_generation/codegen.rs index 434b68db7b..ce68662269 100644 --- a/crates/zk-helpers/src/circuits/threshold/pk_generation/codegen.rs +++ b/crates/zk-helpers/src/circuits/threshold/pk_generation/codegen.rs @@ -28,7 +28,7 @@ impl CircuitCodegen for PkGenerationCircuit { fn codegen(&self, preset: Self::Preset, data: &Self::Data) -> Result { let inputs = Inputs::compute(preset, data)?; - let configs = Configs::compute(preset, &())?; + let configs = Configs::compute(preset, &data.committee)?; let toml = generate_toml(inputs)?; let configs = generate_configs(preset, &configs)?; @@ -191,7 +191,9 @@ mod tests { assert!(configs_path.exists()); let configs_content = std::fs::read_to_string(&configs_path).unwrap(); - let bounds = Bounds::compute(BfvPreset::InsecureThreshold512, &()).unwrap(); + use crate::ciphernodes_committee::CiphernodesCommitteeSize; + let committee = CiphernodesCommitteeSize::Medium.values(); + let bounds = Bounds::compute(BfvPreset::InsecureThreshold512, &committee).unwrap(); let bits = Bits::compute(BfvPreset::InsecureThreshold512, &bounds).unwrap(); assert!(configs_content.contains( diff --git a/crates/zk-helpers/src/circuits/threshold/pk_generation/computation.rs b/crates/zk-helpers/src/circuits/threshold/pk_generation/computation.rs index e5d1331d4d..2376c7193e 100644 --- a/crates/zk-helpers/src/circuits/threshold/pk_generation/computation.rs +++ b/crates/zk-helpers/src/circuits/threshold/pk_generation/computation.rs @@ -10,6 +10,7 @@ //! and (for input) a public key. They implement [`Computation`] and are used by codegen. use crate::calculate_bit_width; +use crate::ciphernodes_committee::CiphernodesCommittee; use crate::crt_polynomial_to_toml_json; use crate::math::{cyclotomic_polynomial, decompose_residue}; use crate::polynomial_to_toml_json; @@ -49,7 +50,7 @@ impl CircuitComputation for PkGenerationCircuit { type Error = CircuitsErrors; fn compute(preset: Self::Preset, data: &Self::Data) -> Result { - let bounds = Bounds::compute(preset, &())?; + let bounds = Bounds::compute(preset, &data.committee)?; let bits = Bits::compute(preset, &bounds)?; let inputs = Inputs::compute(preset, data)?; @@ -102,16 +103,16 @@ pub struct Inputs { impl Computation for Configs { type Preset = BfvPreset; - type Data = (); + type Data = CiphernodesCommittee; type Error = CircuitsErrors; - fn compute(preset: Self::Preset, _: &Self::Data) -> Result { + fn compute(preset: Self::Preset, committee: &Self::Data) -> Result { let (threshold_params, _) = build_pair_for_preset(preset).map_err(|e| CircuitsErrors::Other(e.to_string()))?; let moduli = threshold_params.moduli().to_vec(); - let bounds = Bounds::compute(preset, &())?; + let bounds = Bounds::compute(preset, committee)?; let bits = Bits::compute(preset, &bounds)?; Ok(Configs { @@ -166,13 +167,17 @@ impl Computation for Bits { impl Computation for Bounds { type Preset = BfvPreset; - type Data = (); + type Data = CiphernodesCommittee; type Error = CircuitsErrors; - fn compute(preset: Self::Preset, _: &Self::Data) -> Result { + fn compute(preset: Self::Preset, committee: &Self::Data) -> Result { let (threshold_params, _) = build_pair_for_preset(preset).map_err(|e| CircuitsErrors::Other(e.to_string()))?; + let committee = crate::ciphernodes_committee::canonical_committee_for_circuit(committee) + .map_err(|e| CircuitsErrors::Other(e.to_string()))?; + let committee_n = committee.n; + let n = BigInt::from(threshold_params.degree()); let ctx = threshold_params.ctx_at_level(0)?; @@ -187,7 +192,7 @@ impl Computation for Bounds { let smudging_config = SmudgingBoundCalculatorConfig::new( threshold_params.clone(), - sd.n as usize, + committee_n, sd.z as usize, preset.metadata().lambda, ); @@ -358,12 +363,41 @@ impl Computation for Inputs { #[cfg(test)] mod tests { use super::*; + use crate::CiphernodesCommittee; use e3_fhe_params::BfvPreset; + #[test] + fn bounds_compute_rejects_non_canonical_committee_h() { + let preset = BfvPreset::InsecureThreshold512; + let bad = CiphernodesCommittee { + n: 3, + h: 8, + threshold: 1, + }; + let err = Bounds::compute(preset, &bad).unwrap_err(); + assert!( + format!("{err:?}").contains("committee.h=8"), + "expected h mismatch error, got {err:?}" + ); + } + + #[test] + fn bounds_compute_rejects_unknown_threshold_pair() { + let preset = BfvPreset::InsecureThreshold512; + let bad = CiphernodesCommittee { + n: 5, + h: 5, + threshold: 1, + }; + assert!(Bounds::compute(preset, &bad).is_err()); + } + #[test] fn test_bound_and_bits_computation_consistency() { let preset = BfvPreset::InsecureThreshold512; - let bounds = Bounds::compute(preset, &()).unwrap(); + use crate::ciphernodes_committee::CiphernodesCommitteeSize; + let committee = CiphernodesCommitteeSize::Medium.values(); + let bounds = Bounds::compute(preset, &committee).unwrap(); let bits = Bits::compute(preset, &bounds).unwrap(); // pk_bit uses compute_modulus_bit: (max(qi) - 1) / 2 for centered representation @@ -375,7 +409,8 @@ mod tests { #[test] fn test_constants_json_roundtrip() { - let constants = Configs::compute(BfvPreset::InsecureThreshold512, &()).unwrap(); + let committee = crate::ciphernodes_committee::CiphernodesCommitteeSize::Medium.values(); + let constants = Configs::compute(BfvPreset::InsecureThreshold512, &committee).unwrap(); let json = constants.to_json().unwrap(); let decoded: Configs = serde_json::from_value(json).unwrap(); diff --git a/crates/zk-prover/src/actors/node_proof_aggregator.rs b/crates/zk-prover/src/actors/node_proof_aggregator.rs index a45ca6a6a9..9fce7535c6 100644 --- a/crates/zk-prover/src/actors/node_proof_aggregator.rs +++ b/crates/zk-prover/src/actors/node_proof_aggregator.rs @@ -34,6 +34,7 @@ struct NodeDkgFoldMeta { sk_share_encryption_requests: Vec, e_sm_share_encryption_requests: Vec, committee_n: usize, + committee_h: usize, n_moduli: usize, params_preset: e3_fhe_params::BfvPreset, } @@ -118,20 +119,29 @@ impl NodeProofAggregator { let e_sm_enc_count = msg.e_sm_share_encryption_requests.len(); let total_expected = 4 + sk_enc_count + e_sm_enc_count + 2; - let (committee_n, n_moduli) = match build_pair_for_preset(msg.proof_request.params_preset) { - Ok((threshold_params, _)) => { - let n = msg.proof_request.committee_size.values().n as usize; - (n, threshold_params.moduli().len()) - } - Err(e) => { - self.pending_inner_proofs.remove(&e3_id); - error!( - "NodeProofAggregator: build_pair_for_preset failed for E3 {}: {e}", - e3_id - ); - return; - } - }; + let committee = msg.proof_request.committee_size.values(); + let (committee_n, committee_h, n_moduli) = + match build_pair_for_preset(msg.proof_request.params_preset) { + Ok((threshold_params, _)) => { + (committee.n, committee.h, threshold_params.moduli().len()) + } + Err(e) => { + self.pending_inner_proofs.remove(&e3_id); + error!( + "NodeProofAggregator: build_pair_for_preset failed for E3 {}: {e}", + e3_id + ); + let _ = self.bus.publish( + E3Failed { + e3_id: e3_id.clone(), + failed_at_stage: E3Stage::CommitteeFinalized, + reason: FailureReason::DKGInvalidShares, + }, + ec.clone(), + ); + return; + } + }; let meta = NodeDkgFoldMeta { party_id: msg.full_share.party_id, @@ -141,6 +151,7 @@ impl NodeProofAggregator { sk_share_encryption_requests: msg.sk_share_encryption_requests.clone(), e_sm_share_encryption_requests: msg.e_sm_share_encryption_requests.clone(), committee_n, + committee_h, n_moduli, params_preset: msg.proof_request.params_preset, }; @@ -326,7 +337,7 @@ impl NodeProofAggregator { let party_id = state.meta.party_id; let committee_n = state.meta.committee_n; - let committee_h = committee_n; + let committee_h = state.meta.committee_h; let n_moduli = state.meta.n_moduli; let fold_attestation = match extract_node_fold_agg_commits( @@ -612,6 +623,7 @@ mod tests { sk_share_encryption_requests: Vec::new(), e_sm_share_encryption_requests: Vec::new(), committee_n: 0, + committee_h: 0, n_moduli: 0, params_preset: e3_fhe_params::BfvPreset::InsecureThreshold512, }, @@ -716,6 +728,7 @@ mod tests { sk_share_encryption_requests: Vec::new(), e_sm_share_encryption_requests: Vec::new(), committee_n: 0, + committee_h: 0, n_moduli: 0, params_preset: e3_fhe_params::BfvPreset::InsecureThreshold512, }, diff --git a/crates/zk-prover/tests/common/helpers.rs b/crates/zk-prover/tests/common/helpers.rs index 3400842efc..28bfd35565 100644 --- a/crates/zk-prover/tests/common/helpers.rs +++ b/crates/zk-prover/tests/common/helpers.rs @@ -212,6 +212,57 @@ pub async fn setup_test_prover(bb: &PathBuf) -> (ZkBackend, TempDir) { (backend, temp) } +/// Reads `circuits/bin/.active-preset.json` (written by `scripts/build-circuits.ts`) and +/// returns the `committee` field, normalised to lower-case (e.g. `"micro"`, `"medium"`). +/// Returns `None` when the stamp is absent or malformed — callers must treat that as a +/// "circuits not built yet" condition rather than as a specific committee. +pub fn active_bin_committee() -> Option { + let path = circuits_build_root().join(".active-preset.json"); + let raw = std::fs::read_to_string(&path).ok()?; + let v: serde_json::Value = serde_json::from_str(&raw).ok()?; + v.get("committee")?.as_str().map(|s| s.to_lowercase()) +} + +/// Returns `true` when the compiled `pk_aggregation` (C5) circuit was built for the **micro** +/// committee (H=3): `expected_threshold_pk_commitments` array length == 3. +/// +/// Tests that hard-code `CiphernodesCommitteeSize::Micro` samples should call this and skip +/// when it returns `false` — the Micro samples will not satisfy the compiled circuit's ABI. +/// +/// Prefers `.active-preset.json` (cheap stamp check) and falls back to ABI introspection of +/// `pk_aggregation.json` for older builds that pre-date the stamp's `committee` field. +pub fn circuits_compiled_for_micro() -> bool { + if let Some(committee) = active_bin_committee() { + return committee == "micro"; + } + + let path = circuits_build_root() + .join("threshold") + .join("pk_aggregation") + .join("target") + .join("pk_aggregation.json"); + let Ok(raw) = std::fs::read_to_string(&path) else { + return false; // artifact absent → can't tell, assume not micro + }; + let Ok(v) = serde_json::from_str::(&raw) else { + return false; + }; + // `expected_threshold_pk_commitments` is the H-length array in C5's ABI. + v["abi"]["parameters"] + .as_array() + .and_then(|ps| { + ps.iter() + .find(|p| { + p.get("name") + == Some(&serde_json::Value::String( + "expected_threshold_pk_commitments".into(), + )) + }) + .and_then(|p| p.get("type")?.get("length")?.as_u64()) + }) + .is_some_and(|len| len == 3) // micro H == 3 +} + /// Lightweight backend for tests that need to override config (e.g. inject bad checksums). pub fn test_backend(temp_path: &std::path::Path, config: ZkConfig) -> ZkBackend { let noir_dir = temp_path.join("noir"); diff --git a/crates/zk-prover/tests/common/mod.rs b/crates/zk-prover/tests/common/mod.rs index a16725b4f2..f212c747ab 100644 --- a/crates/zk-prover/tests/common/mod.rs +++ b/crates/zk-prover/tests/common/mod.rs @@ -7,6 +7,21 @@ mod helpers; pub use helpers::*; +/// Call at the top of any setup function that hard-codes `CiphernodesCommitteeSize::Micro`. +/// Returns `None` (causing the test to skip) when the compiled circuits were built for a +/// non-micro committee — the Micro-sized samples would not satisfy the circuit ABI. +pub fn require_micro_circuits() -> Option<()> { + if circuits_compiled_for_micro() { + Some(()) + } else { + println!( + "skipping: circuits not compiled for micro committee. \ + Rebuild with `pnpm build:circuits --committee micro` to run this test." + ); + None + } +} + use std::path::PathBuf; use num_bigint::{BigInt, Sign}; diff --git a/crates/zk-prover/tests/fold_accumulators_e2e_tests.rs b/crates/zk-prover/tests/fold_accumulators_e2e_tests.rs index e5f8d91025..ac6ba69e95 100644 --- a/crates/zk-prover/tests/fold_accumulators_e2e_tests.rs +++ b/crates/zk-prover/tests/fold_accumulators_e2e_tests.rs @@ -337,6 +337,11 @@ async fn setup_c3_fold_with_inner_share_encryption() -> Option<( )) } +/// Expected C3 fold slot count when circuits are compiled for the micro committee (N=3, T=1). +const MICRO_C3_FOLD_SLOTS: usize = 2; +/// Expected C6 fold slot count when circuits are compiled for the micro committee (N=3, T=1). +const MICRO_C6_FOLD_SLOTS: usize = 2; + #[tokio::test] async fn c3_fold_sequential_proves_and_verifies() { let Some((_backend, _temp, prover, circuit, sample_a, sample_b, preset)) = @@ -346,6 +351,16 @@ async fn c3_fold_sequential_proves_and_verifies() { return; }; + let total_slots = c3_fold_total_slots_from_compiled_json(); + if total_slots != MICRO_C3_FOLD_SLOTS { + println!( + "skipping c3_fold_sequential_proves_and_verifies: circuits compiled for \ + non-micro committee (total_slots={total_slots}, expected {MICRO_C3_FOLD_SLOTS}). \ + Rebuild with `pnpm build:circuits --committee micro` to run this test." + ); + return; + } + let artifacts_dir = preset.artifacts_dir(); let inner_e3_a = "e3-c3fold-inner-0"; let inner_e3_b = "e3-c3fold-inner-1"; @@ -375,13 +390,6 @@ async fn c3_fold_sequential_proves_and_verifies() { .expect("inner ShareEncryption proof 1"); assert_eq!(inner_b.circuit, CircuitName::ShareEncryption); - let total_slots = c3_fold_total_slots_from_compiled_json(); - assert!( - total_slots >= 2, - "need at least 2 C3 slots for two-fold test (compiled total_slots={})", - total_slots - ); - let inners = [inner_a, inner_b]; let folded = generate_sequential_c3_fold( &prover, @@ -455,6 +463,15 @@ async fn c6_fold_sequential_proves_and_verifies() { return; }; + let total_slots = c6_fold_total_slots_from_compiled_json(); + if total_slots != MICRO_C6_FOLD_SLOTS { + println!( + "skipping c6_fold_sequential_proves_and_verifies: circuits compiled for \ + non-micro committee (total_slots={total_slots}, expected {MICRO_C6_FOLD_SLOTS}). \ + Rebuild with `pnpm build:circuits --committee micro` to run this test." + ); + return; + } let artifacts_dir = preset.artifacts_dir(); let inner_e3_a = "e3-c6fold-inner-0"; let inner_e3_b = "e3-c6fold-inner-1"; @@ -484,13 +501,6 @@ async fn c6_fold_sequential_proves_and_verifies() { .expect("inner ThresholdShareDecryption proof 1"); assert_eq!(inner_b.circuit, CircuitName::ThresholdShareDecryption); - let total_slots = c6_fold_total_slots_from_compiled_json(); - assert!( - total_slots >= 2, - "need at least 2 C6 slots for two-fold test (compiled total_slots={})", - total_slots - ); - let inners = [inner_a, inner_b]; let folded = generate_sequential_c6_fold( &prover, diff --git a/crates/zk-prover/tests/local_e2e_tests.rs b/crates/zk-prover/tests/local_e2e_tests.rs index 52f49f33c0..72e4bcf097 100644 --- a/crates/zk-prover/tests/local_e2e_tests.rs +++ b/crates/zk-prover/tests/local_e2e_tests.rs @@ -21,7 +21,8 @@ use std::sync::Arc; use ark_bn254::Fr; use ark_ff::{BigInteger, PrimeField, Zero}; use common::{ - extract_field, extract_field_from_end, find_bb, setup_compiled_circuit, setup_test_prover, + extract_field, extract_field_from_end, find_bb, require_micro_circuits, setup_compiled_circuit, + setup_test_prover, }; use e3_events::CircuitName; use e3_fhe_params::{build_pair_for_preset, BfvPreset}; @@ -148,6 +149,7 @@ async fn setup_share_encryption_e_sm_test() -> Option<( let committee = CiphernodesCommitteeSize::Micro.values(); let preset = BfvPreset::InsecureThreshold512; let bb = find_bb().await?; + require_micro_circuits()?; let (backend, temp) = setup_test_prover(&bb).await; let sd: e3_fhe_params::PresetSearchDefaults = @@ -188,6 +190,7 @@ async fn setup_share_encryption_sk_test() -> Option<( let committee = CiphernodesCommitteeSize::Micro.values(); let preset = BfvPreset::InsecureThreshold512; let bb = find_bb().await?; + require_micro_circuits()?; let (backend, temp) = setup_test_prover(&bb).await; let sd: e3_fhe_params::PresetSearchDefaults = @@ -228,6 +231,7 @@ async fn setup_share_computation_sk_test() -> Option<( let committee = CiphernodesCommitteeSize::Micro.values(); let preset = BfvPreset::InsecureThreshold512; let bb = find_bb().await?; + require_micro_circuits()?; let (backend, temp) = setup_test_prover(&bb).await; setup_compiled_circuit(&backend, "dkg", "sk_share_computation").await; @@ -261,6 +265,7 @@ async fn setup_share_computation_e_sm_test() -> Option<( let committee = CiphernodesCommitteeSize::Micro.values(); let preset = BfvPreset::InsecureThreshold512; let bb = find_bb().await?; + require_micro_circuits()?; let (backend, temp) = setup_test_prover(&bb).await; setup_compiled_circuit(&backend, "dkg", "sk_share_computation").await; @@ -297,6 +302,7 @@ async fn setup_pk_generation_test() -> Option<( let committee = CiphernodesCommitteeSize::Micro.values(); let preset = BfvPreset::InsecureThreshold512; let bb = find_bb().await?; + require_micro_circuits()?; let (backend, temp) = setup_test_prover(&bb).await; setup_compiled_circuit(&backend, "threshold", "pk_generation").await; @@ -327,6 +333,7 @@ async fn setup_share_decryption_test() -> Option<( let committee = CiphernodesCommitteeSize::Micro.values(); let preset = BfvPreset::InsecureThreshold512; let bb = find_bb().await?; + require_micro_circuits()?; let (backend, temp) = setup_test_prover(&bb).await; setup_compiled_circuit(&backend, "threshold", "share_decryption").await; @@ -357,6 +364,7 @@ async fn setup_c4_c6_e2e_test() -> Option<( let committee = CiphernodesCommitteeSize::Micro.values(); let preset = BfvPreset::InsecureThreshold512; let bb = find_bb().await?; + require_micro_circuits()?; let (backend, temp) = setup_test_prover(&bb).await; setup_compiled_circuit(&backend, "dkg", "share_decryption").await; @@ -386,6 +394,7 @@ async fn setup_pk_aggregation_test() -> Option<( let committee = CiphernodesCommitteeSize::Micro.values(); let preset = BfvPreset::InsecureThreshold512; let bb = find_bb().await?; + require_micro_circuits()?; let (backend, temp) = setup_test_prover(&bb).await; setup_compiled_circuit(&backend, "threshold", "pk_aggregation").await; @@ -416,6 +425,7 @@ async fn setup_decrypted_shares_aggregation_test() -> Option<( let committee = CiphernodesCommitteeSize::Micro.values(); let preset = BfvPreset::InsecureThreshold512; let bb = find_bb().await?; + require_micro_circuits()?; let (backend, temp) = setup_test_prover(&bb).await; setup_compiled_circuit(&backend, "threshold", "decrypted_shares_aggregation").await; diff --git a/crates/zk-prover/tests/node_fold_correlated_e2e_tests.rs b/crates/zk-prover/tests/node_fold_correlated_e2e_tests.rs index 5e4122e67d..71a2ed574c 100644 --- a/crates/zk-prover/tests/node_fold_correlated_e2e_tests.rs +++ b/crates/zk-prover/tests/node_fold_correlated_e2e_tests.rs @@ -17,7 +17,8 @@ mod node_fold_witness; use std::path::PathBuf; use common::{ - find_bb, setup_compiled_circuit, setup_recursive_aggregation_fold_circuit, setup_test_prover, + find_bb, require_micro_circuits, setup_compiled_circuit, + setup_recursive_aggregation_fold_circuit, setup_test_prover, }; use e3_events::{CircuitName, Proof}; use e3_fhe_params::BfvPreset; @@ -134,6 +135,10 @@ async fn node_fold_correlated_sparse_self_slot_proves_and_verifies() { return; }; + if require_micro_circuits().is_none() { + return; + } + let gate = recursive_aggregation_compiled_json_path(CircuitName::NodeFold); if !gate.exists() { println!( diff --git a/package.json b/package.json index ce19788ac1..3be393855c 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "check:license": "./scripts/check-license-headers.sh", "check:size": "./scripts/check-size.sh", "check:pnpm": "./scripts/check-pnpm.sh", + "check:committee": "./scripts/check-committee.sh", "test": "pnpm evm:test && pnpm rust:test && pnpm sdk:test && pnpm noir:test", "test:integration": "cd ./tests/integration && ./test.sh", "coverage": "pnpm evm:coverage", diff --git a/packages/enclave-contracts/scripts/utils.ts b/packages/enclave-contracts/scripts/utils.ts index beb8d12303..4814d70bdb 100644 --- a/packages/enclave-contracts/scripts/utils.ts +++ b/packages/enclave-contracts/scripts/utils.ts @@ -80,8 +80,11 @@ function resolveRepoRoot(): string { export const REPO_ROOT = resolveRepoRoot(); /** + * * Default insecure-512 / micro committee layout for BFV aggregator verifiers. * Must match `lib::configs::default::{H, T}` in compiled circuits. + * Micro committee: N=3, T=1, H=3. + * */ export const BFV_DKG_H = 3; export const BFV_THRESHOLD_T = 1; diff --git a/packages/enclave-contracts/test/fixtures/bfv_vk_binding/folded_artifacts.json b/packages/enclave-contracts/test/fixtures/bfv_vk_binding/folded_artifacts.json index d6d7a20871..295e7fd102 100644 --- a/packages/enclave-contracts/test/fixtures/bfv_vk_binding/folded_artifacts.json +++ b/packages/enclave-contracts/test/fixtures/bfv_vk_binding/folded_artifacts.json @@ -1,10 +1,10 @@ { "dkg_aggregator": { - "proof_hex": "0x000000000000000000000000000000000000000000000002b30b0403aeee459600000000000000000000000000000000000000000000000db8eebcfc671fdeea00000000000000000000000000000000000000000000000af8f618d2adad1ebe0000000000000000000000000000000000000000000000000002c5040e9c20dc00000000000000000000000000000000000000000000000a2de63e4ca6eb0e210000000000000000000000000000000000000000000000021ae69d4a65c7a8e900000000000000000000000000000000000000000000000a005bc241e7d733b30000000000000000000000000000000000000000000000000002aa8c45dd85d4000000000000000000000000000000000000000000000008ff1dbd0f4b9b41c900000000000000000000000000000000000000000000000a46e1fc8b19f097560000000000000000000000000000000000000000000000075006eb06b9214632000000000000000000000000000000000000000000000000000093433350ca3600000000000000000000000000000000000000000000000c8e6e0c4281f705a50000000000000000000000000000000000000000000000043c924cc53c6b0e6b000000000000000000000000000000000000000000000009a11c5c7358610a3300000000000000000000000000000000000000000000000000001c36379475c900f5f028b1ca9b05f4fd64f348afe95c048291c2608303e91a5c888446ce265e275b7caf50609f9aed4ce3fdda4988dff1b9cfa755d22a06ac9bd70fe011311d3021f96a67be4ae494bd7f310637090a697383e48e1cfe83d199fea464581f5b26f5d27b00505d5850189be9bf43d8b14ee58b28a16c87b3bf9d5bd3dae341de20a977a63187eb07fb817d6f32bd7e353ea5f2e4563e05af30e41de8d76caf2a05fb7411e0736765ea872b88f93642e1a0a122c2beda192429812e49797d0d2b0b2d57c7f9a3d89feb36de6e8925068d4cf01c5631bba6ad66d9dfea89eef42507b82d0cdde68023f51cd886423293963e553af03761d6bdd7e82c5f3f70581726faac8f74102eb6129ddf5940c15a1f473a25099ce9aed7c8502f304535e73f02c89d7edbdc59430a931b60bf65dba6ff6c4568fcf3361abd1e9097cc3446930d256472545bebbdf0cd8202744ebee6b32aded93bbab7c8b07493ffe15d753c2e767d9b71f63f422e0d8397639315c74a3f459246674a141133d6068e91cd04236270fbc4be415c1b3fb0340ab79c0aebf168d36a35a77d26f5507817a381e82997d3d4e6bf47cf282de75db04e846b05a1171e1b27b3378df7f46c8a0d5f452ef0980db9a94784dc6878f8768320b7a5f1327d5a0398b9090cde4a0301320d2c66315a1209ffec932d6318d851ff138899b2fc2f20210b9ba6487e63272dc9292a55757e58a10eaf53bb32db4bd956cb6ea7db2f7d3d376ffde54a0c481c8e2b91e9e7d106a81edff57b8a49e69ba1cbce8d8ad7a768f51040cd0760adda1f1b057d97309b56258908e7d0b72e311d563d0f33a89b025e9b29dbae8430af6c1d5dc9be373e533150316757b50b3d7f39cb3fb983eec9d368f3997f12567c3516a615929225c27f1166fe0b8a910ade60dec004d39048fbb5e348d1d7b8f14e167cf8625eabdff7f7262e220e7cad7c3169f11ed47467b15790ad046ae3ea490d5aef76bcb164504f3b903fdde68d660bf30a4a023c0639d3b0df5986a898291ca9055a779c358e4526204e571e880645cb2634ddb604f97aab892dd8b2c61206a8ad742b79fdd1cf600bb1b100e239a25d525acfe6fb97a5c0a13dccd21c3e1be9395c5f4a8ce11c7c9adf0450a3dc13c753c8b0d37894fdb03746c10c45e92b11c11485fd5cca6eef8495c4fe4a8e89af5ce2321dacfb3de59466cdec2510156f196cfcdf53325e7070710c87d4451690eff29e4d32a8e34518657116d7ac1562534b4b1a9267d5813b831d136f643f2511cdf969567bb8528b3b509274e022485fa86f947eb6caddb7d6aa964114d188ffd141b79fde4bec77997e8de82e1a22e50c704d7e5fa81ad6470e6e610932071304bd9547f446e615d36f44ab582ea1f51c35052fc32ef3fd4004dc82b1bf9a39b670cbd3064b42858de6d62c0e202f260e6c01dc5da58f0f5ca5aadf80c9a9810e700b5342d312a883895208ed277759e4d19186345a6d59fff1e1b2df1b9ed20c49e08dba5d430c5c889d232c0dbec12765d1f90c1243fec4c3d67e1d37e80f7783ef9a1828baaceb6f59bad6211ce93b78dc48f06df07f27a2150b2b744cf2a5a06a0df954aaeec4161a424e2eb3a35a6b9f4e985ee41ca8ff60b38bfce07c646fcb9cd13c438c57afced26e28939f478f3c70bb968c92a82a5be84d9453b1121028cc087d1d072e7e6c7c0205fe83b1a01ceba1e0e90bcce21bc3dd3be897d503f20f49b07d818120c8883900aac83216fa6bf485c26476d03e6cad5643b6c5cf217f866e372b1ad25028ac239027d059b6b09551123523e2a5f42d33c4b330bf9b77e09785e6e48fa657361dc82de67104ad93500c9741939e8ba447f6dc1fc4191770b950772b9f1c82772b810282ebc72e0e003f822c1a213b3ce88f42565589de9c8a22cd5e3fbeda3c210803bc3b27db480707058c2df76c782e29c4ec3ed4258affc6790d85b95c0102af61b154df03951ef522e8c2e2d7c0e65d89bbbac33c8119dd9bf436def3cc2b3767985ed2bbab59f583232694b3a362918f9f72a99af2f0f5af2efcc7697c2d2fcaf7859f1a53585929269d86b3c8973039adcfbbc308fee491644c480a7c27dfa9fa5ef3bd09bffee4577c9bbc3690003ea1e3aad93e92fb3d3049d533190deaec9660872e7fcabfcddd95bc009081df6bff849124e9e9df109416fc751b0d2a98b66c8baa3500d82452f976c890f25ae6399064f155ecdb915f4d008b7a002f0bba3996e8fb749742a4b69120e029e62ad24d4f998cb586da076c916cb321f43d09bf02b75a56631867d73c77cdf9da4de3492a4b650d78b39b367dfa510fe1e9c7137dda94b17f265f6938deee104649c6163212b3f9be3a66234369c113a8e3a54aa3505c8bd668b9bb77dd5eec4e994e0024de8f3203d92f6f301e1223b57e5d4a69b68f6d9c57d3fd2dba27ca0bfb145ab0c29922b9a2b129f0e3f71fc82a5b8a4a881948245a642bc118320f72a2723d6a7a9ebb1bfe185529acce021f5fa2445c3744c8ac48355df7a41a8520486e45fce375c3c6fbd3b33bac3c2e5e29bc45ca7fd84f34893fc756f888c9db6e8d1b33d731af38f622c11c5e180602f9f504ce236d5dd7c1068c9f472f64905dde988f8e4ae7f199def886026f21843689e58f2f3dfe48f8f5a637b4a71284fc5706e649278419b7c8e538926409cfcd311cf3c556de1e275dbabc9e67658d311ba3cb5c17542c186a7da2ffd129684a2f9bdc4f2ebead34aa0cc6f94cbab3aabd66c8fd8bf65350be1ef08abc28a673680e3f8c7e41567d1ded0d1c173be5f3f0c7e080b2f1545630ef9644321ed718522ab1f7584f6a4ad83079823dbe5c55b19701cdf61208e783f6516be01412b7a8746a2c86c2cacdb91aa020b8d1db64dbc78c4889165e11b4aaf173202bc28bc70e00bc24bb8cbe3839f97793b66099528624e7d1c7fca00b911b707b19bc81d8401fa754ba2a05bc955437d15102dd440d1969450617d725d1c0baf51b3d8ba9c5943f28453d574f21fc2f9a08f9752aa61f9188a9cd8574593a82ac1794392b927399e2682bd77ca428316d1a2a77fd52d12be4d3f7fd57b9b33a68065b4112e464cbb09ae6d219c9acc029a295cd67fe60517b04596e84de3cbd1602082cab3609a950d6731f100664632ada637279bec7ead801d854a2b92a322b0f0f6f0554856fed457ba9fc25583f8f1ff8d03d55205a052c67db1a02282cc80559294b448cbc117fe65a32ae25d61584c1993159d4c2329f89293162f89ad02d91f842933045e44515de74b0f6da4625efb734d885a51865862a4c2d8104682c6d83cb7999c411b070ea3a5bc939cd54c26d43025654b66025c683116bdf06294b2eb9482a612e3d67a632d391609406b60edbc28b9c01c5d5b43796bcc3d007d36fb02537fcd6d3baa7bc9c3859846fce0d7b30d65860a5d8d27f6d2718ed15850e16cdfce67e1dc1d63b0fc45f1a17a0d9c7db71f689e3766e12786b8c2a2d60dc28eeadd07ade9fbf8447fdddc4f91d05b10d136058ad481f9b4a7e024a17029bad7d3a24366de116e8077da5b101c14da26867735d2524bcb9864778e02dd5dc33744ca7e50e87806b9d773d44dd60cac69135a5d29dcb4b93fe58551024ca2bae5c4c5f6682cb487546e40abe929304b714f50ea72c453cd38dd5e8692c2ae119ad1d9ef3b605e627d35720d26cde98e914c811cc457ae3cd5252b79e25893e23371561e89a731da3343d9ceeafb13593ccbf355ea34eba49f2e63c47289f58bd3e1fdacbb319183e85582f405592fe19656cd0a23a1cfe79d906f80d1efe414b0a22a209c332036c65cc9d46751c183d8618b839afa04eb21499cde40a98b16c72709e82be7312a6085b0563e940fc80e1cc10ad90615a040be766a204743f7867ec779c8a1d0d5fe3de9462f19bfdb3da14dad8768e04f13148df882eec36da9754f273e15636d808ea116523f0d567b5316bd1ebcf6c4de936d03908774b8f1d132154642b87c20ac9cd2de8088f1d0a55de6db45a75543d1adb2806b5975df484e4db990be106045d32642afbd7a492681e8681c84ec41bcadc6e1527f9ce6a7a670a20f260ae45d21aaaa489855dd747e5340f01a956152504a31ebc51009014c5b28e9e845c3a143d89302c81d5f94bd499250d48ddaf47fcec0afa7a61480263c5273b8acc667e784402be671586cfdb7b4db3f8a0f5e1fecd2aefbcf44e5f04a3617598869909c0aceaf0951635951ed4180a0a9b50cca1bb2b5b775f56a5b46a804330edd52fcbdf477485ad2f90e1aa0e3c6febb4f769eb0a4e62b793e1ac9676a35745509b1b9137cadb86a1fe28b0a00b1ede0523ef0229d5521820274634a635d398df9b85908f4ffd8533407e995995fb6a6f4f8bcf15aeacc9028dd5d83f265d2fe95d44afb3baa593f702b1937c3a27a40b6f02d7058a16f98da0cb85c8c6cc07d602960eb28aed5a6b5a8005363783c4c6ddb2010fd07d26daf701ec005d7765e9701cf8617925e4dc28744355b61d1fc2dffd272b74a06f3520227be984cbf13925584c110fd52798ddecd811ade62f107d939c1379e3ebcb8d71f09dfa48f3f2be201f2cefcc38345ae3ced3286cd06dec45e9115b345f3e78a3ee45db7f9170064864d5c09cb0fc3e8f5b7a763846c9b6a87d11798becb574a394dc37646282a7f7c7db3824cda09f9f8a5741937915979ac90b4f7b5de4d1eb4a3b7d6181a242ce8efe9e99513e83b53a66d91e85ac3412a40f2ed30dc99975a2a8aef2f11dcbb15473e41cbbc7bbb7adcfb89f3a9aa708170af029423d5e3e33e5bcd5bbc040ef8843868fc9243d05539ef570dbe1e10aef20fd382c33955f4bb9721ff64b91dc1ccb64d1c39f422bad3029fd747441ead524ce950b1a581caa7944b372cb78c0f9933a173143d3c99f2ef5203bbd71341e1b580d87c30fdf3e28038e52e088ee5d1729da0d34f16b6485002e49708b2af80a0440fec31f89fc13213af1d473835795cc991ac856248d6947c032bea69585093d3901d6393263c2e887bb58cf5f9e8dc4da7a20bca245b87607de9ea0620f096ccbcd54b6f3921fca613160e8e406d7331807a16d33650e418f91a75a1b49155d96ae9ab1de581aebaebcb2cbda8934bab4be6568e7c921e6ee1e9ce8ac5b280bf12e8b4976159f25c05e85fd4f48faa1e5042455da26784f0378846b00b1019ece0c5443a7276dce936601960c620c0f48dfdce3d7158691ade1f4c89e8e16e33e4c84777d3b261850f67e4cafd59caabfaea137826ce0b785a1efe2a1e308bf9cb95df87413d1bed427d514f8d2f1ed5215cc8cc01b960d2fe3466acb780ec253f4c5b3916132fce27c7d53c269e49e0d5f5cfc302c1815c83a39a842a4196b71ab05ffccdc4453eb6121cad50beebc9506f5e6e7a86325c089c1505a5d1565e4e200c0f947704862ea0bbb30d55ef3b0138243795391ea5660caa47102215bb22876b29def7ec75957f10b4173c7f04355665519b869e5d51c8f7e156b05af22ec3dffc3be18ba8bef4b6112006d557dbc866a984f59a6b4850790c67d09dbdd531ecb6baede53b5f37ec5bf114667e1d26ff037959d61dda4206f612f01df169922373268b1e7e6fad457ceafaf8c9c25e62c37454897d9732b6135712bee728c4eebc919211002d9c6f8735af7b8c0a544391a46f28c3a889d0f2e7a104554aca10104e8de7cff3649c20d0b1f54088096a7532b5019e476647fa05e2080741d0dbe713cbcaaa2afa2303255df9d8e0d391a6532b96bc449d704437222d0edd1fc730ed424ad8d4b5a39369538c7d586ba3e59184dd5f2902ed1146e1a01c7b01250ab358965ae82a0f4528fa5ada19814df0d73e4256eb85c0782e527f1f4d0221ad31b598531d3812ddcc1499f25e1501865e17df02e1b8cbc9909234c2802c41b8f3e59bdcaca7bca354ac8a06eaceca80e576276e089cb5f29e61b0d1e6d85b56c11df39d49c0836c0a3db33fd564f9b81b2dab176127f2020091e84be762866d62955eb34adfb2c036dfdc79652bd5168e1eccebbc106c6e0842a6ad0ccc37f360dc838e8fd4104c57d8d74b677ebea4c070a1d5e7a7fc219ad1169ddb19c6d2d9d077f9a31b480259d7c4dfe8e603ec1953634fc56a67550bf2f4c127151b656bd10e7db9c9b4e19e526d93e483d2beb6d6f95d5dd7dc4ef270edb572eadb4f1e9abd0639860e241ae44ee499db89e92a7971670be22941efb0fffb8af56e85dcb0a48c09ae10131bf2a64b0ecbebfc772259c580506db69ac2156fe9c7240f7f66d4714e18bb20c07f44dc0cd84f0d9b1aa509b66ea5e255e0648ed0a2962ede02665952151a54e8cea60f1ce897f00a3abdcd6fae82e74b6212fb5e7fae591d70df03de924b74918ada838ac568031697a44c273484fdd102cdfa567eeb6b89ef0d9fa657e8943950256b1e7053b0824e4bef3666272ac0314f463083e7bb01bf0a666e722b81cb549429070f0cb17f6cdbd435b5a9beb8a2e4d8baeeb9fc7abcf248cd7dc6a01075c51db5fa579aeeab43a582b47399ced1f5044f92a873e6418ba412cfa0a8a2db3314585b220ed790f35ea358f93a7630fa379be8dfc67d5eb98c3aab5c2f533d6750b19ea957acc6bf9e2796920007f14afd5d25310bf4bd31ffb348452c2d021e55f237a212ae30aee3f52d514f4520a9af18e31091497248753927f99eee28859559b268451ff74aba9de02ee6b4322d7570ff915b07f2cb9c60a3b39cd3b93d33e3e05f149db531e7da3325e7bbc1384880b0aae07a0d00123c89a8dee209bd57008f71bd1a6a5778e3dc257782b1f4eb8695e6c34c7d409d48f8dd796db2afc7267b6c14299be5aa8fc680abb4d14671db1342e867fff13ead25dfd0ec4deae57cb9c3dd91d62eb03725d734f841d9749ba103d39a29deea0e29fae6d44193eb8daeb4b06ceb487292619b51b15221ac506544d7bbbb235a8b1e025e6f95a55d4a9da6e2269cd0fb34f9990ebdb13cb608f09dfd348a611efeb3a20ba7d4911414ef238b948281e71b4aee677131b1bd90b800ded9e14d190e183fc69564ae4f8e218035a2ae98adc09e2dd8911283d549ab1fd630223ac9b69f13ebd7edc52739fa0d86ae7bc7edfa3923fb49f01b6905210ff375d48be2446ec8ad19fd201030784ae30ecda07d819104ee91e060649b3d0c9e9e2b984ff05a62d46c6e9bbdff96c343c82a6512f86de130e771a1a878e6a41a6ac0fc0788e6b068a9acdf76a9e550c760f1a7d2054f006a5c71ac65c82a640ecfdbd3853275aa0ad3206b715cc3ba60919d7a2d307a318d84729e3e17fc47339081b3733d471aa0c4a156a7b54b1b9285d483229a32bc6340e223d87b4069b04d0fbbc22d2a54ac37af4289e9138d2648099c28729bf009c2d28faf64c8a8042fffd8bb899554655cd463010c1dabe9bd2d7310594d704f1e10ece778e01fa0d14bc72a9095f381f288abef48d73e1c8f70323019bd3790cf90609f16cf84220713056f45f8783d40e5baad22fef47a7e37b46ff86b16a7050120dd8a0182fefb468bc5f043da2c84b3c3c1233743dc0d3f812011ae063c60c20907d674016e758411738d08cb7b38ec5cf2675460d6e4979a92f1a6b69a6d80f09ae9f8647a6057406542e4b5cad4d751ce4851fe2043791ccf35977c9694b27ad7a862ed2c107a8ccf062000dc496547dc6b4d6f3b0ed91a689dad868bb70009cf51ecd1b12f4f015bf9b58c6a3473e82736e632d1274d46e8fb9aadc92ab01e0c7c4c9d3ffe24d2a3ea98e88d74bca4b8fc56d7d94fab738c555f2cb4ab724de351101cb87df73b68d48f182811d7bd724087eb2d3bf773a92ae7fb3023d05f7d92e780bc1b98e1bcfb57bbed3078e50104684c04a0297a1f054585de92e285d2c460dd30427ebc79eb4e26c0479727e1884df19ef51e10dc42db993de31190d3d6c988c1c3dfa4e0105fddb7ac35563ecc72a4a196e035f91148ec48a4b119a13ca4a98e0f7a165f6547ee9750bef23cebfb0e79c139d02c6565e92464618471f2483429f5093edaca8b65ec2d966a66317e4fdfa8efb3df367f2511fd514737a1a937a481e7d8cc9a03c3a60841a4bf7f9754bf2fbbe5cb6164ab948c00b2e306a251f23b43d7d25e038afd9bb94e90efa334bea6c0c33b9e527b154f0271d9823269f3414e5b7274cc402fcf960867cc389df326a885484a21a1730d30e0d40999fc462c52b6a00344eb43a6e589008ec5dabc7d3b7eadc04cef996180edb9f5dd33c7c3ec5e30aa494b252658237e1f49445b383aa5221481bf279c824a408a0cba2b07ae7260ac3a8b16e1d481d8bf795611beb58cf4994317e4a8a1f43bc309f0b9a6938bec0f485cd9f959630aa5929c9a94e40f0fa18f3ef52d225323ffaecbab738f0a11859f83e7823fab2368e875eb74f7efdccd9d03906d70bc078f6741689487c98d8823c61dfe17c86e49cff25367cce5f92cbc602a350181120e505a5904a146484af259d3cc7407766ef0f9d0ed2e8c8eefb1455df430b15d7a20b2b8ce47711235c340fbc0f7cd120ab132ce965274b695e8384b0af2f74f1a79885f6871a7fa28a0bc7c26363be0e27b50ec7c8fb14c67e80e2b47118205e0e8472e0dbd61b66277d3439fac17951af5ca2d6b5af0d524ccba21b6b2a6051dd94a1b8d7e7704680ddef09a1b1c4419f2a9ec9820da589e9b20a70ab24d89962987ddadaf53f6605cd3710fa08fd60f3daab58c4ebee1ff8f0c7b88616302942ef09f82722e003f1421f3722d0df287cad3f920171162ba91a98d6032d74219ce8c4fe3c7e33b0ffa14c83434d58870d116e6c36559a0c5276bd3ede2f133f4b9b09ef25e76cc4ec02d3a62df652cd9034f372c30b66891e912e1bef1e17181b25d1ba2eacf2827897b7b2d0c5995ca072785082d059c8644febf9771752e9b58e4c98cfc60c257c9111c8b2bf6734c7ac89d2bf8276d6eb14a2be82084e6fdf8ee543c1a3922df2d173bb2d7a7124e55a2d39ea70742821f08726c31b6c80e32786142546b5c35a2a9a2441745ce704f0e55134024b64036bd28f8d2b8119e8dd0e5cb9245d8c9058a66731ae81cdac1c54debe97ba687b26ff00671d6b69bb7f1dd005c20971d3f86f8949ae90483fc8972830abc6481f17f90547263749df4c5def86d1923157f67fa1738bef66ca4fa004e6fc5b4af721837799245cf824a7f53cd08d243f550311fd4a3d959daac4cfc85f32604bb35af71ca004ed6051ffde6dc1b4fe2eba6d82661319e9cd3b855ae418d73cbb37864fe3c10c42f2fc3567df4971fe7a1774e33b8a72c9ff4a7c9c666df10ab3fc86bdd66d2337af6fe5478206b02c5f1709d87b9df0b8fae401bfcd98b33c30e01e93675f1f355765c7361b84de13e9aef9e4fe7aad73a2117c05f9714a0d361e693470c80506dc72a579afc28392a084af4bb406e51d53782e6ca9ced5f2733ad62194041187cf6819f495e3f36941d42ff64e68b479b4c98047b50d14e9d906b8970b9a1a85df2ebcd9f91bd9f9e23d6a103a4398801cf9fd35ffe19b1d22551a09c77e050ac86b551234e153b9b1f200e5e4d128ada63380f68aaa80df274d0bd10de6129ec811001ddfa3cda1b108abf1a10645def9a8f6089074ff283c624782d8e507e2120f8237004abe881653eb8da68e34bd3aeb10e4a19a8fe7684dcd8fb2160e98913519c62998314bbad28005c4a83290a62f9334bd58031fd66bb0db262019b4cd0c0423184d42dd0524ddca8871512144dcffcd066ff6ebf9298ea84e812ae69c3c6009d6328449e1f9eeea8fecb6b9e5c96a196891777b729dbcd009b11dd6c86933cad747984c5842202dacdb14319ca09f16950b4ffd8e8380fcfa9223d511d82ba615fd3506e86326f1cda9dcc1cfd9e6d5f1ecefe79eec809734300c4b915bd8b2f50d9ed1228836ea07a31376c0e1f4bfd053de47bc04acebc1fe0930c6a3476edb691858be52b6de2b01d9e1e4abfbf3d3c5d2684b4bfb7c657919035941a2aae3ad42a9e63465e499c16d2dfab35f248622e7e58e84bb84b71d01e032044b717cab2d569ebdfe7d5097752cba06245ffc7cad1b18d79eb62ba3118c1524d59d9cefeeac71e447831f83c6f290ca10481e6916ae350b88d60f3e2f0058bdb51489572e95e31fd84ca7260abc39f36938b4f87e6d4835f1ad5fb221a652e8262f018bfa3856a8cbd34144e6976d45a453f3ec06fd6e376dc4cee60c6500c3280e6ab4927048494018c8afd9bc6fbdcecff3018ccf7d03b51a6eae14b7f8520c39787f70776235f01793d7e7f745848413062433200ef7f8cefee602784ed98b2c9d273cdecb02ddfa18a8a661d741f3bf87647e3b8d25eba2360217f3b3108225afa2797868ceaaa866d663881a0008e416c5f2f80af7149f93050203465a7c2fbfb1ae9517fbaca023c9862be40b2c84f30b81d237bd7c3798c30891c8ac7a91dc7b0b69ed9e0982acb177108b867adebdf348d894dd510a0b7e1cd010d9147a550c8f12f60691d111628d9182c83ce9536af7ead503f2d86b1b07c40fabfd7c29d47e4f8720b7806cee007281fecdf927c5a8090fe200db873a0142f5b631901ff537e84ad96b1796bb469b1b11cbe42c2610dd49aa74187a4129a1854db8be04d0079d6f88c31d140eed4d5a1139b6cf42a9b792ae577cfc7a2879bf32ae3070900028e0e30c27d2c5d1e44d731bd3d2e6d6135dfcfb18572d107551dbd61f608dff663d88629c18be0406c8ba65f8ce3422d544efd0e1e9000dcdc683eb0eece6d0ba89d46022e636bc1ca13b2918d04900ec63e29f630e7b09d795652cbd6a6479cde8cdeedcac973f5d240002f8f6df8a75ecb9e1c6d2b609938753bf2c7da02deb6f5f3bccce5e9ca2afebf91feaf1265aabdbe2ad99212954377b6f55c3faa8c03088b93f943eb08faff93d5c958f119889f11fd09ff304933fda02023e503321f3311c3248fc12cfcd7e748e21b1002a39c02c01d09209a0ce90d8026f074000e455d119e776d349ceb3da94cf523de5dbcff0f48b0c1a8048441e7c85fcfbc208ede9faedcd17cc3feecdee4c70aa042c6e441b059a14cf0077b5c8565e3c03b57181839f9f7ec98fb603c272189a6ff3a1d3a4ab621ee17eecc490d3d3fe3b69830871d0f9879d3049ba97804e641d42ee31522ecf1859fd0e2feeff6c4515dec6601e327c6ffebc6958cdf901c0ca743f82214679087d9626e792e9ee6cd489e79bb805d2da252d55a99150fe19bfb245a1fe42170dbbb9e93f584301289b415aa57fa49a31d5a2373d55a75df54190b1e216324d0c11ef5e89f61d21a42d90763ef5a89092a10e1acfb7e523d7f3fe9f8efbeee02c371b165637262eed95245171b22f53990e63e5d7277c2d73a4c391af7f2e4e1c18101c45f8cae2939e17c2a4999e38be4e8683139cdd427060e6f476809b670f35b2c56491d7f825eba12d6626da300fd3c80da328f0ea49b767a41a88ab8321c15d42c0af8fadf6438d42bf60c3a2b3adc5871de99e21556ddba86feeeb79168a27ba4c7f46b716afd29c915ece35e192e47cdff65cea5c35dd963a7b9ba5232bfcd3e8240bf1278b36d6aa6dcf916c22e853761e388d3f1a40a433aa34b506bff60e623daf6dee09ccd69d2781bc4d993565b6370e7684d7aaeeb2b1fca601357cfc35f67331a5714552e9eb3dd6fbf2119bbbca64ea76c836020d19ec9a1f48e6e38d20777c1c4cb8531ba222faec847efc90b465e9c34a7001ae1aae1a1b5e613f47a7d2a35f2fcaeb1539fa3306807755ed92968758d518fb4475f80a0a3ca9d6a6143384cc6083082d311bc387ed1b500266acb41b8126dfd9c93e1b1fbc2e1f174be1d7761604d9964bf196b9ee0a8706f863e1822950769d6662051d0bfd2686444c417b5ceea329e2584442c5bb2f75f8e7c180fedc7a3a6dc21014bdfe5ba28573f6415f77fa9325bba1727fa321aef3c424a762f29b3bf455f51babf7c357a4e5ed8cff49b4eafd2746f73fa06b1d5ed4bd15999b64d6f3a7121d69a9229292044de7007ec9f717fdf09dbf3b367ef4a7a1baa46b10b4e16ea903e4edaa9011039efcee40df9f889a16f1d4f4a9a29abd4c5d587197dc1da1d8130ef6d7f55840a3d60e13734ce26b321d00aaab7088ae1779d826e99d92f54b0b80606aa57ab42c90e751dc5b716baff6a81bf135f4250f00aaa0df2c833761247a34288a2ea47bb0bc836a6fef419c37495bec860fb6529465724011b4e58017dd1415346d52b19101d5eab12b19a0e441575d47307cd7dece7b39f36fa26a012112fcc778b55fbd14f16cdbd3acf9a9169d544f15345cb6173467874f657f11a12cb8d9cd9c39420f84a35791fac6511b78d593d42fc2b8f5d872900954a406331151227f3b4ab61468947e78586055c0c09c0b98362664e5e1c8975eeaf02cbe3fa2404ac419609ca705c7393296997f81a9c8423adfd4de864c57a97922159f4fd88748365f7c0d07563e4d453417656c8833e29d6390b86fe4b794250a151fa247a5e1b9c58149170293ce42a65b9cdd8b38d9ce0ca032a2513a10b9aa13bd582849621d7b26e71960d6ab34544826f40f4772edbf65887cf9c90675a02a24cd768068be5feb2b8020cab1f939df742e78b85890a0ed8735180b8dac5a2cb32325a25e5a55c3dccdd36db1e560cf06d8edaff94c8f8793df454115ab6907e1433a2fb8a9710e410cb4ae29b749c5a56812e5d7f5071e3f281e22439f66040be430da6e3d00d79a926e6d938d9e102c8de762f46132cb877c9cd0719ef3124a78afd322abf925c981c80564d0990d6a8ce664e2e17c87b4a0f4d853162214634684c7c01135a65a96a2dd46dce177320faba9c4559efd833f3dd5086ba8112b30bbf4ac3c13f437f5c875730809567be74cf8a9c816f4fd6716a9b82a1c0305ed2a51e4878eac2537a240468d0bca71bb3db3dc44587370c898536d53d80368b46b639edce91842b66e208b95b7592b85d9d72657432787fe6037eb85211c1c8adab3ff2f751ea8fbe3a00085f306569ec17b74af594427ec4560689fb70b4e6ed89f6eb53a9e4512918249b9551e0ae6c9f36ea559e9e512e2689d090a17415450b584e5c7cca50b33fac3b1787034d0208acdad636fc3d616d98f1dda10eb9991d957f037ea435e3319c366ef658c47fba775755c948610e7a384fdb026d34b79b7c65045b283b693ec39a3a461580d5e888e2bac27ea2c619e06650b23ef7817b83eebcdf4c1046def9755d8aae19209f9ab2556c7c1836228399dbd063a417e004937c4e8f1238d59628623dfef098ace7e0e94d254f75cf60370991373e1aaacd754e553d42045943f1356cd63e1f3db516c660ea72208a93925c913478d2a2d2d9e8f1fadaae136ac42187cbeaf41a1fecca67b1d9f8e45b8a21509b73b3cda6895c83a1346812b5ffe2c1a73db6cbccc95409b09f062caa7414f2a7b9182faddea8857099a424d6bff704d75eeb4793e53fd6c6b392efd365d02217bb0a66eb65c8ea113ee6800c30e14140d1db32a753de462a44320d257b6c021f6b2dd25f7507d6320a391d0b0de1d495960f32f421d11d91c7ea58f1838f225e75d81035ec78aae5007a650551a2130d8380a88a42cc5f00243adb65118f62bae9123494c72cc94cd04a9a48393508a4042ff5d4bc0de75cf5827c32aece92426e6a4df489f63ffd696a5e09c4569596d59d11853d305eb433044f7c58f0208708aff7ec7dfba646904fab95e07c593ad93e76728526f8818fd7aa58402a80feee7eb15a2f0b3c4cdb007544c53de0e1f82c11bd9d37ec0647180f05a657c2933fc48c254c582ab7479a9c83bd7c4f8eb0e29efa3ed8c4095fe08a1b447db0a0b2c4929f11cc7d7829662940098723811cecc8af257c9ca591eff5e55f15c1ea2954f52b5693fe6643d48e9f2f23f2143777b0cd7c33e824b1df67327692829046a46469f24a35f7a4a268c8071d3b08d4de93efe35e71b2ae80a054ae6cd0345a6af2d87b666f3f5babd0cd2158f9f1d0454c258d701393f9c43f96de381042f38b49a73be70882662b7070df771bc438452d607e3b501f82092cacd524912d368f485ca72dcc9607f4b1db83a3bd6b6e02d235791457fb5526e68a78d321645077c96714c920ce0f10bfbe8a0fd9da0b9366ee0db2b686811ff10cb381d13e0536e73e9b49c2341023a2ceb8651403207aba6394c9fe86be75b1f3c92342221fafa5b188657ec49279ea611926609c5a0a8b137d58691968eec74595db30a5eab47f49335e4f7b0e1c82e6cff21317280e2cdc9c35446b64b3c2295b7ec14cda916f25e16626a75feeb120e95eebd9754a395186204d03d9241a401df77194d9938769c163b7eda901948cbeecdf3e841abf27b3b8c92903ee36dcc5d060953aff4f2442313a8191adb4c9b374dd9cc5f08e8ba058b5c03dd111f489e461c1723525286162fc0c4846dbc36eac9cb8d32c1a121ebf3d81ccb322277755a2e55761686f53936d703806a52065735bcf568ac9d9adf605be45a56b980d198260445b04842fa9fd7ff6d367f50ed8553de4d1743d992577279a8d76586f479110cf8e5875e0c4682626f6a1e55d9116fcc4bebe725bf5ff24704153d8d7b94", - "public_inputs_hex": "0x2138b0022ab9af3c96b082bbf307bc9e79f8f1401462e3ac1cb3a9913a5b856c03d33039d45432d4999b9964018d8d6552808849c83503f50a70d594c01b441900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000c6895e67e144556602cbe13943c8169600000000000000000000000000000000808b3aef60f3e74a629e9331d68a14b202c2cf87674c88d6103108c767ab2ac48e35bee25bf5e92c02761b47af09b71a2c17de150116bdca2a3edbbac4f77678c67c35f056f9e969387b99b5c26da55509a23e762ede2ab19d289955f6fc34a289c4196b6f4fed818bca760158098e851aefe0609e27b1f5e4ba46cd640bb7bbcf5d11024b93b2b80830d9827e59538f1b1e385ae72fb3add3fe838e63d0e080c2409bd2fe5f57f926a01a4e31278a1e0fd8fef8ee3dacae5dd4bd8666f29088e7e2c1680f50451cf263d3e53ba2b8b4135a40b6144087f868125f387412d514b5747bfc6d2fe2bf59b31a94cba4d7b722725d5e5594a87fd3ee32e41daddbf89c75efb45a474670af2162a31702ad09" + "proof_hex": "0x00000000000000000000000000000000000000000000000a4acefed05d4fa009000000000000000000000000000000000000000000000001cf55700cf97b377500000000000000000000000000000000000000000000000f9d6db632f0b4e43900000000000000000000000000000000000000000000000000024fa54127846a000000000000000000000000000000000000000000000000e9fab8e6bcefc3f000000000000000000000000000000000000000000000000275b3bc4f33ced3730000000000000000000000000000000000000000000000039d6dbfc0aba511900000000000000000000000000000000000000000000000000002536352b0878600000000000000000000000000000000000000000000000451db1a43a3d23fd0000000000000000000000000000000000000000000000004c50309bae54fd78f000000000000000000000000000000000000000000000007637168cbbf653d0c00000000000000000000000000000000000000000000000000007e0366f203b100000000000000000000000000000000000000000000000ee02dc1c082ba5d2200000000000000000000000000000000000000000000000489cb2962dd0ef75f0000000000000000000000000000000000000000000000092d247934d1dce7110000000000000000000000000000000000000000000000000002e1fc829ec2502e41e52594096e32517dffa58a2746b375eff260404f82c0f80c8088fe05281e1e697ecd3a95631bf02794fa2188d109a807521eae87a62d1b5ea7a1a4f151b227293d04a3b7f0c5e9f3508414cb82eadc9d3b8637c9c2afc637da8cdaa5499b2bb8197ec2373366c2dc72c92c277018224f25106bfb86b7146cc070785a452d05599a4f36779a8b459846721d17766571b96c202e312605428787bcfffa502d0b7c80e3ea21e4c2769edd5988d49a36501b67f6aa4c80e43ee27e669a34abb61cc62c8ca2db8875eeee091f583fa28c063987ec22084bcc856ce8bc80a207f32ab7c4c5f27222eefcc30664ebe8bf0a22ad366283864800d8e78de9a14ce41c130ac42bcd2a6557754eb933a3a851626cde7aaa5160b07dc9eedc397cfd31c42aec556602c3c945c01fd0620c4188bc514b9674c5390f3f1c23cd5001ee79081af52a88b27357d150b1ff0d1d1874f3d64fe7870a3539dc6f10877874350de4123aebb807bb13c85123ad45e688029002e4c926c8eb1f4739d4752c5b9452ec2bae0756f72363e4337b26283fbb8155ec6a738e7c924d2ca2551f3d12a2ac832f7998d2fcc20c13f39be57dc0934346d020c3172ebb2aee4596c3490e12ff641e08f3bc1eb18771b2c2b8844fdd49906305e73384af1a1d21d5aaade9166451072c6dc15e4a32d130bcf52f526fd243f0157f6fd451da80690ae755710aa3c912d5314d22f423fbfe3bce2bc010b18749d723d2b940d7d74cf8e28aa1765c152be18789f509b76d659f7b15d3c48aa5dcf2e843b9ef86a3812b765f07a334722cf51b611d49c5e375b29552b47bb10e1d19e638ad76b2915bcccc4b2be804fa0ad0dc63f008fda0b22044cee17effcc83b604874d99377e53c422f733c130d012381484fcc67fa81f8047d10420db8f9b6c40fec74ca30f1f71d8a50dd62e57146e311819595da762e2b26075b23a9d95c07cee7b37ac35e8febf8d3d3061ae02524a80034f6e58d856bcc9d04afe30398d819b9a405e0e0c68c0158ca071d3140214792c8658ff15c6fae412be23a8b46f2fe0bad6ad5f7d6b5df44ec89bc600c7c8b8cff6bbf4865335737eaf3c4ee2169f46d9ee1d4e03c864ae8a66d4f40973003b7a02388b0faf3e9303b2844b407a137cc3951963dcf7c7e269867a3d2337efb7ea149c84e1966a8641d026b1e13234eca191931dbcfa34718510d5d6023d006c942cbbbb6863a8eba0b3041fcaadf3837fe4c4b4b0265d4020596ef81c65dbb55c07e07726cb82e07f2603724a9668f90ddcb4f7752c9007e4a0419b1177a971a8edee1123b2fe11441283d525785f43fc910a3afd2eff67a8575cf00d24d9ff67ea069551e54578bc1fd6b2ecca213f041d6f3be825b26f07fec0860cd8164523c06055c3e39bf28fd74affa5dcbebc26903ac6eb981c34e5d5f641001499461cc1d34bb390dbd2f3ad00f52a5c0488cc49b2846a414651bbc62c881112de4f9d4a4e452829070896e70ccbf78a8e0cc545cddd7c7cbf0fd20b1af5056c2e2faf92a6cd48969cf2ba1790133ca98293d18269d67c964141d6f235ed00c2f00ff22fc5d5ddcd792bf47d11538920c8c641ca75d2543215c1619909dc1bdb7c7a5fa40c351b6394e89a9da3321d50b3fb2228be4512dad8c5350c15392ff702a4e8a81f1738268819171080b0da11f2c09eefc8a8c373365b871b74b102aeea78c1cf801f0ecfe596e77c7545b98c2242c1d6b6163d09cc3ee90df91b1f6ea9d2c8bd06e3b7582505e2ee6bd964d5d59d1e0688654110b4419194bd1426bcf5ccbccc6cb73d60cf04157945ce8f4af04738877a4eb49ec3dfcf643ff7300952a75fc8e664165af64cf2afc55b1180bf54987afd5fbb10df898b7f160609c1b7866b3984a39df96be3f59b224016534635743678934ad8e36ef87340c80b45f66b32c85de5e30e6f5b3671c9c91a5d577b76f8b34dc31b9d41efb9d53e0baf5c4a556c300f8d9a5e2ed91e227b3facdbb2bf7153bd0be13433c17c12162cf30a922a7d409e22e4d73874bb802cc42990bdfcf4c5b1d3e3648d3b90ab1425ce37b4e5da98be75011a1fe76bcafd453335b385c7562c966beec92b8c9e0e26ad59a991bb57594a04a3c5da939a1ce81c449b464540e8c1ee28283c5b9a4f1d3e76261af6a6dc4a87fd70cc794619982807034ecd90ca16f327038c041da5243a2448dd1271b2bb4df60913ad7b714d38ad1ce187decb6043b6e0b4c0bad4097e01f07680dfd67788fd27e2158702785f8e4de672c3f6acc5cf40e88cd6eb2b1fc387bc48ecc4c72d31bc3c1fe037b675f7c5a72b165c9dbfb7f315f1017105baaf034ac9b6074e19e0372dd63ee6083dd6ec22b20c73896fda12c351b3621866b9eee55b1b066aa41555619220fc2d7f5ebc4a9e20c5eabc34e0bad1bcab1392725f0bc30cd80fd52386453ae932c78e7319c5022f7cafc82848df494f611f497d821fed1675ec671ef62891fbcee14d232c0ad462f73593aaf9f86735bc1fe3f0543c5a632d343195619fe679174453494d82ed91c715d875121d256fa21cd254f166bac5a35618ccb4743605673b8e2d7cfd7629c89705be49d9c15d6b0adc2633940dd9ed68026ef217f7ab37ddceaa92b3931393dcf7d688cb4aaef31556c3d730b4bf100b07fb772331e23a681f4b31808262752f6bad161ca010a3286bb94226edf3ec9374f20948d2f52e467cfe5dec4b77e2285622a173181a5810f01f494a64c204e434f2c11d6c2c18395cd14a2a6a8cef22ea1b8e6a35f54d0b8240836330fa6ee4b2c716aed3ec388fee402abad304cbf4e1a513d28812e201cf72454872a9b029346e153a4a1c100710c0ac4f267d0648f9fd38abda4fa10d5ddfff207bb7618596bb6de3f0b5e76592f1b691463d0633a7cd5ca968475a2ccdf815b6aa1de2faf1a0c5b0e01d40d94538fd747b3e5666ff9f427e70beb122bdcd22e48f92f1fd82ce75ce89f92bf93e12817d4abfcf90c830939174066713664f94dccafd71683202b37b1487760b73d241ffb32755ef8e25926041a1491619489cc6844c3e2a799ebc3219b4a2b3bef594e275542b8f706b1965069e141a3a1e3f48a37ee3f7d8b6ac9bb7025559cd4531b967d73284b9f20d7cdaab1702c9dbe10ef5cd86a904e61868f981d7c6af27acbd9bad45249aa2ca387aa14d0c8c51e0a2446c2794f76faee6b6e2c35d1ef9c56f2eb84b62769eb3379b0c6a05d8d438ad60e0671a8599ac625ea0d27962b1235ecf707843e2086333d960db025ff3d3a7e278c946a6c91872719c8990bbfe3a5ea4d45749da25328031459d2d7e0c9c06d3bd244074808eb54e7a68cad68da03ae71bd765373ebaaa4a41930c7d967ea48418b89cb30e93a3a9227424eb08067ba9ed56bfde6ebc1a474820235d513ed0a6ffdff97a7b2b7ce77115ace5a8af1d384b4f43d7236ab264ec79037adf025d984fad9845b27360173aaed08ca8d88b1ef1f628441836be60ea322490349bfb694cfb5b659f992e018d87cbcee7052f44ac02e7e887c51b5fd6b019cf9cbcdd3e45cccf2061ddcded2d43a4e0fa77d8d26eee204087ee75a1840c1fb721fbe30139adbf8ff6af47c1d2d5a145bbfe80adf78198077c0d266a8be0137d70ed8f657057e133b5b0637b6fea48cf98ae63f8db0f22a81884c359bbc82897081ff621ae1306b0c6fa044dc49b8cda411e65ba6b3a119b0b52febae9e024f67b5de5a00ce4c67f74635b7e1c0c8a12c63d848f25f49e32fef086a3068d0977cd0dbac8d24e7e15bc1e142309f8e80b334f51c909b9e95cf03b5238a104115e67d8ec4d8e147144e12739d99e67df2b28ae7810f25ffa9256ac14b4ddcb0788854451d761fef4eb632bf97402b2afdb5e8057b201ffae4c1e7004ae806e1e979d2e5ebc7fd0a279dfa777ac3a1140596274d150b70e9735a9447f48546100568dd81c38db7e753a1998c937446475517217b055faf55f19e945c33a599c0b0630a217ee89ae54a5c2ffed069489d62b98ab9a45847c0794af77aaa94c1c016824a688d221a37dd04eb64107c3c658a8b37b7e03561a94e93325070c00ff0df688ebc1731da39c7c670aa0c59cca18ccce9f7296a35e5fe85936b8d445e70c2449fe19a80dd2e81b8cf8bbcea1fcfa3b20518a25747c1eb720bafc613e240565aaffa843315ddbc43df2e5d9bfdb01eb9d98bf9ca6c4eeb7e66e2e57cad503f384223d64c4b3e061a2d51d654838696321ec2c6520bf20d72a91490ed1bc2837ffc620bf32a6764ddbc7caa905e3f6eef925962ad6a7f02850d12a51b826098745bd35ec7f06b1a0bb70f81eabc1d8065ce0b39120a5b944c54c9b48890929b2e54eac2d45bbdab038439b2326f197aceb0161c6c5274c8ccbc8320016eb077556908dc67bd63dd7a68711628ddd6e5de7135183766caf35a7e0dd930df60bb51522cb0f6a3a85baa0fd66b43919885eb2ca06754e5cc1d02c5da4b378f6272f639c40a5c4a8aee8362d913c7a6abac27bfaac0c64fbad5aaf4da56fe61e0e7cbdc405e8ba295f291cfcd4823344c4ffc8277d80cb4d76396d12063769e02f806d878acba62597462c5a375b70522d47adccf1485ed5897a3faa86eb48980c242fdac96ba763ddd0d201bd55546472ec44f75a4adae6afe8de8015baba310b4625efadd48a2b0ad7ff033c45f78788de3c2ad0a29cd3ffdc53451711833e223eac974597e68e20781f0e2f7b4f19581a87604606a0a957a7501e2f61a6042cb637faa57dc3b04ba62af832bc5678d5b88cecbec3f078ad7c70b4943bad082a3c103054e2c8418d8b65913e3e294f023cf8493d69c1e9fedb6dffdc50839b09cbd3053368401725d2905d23a2bb559a64a35dc5e5ce1ccef75a54129cb0822eb2287cde47df6a0edffa72e50522afedda4b23ed82807aad9254d314236c5e025a1513e093344dac017204cf41ae45f71f83b237499fefebb1e16783fbac9110b5e91d260ff267f11d3768b1a8938263785ae370d28fa198dc41d370c8bbe90409490c2310ab2ad5725990e90f11e016b60bf116f7aef88e31affcc675dd32103325851405e0e6ff130edfbaaf2afcc9cb1fd96bb65bccb2eecd0074381aec13d9352bac9d633bdaab6680b78c1a91f1653ff56cb4735e9743f18296057a240820eeb13c0dbdb5a980dbbabe91826a802b1f84dbea8e6d7d2fbd71dc0fb4d917ce6f4e9ff312609ed37d330e1805dad95dcbae189be93e3c104ea1b98f60fc252628e56d48c74bdab5cc606d71383a845b0219ca8ad8e8d7b12413233979e72ef0b23fa9bb2b207aaa41785c08cb7eff816a637613c00e5185c5d85c5d3c5623fe0b52d14c1272e757c8fd54dff9e3c7a5e781a3631a6d6f148400a3b5272e0d56fdd8c141b75a19ac4c1007dc52e8c09bb0959f6c308aeae1aae757c76fd50dec9a13176e87a28afc8a78e0276bed1b8bf539c93d9d2be8c5ce7dbbb808a91899a3cadef7b1c04ee4a6e1138e52995445eddacc93a6798259ce9d4a59dba8072c18fc640cf0e4efef24daf6c6545334f32dbe952ba1d6bb51ef25ee7f7e8e123d50d72b9313a60649512a284236047595ff1fa20ad176fae04875a407e9fe1a8f80b15b3b2db876550bd378fd2d521cf0a741264e42cfd773f21c117f3a8f05704d8d30b59b75ebf64f0d2c2e1e074615ff4a2b0c7b5a9729f406cdabcc3c0ef7ae9b2bf66d481e887cb49614c84c51205b711507afdf3ab117d29f6dccd614204f28e347166c25f39e4f00eec47534df97115895e8930e532f0a484283e02c81865abb5c5d2c18f4bc71f91dd543bc2e573a7ffa2a70daed4af0273f997525693bdab05e8ceefafc448b167950f2f8ba47c23e333dc50b4b03981be38032170d1b156d90a4152b5591b1375582ed0873da6a4817fecc9ac956a8a7df9922077d41eefb737954a3390e15c9abba2e4266b160082a1f6b929bcccda87321512b8fc4c4517d545650a439355332d9017d5216d02cdf59f5603c4075e5cd996712144255efafb2a0e11234f9cb1418bd236fa2649612061ddfa8e36cbfec50970d1eba3c7aaf4188c66bb4809ce899326dc36aebae5272f39f8f6915317ecfff21149d150c8dc798ef2751ee3d0e370b7c8577773dd250f63306350d07b8b89920a58b76de963ce51f4e1a889a945732d86b001ccfaf7252664dcab9b4300fcc1145ebe177e21e6feacf2b62f2f925359e8242000fb51a14b8434afdcd70e7b71d3af0d45d16961c9aa9e2d9e2a0affc8b3437aab0c7c8118696fa99d6cf5a9f2daa98464864ff56547155a9bdcdf40686a2b57d7c3f3c9bc672271afa92b829220b881297ffb5e78edc5558ce804420eaa74e179e3fcd6854be0b7c77b806c31606e52ac26cf9402ad7645e7917fb208a601ccc6fcb7644cb87835acd1dcb33189ecb3e3f1700ac5f5ee9bb321e8361713abde3192680a5197b02e1ccbf43ea185364373b6bb982af377eb73c5db12ff0c01bd6ba657aa2212507d2c7db7f442e862b2de6773be0c683638a59f5a9591c2a485b9d1b42729fc9d8567c68db021a8af6adad12429d879aa665831e515547f0883e008c948d3c79ea26101a3567247e6bb341bce37aefc33919de39cba3af5efce680de2a16b24841a41f9f0ce400541e30dd5c0a8d20d168d03f56ab1ad90118a700209093244da96853c15cea1050f9ecb7f590b3850710cc0a8df688cd33d9cab9f5b3f19a1b0243a5e2d6961203aee921e51b07fa540f29c77be80e9d2823cc0ed9a40125ebbfccd6a191c017dc194853369fbda1be210c6f2e5036101001574e15ff143045d0fba27df21524991d97da014ae6203c6b82d774fb910c996fb4198bccc5d0ffa0a5cb94451309596b59a6eb8094426695e70d006716be30304a0affc2553e9e83ba9c1a5a651710c9ae7bd7a49ee1deb39aa1e4e6a1699fb178ea35da31628ad817a963efa3216072e6730d617847402c77108f0a68f40015636e015faab579c4bda7a4916114be601321fcac453d55982e8c7d59cbe1a55f100928c2b05821ca8f60c2c054110ed675c641a883a79b1cdeb1076b5718964a4656d40810f54183d7d24517ec1950624e5d81b796247b086338652967c4ec689bbfcd9a51cfc1c3b4a4b5f8aa175007f62973ae54421129a4ef921e2e325d2931eb2be42cdc78a0c1c5c6dcb81250ab9f3b1795dd663f0b3a91616e0cf532ecd5639f16a0c9d8b57a44536758237e229502633860e5148c460f692d6123a893d53d53f9123dd8bd5069e581450a5b2acaeb3fa9e09c07b280066bf42d219e7ce5e8c5489e993c710424259d070262797b74f3205ca5659b09bb5769658381048a7bb49c0b913ce78e49af4847207f41948b1368a0cab9648e3da13bf2d2ef94d82835690faa76fed315ff291a1b7be7f232dbdba9611a91f987db78f49363f1ac71156a3ff2cb71cbba155871020dda00fefb8a48cc80e4fa87370ecda1787333e66e4634719b21c3ff2ed5db04007a4bd13e203ce1f94754cf20295901d2d2f35b6807dba597d044c666f88918c6a8ba165ce0c8e75d75fee313f9dd1d11e1570842868849cead305d7321f014df4624b4a067aaabaae21b82aacd7f63ba98614e3b73a91342ca17c2c3b1ef26d0453ab8005e954085f3dd7cdd99f49233a21afd0c77380adcd6f1c8f15ec4304c777a1de368dbd8eac1a25a0bce05a604e6a6dfbf57bef822e8ef85e7010d2e2d8b1b23d7f4c48a6fa8ea8093ae1477c7ec215362a34ec8e648227626c7af066fe7d051193f9adf36a876f975c1958ee7dd08aba209fa30a092784494c03503e11df9a6d153fd6c35ebc7078350b3174f0ef51ba1877421e970cacd0f99f019be253d7fd1a4bf423d8702e47990fae910619fb4d179acbe4ff3e30d032fbd2a35194fbb8ae53cdd0ad4037adc6c31745641e1245749d1083e74e4b34d912000d603de49516b4b1e4e54b4b31ea0678419a50f2bae726c2478487c7b1221001a243c7b459e1772e1628b21a82b94029b918b99878af98a2b65b156eed626410320db2e7e2cac559a0ef1163c601da58f443b0c28499fe1e6382dbd8da28db727b6a400a9b2e8566dbffe3ac5c3955e452f9ca8d4fcc1990ed638eb6a2538010bf9e7034f30b260c8197830beddd05ff3267fda2128748cfb8540ea287c67a11a48c71eb3d50002dabf0e386b41e8073dc294d36d3aa3c331ece51089f2ed4c04d46d59e0aed700daf95541926bd934fd36543a1089c38242212138167ffd372be54b8233150d631237ae3a2658c7fa3cc4b36ace0fa832dcada3b31a85036e2cf33dc4ab9f5cea673b4f3f260ba8c57dca6f0e104b0f140751bb19036b01712be20c750d89bfe81d0ca616077d7e481408de5a68c0b8d3006994a67cf1b414140bd5cccc2ceaced5b4fe399ade513d13d25582475126f6ec4efb5e3b6e1b2f19d68fdf60c876d090639e3304228fffb790a1dff784c45598b09df0bede739c074c38f3e5318552b9e049da01c3ae0d57814e10df0d4f74d39ee6ced745639e09d6e33e631e96fbe8af14e7f999132b52c5ed2290e85d8cd4004d421044914b0edc51cecf40378d9f0dc0967cb713f81d487d50b1ecbbd033afb79c3b8ef4f602beedc394f29fb03650a878e569859cc4aaafc91c42fbeac6d569754338c3321a2863cc32823b16bf5fb6eb8faa792daef2c186633eeffccb3fd01ee853c0072a63d905624142cd6ecc1e4760a95b69c0dfa8b453187d2d40ecda04de7d5df02e1cc8b988f81c5e4429ddb0e5dae681d2b5c1ad493c39b05cf04257944f1c4d1f87187e921de2319110b516c44b3ccae3749736d2a291ff66a651d07501788e18817f573a0028cbd5b994f8a9afb474cff5b6c4b091e9f3a60b792f26ff2302007135823a810ca15243198d515a7145171b579b2b6463688ef41bdf24cec34310063ae3ef6ce8fbebd01d17a97e54ec79a4c74d9e5820909a4253cb256810a40098b0c6e5436a48bcb4f6d3d42b5c5c6af82cda518a5871993d4322177c5e782d945af3b64ccc51a643f8daee614465c9cb9e42dca56e5ab4135d82edada9f6191b2cfba98b7d9daf09af1a80e83538dc282fcc0a943a897d04c94d94462e40068b7fe67f6acbfa2904873b83ed5424ccc93a01dd15dec1d142137029925b3f0855b22720477c81a786005a9a58ddd22b56016df6251a5ce0c72c908eb4cf68227671456e88f14431020fbeb45a68041ae0c5d26697d04fba06cf0857e1a8bf1d545465820f8d3a56baa50adea60b9f8972472359d08b8fa2fd0a33c6c3d16f2bcf545cf0379a277fe00cf2fe26bcef57ddcec01d39c12afa9637a38b27359408f3dd34338c4627c45fdaebf4108a2a0d01dab4eb148fa3aa28938da7192bf51128ce336466e6ee0b3f62f872c8a71ebfd548c353a9e9415ee7a98cd0fc4fa30664692cf2a8ff02639e3b2d48caa677d736d6492106c21d6d2a02eaedb72d2e2cfd0244471989a1608309062f987e1dcaf22ca9856b13ff74ee1c5e01b4caf82cf4fa359e044fde696e2995f3906ffdcd9cfa64910ee0c0cf70eee26757fca4271eae66146f8ee0b583fcb000bc6713c84752baed62b4a9e2103439918964030d8e3d4af5823d14c779bd67476dd9996c41ab785d85ce9a398fce6b80828fb30c7f104d685992f64cd7ecfa8a93f17b7328f55d315396bdd74c589970254f961d52af4bb3e37f3dd1c5eb7f706be3c828558857dcdfb22216e32a514c2d4fe527d37a3cd4487eded4da4932e64cde9f7ed4a9542cacbab3229895fdd21a34842cfe7b2af601af6c7cc16977259daf2b083217a8963cf7e31e258dc07372d83a25de84a9ad6218ada8ac951430a5c3f11e69cb3ec89a85e93ac78617d1ca9e2104aa0ac4cea50ed2f56bccbd1842671c7fc64a60a7576e159070501853379b8a1c419a83f8e3060377e77a74b959037ef8c8a7ff680da4bdcd9079c82bb145aa225a497d21a33dad2ca1d1e7df7e87947d4dfd080123fe544fdaddf747dd3f2a029945a47f2f7747c01372357b714d58b1b1694129578d342615827a7211167e18f07b3b010147309dc40cfa9d73727f70d3c878e3070f92d0ceddb121cc5dd6148258ab8ff49534507d05ab1569ceca5afd016b4198e3eba96076d27cc8f9de17d91713b5cfc8d074f4b61e557868ae11ac38e320789e75ee6f4595b1f8b62b19cbe4036b6e80c0922dd8ddad723a2f2396d584baf103b02310eb7797af235f05fd04816b73e3385bd88637eaff30aee3771dd731ee72ec2ec26eb98e2087c701f3994d1d5503b9b674b0a295a3c5ada138243c2f2243809429660de9605f0725d70580cc6fc06dc6cac5aeb4eebfc21fe5a36e1d5bf9df1b94ac4598c819e51ba68fa1511bb6a2142d429cad936224f74e6ef03794b9a1daa6c702ae7b8bea070ce75b6987ecf2d687ad48a5e70aec2e8494cce30640876deac6fe79124d4806e77391051113671ee17be13989049c9fbb99cfe9532c149bb4c001b2ae068a26eecdcad4ee0f953c548cf17c944be3f571b72adfb5e385da3372c8b5ade47e1429c340dd7dd6596921e355dc69fc0bdb6ad091d5426e769704f971d253d311202ac6750aae600e2c01db4a8227af3c034fad81a67be6ef1bb23a813c556c1720c16eca108a4f3886855dcecab228b76c8d1537926b3af333fb21cd2c808cb302e23eb90651623818f662612182ac471577847085002b2a5aaece08274d7d212b9fb5fcbb19308c07a38cb7d917080a9a516f157f1e1160340d95d9f807445f2a0818e731425548fcdfe427265c72178dd1ed82409b8fc83373baf0e69084e215104accc6fb5b89a294b2f9a23e25c6b1155e7466436a4bf4a2648f5bfc29761cebddd50680a4c96e13f2dbe91a72f16ea1d2e6edc2baa9e65c281ad6e607711a0a21db4ecc7916de29eae6b243dd1225927ba0e7c88a2e3537bc135a1b37f70ecbc20f3ecb5b5ac8114c2e779658c59effc38832c42128ce99b7f9dca503a918380f702e07a462c1c748d0ed27262e2464078cabe59b6f3009e9dfa447dbd328cbda1fa981b043066245d23aaa4fd532223b008e45d8cab8b9b95e8fc86edf137c797e2d97d043fd83a3aca51155f1e63af220800fb52678c3b2e1e737dc730e16b741f07f769744d783e3b57945b46f8f081328d37fd3435338361d7148b700f518bf194f9239514b105785460f9c8cf98b0df99b3bd0924cb30151674ff91933c7b93403ac971a852d4e837d8af1700f9fe09b42498a45fbf478a061668a2775f5095d8528b6052db1e77a2985c2eef167055be3187b55319cdd0600437f2f0198211ffe5abb08066354661b6980f4243d1d40dfa5448917041d5a967f07302bc526a6e662a35b7092c41ebc0286bebdb1060b124b26373a2829710b89902cf52f3a6a8abec0a25da9fde177d85248d5d7ecf286c4220be850831f558e102bf2bbfc1c3432da671b46c534ca445a13d5219d44b25851b065bb5ccc675a4a0a5effebc44b5e96a44b5fb772bf511e0085de149715949e8067269ecd79114b21a5e6076849c0c660b294ada0bade0c16e213cc867dd8bc4e1d6fdf1d6269c707a60e469df7c00806a97c08ad81b1856465efb5d90e2e3970e0b46bb929d57006ae8a021097d37c93cbbe7c95969d14870953155c6c8c84dbb34ef4110cd07018d5f359b6c4b1445b8767d8ea29b4f706e4aa31183c351629b86b5fca4f356920dccf44c44b7a066e0afb347152e9c69f1e74a43e40d3ce73955cb232b3d7071e04ee4db0bc742e529fe575aa98f3b2df3a201f002210bde2b3fb31aeff64e624beaf37adbfba2ee8984d5e36869d627f281fbf5ae14b5199fd4e26323652460a1c2338f7815ff240d115856708581d87aee29eb07f7f05d1823a07fdf5249023b6dce2b7336d0d921891103d1abf558961598c5e860c896b2629c3892baf7a09ce9ca9c683311c6e14fd7e842543ec10c1da6db639e64add8ff38861a31a9f1a06ddd52aa6c5d5a07e139a13de31229699f1d2d1f0a30a670400868601364507ef51d0216bd3ab7d4ae9bc390e7aa33dfb91973342a5eeaa93000e067484531d586243cce5d5b66210e64c0a905a9477e30ccc937a1aaf4bf3e392f01a643b07c144df7241aec01f5b5dccaa9e5530fc42d16feccfddcd3645b52609cde67b15ada9e2cbff8d15deb5e593ff6cc3f0873c02f9398094ed1acc3024abe6b4522daf5670fc0303a5f07befa2d0f1800ba03cbfa9e4e631b481028d3d0fdf79de1f7fb62f10c295b3f8f3c200df4d03b0b6dd97d3bfb041af3ef20b732ec160180ccba4679b6311a16c517f8fe0894f5394eca647f3efcc3015faf515fd3223bf2926c841390893710b26a153470805224c74b6a100d9f5e5f1fd746c71faeb7e2254ab01338464292905ff38956a35ecd0114a8bac0e56ecde0824bd8cb39f222fc0f570ba76688ca0feba7509b17de463f05069b399aa82b2c464a25831132d21f99c2d7435ef1e9001fb09a194896a1d9db018813ac008cf1373b5c6867df515af986b6d47819174aa841a4f0761c0f73f75f7752a920f5fc39e0f37881cf111e4f94748a0eb1686bd0c077b7d9ac77a8abf1dc870e722d966105bbd8490682cfd7e152918a91397dd8c6b49b423893a770e952e92b7f82065301791269377032b1b330735f5e04e8eadbf99b480ffc03e3337e95297355d0d1d9bc9344ec2215acab8737239484181096069cf369204a56a7198d3387d28a55a6e1fadd79a2269682bcb32780baa28cc7c309d5541ecc6ab18e502b051f467f234cf6ee3ec15a257f917559b13ff0792bf5a468d08f90fa2eb0827ff5ad39de66dd36125b82593df490d0e4ee6e6df031acba11a83079e67fd016be769ef1f583c66392fe72b3e2560db1ac0b8047c2f17e1d395e941d0f57f516e039804661ffd988ba1c21bf71008d515b43b072f6bfe9aa077ae5511926145e1df0559945f22f9d17e210a858b8293327738233bfb266c0521cc3d5d747e1ae0d4287011590c27ad170b0d608f640d92c37ad45caf1e34f0102b7bbac28dbcbebfbeaeb2c3418c4ff0380ab1859a9ddb9409141e563bf9f219b7b494acc23b44a85b7566be871bd884782e73a3f45a3610cbbc44a6ba9e506176b54b27f3d526be778ec5203924ea61300c95fd6680a59cbe8f49f541e7f1a15d840b82f96fa8ef969b0e018acb3141c325776faa06dd8811a420fad9618970f730f81f9f4cbb579233ba9726f0c3adff14201324569419d67f3f1e87fe514a9e6f8124bd09f1523225bc0632422f3c090614e4f98ef34cc85328bd206eeff78177d312bfe519f65a1d4eb6093be20a522c1bd26e0efe47b44ab9ed295a108d673fff2e7dab44d923ea12ebde9d3afd720652341fcfdbc3214f1d4849f0447bd97e5d62f105e1196a6f2363ca365c4aea26e19a9905e209d050df3b0083b924176e5694984733c020255055fbfad2585f081d57304dc025ad6e23fcc7cbec39a157cfe39611ccd91a2f0f3d035892737a1f70d411a435500b42dce288048d77e602ca7c207df011249be617dd284de1932ba8cdd2fdbe8c1a8e3649ff7fe5079957e8fb904f4421736f9d0191cd40657e1d6b9b0b6509a3122f033fe411d0d9f41b57e2f870e47a100d2a440237ea64a32b1dcc3c5f6dced39f7cf45499e43cceb139e4575d9501cfe50cafa6795e9ee6131daa742210005179045f59b74f27801e068f894e933b60e5d8ae1a0ca2e2f927bac1108e47545466444f1a7a04fec2cb19f279dc80b7ce3097f1f86a422ef71b999c6081b256a65225fbd30d7d9946253fc8c95a5d00f8365f25375273167516c933fb70cc98532f1fbd95afc165343bf3fbb3a23d8f66555dbf0c02840a8405405a014d3ac72040f57a53d7895c73478e629c48d83eb7edd681b25b1777a9075f96185ee6f6a720832c085ad1ff1d8eb436fcca0bbca6bc5cde4f1aed45b720d6ac968c3526b331b5e9322dd850595345e9a54539b3ee17a6f2b1b704bae724e2d9c118a3eae44ac1a003264fc4712578e1470d58aff6ef78da959bb8b0e9030ce06912be41f272f5399bb30b90d19be967066a60387e235d207b7937836e0b9a2d0285e7c305627ef455d8bad7a82b5d785b1ac4e802b3eb2ffd6df236b5082a4dd64f9a32017c8ce41cbad78b2e8b8d9f13b84bab60f1eaf661c48139df1f15b73b15c4bb7f462124adff56a46106fa5ef74352d473de9f5012158c7f2d11cb4a17b2745f0b209ab1efa60e0c3d281ace46fb1a3e0ee0ace2670dc90bb90d60bc4fcdbd1e2341698d055f4bbd9de5a2d4f7ab165323e9558f71fcb546981a96fe903320862e1a12ae3adbd22493d1175d575eac487de95e1e6afeffbffc231adb847ace75ca9915958bbdc603687b90e0530daabd62529bba3b88f7d5f710b06524ebcda1811aca44d97cca053623956dee579c7f0b46822233a3fedfa50a07e5bd2c6a0b4e8e8e74ffa68041303907ebc63b05b0a1480a389822e0a1b5155616944ca4921f4e3b90aa95e2bcdf7a14e9c0e1ef5e4e6c4e9d4f531b87342b0151c9327cc28475e2ae7762d6d0d8ba9ea7654833925ab8494afa9a3dbc151690d523e57e0df6d387cdee753eb7dc40b37deb860e63bbc54a962bdde3650d", + "public_inputs_hex": "0x10a1ac9644cb5fdb549ce0fd756c92ea6128994f008935be25165bdfa5870d6c062de3a2e979bd9a7859b90319a0f88b277dd232d71eee4682fd8c278eeb562f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000a42c244ebf301109a516d4bcdc64abb0000000000000000000000000000000007480885e28a0d52cb856afc3a3d5a47c2688a5e2187f1d3b34e2b8d32c951c3d3dd98bb521dad5cf33bb210aa823c3a81c32389eed65673f0b7793f23ee22e6c38d700a46ca632733594b0c158fc54cb0923c6b5ff393dc79cd373f86dd3d700bf0be6de48b7c2eac952daa48b0744522da7021599868cc17be0d80067a33218fefb0212527f7eaade058495f762f63d007a2f19dbdf8381decdeeba4d8f75e6530b44e88727e83e49750e58c5f314b92034dcd56a27ebea949c9f9c186ee1bfca874d3feb04621f2dd72ca21e965e7413fa1942f05e206cf4c4d7d0f5206b1615a34c9f3bdf69052108635215f0082c051e28a3845a44b4bf5f99d44747d629f6925b5ae09450f514d509c24520f6771e702fb8d8426f800bafe4ee4b9b1bd82a41d38c057eb217d7d66c40655865160e295978afc7fba44869bb371cdafd4a44d9e153717dd7be816d5c5bf78eafdc2ac3bf06ea50b0b75a21ff21292197611e6fe29433762d425ae9f99ebe4cf4fd0b5502e317f8fc7ed7ec519f48b3128513ab70c87d21729b51f196356088488d1c9dec194202d7cfed3ce8af7a02bb1e4e148defdd60092d331ddae254ecedd82a409a291d3a9da98b49fd5ed49ea40351f8dcc81ed6797c4c74ca0b954f738a06b54a6d707a68f3d27ba9eeba66b2443dc2f41eddb0612facdbd2e4510d68a22f6e97ee8f7b0f898cce0276de513561f8466402698b2b42a9e33297cfde0655121c031560d108d89a3930b61a43a2dfb204d79b08d9e59e488bacfaf5edc81312c89a1365ff7ef3c8f97bf3add1203b77da320a13e796fd3e3b8cbec3d2bcd3" }, "decryption_aggregator": { - "proof_hex": "0x00000000000000000000000000000000000000000000000a6a7b38193b9791f900000000000000000000000000000000000000000000000938adfed18caae40000000000000000000000000000000000000000000000000e21f5e071314e88420000000000000000000000000000000000000000000000000001dcc3d8161f47000000000000000000000000000000000000000000000002e46c7ed7ae9e45950000000000000000000000000000000000000000000000006b452c19c9c3a95200000000000000000000000000000000000000000000000f937207f5e9d7f27200000000000000000000000000000000000000000000000000011234ce13989700000000000000000000000000000000000000000000000bc917c80a1df8a9de000000000000000000000000000000000000000000000004158d1dc6c5fe0793000000000000000000000000000000000000000000000004df57309713331b9200000000000000000000000000000000000000000000000000007698a06035d700000000000000000000000000000000000000000000000b5363c615bf3049790000000000000000000000000000000000000000000000084836ce0c2626f54700000000000000000000000000000000000000000000000de7f5f0f37ffeb22c0000000000000000000000000000000000000000000000000001bca3c66a8927213f200493e130f2f241df6f50e717977080ee976b404ea52ce9a1739a6538942186c4ce5d408bc4469b54741acb17f81532bb104e167f13788ca258657e19ad18bdeaeabf611459f9516a80aa25dae22a716359feb8721e6f73ce82c65ed90504097a64060c9b98a318d0db5087034f8fb8be44fa54632799b74281b02fa3201b5874dca01aa6c15157bbcebfe698062bc743018cbf4c1838fd88dbc7725f1e2cc9baf93dc954f7630b60d425d36ef81eb1be7d8436127e0444eeea525630a31058031e3a95f311de89e96eed8d8edd125cde39fe180ff58ece8d79e1d4b19f2d6403f1677a3e0f98f7d8669a44ee9d1c5227bc6dc8f7fab18b5ea38a23a8a909d6b647f178c12bf5765e4f3fd9e9353f1578914f6289ab3626968195e2204a0b75d68cafcb752224084dafa2b4ac94248907a3cf380066780a921c968cac8c1745343af4f66eb1673679b9c00300c26624904c97f542932abd632e9d9c20b613f65677439219bc9826056b26cd285c1f6ad8cf48940c417ae82c3b6dda3ef601d957cb411fdb0e5a236ac0758e0f106e5c2aea4d997e4e082051f36f37a07e193e06fcb0040e75764cfe7d7b19379e865f44cde8c4021fe7a2cecf7276e482125b04ce7829f541ae0f786317799e17a5d19b18c35032546d862d824f01aa2b2ec87c35f2af31bba08cf65076c41c5b2a532fce570414bfc6619bde14f1f90519c766248124f4e391908fe40e4f4c2e47d959872db00ccc6c66104be6e3a4a01509488b91bdae4548075814bb3cda9893c4acada580aa2c29959515a57de7a31cc4f2c4335d29fdf50154c3993f6ae9031d06f0541f0e718afaf53d83631efd232f3df1898a0799134d1f263b0bfd6dccf19c72088d8811c5e361ba2efb54be181628501e2f6edc49dd9c2140408a2fa36d107456bc9ca11d66c1e426b5c3300cd87deaf468a61d8cd99c96247bf074714476fdffb493aaaf976d4dd235e99b154e79b2ff5e50ab7f8c6ed0796649601b9c5b5efbb5fc5f5b4f216469ba83161e04612689209e87667d0a819663d69a261da2a789ec0318543355b471178ee51394b1536f2652a7fd5ae364f01c53350a79a0a2c030636f3c2b0b1a4f11f8f70b7dd2a2ab687739334dfa9d83fc290414ae7a1369b7b416834d3971e6e4d10c1e739ee4f5603547ba8ba72746f349ac646d2ab09e4faa5ab7e68fd55609c6fe055052cb8a99d490c94cdd0e20fda8125a7fc867867440b977632d440bc72ddf2a79774bb4346a8defd31709e0d3be983bce16ec2f1b6eb0d064df61d33fe4eb0c0a9a31f221442947a6eb27a710db271537ecb73fcaa4ddc4435b85207362ff13ebd5a7cea692e2c11170b8f0e19c3996c9d4fe03f579bee10705ba2cb6a64120e3ec3fd8a3623c614a7233e19fd586b3dcddb5ed038a7b87085bc0d01f35ac0a910d04789ce430f092f249b8a95e3f3e9e57d464b7e39b11b0b2ce0511a53f06732a3e7d8ef4a98f1c0197fe86514ff68a832af68a50812a33c5b1b3d7357f2f0fcac439af16b2c3c51ccc318db8bfedef50919ca1df0ecef4cc3a1295d63a16e24b4427e5397d2aadf907e4021dc59573232a6851a4772bd0d7a9511e5e940c45c13faf58cea6eeddbb0a5bab2b269c8d205cd66a41192cb1a02c691451c60cd43ed39782c235f5b7222db00e52277c1bde022d68a3dbef6836899945390002967f653a03db955a5c8ce104f9bded599366c20d9e4e10815d1676c7de75591876c3b768ca0c50d93bbf03fbebd73298b550e6731cc9df74ce6b043d391fe501dcac5bfba80aea4039869994a026ae689f9fd7bbc45b9da35927b07a1400b8050faed5f52a92daf28e2f7a1e113694c5751fa2819d425c7038381219f561d31ab37ed6c11585362715d889de16fa9c110bafe87a89fb3437d64c75602257e3111a8aae71085083c00061af68a50a444442c811ca0702b1ba59efa80707a12e0574243f7c35ad11d0499bf94e73ddb1a0551fd5dc7137b31c2cb4ebc6845b5c11c03ef720b358f0b3417c3073e3d486c03aebb7b020db1ea2ebd23e08aa22bd2657df69bdd20d3023feef2bd7b0efde8763523aae1b31d1bebc86a1577122722af7b9eb04d62bb5d2dd340cb78eaedc412be64449d0314cfaf30771d59b4913156f4b94b14bf9ce19924e16e516ff1bc66e6955224645525d4eb36650422744014aeed42b2f48def893f4b59685a7a00fd42ae1856463b2ee65aa8f09c21def2f6d4a920159b6487b8928519e70a5adaf40e615c04e7b549c276109ed3888e808c5f4a847d257ea6478a544aab60e354c2cd9251e4456ba225db340d3c35b841ab4876ba9361592e0e2f351f1cef7a81e5875c24f4deb7bd8720b702b4d02941825cdc9b2fd2f8aa1e13b760f9e5f6b87dc45dd74defd1cb013a8894bfd211818a2926b858bb7f334bded04473e5c398fe186bbfa744b7c667066c72db7d9a32d8649606e140be47dbd386381b1fbb1a6238a8c38d9346a624d27d057ca8ef71e68e91fdcd8345fca7dfa89faeebce29c454669b769baaaba0fc712dc541ef8280fe2e79458e28de1f0312d7a3dde0572fe68bbf86f046faa8c2e07927b080f28ec7285880a3c089913308ed80d9c983352b34317079dc36f024c88cbe698f1199da4d50f7601e1a92ce7e958b907c3d08ec1c966d10f838864b06cb903a26f183dff4905cb4bd6861c48fc2e538b3fa22385197567809a7167ec25251e71811b35520a843903bea42f31b157ee343aa5335adec9bcd3120a6d1e4edb158539292537016521f1e1719774bc3472bf8cea73aec615aac019b47e7d879642f462263b44a7a876820f0117f968f8b0bcd1478699159b190360eb331181a2c04be40bb9562ccf1693476d7beea398beed58780d39123f31c1c401b3e59502899dcb070a2498fdee2da8d6266a91ed4ff61d016eaac361e643de776750e0b5e0675313820988967945cf62b69b46bb5aa6914de5556c053dd102f5065ef07c881fcc2858d7069c1c6f7915d99118c1d498f3232b2fbe53f19ae68faf49837c761efd1110cb2769cf48c492062503b64b03bb339905c4871ba162089ecb07e88f922b23a72ef676abd989368ca5ca6efaca4a3546caffe57f71aa15550539f41efe8523d17d0a9e67ea0a1f0e79adda4f7729011eeba0d13f56e2e03db3aa4ea0f1b62ac55a22371b0798281faa7e0ebffa3f57ef9db292b0a30d64528ff64c693dda2a3524a0f84f2bb33871e969321e34c0af763e3076e7f460e92e6cc346eb967e087fe895a6acbbca4f7dd6b474ce3421a5c24f07129f17b389059945b911b318113acae2204d6152a672ffe6be7699486fb5feb674a9fa1d63454eb801e0b0071570f519abe7972bf439e8cf28cce87ba571e359329415b61dfd9605d2e5ee440603623c89bda7c629b4a2dba72f964bf3fb0a45d364198059f2bd2b10ffa4bb0a422889998c100754be16415e5a16450ec06bad480226610e78379eb5be4c2f04a91545a58c5916584ce39798d9f1dcf7742481e3fc90226b8a508e45a3179b207ca949a9e68369a4e7a0e259d4706e083f51f4172b24d00940a5e40c5041721c4e2ba1ee11f1bcf9c2ba0876dcd5bc3b74e779fe4fb8318c7406d47ba5b7da0d76ef4979ba783d83ebf8c7d834f6b0e244320263afd46395579b9a73d00a400646144e651a725f8d554dd3612862c70c98fac4a6dc4e7648ae1c99498221430bb83c7a9e1667315b09ff19d292693ca49c81463918d0c8f89e56e7f1cb588f12100b03aae55f7fbf686c6d8fcdfd2ec95fbde59c33ef6e9162c39088034e3427bfb892d72474b03a197db7242e68fce96b631564d2f94eed762c1c722e38040e22909f91577a6ec1e2c330e5a47c8bb5e6ef018f1a83388c73eb754ff32cfb0c4d38ba8b27885ddadf3f520c796d6fc499fcbc2a3c5a83b97cb77a5174d60d2c1234826405656d94521ee61b88a233af7754bd82be24ee44bef1648438d4fe075b2767664640965dd21e2f989bbf4f2f69c5b1d0d1ca61c90f1ccf62a2f766251a5ee4b01447113c913372d0d49d6415b7a479dc7ef064c184b9140d8bee6a0c1089dd993d092a9e654da9b9d13748d9ff552c1d284a9543151223275818ac1bd3d204262544f9b536b40ac64089e0ffe99370db2f5a5303b14f7f1b43feb901c4dbe086dbbdb2f83982b5a415dbd75c8eb212760574f15b9065a39654e17829f0ed29bce220f0eb2ba77754697a8babd74c5dc104896f4bef310d99a77532076a118a429672a66d8dd32e72a259623f4a330291c23a0b39b4376abd57c6b92ef5e2faffdcb6fdf0419185e0528d35366a1b865dc91dc4a1e228379b219eb52a47d3160a98e6bef560957039f8687bff28bbd1654b0e1a2290f335c53f0e0016dcb8f0a0c2e0d7bbccd7415da0fd8725055b26393b87f071918eda8414cbfc13d7d1c5beffe174876dd3ddae96fa6cdf87acad3ba1709dea8c80f4c7d2e4bf0e894e78471fa89f727f99c2073b57ad0ab2b23ab429995f9eb947fdb176e28c2ff432eba5830407d95888ac9843beee5f7c224ecc1a40afaf7534b5c3010aa00d026e74c47892b4c803ccba015b1341b380f9b441eb79f26c0b1c8447d23f912dfb9d2fe28a5cefa496ff3dbde6fc9fa6767339c8035ca97086d6aadb88b0dc1321688e887d98b25cd01819655e9b1432200c665a0a21d40e7e0244f1c373a202aecf5ee088442b4fd2c5313001a02f584d75eb7b6e52776bcfe474f016bd692a2062da16361e2626c90db4aee731753bac3d68a2963f02fab8f43d4fbf52461e1737999975f52f29533837f361e89088c3be55ca975278143f7bc986da19f71c483e99e599ac5ec9c532fbd2c9dab0e088b6978ed7e65dc278a736e5d03792040ddeb18cea5bb841cca78a2f449e0b360ab2ce1f1dd4c8cb39ea12679615111308ccef9632654f64e19d97906c95bebb106b2700a865a5165b9b8ff470a3b72fb6a7f3a91f58d47828e155cc94dcdd10ad68ba207859b696ccd40783fd81f814647a611ec4c8370bf8c01b1ecc618a945f5432f2981b1c4b34c75077d83d252d91e6be4bafe7db360df60b17cdc52871f581610fd0a35442b466230b85830d294f38eee8d3f464f1191bf6f3697840817fab5682593db32bd18c3e35c279a623cd32c6a3098f4ebd0c1b8944809175090b273ca8fcfc6b2381835cfef50ad7135204c539b5ef18e1256f2107d81daa0665d4e3bf06f0ecfc0a1cf514d0aab105a9eb9f695af73b3ba0df3cb2d1c46b7c02bf108567e6d01cf49e6d767d078d0f7eb40d460e34d78692e0114c3f260886fcc7e00c8b3c7008ff429d1a53aa9c2e2a41d1cb34e154057c4686b4ad1d704d5fdca331c9f8168d21ee75a74a465224f3327845653d52575e720a797cda03fef68668ce7623ef7cc9034bee94b8b0181f2b11ce4e8710e7497246d272de79509f4e2fe6c8b42422f866c5c69f6fd41d41c9c326912a2fc919382d4e3d414ef9fc9ddf546ab52c8d93afc585b420390737f26228865603a7ae33fc8e19c944994028eb2a20b57bfe1a2f15f0f372fd14ef2c297e78695908b0d6cedf144040f14908d59b7ffa58b1b1930bd65270942bd8043e38037bb5213ccccb00db3df8a661e6fd31d165ae465810350f8182320df72bd876d111321de34fe704b96862982f670d697336dcd782eee7b90ebac50dd31b62a91af03d377532a157b4262a7d1cba57fa045d75bda66dfc194c0b8d09ef91d887469dafcae262b0ce0c2d8876e189885ee793cc622d42f5719247341ca89e1cdd4026584e5087558fa70f750cb3e58f15f4655cb2aa5c2072ab82f11dd0b47a22d769197a373b5a799afb067f275a5477a2592432165fbe5e5fe93416f0816a98599b5cdb93b09175bb78f688bfa15eef313efb9d49047188736c9f096d86d047d951f18de0d5bb2b435d9cfaa88521fa55553ac1171aa3676e41ef1387921e9df4c7c6e996e54033a9115e1159e9cedc6121ec9e81a1f516dcde852f17605c68e6a41ce312832b731dee504377e669986a4438985af9523357a9f41ab6b9d08bd5e05aa971a009802ce32e31c29228a1f314a2da664067dae295662923d7715c95afb00e860d12d7b168ae050cf29e4bf1ca4fd61b9129794383fc25db22ad3229fe1d00f4761e37e897caa298944185e893a6bceeb54e22b467102f2d8e3e1b2aa2658687b4f52d165f059f4053284f6f3797ed016a1cd51d6ccd1920f19badf516351bb00b5ac3bf3f00da9600778734dfe59ff118b80c46662518e010c4e1220cc9a38032e0cfabd5a5a5da75a1a827179c567443a9f95c14710c03c74cfaf3ba71459a2e6c84aaa0c8dee4d69514795029ea15228a4696961201437035923818557408cdb632f2206a5d9b67d82fb00e9c7c62a3a47c330f5f0875884e7471a7c2cf9b2ed4d9573c90e0ddd52b583e9ef1b23884e89a0c0c801599f00ff79b96f561378e455584cde3a3f5a4c84a86cb62c0998f4f6beba9ff1d9cc5d092a623abf9cd026ca12b2c816c0a63ba7666422d2609f8896501f94116a4ffe86b44b683ba8071cdd9b7db1f7aa2a76e30c1607e8a6aa03a5384ed982b6b6e809ead534b62fd2963a7027800b08e53c94f16a1b00b753322db877ab20fd39eb60b9280409a4e963c6e5ef6f66e7f8713a7690762ad71158a9c3698d42fce32038142ee603c46b0d6510f279e56c2b05d7096c2416cc3dfba58fdc0c50a8b5d89048bef8ad00d7b6fc744234baefdbc29faf5e4694f0d0bc87ea2397a0de33752094611077ec049e3deae0062a3d54d9c55d2986f356ee54d7ec2645c18012c3dfccee4fed0bbf219d4cdd93b94c2f1dcdd964a7ccba4954033a07815248455ea2bc5b096f90cb81d4b534a82a8c55f8df025430884c395c2992128871e87c67a24158e7d9f2e700b685d9450e5084256931384cb517ce80ecbd955671b13c2855124079a3f8a423b00e0512ba3ee812ac85cc596ff81ccfa7c31dea015cfeea3704b8289741c066bf18d60a8f6e453921513d10a7494b7a8ed8bf4430e906fe2dca5b1f2daf50b5151e78872f7f971fde706bfc267af4d6c71c43c461b331c16f81c053dfc33bbe0973f91e979d96622bb2805eca8bd1ca1c86a7e4f2222e04ad38f0cee9892e7f9aec41ea9fa52334b246d476203f7c2d5f6575b7d126f845c8396208049ac014e067a49c7da865ae3e17c4b4630e63630abc4958e1924a21d32c26166f01ae2b8da72d7a56e1afa6621287663eb5d2983187964f81753ae5213daad6800140e34f3af2d7e227cd2c5bd9d4758586f6a4d60cd0cc70034d64e1fb4d2ab6ed9be9b2810571f2189149d9dfd08f1f8abe05475d3f445230413f3c2d8d7a32ff4c27a59f3922a9523e81ceb9a2b0a35482808b08de05f2686e7dd5fd0b5cf19516cb0558a76d4d97770e28404a2e78dcb63f3b96eb19f1bbf291e88a6145eb27e6fa5ed3609e829094f9cf937c58dd2bbeac045e27afa19407b425abe489f434d671692197d5cf72c07c8e2ac447b2db81b8e0e248d621f0521aeedf472184eff3527a64c13f0c601b3ec2048af2672255c14010fb1430fdd8b36f426c6469ce3c6b0be2cac2ae4ceea8baadd17bd0900a75114a14a370e499163de5a0e817ec703ec5b636140892fa8203d20c032cbd574fc34d2385320f8ef889048179132035bf18bc196f5b08bc5e4d0ae4bf18768342d5b48f90d27c5eda7c200bb025a2de774ef9a8dfd0d75fd844969950a13f5b4320a250d4a124fd0beae2313ac372d0583b79543c07fe4a31afc144acf99238c31b3e0b9c6241225467d7ef6a633313309fa84669b737cda0632d2dd36ec901e1ae3e4a68210fa0b0fa02588eff6e72f73f015951e42f85868c622a8be41f3247a2140f3fc0a30d31f2379fd387240e5f306a17b035720f57dba876e1cd0d33bc87d966d620e65736370fc817ac4ff15db12147cc85c230ebef736047408e03ca8f0be6a642030b5627458aa1e65dd56737ab810b2a8b492586c42e193ce28d9aae97a13db0cc36d358f6efdfc379ee394140a6700fd99e86b8f7d3a594cceb4bbefff68ce15866cdfc9894097f08e89b66f8c30bffcc001044b0594922e11b8a055c9f6ee026ae31ac020370a1f3e06daa5a772272941a101c11714fe8d8e37d40c3122c61d8f610d194cf82da8419cfa1680eb14ee96b6686e9f209a00df36e96a9d6f842571b23c753c5577e9ed466bb585e8910722050a93a8463bb655ccac5d9900a31a460738ff88a624304a1e5b37fb9ffb23887000c006db10e2b4b8985770d88102ff55d36e7513f37acb4c5920fbd220fc20c8b9b1a83128b0c64bcf26f761bc01407ff23a9b11942b6034278ae1b4817169180989eef86eba3f781c6ed7c82b279089823170533c0791d57ca17f1beb9bd6fda0242993bf5be154fa2377340d0c0c8fcd0da22a25000793deaaf634421431ac4d940c6ccbe9265f52eafaa6660cffe9ce6f0ae13c38cb7ce5304e697ff3814a992c030ff909d9b33615c8f9be2f199990be4b96c115324f1f53c609d9c70c9a3d643973be4f407aa54cfcb7741124c48570a6a3906b2eaa017d1c4e98b1336932976e7ac4b2cc3ff548a3d5272ca9b66092c0be62c903cc5f6022fe892c37fbaaa5bba75f41e40b410b223b052ed39b580fcc936b9582cf7c479ce148f56a374df66ddb07dd6547ed67da09e72e7820676bd33cc3dcc778b5e5929677908c6f43d3f2e793b768cb2bb6c11cac258438c7630aa10ec88ac11e66c0855e0be63beebbc4a846a4210d3b16a1a45b07144aa8b8587d6d981683640bcdb7390599cc6b806869d01e425cc59f78d26e009412daa789b0872610de5d576f928321c80f83d64dd5cac4562cfbd72b56bd17165c7c60feb78c973289e4afbb58225262f916b2e189f9195aaaaef30f037d1a0b47a5e1ad425f16c581f4317b4a1cce0458eb64e01a2ce88067b6365f20570e7a6ef374c26e7df9d9b86f1a2ed3f3a6f151d108f24245346f7fbacc41e39d1b89bbc83ce93442bd733e4fb70c090135e71518d07f6f7cb5484256d973b5e107cadc46b3caecb4a0c85930d59631ae69c164b9b51d4af12b414da442ca6e2e2e905b3d35c848bc74803d93cdd1a52642f101ecb76adfbb324aab602cda06f4142f88ea187aa2d9bc2770fb55738bf1c22a0172dd3aaaf0756da7919ea8fd480bd1852cd97487ce18b5406f1e208103de94a56189a902b0e677d3ebb09b9b4403e78dbd0aa42f5e177f3c0e44bff9304af9cfc15d61d2b7172aaff7db8e31c401014a1d5637a540050a7c24f8ce92509be63c99f33c3e169be4e48c5c46c0d00536d73fdfaacd543fc05f62e194e64df3916521560c2e7c70651b0c8cd1711e13cf10ed6d7db7642d832dac4b6699b200a8bae01e5c271a7cb1dd55be7593252ec16d138fea76b7ab76eb2597f4847ffa61f1e5560f85d5b1dfb976384bd384137d0d599a996035b696364b2bbd910add9dd520e1d50d4acbaa28865a9eceb70caf6cfd4e46b787fcef171be5316b41061ad0f844d78c571948c0c3b9ca5b581e66da9006818668cb3024873fb6c209e388964e71e4e7481f60e98293614a491c4343db492b43eaf5acc1b24720b645f73a741b8082ec8e7f0940270bd337222e0e5f38ae454a0bbbb97e2684eb4c0f8665e2f5fb567a7fc8f46d42d76a87b9167d5caaa34cac8c6c35e92f339daa280b074923950ca4fbe26d12fc08df611b122b294ee8165d619809c84a8483ac031a91a321ba578cfff08ff1da3638da881a658ee5025ca8cd4c2412bd64fec5acce4a063c903a928a1bbe47a19d6f20ce2a45e48b775e956e7328e2807bdf0699717624dcc4bea3f49696076d6bd1f3b32648c84b627afc98ee7a255a9b6a7688bc2cb1d022b456c914d73c31a61cdf1f0990d46e50809e625fee7f66f13f3fd3d711053420474e2137299fb499c55d280fadb264bfa1c01fb103c85e1025144416fb45c410b1de94ce3b6b39e31dbdd40085c18596d5a4f3aa5d72f5d762f32657466c3d6cfa119e4b15d66c166f9235130b6b5db7bdeb688674c2c9ffe5953f913dc8b70c89ee3a3e9d0b900d3eb11b0c998e9028b8af68a3a123f0a5aa56f987cb287bed1b4ec7ea4d5080f7460191140fbbc521c4b4ca284d2f52ba94d12c57cffdf6b3a1823c8bec3f227f0964d0269567969b2a6952d67b2cf3fe4ed64ad32021de8df302d6fa0e5934dcb0fe0207c4eaf81924185e0ae50fa740e900c098f17483a8c8e9acbd142b0d3b8d7ed31222b7d9d9642133a4d710850b29be1b312f2043e0553468a03a468da16119a0147bc6655daaeeaccef77df33300f0304b229d0a67f2e2686ed0faf697a8c0be02a92c5eecec61f86730c46d3e4060cedea01e6ad69edab787224daf217fc00d25bc51eaadc89bea9ed8b8b064d00a603bba923afd50feeaa28480fe0bf5208e1f6c3c1ab06c7581870abe1d4263967bca1c83e6d829d9967b15b03c71662b051fef32423b6f60529ef22b34e79fd39a03188920fb378c832b94ae04ee9c1e611c19e994f3fa9a123454d8453ff1ab96e3dfaf32adcce9ce3a58d3ab46800283017c41df169d9030faa8635070293a6b4f92c2a03a23f322f9219eea5c13a65e16f8cfbb4c12898a9b5666c005ee1bfaa0d64396e1ffb0c89394ac75ce404e341592c70ec8ef696ac200a491dc290b060b0d8ab0b0d73a785117cb992fd5082920edf8a802617e40021efd904982120cb763677cfbf5fb26e040250ff71a9e8f0a74f8c8c0cbb2d83b70592dcad430759e5e3365da322b45198c34067f1ef09108461a7aff586e522eff5dd06ba39f32adbbb2ac11cb5ed218b080ef6b47ab0a21d7658d2c57a0b782547f8c5acce7c340cbc4e32291a4f4d261d51eb5d19fc313f13da04d155cee22bdda2a05328dfad96d058d2752e41372178a8ac3069d27277f5ad615312c8a0da2d6f5967a6191fdfa66a465ba370e3d8a8b27f31b75cc1d1dfc9e914df09e8044c0d753950f5a662bdec0dc6b50c3fac197df947b2fe927b02824b638eba85cc6b3a3a4633ea595e9e7c01764122a2a188c7f05b86a0901781fe9cf000e194128b474d8334de7204e7cf9ba4c45a82851cc873cb2d851257d3c067a363b22d3ffc4592989e1cdd50333e7d20858eaded8fa02b85209c329cb4ba3f99922719ac16e761fee300db4c4022070de18149af7d30df3be006208f5703c677000acfdbdab00aa099e0c515cdd6c36e4c2fcb14d4a169ac5226206d780418161648be96d949099a7cd18b491d72cb00baf6a36552c49578cb858004493fa5ffabec5316a34f8af4e3e329c28ace755c8329add179dd15a716fc30cae70fd816fb9ae67f0e595a39585efe683dac6569cecd5b4612600ca7e58142774ac04ad50ebf3fd3ffbe32cfdacc60c4942daa5b1dbd52cb4570ce3acffe92365dd10cb6526daa7ba1a0b8635167f7220c97ce29b11fff0e2780c3d43d82700b6511664384bafbc8ace53cb17529a7cbe4fa1e5b8242a149af5120092d5f50af044e091387602eb00690a21ed41b2b6cd2ea58ffd23c273f07932cea2d0e81664d0b1770c1a8726cbf09e109bb62cf0bbd05bd068eeb95e2f120470b4082e0f037bed194d5aaedd71fdb36b71ebabfc29ba3fc10086cf780c1cdc74ebe0250fa517cbde50830063cefcc39e7848ae2f4ca899903296fefa908e8c18e1bb8a1437ac612ce96cf6c0617a6cd6c6e8a631315a1d3e29d803b558c3a4274960d005b212c9c31e65649812c0dc066ae224f5001a4893fdad31cf49271b8df0353c2feb0c6796198d5ddff04951416833ce4200813f0f39d2ce75da2985d4329c1f2b2023d34a62804670f522d449b1edbf12c255673077c821683b1d8d7e5ddf800a4b7b539cba5dcaf1fdb336daec57ba5cc8e484c04b5e70f74ee3a0a2e954e2175117e97ac2c5bdc2dd375946a0355561c2cb8edb457d5185a93189e13a4aea066c51edf64ec0704d127db99b2ce23ca840435bc4ce9d8b533e23bd09c80f5004b23d8666c77a078368ad040c4e1ce3d4fddf9ed1b1863c9ed1d2eea60ed85f24edbcea0b513edb75f6321e428db3b3082154a7923b2776b96f9276f251b155188c9415d7e4f09e37f89fbaddef8410979efa36c6a1efe5565349a96498aea518ac498adad8a301e7d171c35883c89798ca890032253d77b00393525dfc1c992b73dcd9fdf3f304f8b5c1f7a71f4036d4095ffca43ba1c2ed25761063f0ee3925fcb36659ca28e692b6f5e89599405f990c57ec7237311d663bdafde7d2f81d0dcc1c522e2497eb105f9d9bb4f969cb1c89c2c4010dead0a19023f4bf15879c2f13afbd1caf80f6e3b5628c1e36f57189ec2f5a61d03eaa58e379df3027da6f24403ef8d186c62c5176573cdb2e799c65bb6c0da4fcaba21d4b8c02afeb6b8717fe4b74f45e45025aaacd2ee55901d81ab63d04853f222695e0969e3a9f89b9297aa44364a7a2bcd0be5759f3a27bc00d7a99f32b69cce48cbba3cc858a9fc708deb0b9515755e48edb793a598de521bfecb827ca3fe1e58b9875426b76a268137ba4e5fe24a5d7f977fe9d1b50ce573fe98be883ce057ff046e26d999403f52ff08e8a7dfb7f993a389212ea2ed1bf7725f4a265bdbfc208fcda3df33465c90928f1e1bb77db1955ef73583031893947c902eecff3fe24903319d5c2433e0b0546305540bd96a71fda765fcad36af678a4f07cc95fcd02e81ac2760931d40c132c998a8c0b120abd2d3e666518d1ef5ffa130cca13b78e57cad7a151bb594a1e394e73d71aea3c2d6e5cbbff872c98714fb5fb571e1e3743eea704b295666d21ce4e84ca11a1d673a27b169c5f83088e0ed344fd75dd4b741b05226ab93513305f4a7f83ded532c62d697e04ba2a963e30c321f916c0080e9fbc5ab619aa8c220f38de69ea6d5a49d99f904ace4f9c6132a8708e225fa2ab197c4508ff25c42a92d2a7cc3855cd59f6c96407266922cfb6f523d46e47e29d0447f32582e1951a6b0361e26226f8379a50f2d5e3204c6828da40b8e7cdc816f6b166ef4aa723077f7be16b732f1edab20a5668e50844b717dacc74dd94451cb9460cca88ad8a22ff47083c488ffc04e3b9c39ec7b25f41ee2a2a6cae755bc5d1fb9e1633549013968d569bb6c6f0d95547d93eba03a1da40766f3ab3b18f19b30964af1d69db15b13c2024eb855dd70af579f46fad36a77a77c2cf65812e92125f2f9e4011eb2ccf4716ddca655668da9838e29677662101824afbe875bd3490fa1a7a286ae31704b40587eec531af8bf89a26692686387927daec1d6e004fe9105160219a7d23035a362fa532f57b6269292058de35d8cd36c4c6b1143821adbe16379d11e1232646f4d497651f0954ea9a1df894dfc491003980f60b52cc0a1ab26756077227ee3102ea57dce3271965fbc8bd6e66a68a2b9543b577278024cd4536b2741226c3b1d409828f4e0d9874ecd7069da3c9c77f290915adcdf6b456983796b3fc28042c760483b93e07a9ac85a3991713d1c2f85b94556c6d1a273da1ee90265d01a8981245c7f7f8d10b2915126d9f9ac61a2d6a8c055ea87be9bafcb5643c9b119120d465b5ddb005f7ccba998fd30058ffa33d82c9d8e4e301e780bd7f93832604cfea9de23f1d6b2a50f65047ac9f879eff0451f311164941d680b76395aa208016ec3c5dfd1e4e2451ec13fb58f2242b1c26e54bbd88b44e163e4e7c7aad0b3d5897b5f0d8d49522bd7b5c1aeabc1faa5f92051b7c9609bf3dabb085a533130bb3f740556f8e71453758b79613a124d615ab01b2e1de8a4e519947fcd62b059aca90452fd3b086e6f37ec6b9c8c565885d7bc2125f2a6edc128992c986ed1e16fd93e88a03407f497ac742f49836ac0886ff6354b8a0d7096dd464cbbd9e1182fbc13662c46028cf859e93de493b32a8060828596b2fc4245655a4f9589c0c3e6a3130d7703084bca793e15a9e9d6366f1898695e5d47b7da2fe660461450c47a7186e240f9f600739c2fa2038f28aa34075563b42e39189fff917f77b1d169abf6085508100e18e9651f68113f0371c993ba004d5ac582763655c4df79c28668406aa60c8966a70355446b5ef97eca8f9c21cd311efbd65d6701932662d214ba804cb02a5d0c4e936c50435a6d8a2678558c26aedd38694ee726b9fd89a039a0378b17166714bb1379bb173d2e916411278d8285e9e6dc901a616904b1927280ff562b631da5d3cc81ff70e3269a358e8c4dca3696ccdb546ae1147014621b472511388d61cb1e60590ad87f05617f122417a4282d94bbc643f0547a6682008695507d53505be0bd9b78ed3c7adb01360df7cc3b4e8ac5357485facb49c2e0600e9a923c71d12fcaffcddc8de640403018a9a2ff1c2ebcdfd6700facbbb2dbc42db37fa4e0b64fa45559ed421cf9e91bbb8533983393113a75023ebc8090bb50f8d0b75903c3c8e4b51137f3ccf2b5ee42e549fa6c2c57a336718e1867420e656c75e985702a0b1d78e451a4d0e7abfe681ecfd92e1fe5d00c00a22acdd0ff415858ee7fa9d195fbd1071d672106427bcd2c8f5114e6b4e3b8f6fba28c62b38318cbd8088a2b956ddcdebbcfe0e6670d37b63276fa30a16791a3fee1b9d", - "public_inputs_hex": "0x1a207628cc6936816ccb62a7b56fdbbf8e975293b677c988644e018fc402e4411dfdc7cb6265f100524012f038ee1f205bf8789b70b46c57463dedb4998f7ac800000000000000000000000000000000c6895e67e144556602cbe13943c8169600000000000000000000000000000000808b3aef60f3e74a629e9331d68a14b21806572c19ee2f3532e970d617919b3aa8cdc582782dfad0699badc631f75128000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000022c17de150116bdca2a3edbbac4f77678c67c35f056f9e969387b99b5c26da55509a23e762ede2ab19d289955f6fc34a289c4196b6f4fed818bca760158098e851b1e385ae72fb3add3fe838e63d0e080c2409bd2fe5f57f926a01a4e31278a1e0fd8fef8ee3dacae5dd4bd8666f29088e7e2c1680f50451cf263d3e53ba2b8b4000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "proof_hex": "0x0000000000000000000000000000000000000000000000054660a1101ccab4da000000000000000000000000000000000000000000000004a54762957be23217000000000000000000000000000000000000000000000006cd0ba64f5e5b5e15000000000000000000000000000000000000000000000000000043ba6297414b000000000000000000000000000000000000000000000009f775df3095951c6700000000000000000000000000000000000000000000000c5c06afbb747776ba0000000000000000000000000000000000000000000000021c9a1d6d24b1ff3600000000000000000000000000000000000000000000000000020e0181a52fee00000000000000000000000000000000000000000000000a8a78269d28be864900000000000000000000000000000000000000000000000bc00b96bf9b922af8000000000000000000000000000000000000000000000007297565c9d62ee8670000000000000000000000000000000000000000000000000000990cd46fe7ef000000000000000000000000000000000000000000000002cdfbc8f2f291634600000000000000000000000000000000000000000000000494fd71aca7c8012e000000000000000000000000000000000000000000000002cd83a1a1c2ca1cd50000000000000000000000000000000000000000000000000002c8f42b1c8a52131175ad815833c3f0b7743f9084a8555e40843070b2d8c495ad8cd8466e4b612f745523e43c756ae0692805054536e4ebf95516632bb895d228d4925288839227f2e6297fcc94d48ac123e5da6a02d67919a7b33438f907cc523cd0a9912c750c9cea7f41110cc11e89a7f728f797e38d3cb76fb0e22cc62fff9434db6f00951f0792644ff93cd4919d064bdab2f9b2f0c5d0815e3f94c23adba661d54094e20d6c85d683bc124664d4c1e22d234de62c128a84bf662a90a7ea8537c7fbb3db0f08ef8e80733ec1641cb74b952f0d8c51f530db118c9ea63f85729c5c0e3ee62a6b7ce82efddb5a6a25c5b30106790e1a10403a9beb30484b6f4ca2343d7fe62bdffbf60e4bc0866aed22e1146268d0c065871190f1d2de4767abfd9e1788f823407cfcf4e5854512e243796c424d05611fef758de65e8fdbc5bac5117f3269044a7e1d94f57bfc4b02bcc2f0998c9c498340a342eb93e95bf5aff9a7be67ab2516b58add8c7a5b621976ac206c3b31910cca1c32c61c313efc34b276ba6ed11d0e938928c8323bfc233b55ba9c1c42adbf72b672b98774471c622e8d321c2f1f2703e27b2b9d0cbe65bf61bf0ff5b1ba93a6c0c8cdd0b39353b9e23546f9e1270713686f9e9a3959ebb1b6040da0a23473a92feb4a4e0f7745d74d3cd60d971a6814da8ab56bae7eb9606343554f5a69fb0878229708237d8804d950f22ba91ed8e83d30a866b440db2b2f4b42ae38441fccf0d75d39e9865b58ab08ae17ee1667c91e341b4f218ea544ff2f8c9db29f894eae6cad6aabb1f1645463fbfacb0356c2dba0bb459c7e42e9eecfeda3ebc9ea5d90c258f7dc5cfb1cbbd369da421eee2fe2baadb159f254271b5bc4c7864522a944e2678946f874cc2eb67c79ec2b802914bdb25a8b3ea9a1cd1688481d36f1ba6c609ed7a266c4b1512fc0876e2f1de26564f2e70155fefb59ebf87c58bc780b988d47fc04008150a14292ae3c1af863bbb3013e59dc22f5a60848195e5aaf3e59ef10112dc486380045d758f90abed51283849dd4fe4d9358d4bdc68805737bdfbda22b53f5070f122086e1fa0ea2fb2fef4866e18ad3cf7ba57e068e92f9a3c7fda44a370de61afe35daa09e2bf7c038fdbc70dd5a6da14a46a9061a8587edbc401d90565872df6b5c9e8a7125008f72bc83a1bb469e6da8cdc4d40ebc83bb33c9acac83364ab523f356da152411bb44df541da3906d77c5bf4371a9d5bc64f0897bf406c0302103d293cde82d4ada344ceee04b805e7922e35ad35d351f0f7b5583128aef1c50ca96863e5722c69a0a3393a115ad8338f505960cb10a238cf172acaaf2e59828b2a281b38c213960604511a15d3539e0c36c294f53a756eeaedfb70bfa84e176b70de18caa13dcd4d0d6b1c20e06e6719f4a0c5901c94fdca5510e59d602fc3e41c898fa431a2d5b305ae4f487b5ab5d4dd583c8ce5f24571d9359ed0ac8003bebf462d0dd25c5530ab799b2f331267710a816f88b74706b3593b988ae1e8d6b095975e45224e65987ae98540fdbf66aba0e6c2d6ee8510a0a38d6356d24817f3a2b16f7ed2fc724c8780ed2f0f311ef6b199499049f07b18179a31ad3e17b53c3ba65129e08d99cab37346b78aa9e8248886497fc697aa7054a12439ece38fc14c9ff82f92979a70a8f250a1cfae78f91c2349ab1eb9acb7d88fe11eb866ecbcb5cc2c71b25449623abcf93dfbd94bddc11f96e6aa2b792a5a2171dfb6b2bc3e34b8d5cf6282bf1af767698a26c05fa9aedf8e1381e6db8e74043df1ea0ff86232294f59d24445b99448d727d8f40086d812b3f37a9108cd36790244dfdb26cacf8b09c18295d9329065377a6bc757f9546e01be46f5ecf2690d048a8a58448123dfbc93f1ee6f671b236190ae73ec84238540dc9095f3be9f341dbb963e40df81e4262b6292d41cd63879f039105163e2a91b36175e9824f4c8c7959367e5a3c8e528a0f13e903665ee58a1cc1a5f12cde84efe21f855b9efe37d36e52953fcb8da37a85256fc0e65e6e96c7be8364070e1e99b829416a338dbae63f33c8f51249ead1bb069c2d2088fec99489715e810212822aece023640803707cd0c8d9d7ce6b91e406c25ab3fdda98d4cddc76b9962b2f8bc5161531ac93287c0c584001941eb9730406468f55b65639396c4e75ee59f5113d541883d30e6433a162659f50d5d49b22450d0414f7f2d272faefc7e2744094f275293c8af46f8deb082ed288ced31e1fafd7e46c7cf8083732ec222d8b1cdead5aad0076d91c20e5542cc383adbd611902144c4915da407d36ba1b166698d13583c0665078acea1e2331d0fda094262c856f2c93fbe5490a1fd326401a7a2c29aafb21662a8e35a258408909b114ce29d69eef35e7ecaf418c2af1f13f60ee97ecc84c3b96f51c933d3a5f7d98c9231abca6e21f98d45bb47348cf82f99d1682502265256cdbf85ea2b30b5a83fde02d242a93fd635d18fc2401301a09ab92d583370b4c31e5640bf03886b4d0f4ea2b934c723fafdd2bbe1048d131f6266c9af04419ee079c61ec771c35c709beff12fd205d39c44b645c1e5cae644a7a0f1c2c6e0a1f3a8ba69437b2f7ac699f68149649999714afef2b8c2350d1020a63f5e3376bfe676cde92c423afad0a8f130b48a4d3e48299a50312139f967d2e7f456613e38f9482e47e8ac343f3cf8a822b790770c0a985b66c925307dcd64b2dbf2ed898a18fcd85e0e1ca3c3e975a351b03caf32b8ff0561c379946e56d9b9ca4c0a2b393a85dd1f2e1c3d8a26bab982c4f7b1acfa685cb361fb01cef9460c91cfbadb0b8c9f6f6c39401d8967bd1990cde26b9878d6247e9c731773bbc30012c483ea4a7a10921e92e72bbbb6bcbe50609ce4b34c3ec41c790bdb355fc0c4473dd81c2d998ffe12bc5d1d6bc5d99c4105e0f0d771724187d28655deae1814bd85084d0e11b6b4a8be71f20a9f1b3782dd103b784fef0ba19ef8490c24ca0d0614a4a618c8c6d83fba77dfe3445b9a9118c270078dcbda8b46e6cf5e3a726d6422f1c47621e90735d4ccc7db61f72520a9418ef5a4f1cca0ebf4c296e326cbbc0240042171fafa89684c875ff7ac42a0a3112c2cae23e2379cae30b840c5e88f500fa8438c4a5c241e4ace10295c70307a39f1e2e40f25413677ffbc9ad2a97a8c8e7716d08189adfb3f2563c9d701725c9df0572b2a09c5ad7eed157553adc1ea622a053782eec92a6b3052950b671157d98f187c08a92ba97a250eaaa105f568cee9f4310beec488a15f2352ebc63115f20f5a31c29ac8ab4e02025d054a7304f27180d9ca58b623b21e109137993271e7a58b736658c821530f7f4128e9f9e68fc1225a7e0ebaad64aa2796023bd18edd7c3d07251edb09e07ad430161342589479f8a3d0ada3e1fb1df596301de30453ce131276871408d88cdaab9805e67cb3fd1829d00169670fffbf83230a40faa113cbb07b90833d6808c07b4a7ea09ba7d6463d9ce2f0353d58675f981a91044d886a20855cf8b423cd631128573ce7ce0f82a45ce6a4c786545751ade1f038238e0e8d986788048c32ca3a9b5afa37fc8456e2c8733e320225b2e22625b09fc35ccf48554870ff8f66f0b992c77aa0d0ca98cc744d549c5bca4736b77980a8a316e0dbdddf39ab765d830a849f79dced6c53389d67fb1f6e9d6772f31b90095b5b744b0ccba4eaf79d0d5c62eba6e80e1e32ce3c11e69aac97896c485bd2ca352148ec701f167ffa1f8cdfb2b335ce1b93ebe4f4ed31981e3baec953a3a0c1c9b9ed2f826a6a9021956d7400bcd378072543d7731ee09a6d4f92e2b60f0109c11d140bee9f93155954db86ec6eff3533fe492cde0b902933854cf26da5225b1e0cfc4d271457d3bccd5d2633c0ebd87a875fde1ba66abe58a9a7d0716cd2d9d6b7a24758ee62903816484718387a33350c48916d1fab8c6d1860a4babef178622315752e92a5aa855d882f5a80e322ff0b16bb3f9d4010e3902b50d7211051cce6f6b2bd7019f3dd708905db8d76dbbcf118ba655cd791f0f265a415b491ab3357836895f85b201d1e2aa95392ddf2349917d5284d48f9112bf32494f3f2e90485fb2b1600e6a3b4af8dd1056692cb247688c3c6efbedb4849bfda5e82a1f6436dcf36b0240101bee323f20649f12a7bce138903a3a94059e8fd811e840176addb2b2c0d9de00fed7d6c72fcd20f7c56cbf59cb92578afac6faf95a09d2103b18316d73975ff4195cdd9ea129cf8f3bd04bdaaf10a382d4e1ebf80fc6da02bdae1db22530b90becb1fbd57f11966bb6483418e2e5053ee441be44ce59f2227a24edb6c50ffbc5b77c8d8f06a82506a2a520874050b50ceaf5a57a262d0712e1ccfe95128ad3485901cfd19e2f63402fbf84a6d0e27381218cad9244897e03a53ee35b0b0e7bb75c56ce1b7c9e0a96d960b8254455429d7d39541bb13fda11c33d9fb9ab3bc3d84d918577f6dbb727fe0d6d5aeb82c09ef91e22af30461618e20b08179df2a32566801d58ad526ad3fb245bd078e55ae7716a8edb1a83ba2b538dcd78f067b7890f2976bf897c4241dedf89f424984cdfac3aa29f41b61328706b62bfa54e0fda490b39af20e0f9c252180e73a4f744d0eb6a4bd254429e24b0c4d49f427cfe476faa62ce3e0d433911ecf9a9d2bd7c9df13a67d3330f22174279574693ecc0597e63f915240d18194326a8d0d2abd9c161c9b525bf8def2d29b253c82c33616f0a6f3b05d326e9301ff704b4d060906fde537156e3c74522305d9987bc2f3bc750a985dfe55e28af9b0f2fd74e5c0cad9ec0bdd763a1b62ba222b0f76dc3d20136d7db5a1eff8b58c4e238f6c5e2f369bfd1c1888e361227ec91d4f0e5f01d26401e4d9bf4a925ae3ebb76ba6b802d09d745be340491e70b1e93807b1ea40d58c03ff016e359465717b262f7cc389842c2894a7b8ab5d5096ddf66e88457fe6a4dee8cf76834c456b45bf83d14061203633461cb962e8e2f9cae6db0ffd92d6a8155058167269bc3aaca4f4cd49ccdb75d65f8e925f3a003c1ae3f53c7e3a3792f2a54e51ca4c41ceaabbede664ad6894582adab60e8b709ebb40aa57a13def3b87a69a312b59df0eece4a1db7034ff068330163cf9e471778cd98565bdaa7d1ebee168c99a07c124ba1b8b9d525aaabb1cfdc8c38af472ebfbe408dda38cb80e68818837dc2b056e04eb3887fbcfcd41f2b3782ece04913faff03fe01131739086bb245e69efa28e6c612f44ba2bb0fa86921db7470071701b61b63578520ce108feddc1d7f57b4c0f45dbf93cac8cf5b9cb27333fef304b1475779db3fca9bf1592271d022059e562f98067ad18d0641bd73a9fd67a60470ce20a90c7f00f278cca73945b972f9c1bc3a6ab23428a0110d1a56c26a680ff7bd01512326a58979b047fa9265cc9252289d722ff884e762c515ce2b608f1e29b2b49030f003d66e884b9655d4d981048a11cb8366c752705d65dcdbcd8401344344e700f37b220a3d836b1c915f61a02105b32a6c48bd23622d784935e21abdb971b61b28a1213ce590f34680601f090bedb408aade106430eaf2ce71a4094fdb7ae76dec31b5c73f3607a3f6fadee9e40250abbd98c820842cd9631bd627079e8e2ef713fcae35185116e82ae34043380f6b20415b41cc0eff9ece8bf524eb2210cd536111c999274cd9aa36f0e0feebb045cf4607e9efe18a0511d81607573efd071176fd5de9f4a9e8b507f36bfc8c173421e6d9ecb65269ee9fe59d029fefa2d95ef7e6271880d0c466f3fc2058e555de28f8e3a2e9c8a952bf119e25b72a3e2b62451c59261c59d3b96fe0e6c89f1acbef47f036994f123528adb900acbc0fafbd130a2fc696c7a383f85101e7444da995c8f4442b2a8b27324674171ec6eb40382b46f17d1ebd9ff9403ded24cc93800f9c8923143260f44b26172466de602e7182aeef042eabc45d329da7516c8dea9e0c5a88895ea506a26b6a18ab4b4f47813bca4f917a50260afa1379879ce4849aa4f471a9d43f442fe0fb2fcb2cfc447681d12beef637525bfd2f9261baa176beec1ff9d1e30030c85e3c2e18b44def019d6ce0c398baf4b626fa06f1f721bc7359f267467073dedc7bf02d204816921bbf177e8fcef1bd3c4709d4f74c528d63f000ffac1fb6481dcb47022f5c4a8abbcd5fef307c2c0bb4e34ddb6787f0fcf1c805b143abca3d59b0a309e98995559824a8d25bd5d4848c3f0f6d5ee3390a8dca9c5a60843c4a7f701500152e7ab85730a50c74cd537123b9356bc1f93e48f0449c8b3d4778f8ac22ed201177a0383ba9de96a4e5a388f8bd4e9a152b12db8d0134cef310cc4ea850e92e9f3e5e3e5d3645904711608073c67ef2c28c3a462eb1425c6434d22ef64e7326498da66018616e623d6ce6fd312ba9aac16b18b445ffa9712409c6b99f5e1b09f1370fcf8bdee03ca05f3e93e8f1c18e0def62ef9773f11a7a6187e05c32cf01abb24564d7139ac2354204796580eda2bd00ad8b88f585fa6c599ee65794f80175e352428d56a0795772bb24c6970df4c870759d53f24fa816b9138a6da62202a3668bfdc19a0da006a003aeeb148f46ed7164b12de793287534948e2a9f5b17996f4803bafa1a9a3b4df65ef588c96d9ecdc28a722e3066728f39de3de1b313c80ad912dde90e78d322eda5fc0f953752ccedac5079a69a9d06736a93e26c2f4eb102a9d777224a252e421a8fddf62bbb8d4decd38de750f32b0551b245a51d2073cd71e1aab21f020a40fbe1d886c5fcac8e851b4cfdcffab709dda1608a10e3d5079db1c04d51a58a13d0aba097dc2a92ae7c0d66d6a4d5708fa704829801e8d55fa1a5f1496509194282d26b8ce690cedb1d0b1d1e4f2731a8bdfb7b1b09e5f3fc07214f05b9d8fcd80ef126017e023065651e7fe72164976276bfbb91080a2e93a970f5ca2ece97e919166d4839366679c2adbc38ea26d21aad65bd3e2f603c6498c6b16bcb5c9130c6d7a48e0fe971d1e486c7640f882e018790384d247ea14af0adb54e5450ad5906d8e3939e6eba28db867d467597b35043869a0b20bc9be77ba35c063e8aeca2b9bd8e00c2b6f26415facfae063ea4cdd52ab7ec0e9715559c94f7b12fc195e214af3e21f6258ff739592a0b1ed09dde7f1234fd02a5dea1de89d8e8b1f9d10cf6b98929087e711e91d5c35d88e1bed2d0555abf19c4ffd6c702e6cdd30a1e93b4899b27e13671f0f6d0ec7655829599a099ed761406e7bd6a5591f66aa67221a4ae6ee9b1f53c4f1379563355d401b6b9ea67c91297e8cf197e9c0d4335e84e653b4f655e239baca07a8a3b6365bed6a6fba3a70b292fd5de7d35dbeb3439fe8fd3fc8d6aeae022735ba27e595066386242785011c385ef6a6e4da3ae89718b37c8e66d4061c70ecb3c99c31e08cc6684dfc6ed27007d838b58d1e716287b83d5bc499e7741a004499f55c8d3e87d801d879c332c4211cc755c2073efab2f81711c1c5a5f4deb0aac5459fc1582883417d40dfb153782bdb5d5f64bc82eaec43cb6f56a480a7f17bdd5b639bd3366045c03f0ed1d3b2b807218cfe2bc91d83455c0eefbc35b53b89f99eb8a34fc9ed1ebf319d52f764df8e8bb970a27e79a8c3df7957227e55d672ae18d2c78e37287ecc4278704186b900dba6c2c0e3e2835489d443c042f5c4496339569360b314300a57ab508ae5a4dd5af966369669c849b0fa2c5eac77d5699787f68e9050c06ec325539231f666aa162369d93e0f9a94d1cb46079aef8b1414dfeffe38dffed5e13489914ef9e0806234f857ef39851a84ad5b11ebe9270dbf957cf86b8a5983b4f15d412f4fabfb119221d64d6b63d8d5aa4f0c5fd88f3f92cf8d2c453d3f02ec21e631341581c3c22169cb12b01d127660f1e407d9e2dcfca89209ced6dfaea775cc21d61d45c0b5ea2386bc49cc02544cb3b8749ea51189ca3e16498ad08023e00021c8626ae1301e5319f45e19633f0bcb277550118901038149234f4a2f751532406e773c3d92e63563fd3c98c5b88270291cfc56c90d23054760a450eedbbc7b0246bfd2d1b31e40de7221ba853b8342008a2649e54977cf07aa4fcfad6ca6c22025a537f1685fdced66ddcb8b460ef6c54c0383a04af2637ca967a1441b1286b2cd63c5a4aa085834b38fafcf1e85b2009b5867a0faee5aed99e7ea33793034f255b3c7480acff97f3e53ba1d82ac78462a0a3d31c2fa5544e0edd5010942dcb02efb495e7d5894b850a241eed347c8ef95fac78c304d32e3edd24044e66236c1e9ba2d64dc71227d171c25bdfa073f2e1d95022eeec6e0019aa2bbc70266e33038c9f352b66674a994f44e75b9cb0d705a8997a0627bebc50e14bb36dd8967e0aef0f512ea0b1f82c4a966404587a3af18c6dc86bd3686a19097e81bb1ec6ac29d713ccf7ecf6c3fa5341da75d1bfbc5c0fb41f67a9414780a647f3687ee52d2724834df84a5475d0d52cee945ec76bf927022183ec8f4e6bfadc73c93326cd1e430ec191e243553cd59e1fa7494c37eb562e691701d846003eec7c7da0de132d47d6f5e350431d0b066e0060324c52ea30db88c008664463b670691a1018b510de0dd10db55cd93774d315505e161417523a6569ee11210738d710c23bc98f1e255175decfe7b021132a34b6072043234d16562ef3c32632921356f18f38761430dc0dd3d5c8949afbf412e235d4d7f6d37bd559c971a0e9fbfcf1be1b2a8c1e5c8f0ddbd0ee2397a50a25a9ce9912456f22308d9b839b74c52c727968a79720269cee2e2227a602c69a2c411ad97d810b3207495848a6a696c3dcdf5241672f44b5d0b1817de2ca10a72c43fafb5605b2607f757627f0b1410574ff544e1f1141d3e855748483135a01cc5e0c6d041cfc8db1c279c871e903509cdb35f45e2bb47c92e0bdaaa230c18b03666766789b48ebe64c6074f2d13965abd3dfa445303731243276fa4cce17c87f2e9351f93a0ad3c9837067214d8e9d877285a05023a6242856e396fe54ec611d45f9b6036dc06b89806bef5c3763e1206856d32c19b5e017d8030ddd0938b3d202c208fec50ef5375134cd1966aea34ed856930416c63e77dbf5d16bbc9b755801b0f756406ddc43cb45e4837f6f1c3ff452fe2b00e82ab3e87fe003741c4ab1f81aa32621fd1da8361041c0da143729726bd6ec2cd0068094304b802df17ae21a6450e8060287d086966f998a718b6a4accad96272224e3149d6da05ea7f5f4aca5274915eca2978314455202dc044bf409b26e11cc78600e3bf43814c2ee291332f49ceed55be1dc2c2684b50172b22c8141072c4d6e78f04fd00684eb13d3feb6c675c92c7a06ccf1c402462ccbb6e31e4b6b2532fe797462dae8881562c5338af0a3f192263d4c909bc14d763f38546056ff0d20997bbe55a87d6a84066b8a149bd554f8f23dc42b0c6506d51edc1fb1f9fd2429704b930c4b14ecefca1a809e66a27be90535fffda70173cceaf017ddb7131ae8499d0646a7dfe1390517ab9fae185b4722f0e0f3d315414c919915c6abe416369122710341007a3199137d4e5b6930fbf1020b7621f991c91768b859dc531b37690d81205fb97071ca35227668ab009cb2dabc5e47d8371e1a980db81e6820ae137d5ca3c5a65bfc9eeddc7c7d496ed530274fd2ede5f160f424b2cdb2a42c3df1eb9985968750c7058931378dd3283bd7101c1d5f89155b305db35e091b12cb2ae4b73606240967b362368c48cf1a67bc70815c136a0df6e52f6be76f1202e7ee92117e68e2dc5bfe5ea52f079591277309a72ed99736051a6081d9ea432caed9cc9c3acbdf28c2cfe997da80b49ffe91e5d5e46cdf86928ee8d80f2db000f435ee362605a7aacd97f99aa2747355fe1b08c23d243ffe64b95cec3af52424cba783f582621358345ed6d5460cc080efd7555ccfc75733c53eb00a105a4006ab34b562688deba6eb9fdf6e9795e3eaf6634f4199440874c494e469c9035f11366cc93fd6f2ab9fe93047b0e1a07bca65725a68b05fd2eb7bb9e720a6427f293147e5f4e061438da7e46fb74f4f2328fc30ec0e6bf64223807b66dbea464619686990e46f12b43969efe6bc1df00db91aee0d752caadc26a4e51d174b077d22e5418da3f9db667a7d9d68a4979259129032dc2e9c2fb6b8791bb0fcacd63e174efc2dfd091ee1cdc490b44f9ae146674e84d4037872f8a6d5e792148077970220ee62cbcc3a8713ebc88d71ae74a48c6ae275c5149b0c4b30838616ef14c8255f31e263b0b3fea25c240c75bc5d42589a5988c9bdfcf8de25f89d1cb833fa1989c5e4c4f26ed9d0718d6f673c0604f80edaba94b2b648e23649d7254afa7708c61a966a4ba3a7b2af6aef5aa26297d0e0294e8d84d231ad997afb0679530e073f83d8392c6fca808fb3cd083485a04d14a9e7e744690ef64854f661dc4f5e0a9222f8c84093569aba3edec7161cdff81b8372f2efd69295b9c9fb339b254b07263b17bb983b58f27676568a1c27bd01562f932bce39abb37b85189ff9373b2af86c69561108d80bf3d0feaa2b29f856780ed1aad09f85378ebff5ea2399891df4b3d25d50e9e44d6439085894b0396b5d25c86a5a659cd6799c75fb1518f42f6ffda4f1a464f39ae375d5c331a5a22e7a30b6a66301579a59c6f6b81d50f304cb613b14696ba3577501194227648641057036368cb9e8d9388a34feb8573623893426adbe3135ccfe6d571c862673b19975ed2458167bfd7a4db627d601af2092c94601f1cc539a8df58bf0c30faf8d01edcd5d1481ee94684919da2bad262d4c9c09508209fa9d185209e9c7c9fc218748d2881d5a8717e87dcdffd264c61d5c7ae80dd8fc9a0ef384e31ce4fbf4b01bef8687c4cfb2832fdd0369394b350b373db44949b0157e44350ed7d1e08c6b735cf971f64af43b539fb5e51ca2800331b97eedc45da66022ef1082be74ef2cc0fe7a62ec4c0a96a733727ab8a801083cd7ee148da2c817ef144f76ae905b803111272f58bc28bb856ee58617768b18f846159ac07b88108d25af523e56b7f01627d695b5e20a45d4fd2c6c664b47238222f2659ad990a6aeb0cb2901518626555f22068098bc2cee243864482e3c0fde7d713e0bcee3a4daf6af6a942a8ea39a8ba90ff49e41f46e3e26ccdf3c5602ba28db8a34dfc07395c9d17994d27069da9c1e3f460c6c426b3f3c84de3a36194a16be7b15a2358258558eefb7b4db07fcae6e65d743da8c428fb4b73a69df23624bf790970bd3d94c4cccc5cfeaf50a02c4705334056a91b5997e5631b7b72a5a0f7085cd1728a063d55653ad58498c37ab782142a8bd7ed408cca024c6a7056c3b60fd204d8d6ca1547d58070db2188fa039f125c044ba667c416835c1a825722a9495a3c60f4f12f4f7a4a92b40d7e80a7ea18ee348b0489e44bb8487c414fffc5f0de6bba9968ef99b7786580a43e97503ec68442f4c71ebaedd909e7c16d40e9a540cee7101951e47410cae188cf740f578ee77fc51af3773d21218ff2401af74719a23079693798e5d213d03ed46670ee21275209d27eddb10613c8509dda8cd518c2c6dff1e5165c55a989058962ea7091f8ac379fae2f376f5747c19283f523f3467c3352ab6f7c1eabfd8cf03d81ac820a61459d016a072423b4a064a9d9fc2ea7204ee4611805bf31e125520aa38a3eec219276e2633493c932e189ac235aec004cdbee904f3a978d40197bd097c0aaa87ef5d5fcd09479f2e1c08a02a29197e530d1292b76a9d137426797a69d0572ce148d4e46c0c22917d2f0832e979d58ed340ea8038d721ca767a3ed0656773cba02be91b36d0d9067de000b5ced4de14c23eab10e87bbe8c05708c3ba4fcedc0daa0cffc142936796e7114d9343be6e0a7114f38436824aa04d23cba2ba855083471e0ad5feb37990f700a9608553ccf6d2a4c4f46c85705760df1a374e7a5c7dcbac5accc5f6f5a21ab053cb8d9a4a0d720bd02bfe00eafc24abeec1a64d120a447a5375f8835f7cfdd1bcf9cd8732ecd66927eaebde431f0529e43613cf85dae8a042a82e6d89f7e6c2b0286b390b22a2be2aae07eb255d118e947dec6e50562d305ddfa36a14e24763014bdbcf50af384a0c30fa850c3e6e8894f5e31e2152ccc5218f55190cccbab2eecbe87813a393fa4b675db99f7f3cf5e47c9dd3bfe2ad32b7ad5af5f034618161ea8adfa0cdb4558538ba6e4e059e12af5c0ceba1e5a13e6d5df2b67ce176c301850dde3650faf5cc2bae417b2793496c803b6f2fb019fe9fd57f125ebd0f7010c9da6e8bbb1acdc4238f5321ba0713923c04fdc2b17242fb41706addfca7b2462e23f46564d49190736d036a8a8e241cab156e5406ff0d0bf7dd22a58f7c4117a000ceff166b0a68f9d6351d172698b6ba9c6f4b12ee756fa77d598f02c762972ec093d8107002cf30348c168a62bb9ad42e4c364ce552e2b7cf97ba077441dff5fc22a3dbe828b13b63a64463179ac1c3a55c9a61abeeac0d0acd9fecd27194d4c4504fda975ea18d70eec826941ec3a410535fccbb73962f140a5dc074906cbd320322e45448dc097a7b75abc9773d552e57f2c40d112b46fecd091be67281b6805d2fb3557fef58da5d9be0c228d555422c5dc8627c4dc37708748fe0014081365bd3dd805e3055cf817c8488b7eaf1be4b34e8a32eab95157d3e8769216509c93d65300d7ee49eb34f63b4256ef1e69d0cbf17265f91dfe99d46a9ef80ffcab38e1d284b683bfc3cb9c108fe7ec5c79ee95a78ae60d1d3de945bdd4ae304cd8fdc768841335e515fb2a14cd2f8dc6391705858fe9a1915150c04c5d981375af461634227cf2fec9f9a833fad167479e16e30c5238b04852a9d72c0dfa24fc02733d4a652d8c0d931c40ee228c58dbefa2279402d95ccec8650663dc743007b99013821aac93a2948e232c211db447d32927688a6863a994783f0439ac1287f9169d9a59edbc9297c1d21010fee4c09d854537bf2d9a311ed2c3c0d68118b1100102e986f64020d6c2c8d4b049b659b0ae0142407a28384cda4a79b92a19b028f45a9005bfde934d21e4f555a645924d22a19a3da586df5cbb80bd792a26a0d3fd42ffb99fb7ffb2aca447fe7f05cc25b81206a9faefaa0d5507af4c260cc2e33a9ab9c3ff0972989bde0a9df62c15333104f3afa8eba1d7695571aff11fb1be5b708eb70c303b170023059c07041999823df92142530ee9faa175f1652b47c68bcceb488c2b4697be93ea843f787ef9656d51404a86fe86077d128ac30a940d7ae2886cc7359729295a84be88caa7aeddec1d36e10b5347d7ed4030c818588186bb902d3071768afc0180481323842a4262131c6729e81122e6432cd5131bf90ae0ea8d4c60f3ef6eab63c8b148de5ff1f406a2134cca3d860e3bede02aa56446f2259c990e88916700251a1c87fa1eafa572b00c39ad1547dddf4e342de2a7787560149557d47eac074f961272e9a4815c1d2e3c1ed56deb30a82e9e16deeebe5e0a3ac6b4b9b2671591e45bdd26e21b83121e7c7c3129bf2937fdd60644d0039dff33c44076cf4db5566fd9b10f51a6458a7bf356eda62d36da9f3803e1873fa5c80aeffc8324f22672322b0cda68b32e171fd80c4d8a3e3f8f28d30cde60f84690a7c594dda5c27f45794bf970befe03a34a3e750d7c89820b86502366374a984e3aced169dee212f507c7cb515a7ebab166893621c9163c9f064a0ddf9357d9ac44e746783abfaa6c35b3294b6a3a2ad6d29717795d95df2352220bf066c5168bcc0049dc916fda42a20436d413feadcb79ec6caa7f3b4630e87c26326270fcb8925c0589ae91e38f7036d864cd0cb4ca9f6592fe8c0919ae5b8a144a086559f11ed54b52deb5cb0e46fca451766c3029279e2c6f828f40ba8b8c04ce33b650c61282fdd401c789e38a02a9186672ba5039725410bb18a0abb4880f2a7bde26b21cac54a7ebeab782286c9b76c28b07653813dc934955090f6830008bedcace064f598696deac08f8d07ed1893036ee9d882b03bfea934def1c540d14e107c68a6b7fcb73c213c5711e3142c040099340f3060d7fd5724618286e0aabcd17e11488dae06f458332cafaa72c53bc66a6234296881f895127c34d6f101a7ff6d56e4f0de5067c60e7bd73110e1e277cd56ab1dfcc437f8893167bd9128b67661cf296f916acef6a5cce64388575e3984133ef9ea51d9a5c406c0aa806b3c954c950444b03d57114b30cc62d9a6ebe77996fce534f16e6c293b423930f39258fef4fa2a0074b32202b353b5cd2bf535b3e9bd77f21998fc090c714942c30b65c9991d36e199aa230e07b874c52b15774228a53bad87959503a85b6ab1d39c11ef62285b432b9523971f083f09a148e46fa27fd88b002dfd4277431ad26539af50d6ad25ab2766cbc732b3739b7b0e8b0517f4d5915a86f4e1d75e905034ad546495bbb601885d8de41621f2e800aff0ab4d8fa3fb2e7812c562e9fb113f8ff79700a34bd7acae14af735631faff0c3d5946534cb6dbbce5f7f32850802ee0a38704c0a28c325f86ee56c069164f71b53ce16b3a62e21cee1e2d0995a1bc6325c11784a2f1c7e124f638fb23055b14373e5efe84c5734ff45c7679faf0855d0ec2364705f00a5983fc25847a848d5615d82dc2c37feb54e8346cc0258", + "public_inputs_hex": "0x1486143d0564ca941cac449924e8ee74c1b4433cf73a6b4920737c223ba6b1e10be8f5ea95c2ca670bbdf5960949af6961a772f4ec6b39a3844be116cacf99fd00000000000000000000000000000000a42c244ebf301109a516d4bcdc64abb0000000000000000000000000000000007480885e28a0d52cb856afc3a3d5a47c213d1251e5de792d246be0ddb50d40044401009b3f1b6e371b8952ccaa26d1df000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000051c32389eed65673f0b7793f23ee22e6c38d700a46ca632733594b0c158fc54cb0923c6b5ff393dc79cd373f86dd3d700bf0be6de48b7c2eac952daa48b0744522da7021599868cc17be0d80067a33218fefb0212527f7eaade058495f762f63d007a2f19dbdf8381decdeeba4d8f75e6530b44e88727e83e49750e58c5f314b92034dcd56a27ebea949c9f9c186ee1bfca874d3feb04621f2dd72ca21e965e740e295978afc7fba44869bb371cdafd4a44d9e153717dd7be816d5c5bf78eafdc2ac3bf06ea50b0b75a21ff21292197611e6fe29433762d425ae9f99ebe4cf4fd0b5502e317f8fc7ed7ec519f48b3128513ab70c87d21729b51f196356088488d1c9dec194202d7cfed3ce8af7a02bb1e4e148defdd60092d331ddae254ecedd82a409a291d3a9da98b49fd5ed49ea40351f8dcc81ed6797c4c74ca0b954f738a0000000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" } } diff --git a/packages/enclave-sdk/package.json b/packages/enclave-sdk/package.json index d5eb121aff..9656129184 100644 --- a/packages/enclave-sdk/package.json +++ b/packages/enclave-sdk/package.json @@ -40,15 +40,13 @@ "directory": "packages/enclave-sdk" }, "scripts": { - "compile:circuits": "pnpm compile:user_data_encryption_ct0 && pnpm compile:user_data_encryption_ct1 && pnpm compile:user_data_encryption", - "compile:user_data_encryption_ct0": "cd ../../circuits/bin/threshold/user_data_encryption_ct0 && nargo compile", - "compile:user_data_encryption_ct1": "cd ../../circuits/bin/threshold/user_data_encryption_ct1 && nargo compile", - "compile:user_data_encryption": "cd ../../circuits/bin/threshold/user_data_encryption && nargo compile", + "compile:circuits": "bash scripts/compile-circuits.sh", "prebuild": "pnpm -C ../enclave-contracts build && pnpm -C ../../ wasm:build && pnpm compile:circuits", "build": "tsup", "dev": "tsup --watch", "clean": "rm -rf dist", "test": "vitest --run", + "pretest": "pnpm compile:circuits", "prerelease": "pnpm clean && pnpm build", "release": "pnpm publish --access=public" }, diff --git a/packages/enclave-sdk/scripts/compile-circuits.sh b/packages/enclave-sdk/scripts/compile-circuits.sh new file mode 100755 index 0000000000..c5c5219288 --- /dev/null +++ b/packages/enclave-sdk/scripts/compile-circuits.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# Compile threshold user-data encryption circuits for the SDK. +# Default committee is micro (matches DEFAULT_E3_CONFIG.committeeSize = CommitteeSize.Micro). +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)" +COMMITTEE="${CIRCUIT_COMMITTEE:-micro}" +case "${COMMITTEE}" in + micro|small|medium) ;; + *) + echo "Error: CIRCUIT_COMMITTEE must be micro|small|medium (got: ${COMMITTEE})" >&2 + exit 1 + ;; +esac +exec pnpm -C "${REPO_ROOT}" build:circuits \ + --preset insecure-512 \ + --committee "${COMMITTEE}" \ + --group threshold \ + --circuit user_data_encryption \ + --circuit user_data_encryption_ct0 \ + --circuit user_data_encryption_ct1 \ + --skip-vk \ + --skip-checksums \ + --no-clean-targets diff --git a/packages/enclave-sdk/src/circuits/assert-micro-circuits.ts b/packages/enclave-sdk/src/circuits/assert-micro-circuits.ts new file mode 100644 index 0000000000..051ba9c494 --- /dev/null +++ b/packages/enclave-sdk/src/circuits/assert-micro-circuits.ts @@ -0,0 +1,57 @@ +// 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. + +import { readFileSync } from 'node:fs' +import { dirname, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' + +import { SDKError } from '../utils' + +/** Matches `IEnclave.CommitteeSize.Micro` and `DEFAULT_E3_CONFIG.committeeSize`. */ +export const SDK_CIRCUIT_COMMITTEE = 'micro' + +const ACTIVE_PRESET_PATH = resolve(dirname(fileURLToPath(import.meta.url)), '../../../../circuits/bin/.active-preset.json') + +let checked = false + +/** + * SDK encryption artifacts are built for the micro committee preset by default. + * Fail fast when `circuits/bin/.active-preset.json` points at another committee + * (e.g. after benchmark runs with `--committee small`). + */ +export function assertSdkMicroCircuits(): void { + if (checked) return + checked = true + + let raw: string + try { + raw = readFileSync(ACTIVE_PRESET_PATH, 'utf-8') + } catch { + throw new SDKError( + `Missing ${ACTIVE_PRESET_PATH}. Run \`pnpm -C packages/enclave-sdk compile:circuits\` first.`, + 'SDK_CIRCUIT_STAMP_MISSING', + ) + } + + let committee: string | undefined + try { + committee = JSON.parse(raw)?.committee as string | undefined + } catch { + throw new SDKError( + `Invalid JSON in ${ACTIVE_PRESET_PATH}. Rebuild with \`pnpm -C packages/enclave-sdk compile:circuits\`.`, + 'SDK_CIRCUIT_STAMP_INVALID', + ) + } + + if (committee !== SDK_CIRCUIT_COMMITTEE) { + throw new SDKError( + `SDK requires circuits built for committee "${SDK_CIRCUIT_COMMITTEE}" ` + + `(active preset is "${committee ?? 'unknown'}"). ` + + `Run: pnpm -C packages/enclave-sdk compile:circuits`, + 'SDK_CIRCUIT_COMMITTEE_MISMATCH', + ) + } +} diff --git a/packages/enclave-sdk/src/crypto/user-data-encryption.ts b/packages/enclave-sdk/src/crypto/user-data-encryption.ts index 8440b5e2e5..51902d4421 100644 --- a/packages/enclave-sdk/src/crypto/user-data-encryption.ts +++ b/packages/enclave-sdk/src/crypto/user-data-encryption.ts @@ -9,8 +9,11 @@ import userDataEncryptionCt0Circuit from '../../../../circuits/bin/threshold/tar import userDataEncryptionCt1Circuit from '../../../../circuits/bin/threshold/target/user_data_encryption_ct1.json' import userDataEncryptionCircuit from '../../../../circuits/bin/threshold/target/user_data_encryption.json' import { CompiledCircuit, Noir } from '@noir-lang/noir_js' +import { assertSdkMicroCircuits } from '../circuits/assert-micro-circuits' import { proofToFields } from '../utils' +assertSdkMicroCircuits() + // Conversion to Noir types export type Field = string diff --git a/packages/enclave-sdk/src/utils.ts b/packages/enclave-sdk/src/utils.ts index a394efaf19..1bb485f788 100644 --- a/packages/enclave-sdk/src/utils.ts +++ b/packages/enclave-sdk/src/utils.ts @@ -76,9 +76,9 @@ export const DEFAULT_COMPUTE_PROVIDER_PARAMS: ComputeProviderParams = { batch_size: 2, } -// Default E3 configuration +// Default E3 configuration (`committeeSize` is `IEnclave.CommitteeSize`, not circuit N_PARTIES). export const DEFAULT_E3_CONFIG = { - committeeSize: 0, // Micro + committeeSize: 0, // CommitteeSize.Micro duration: 1800, // 30 minutes in seconds payment_amount: '0', // 0 ETH in wei } as const diff --git a/scripts/README.md b/scripts/README.md index f94c39118c..7332497139 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -166,9 +166,16 @@ artifacts. ### Usage ```bash -# Build all circuits +# Build all circuits (defaults: --preset insecure-512 --committee micro) pnpm build:circuits +# Switch the active committee size (regenerates committee/active.nr, +# default/mod.nr, and patches BFV_DKG_H / BFV_THRESHOLD_T in utils.ts atomically) +pnpm build:circuits --committee medium + +# Combine preset + committee +pnpm build:circuits --preset insecure-512 --committee medium + # Build only specific group (dkg or threshold) pnpm build:circuits --group dkg @@ -182,6 +189,27 @@ pnpm build:circuits --dry-run pnpm build:circuits hash ``` +### Committee sizes + +Three sizes are supported, mirroring `e3_zk_helpers::CiphernodesCommitteeSize`: + +| Committee | N (parties) | T (threshold) | H (honest) | +| ----------------- | ----------- | ------------- | ---------- | +| `micro` (default) | 3 | 1 | 3 | +| `small` | 5 | 2 | 5 | +| `medium` | 10 | 4 | 8 | + +All `(preset, committee)` pairs work because the Reed-Solomon parity matrices in +`circuits/lib/src/configs/committee//parity_{insecure,secure}.nr` are auto-generated by the +`generate_parity_matrices` Rust binary, invoked from `build-circuits.ts` whenever the committee +changes. The matrix files on disk are derived artifacts. + +The currently-active selection is written to `circuits/bin/.active-preset.json` and checked by +`pnpm check:committee` (pre-push hook) against `active.nr`, `utils.ts`, and the parity files. +Switching committee always goes through `pnpm build:circuits --committee` — never edit `active.nr`, +`utils.ts`, or any `parity_*.nr` by hand; the check will reject pushes where they drift from what +the generator would produce. + ### What it does 1. **Discovers circuits** in `circuits/bin/dkg/` and `circuits/bin/threshold/` @@ -193,6 +221,10 @@ pnpm build:circuits hash ### Options +- `--preset ` - Parameter preset: `insecure-512` (default), `secure-8192`, or `all` +- `--committee ` - Committee size: `micro` (default), `small`, `medium` +- `--skip-utils-patch` - Skip rewriting `BFV_DKG_H` / `BFV_THRESHOLD_T` in + `packages/enclave-contracts/scripts/utils.ts` - `--group ` - Circuit groups (comma-separated: dkg,threshold) - `--circuit ` - Build specific circuit(s) - `--skip-vk` - Skip verification key generation @@ -247,18 +279,24 @@ Circuits are built locally and stored in a git branch: Noir circuits. The generated `.sol` files under `packages/enclave-contracts/contracts/verifiers/bfv/honk/` are -**committed to git** and correspond to **exactly one BFV preset**: `insecure-512` (the development / -CI / benchmark default). The Honk verifiers bake in the recursive VKs of `dkg_aggregator` / -`decryption_aggregator`, which are preset-dependent — different BFV parameter sets compile to -different VKs and therefore different `.sol` bytes. The committed files only match `insecure-512`. +**committed to git** and correspond to **exactly one `(preset, committee)` pair**: +`(insecure-512, micro)` (the development / CI / benchmark default). The Honk verifiers bake in the +recursive VKs of `dkg_aggregator` / `decryption_aggregator`, which are preset- and committee- +dependent — different BFV parameter sets or `H/T` sizes compile to different VKs and therefore +different `.sol` bytes. The committed files only match `(insecure-512, micro)`. The generator enforces this: both `--check` and `--write` refuse to run unless -`dist/circuits/insecure-512/.build-stamp.json` exists and reports `"preset": "insecure-512"`. The -stamp is written by [`pnpm build:circuits --preset `](#circuit-builder) and is the only -on-disk record of which preset built `circuits/bin/`. If a different preset was last built (or -none), the generator refuses with a clear fix recipe instead of silently producing the wrong `.sol`. -If you need verifiers for a different preset (e.g. a production deploy on `secure-8192`), generate -them locally for that deploy — do **not** commit the result over the canonical files. +`dist/circuits/insecure-512/.build-stamp.json` exists and reports `"preset": "insecure-512"`, and +`circuits/bin/.active-preset.json::committee` matches the requested committee. The stamps are +written by [`pnpm build:circuits --preset --committee `](#circuit-builder) and are +the only on-disk record of which `(preset, committee)` built `circuits/bin/`. If either dimension +drifts, the generator refuses with a clear fix recipe instead of silently producing the wrong +`.sol`. + +For non-canonical committees (e.g. `medium`), pass `--committee `; the verifiers land under +`honk//` so the canonical-committee `.sol` files committed to git aren't clobbered. `--check` +mode skips the diff for non-canonical committees because there's no committed file to diff against — +benchmark and deploy flows already deploy fresh aggregator verifiers from runtime artifacts. The script has two modes: @@ -280,6 +318,9 @@ pnpm generate:verifiers --check # Regenerate (default; equivalent to --write) pnpm generate:verifiers +# Generate for a non-canonical committee (writes under honk/medium/) +pnpm generate:verifiers --committee medium --write + # Generate only for specific group pnpm generate:verifiers --group dkg pnpm generate:verifiers --group threshold diff --git a/scripts/build-circuits.ts b/scripts/build-circuits.ts index 232a8e79ee..bda6a25df6 100644 --- a/scripts/build-circuits.ts +++ b/scripts/build-circuits.ts @@ -10,12 +10,17 @@ import { createHash } from 'crypto' import { appendFileSync, copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'fs' import { basename, join, resolve } from 'path' import { + ALL_COMMITTEES, ALL_GROUPS, ALL_PRESETS, + CIRCUIT_COMMITTEES, CIRCUIT_GROUPS, CIRCUIT_PRESETS, CIRCUIT_VARIANTS, + COMMITTEE_PARAMS, + isPresetCommitteeSupported, PRESET_NOIR_CONFIG, + type CircuitCommittee, type CircuitGroup, type CircuitPreset, } from './circuit-constants' @@ -61,10 +66,16 @@ interface BuildOptions { hydrateBinOnly?: boolean dryRun?: boolean preset?: CircuitPreset | 'all' + /** Active committee size — drives `committee/active.nr` and verifier H/T. */ + committee?: CircuitCommittee + /** Skip writing BFV_DKG_H/T into `packages/enclave-contracts/scripts/utils.ts`. */ + skipUtilsPatch?: boolean } interface PresetBuildStamp { preset: string + /** Committee selection at build time. Optional for backward compat with older stamps. */ + committee?: CircuitCommittee sourceHash: string builtAt: string } @@ -91,8 +102,18 @@ class NoirCircuitBuilder { clean: true, skipVk: false, preset: CIRCUIT_PRESETS.INSECURE_512, + committee: CIRCUIT_COMMITTEES.MICRO, ...options, } + + if (this.options.preset !== 'all' && this.options.committee) { + if (!isPresetCommitteeSupported(this.options.preset as CircuitPreset, this.options.committee)) { + throw new Error( + `Unsupported preset/committee pair (${this.options.preset}, ${this.options.committee}). ` + + `This combination currently emits stub parity matrices and invalid proofs.`, + ) + } + } } async buildAll(): Promise { @@ -101,32 +122,30 @@ class NoirCircuitBuilder { console.log(`🔮 Building Noir circuits for preset(s): ${presets.join(', ')}...`) - // Save original mod.nr content so we can restore it after building const modNrPath = join(this.rootDir, 'circuits', 'lib', 'src', 'configs', 'default', 'mod.nr') - const originalModNr = readFileSync(modNrPath, 'utf-8') - try { - if (this.options.clean && existsSync(this.options.outputDir!)) { - rmSync(this.options.outputDir!, { recursive: true }) - } - mkdirSync(this.options.outputDir!, { recursive: true }) + // Preset and committee selections are persistent. They're written into `default/mod.nr` + // (preset) and `committee/active.nr` (committee) by `setNoirConfigPreset` / `setNoirCommittee` + // below and intentionally left on disk so the operator's choice survives the build. + // No save/restore — see `pnpm check:committee` for the drift guard. - for (const preset of presets) { - const presetResult = await this.buildForPreset(preset, modNrPath) - result.compiled.push(...presetResult.compiled) - result.errors.push(...presetResult.errors) - if (!presetResult.success) result.success = false - if (presetResult.sourceHash && !result.sourceHash) result.sourceHash = presetResult.sourceHash - } + if (this.options.clean && existsSync(this.options.outputDir!)) { + rmSync(this.options.outputDir!, { recursive: true }) + } + mkdirSync(this.options.outputDir!, { recursive: true }) + + for (const preset of presets) { + const presetResult = await this.buildForPreset(preset, modNrPath) + result.compiled.push(...presetResult.compiled) + result.errors.push(...presetResult.errors) + if (!presetResult.success) result.success = false + if (presetResult.sourceHash && !result.sourceHash) result.sourceHash = presetResult.sourceHash + } - if (!this.options.skipChecksums && result.compiled.length > 0) { - result.checksumFile = this.generateChecksumFile(result.compiled) - } - result.releaseDir = this.options.outputDir! - } finally { - // Restore original mod.nr - writeFileSync(modNrPath, originalModNr) + if (!this.options.skipChecksums && result.compiled.length > 0) { + result.checksumFile = this.generateChecksumFile(result.compiled) } + result.releaseDir = this.options.outputDir! return result } @@ -142,7 +161,9 @@ class NoirCircuitBuilder { '//', `// Auto-generated by build-circuits.ts for preset: ${preset}`, '', - `pub use super::committee::micro::{H, N_PARTIES, T};`, + '// Committee size (N_PARTIES / T / H) is routed through `committee::active`,', + '// which `build-circuits.ts` regenerates atomically with this file.', + `pub use super::committee::active::{H, N_PARTIES, T};`, `pub use super::${configModule}::dkg;`, `pub use super::${configModule}::threshold;`, '', @@ -155,6 +176,120 @@ class NoirCircuitBuilder { console.log(` 📋 Set Noir config to: ${configModule} (preset: ${preset})`) } + /** Regenerates `committee/active.nr` to re-export from the chosen leaf module. */ + private setNoirCommittee(committee: CircuitCommittee): void { + const activeNrPath = join(this.rootDir, 'circuits', 'lib', 'src', 'configs', 'committee', 'active.nr') + const content = [ + '// 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.', + '//', + `// Auto-generated by scripts/build-circuits.ts for committee: ${committee}`, + '// Single source of truth for the active committee size in the Noir codebase.', + '//', + '// Importing modules MUST NOT reach into `committee::{micro,small,medium}` directly;', + '// always go through `committee::active` so that switching committee is a one-file edit.', + '//', + '// This module also breaks the import cycle that would arise from', + '// `math::committee_hash` -> `configs::default` -> `configs::insecure::threshold` -> `math`:', + '// `committee_hash` imports `N_PARTIES` from here (which only depends on the leaf', + '// committee module), not from `configs::default`.', + '', + '/// Number of registered parties (matches on-chain `topNodes` length).', + `pub global N_PARTIES: u32 = crate::configs::committee::${committee}::N_PARTIES;`, + '/// Secret-sharing reconstruction threshold.', + `pub global T: u32 = crate::configs::committee::${committee}::T;`, + '/// Honest-party count expected during the DKG (`H <= N_PARTIES`).', + `pub global H: u32 = crate::configs::committee::${committee}::H;`, + '', + '/// Parity matrices for the secret-sharing scheme, sized for the active committee.', + '/// `configs::{insecure,secure}::dkg` re-exports the relevant one as `PARITY_MATRIX`.', + `pub use crate::configs::committee::${committee}::parity_insecure::PARITY_MATRIX as PARITY_MATRIX_INSECURE;`, + `pub use crate::configs::committee::${committee}::parity_secure::PARITY_MATRIX as PARITY_MATRIX_SECURE;`, + '', + ].join('\n') + writeFileSync(activeNrPath, content) + console.log(` 📋 Set Noir committee to: ${committee}`) + } + + /** + * Regenerates `circuits/lib/src/configs/committee//parity_{insecure,secure}.nr` + * by invoking the Rust `generate_parity_matrices` binary. The Reed-Solomon parity matrix is + * a deterministic function of `(N, T, QIS)` — committing the output keeps `nargo check` + * working standalone, but the build script always overwrites it so a change in committee + * or BFV preset constants can never silently desync the on-disk literal from what the + * prover would compute at witness time. + */ + private regenerateParityMatrices(committee: CircuitCommittee): void { + const libDir = join(this.rootDir, 'circuits', 'lib') + try { + execSync(`cargo run --quiet --release --bin generate_parity_matrices -- --committee ${committee}`, { + cwd: this.rootDir, + stdio: ['ignore', 'pipe', 'inherit'], + }) + execSync('nargo fmt', { cwd: libDir, stdio: ['ignore', 'pipe', 'inherit'] }) + console.log(` 📋 Regenerated parity_{insecure,secure}.nr for committee: ${committee}`) + } catch (err: any) { + throw new Error( + `Failed to regenerate parity matrices for committee=${committee}: ${err.message}\n` + + ` Try: cargo run --release --bin generate_parity_matrices -- --committee ${committee}`, + ) + } + } + + /** + * Patch `packages/enclave-contracts/scripts/utils.ts` so `BFV_DKG_H` and `BFV_THRESHOLD_T` + * track the active committee. The gas-benchmark and verifier-deploy scripts pull from this + * file at runtime, so any mismatch between the compiled circuit and the deployed verifier + * surfaces as `InvalidPublicInputsLength()` on-chain. + */ + private patchUtilsTs(committee: CircuitCommittee): void { + if (this.options.skipUtilsPatch) return + const { h, t, n } = COMMITTEE_PARAMS[committee] + const path = join(this.rootDir, 'packages', 'enclave-contracts', 'scripts', 'utils.ts') + if (!existsSync(path)) return // optional in minimal checkouts + const before = readFileSync(path, 'utf-8') + const cap = committee.charAt(0).toUpperCase() + committee.slice(1) + const generatedDoc = `/** + * + * Default insecure-512 / ${committee} committee layout for BFV aggregator verifiers. + * Must match \`lib::configs::default::{H, T}\` in compiled circuits. + * ${cap} committee: N=${n}, T=${t}, H=${h}. + * + */` + const docPattern = /\/\*\*\s*\n \* [\s\S]*?<\/generated-committee-doc>\s*\n \*\// + + let after = before + .replace(/export const BFV_DKG_H = \d+/, `export const BFV_DKG_H = ${h}`) + .replace(/export const BFV_THRESHOLD_T = \d+/, `export const BFV_THRESHOLD_T = ${t}`) + + if (!after.includes(`export const BFV_DKG_H = ${h}`)) { + throw new Error(`patchUtilsTs: could not update BFV_DKG_H in ${path} (expected export const BFV_DKG_H = )`) + } + if (!after.includes(`export const BFV_THRESHOLD_T = ${t}`)) { + throw new Error(`patchUtilsTs: could not update BFV_THRESHOLD_T in ${path} (expected export const BFV_THRESHOLD_T = )`) + } + + if (!docPattern.test(before)) { + throw new Error( + `patchUtilsTs: ${path} is missing the sentinel block; ` + + `add the sentinel comment (see scripts/build-circuits.ts) so committee docs stay in sync`, + ) + } + const afterDoc = after.replace(docPattern, generatedDoc) + if (afterDoc === after) { + console.warn(` ⚠️ patchUtilsTs: block in ${path} did not change (committee=${committee})`) + } + after = afterDoc + + if (after !== before) { + writeFileSync(path, after) + console.log(` 📋 Patched utils.ts: BFV_DKG_H=${h}, BFV_THRESHOLD_T=${t} (committee: ${committee})`) + } + } + private presetStampPath(preset: string): string { return join(this.options.outputDir!, preset, '.build-stamp.json') } @@ -172,6 +307,7 @@ class NoirCircuitBuilder { private writePresetStamp(preset: string, sourceHash: string): void { const stamp: PresetBuildStamp = { preset, + committee: this.options.committee, sourceHash, builtAt: new Date().toISOString(), } @@ -179,10 +315,16 @@ class NoirCircuitBuilder { writeFileSync(this.presetStampPath(preset), JSON.stringify(stamp, null, 2) + '\n') } - /** Records which BFV preset last populated `circuits/bin/` (used by benchmark gas extraction). */ + /** + * Records which BFV preset + committee last populated `circuits/bin/`. Read by: + * - the benchmark gas-extraction pipeline (`scripts/benchmarkGasFromRaw.ts`) + * - the Rust integration tests (cross-checked against `ENCLAVE_COMMITTEE_SIZE`). + * A drift between this stamp and what the consumer expects fails fast. + */ private writeActiveBinPresetStamp(preset: string, sourceHash: string): void { const stamp: PresetBuildStamp = { preset, + committee: this.options.committee, sourceHash, builtAt: new Date().toISOString(), } @@ -268,6 +410,10 @@ class NoirCircuitBuilder { private isBinReadyForPreset(preset: string, sourceHash: string): boolean { const active = this.readActiveBinPreset() if (!active || active.preset !== preset || active.sourceHash !== sourceHash) return false + // Committee mismatch is also a cache miss: the same circuit sources can compile to + // different bytecode under a different committee, which the source hash captures, but + // we double-check the stamp field for clearer diagnostics when --skip-if-built kicks in. + if (this.options.committee && active.committee && active.committee !== this.options.committee) return false return this.requiredBinMarkers().every((path) => existsSync(path)) } @@ -294,6 +440,19 @@ class NoirCircuitBuilder { } } + /** + * Writes preset + committee selection to the persistent Noir/TS config files so they stay + * aligned with `circuits/bin/.active-preset.json` even on hydrate-only or skip-if-built paths. + */ + private syncPresetAndCommittee(modNrPath: string, preset: CircuitPreset, committee?: CircuitCommittee): void { + this.setNoirConfigPreset(modNrPath, preset) + if (committee) { + this.setNoirCommittee(committee) + this.regenerateParityMatrices(committee) + this.patchUtilsTs(committee) + } + } + private async buildForPreset(preset: CircuitPreset, modNrPath?: string): Promise { const result: BuildResult = { success: true, compiled: [], errors: [] } const presetOutputDir = join(this.options.outputDir!, preset) @@ -320,6 +479,10 @@ class NoirCircuitBuilder { const sourceHash = this.computeSourceHash(preset) result.sourceHash = sourceHash + if (modNrPath) { + this.syncPresetAndCommittee(modNrPath, preset, this.options.committee) + } + if (this.options.hydrateBinOnly) { if (!this.isDistPresetUpToDate(preset, sourceHash)) { throw new Error( @@ -352,14 +515,6 @@ class NoirCircuitBuilder { this.logSkipIfBuiltBlocked(preset, sourceHash) } - if (modNrPath) { - this.setNoirConfigPreset(modNrPath, preset) - } - - if (modNrPath) { - this.setNoirConfigPreset(modNrPath, preset) - } - if (!this.options.noCleanTargets) { this.cleanTargetDirs(circuits) } @@ -800,6 +955,9 @@ class NoirCircuitBuilder { hash.update(`preset:${preset}\n`) hash.update(`noir_config:${PRESET_NOIR_CONFIG[preset]}\n`) } + if (this.options.committee) { + hash.update(`committee:${this.options.committee}\n`) + } const circuits = this.discoverCircuits().sort((a, b) => `${a.group}/${a.name}`.localeCompare(`${b.group}/${b.name}`)) for (const c of circuits) this.hashDir(c.path, hash) return hash.digest('hex').substring(0, 16) @@ -866,7 +1024,15 @@ async function main() { process.exit(1) } options.preset = val as CircuitPreset | 'all' - } else if (['hash', 'build'].includes(arg)) command = arg + } else if (arg === '--committee') { + const val = args[++i] + if (!ALL_COMMITTEES.includes(val as CircuitCommittee)) { + console.error(`Unknown committee: ${val}. Valid values: ${ALL_COMMITTEES.join(', ')}`) + process.exit(1) + } + options.committee = val as CircuitCommittee + } else if (arg === '--skip-utils-patch') options.skipUtilsPatch = true + else if (['hash', 'build'].includes(arg)) command = arg } const builder = new NoirCircuitBuilder(undefined, options) @@ -893,6 +1059,8 @@ Options: --group Circuit groups (comma-separated: dkg,threshold) --circuit Build specific circuit(s) --preset Parameter preset: insecure-512 (default), secure-8192, or all + --committee Committee size: micro (default), small, medium + --skip-utils-patch Don't rewrite BFV_DKG_H/T in packages/enclave-contracts/scripts/utils.ts --skip-vk Skip verification key generation --skip-checksums Skip checksum generation -o, --output Output directory (default: dist/circuits) diff --git a/scripts/check-committee.sh b/scripts/check-committee.sh new file mode 100755 index 0000000000..4f1e3c5b95 --- /dev/null +++ b/scripts/check-committee.sh @@ -0,0 +1,194 @@ +#!/usr/bin/env bash +# 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. + +# Asserts that the committee selection is internally consistent across the four files +# that encode it independently: +# +# 1. circuits/lib/src/configs/committee/active.nr (Noir-side active committee) +# 2. circuits/bin/.active-preset.json (last `pnpm build:circuits` stamp) +# 3. packages/enclave-contracts/scripts/utils.ts (BFV_DKG_H / BFV_THRESHOLD_T) +# 4. crates/zk-helpers/src/ciphernodes_committee.rs (committee enum values, single source) +# +# A drift between any two means the next `pnpm build:circuits` would silently produce +# verifiers / proofs against the wrong committee. Run from .husky/pre-push (or CI). +# +# Exit 0 on consistency, 1 on drift. The stamp is optional (skipped when absent — common +# in fresh clones before `pnpm build:circuits`). + +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$REPO_ROOT" + +ACTIVE_NR="circuits/lib/src/configs/committee/active.nr" +STAMP="circuits/bin/.active-preset.json" +UTILS_TS="packages/enclave-contracts/scripts/utils.ts" +COMMITTEE_RS="crates/zk-helpers/src/ciphernodes_committee.rs" +RAN_STAMP_CHECK=false +RAN_PARITY_CHECK=false + +fail() { + echo "❌ check:committee: $*" >&2 + exit 1 +} + +# 1. Extract committee name from active.nr (matches "crate::configs::committee::::N_PARTIES"). +if [[ ! -f "$ACTIVE_NR" ]]; then + fail "missing $ACTIVE_NR" +fi +ACTIVE_COMMITTEE=$(grep -oE 'crate::configs::committee::(micro|small|medium|large)::N_PARTIES' "$ACTIVE_NR" \ + | head -n1 \ + | sed -E 's|.*committee::([a-z]+)::N_PARTIES|\1|') +if [[ -z "${ACTIVE_COMMITTEE:-}" ]]; then + fail "could not infer committee from $ACTIVE_NR (regex match failed)" +fi + +# 2. Extract (H, T) from utils.ts. +if [[ ! -f "$UTILS_TS" ]]; then + fail "missing $UTILS_TS" +fi +UTILS_H=$(grep -E '^export const BFV_DKG_H = [0-9]+' "$UTILS_TS" | grep -oE '[0-9]+' | head -n1) +UTILS_T=$(grep -E '^export const BFV_THRESHOLD_T = [0-9]+' "$UTILS_TS" | grep -oE '[0-9]+' | head -n1) +if [[ -z "${UTILS_H:-}" || -z "${UTILS_T:-}" ]]; then + fail "could not parse BFV_DKG_H / BFV_THRESHOLD_T from $UTILS_TS" +fi + +# 3. Expected (H, T) for the active committee — parsed from the leaf `mod.nr` (same source +# as `load_default_committee.sh`; avoids duplicating numbers in this script). +COMMITTEE_MOD="circuits/lib/src/configs/committee/${ACTIVE_COMMITTEE}/mod.nr" +if [[ ! -f "$COMMITTEE_MOD" ]]; then + fail "missing $COMMITTEE_MOD (no Noir module for committee '$ACTIVE_COMMITTEE')" +fi +EXPECTED_H=$(grep -E 'pub global H: u32 = [0-9]+' "$COMMITTEE_MOD" | sed -E 's/.*= ([0-9]+);/\1/' | head -n1) +EXPECTED_T=$(grep -E 'pub global T: u32 = [0-9]+' "$COMMITTEE_MOD" | sed -E 's/.*= ([0-9]+);/\1/' | head -n1) +if [[ -z "${EXPECTED_H:-}" || -z "${EXPECTED_T:-}" ]]; then + fail "could not parse H / T from $COMMITTEE_MOD" +fi + +if [[ "$UTILS_H" != "$EXPECTED_H" || "$UTILS_T" != "$EXPECTED_T" ]]; then + fail "drift: $ACTIVE_NR says committee=$ACTIVE_COMMITTEE (expects H=$EXPECTED_H, T=$EXPECTED_T) \ +but $UTILS_TS has BFV_DKG_H=$UTILS_H, BFV_THRESHOLD_T=$UTILS_T. \ +Run: pnpm build:circuits --committee $ACTIVE_COMMITTEE" +fi + +# 4. Optional stamp cross-check (when circuits have been built locally). +if [[ -f "$STAMP" ]]; then + # Older stamps (written before build-circuits.ts learned about committees) lack the field; + # treat that as "no cross-check" rather than failing the whole script. + STAMP_COMMITTEE=$(grep -oE '"committee"\s*:\s*"[a-z]+"' "$STAMP" 2>/dev/null | grep -oE '"[a-z]+"$' | tr -d '"' || true) + if [[ -n "${STAMP_COMMITTEE:-}" ]]; then + RAN_STAMP_CHECK=true + if [[ "$STAMP_COMMITTEE" != "$ACTIVE_COMMITTEE" ]]; then + fail "drift: $ACTIVE_NR says committee=$ACTIVE_COMMITTEE but $STAMP says committee=$STAMP_COMMITTEE. \ +Either rebuild circuits with the current selection or revert active.nr to match the stamp." + fi + fi +fi + +# 5. Sanity: the Rust enum file should exist and contain the committee name. +if [[ ! -f "$COMMITTEE_RS" ]]; then + fail "missing $COMMITTEE_RS" +fi +CAPITALIZED="$(echo "$ACTIVE_COMMITTEE" | awk '{print toupper(substr($0,1,1)) substr($0,2)}')" +if ! grep -q "CiphernodesCommitteeSize::$CAPITALIZED" "$COMMITTEE_RS"; then + fail "$COMMITTEE_RS does not define CiphernodesCommitteeSize::$CAPITALIZED. Rust and Noir disagree on the committee axis" +fi + +# 6. Parity matrices for every committee must match what `generate_parity_matrices` would +# write right now. Hand-edits to parity_*.nr would slip past every other check, so verify +# them by regenerating into a tempdir and diffing. On-disk files are kept `nargo fmt`-clean +# (see `scripts/lint-circuits.sh`), so we format the generator output before comparing. +# Skipped when the binary is unavailable (fresh clone before `cargo build`); the build step +# will re-emit them anyway. +GEN_BIN="target/release/generate_parity_matrices" +NOIR_LIB="circuits/lib" +format_parity_matrices_for_committee() { + local committee="$1" + local tmp="$2" + local variant live fresh backup formatted + local -a swapped_live=() + local -a swapped_backup=() + + _restore_swapped_parity_live() { + local i + for i in "${!swapped_live[@]}"; do + if [[ -f "${swapped_backup[$i]}" ]]; then + cp "${swapped_backup[$i]}" "${swapped_live[$i]}" + fi + done + } + + trap '_restore_swapped_parity_live' ERR + + for variant in insecure secure; do + live="$NOIR_LIB/src/configs/committee/$committee/parity_${variant}.nr" + fresh="$tmp/$committee/parity_${variant}.nr" + [[ -f "$live" && -f "$fresh" ]] || continue + backup="$tmp/$committee/parity_${variant}.live.bak" + formatted="$tmp/$committee/parity_${variant}.formatted.nr" + cp "$live" "$backup" + cp "$fresh" "$live" + swapped_live+=("$live") + swapped_backup+=("$backup") + done + + if ((${#swapped_live[@]} == 0)); then + trap - ERR + return 0 + fi + + if ! (cd "$NOIR_LIB" && nargo fmt) >/dev/null; then + _restore_swapped_parity_live + trap - ERR + return 1 + fi + + for variant in insecure secure; do + live="$NOIR_LIB/src/configs/committee/$committee/parity_${variant}.nr" + fresh="$tmp/$committee/parity_${variant}.nr" + backup="$tmp/$committee/parity_${variant}.live.bak" + formatted="$tmp/$committee/parity_${variant}.formatted.nr" + [[ -f "$backup" ]] || continue + cp "$live" "$formatted" + cp "$backup" "$live" + cp "$formatted" "$fresh" + done + + trap - ERR +} + +if [[ -x "$GEN_BIN" ]]; then + if ! command -v nargo >/dev/null 2>&1; then + echo " (skipping parity-matrix drift check: nargo not found. Install nargo to enable formatted parity comparison.)" >&2 + else + RAN_PARITY_CHECK=true + TMP=$(mktemp -d) + trap 'rm -rf "$TMP"' EXIT + # Mirror the committee dir layout so the bin can write into //. + for c in micro small medium; do + if [[ -d "circuits/lib/src/configs/committee/$c" ]]; then + mkdir -p "$TMP/$c" + fi + done + for c in micro small medium; do + [[ -d "$TMP/$c" ]] || continue + "$GEN_BIN" --committee "$c" --output-root "$TMP" >/dev/null + format_parity_matrices_for_committee "$c" "$TMP" + for variant in insecure secure; do + live="circuits/lib/src/configs/committee/$c/parity_${variant}.nr" + fresh="$TMP/$c/parity_${variant}.nr" + if [[ -f "$live" && -f "$fresh" ]] && ! diff -q "$live" "$fresh" >/dev/null; then + fail "$live drift vs generator output. Run: pnpm build:circuits --committee $c" + fi + done + done + fi +else + echo " (skipping parity-matrix drift check: $GEN_BIN not built. Run \`cargo build -p e3-zk-helpers --bin generate_parity_matrices --release\` to enable.)" >&2 +fi + +echo "✓ check:committee: $ACTIVE_COMMITTEE (H=$EXPECTED_H, T=$EXPECTED_T) consistent across active.nr, utils.ts$([ "$RAN_STAMP_CHECK" = true ] && echo ', .active-preset.json')$([ "$RAN_PARITY_CHECK" = true ] && echo ', parity_*.nr')" diff --git a/scripts/circuit-constants.ts b/scripts/circuit-constants.ts index 544c6f2a62..f4859ecd0f 100644 --- a/scripts/circuit-constants.ts +++ b/scripts/circuit-constants.ts @@ -56,3 +56,55 @@ export const PRESET_NOIR_CONFIG: Record = [CIRCUIT_PRESETS.INSECURE_512]: 'insecure', [CIRCUIT_PRESETS.SECURE_8192]: 'secure', } + +/** + * Committee sizes (matches Rust `CiphernodesCommitteeSize`). Selects the active + * leaf module under `circuits/lib/src/configs/committee/{name}/` that `committee::active` + * re-exports from. The wrapper Solidity verifiers (`BfvPkVerifier`, `BfvDecryptionVerifier`) + * must be deployed with `H` and `T` matching the active selection. + */ +export const CIRCUIT_COMMITTEES = { + MICRO: 'micro', + SMALL: 'small', + MEDIUM: 'medium', +} as const + +export type CircuitCommittee = (typeof CIRCUIT_COMMITTEES)[keyof typeof CIRCUIT_COMMITTEES] + +export const ALL_COMMITTEES: CircuitCommittee[] = [CIRCUIT_COMMITTEES.MICRO, CIRCUIT_COMMITTEES.SMALL, CIRCUIT_COMMITTEES.MEDIUM] + +/** + * `(N, T, H)` per committee. Mirrors `circuits/lib/src/configs/committee/{name}/mod.nr` + * and Rust `e3_zk_helpers::CiphernodesCommitteeSize::values()`. The build script writes + * `H` and `T` into `packages/enclave-contracts/scripts/utils.ts` so the EVM gas benchmark + * deploys verifiers with the matching public-input layout. + */ +export interface CommitteeParams { + n: number + t: number + h: number +} + +export const COMMITTEE_PARAMS: Record = { + [CIRCUIT_COMMITTEES.MICRO]: { n: 3, t: 1, h: 3 }, + [CIRCUIT_COMMITTEES.SMALL]: { n: 5, t: 2, h: 5 }, + [CIRCUIT_COMMITTEES.MEDIUM]: { n: 10, t: 4, h: 8 }, +} + +/** + * Every `(preset, committee)` pair is supported because the parity matrices are now regenerated + * automatically from the BFV preset's `QIS` and the committee's `(N, T)` by the + * `generate_parity_matrices` Rust binary, invoked from `scripts/build-circuits.ts` whenever + * the committee is set. The matrix files on disk are derived artifacts, not hand-tuned data. + * + * This constant is kept for future use (e.g. if a particular pair is ever known-broken at + * a higher level than the parity matrix) and currently returns the full Cartesian product. + */ +export const SUPPORTED_PRESET_COMMITTEE_PAIRS: ReadonlyArray<{ + preset: CircuitPreset + committee: CircuitCommittee +}> = ALL_PRESETS.flatMap((preset) => ALL_COMMITTEES.map((committee) => ({ preset, committee }))) + +export function isPresetCommitteeSupported(preset: CircuitPreset, committee: CircuitCommittee): boolean { + return SUPPORTED_PRESET_COMMITTEE_PAIRS.some((p) => p.preset === preset && p.committee === committee) +} diff --git a/scripts/generate-verifiers.ts b/scripts/generate-verifiers.ts index fba43940f0..00a2113877 100644 --- a/scripts/generate-verifiers.ts +++ b/scripts/generate-verifiers.ts @@ -37,7 +37,15 @@ import { execFileSync, execSync } from 'child_process' import { copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'fs' import { basename, join, resolve } from 'path' -import { ALL_GROUPS, ALL_PRESETS, CIRCUIT_GROUPS, type CircuitGroup } from './circuit-constants' +import { + ALL_COMMITTEES, + ALL_GROUPS, + ALL_PRESETS, + CIRCUIT_COMMITTEES, + CIRCUIT_GROUPS, + type CircuitCommittee, + type CircuitGroup, +} from './circuit-constants' // --------------------------------------------------------------------------- // Types & constants @@ -72,6 +80,16 @@ const LICENSE_HEADER = `// SPDX-License-Identifier: LGPL-3.0-only */ const CANONICAL_PRESET = 'insecure-512' +/** + * Canonical committee for the committed Honk Solidity verifiers under + * `contracts/verifiers/bfv/honk/`. The committee determines `H` and `T` of the + * `dkg_aggregator` / `decryption_aggregator` circuits — different committees compile + * to different recursive VKs, so each committee's verifiers must land in a separate + * directory to coexist on disk. `micro` is the development/CI default; other committees + * generate under `honk//`. + */ +const CANONICAL_COMMITTEE: CircuitCommittee = CIRCUIT_COMMITTEES.MICRO + interface CircuitInfo { name: string group: CircuitGroup @@ -95,6 +113,13 @@ interface GenerateOptions { check?: boolean /** BFV preset whose artifacts in `circuits/bin/` are used for generation/check. */ preset?: string + /** + * Committee whose `H`/`T` baked into the wrapper verifiers should be used. + * When unset, read from `circuits/bin/.active-preset.json`. Non-canonical + * committees land under `honk//` so they don't overwrite the + * committed canonical-committee `.sol` files. + */ + committee?: CircuitCommittee /** Override output directory (write mode only). Defaults to committed honk/ path. */ outputDir?: string } @@ -112,16 +137,37 @@ class VerifierGenerator { constructor(rootDir?: string, options: GenerateOptions = {}) { this.rootDir = rootDir ?? resolve(__dirname, '..') this.circuitsDir = join(this.rootDir, 'circuits', 'bin') - this.verifierDir = - options.outputDir !== undefined - ? resolve(options.outputDir) - : join(this.rootDir, 'packages', 'enclave-contracts', 'contracts', 'verifiers', 'bfv', 'honk') this.options = { groups: ALL_GROUPS, clean: false, compile: true, ...options, } + this.verifierDir = options.outputDir !== undefined ? resolve(options.outputDir) : this.defaultVerifierDir(this.targetCommittee()) + } + + private defaultVerifierDir(committee: CircuitCommittee): string { + const honkBase = join(this.rootDir, 'packages', 'enclave-contracts', 'contracts', 'verifiers', 'bfv', 'honk') + // Non-canonical committees go under honk// so canonical-committee verifiers + // committed to git aren't clobbered. + return committee !== CANONICAL_COMMITTEE ? join(honkBase, committee) : honkBase + } + + /** Reads `.active-preset.json::committee` or falls back to the canonical committee. */ + private targetCommittee(): CircuitCommittee { + if (this.options.committee) return this.options.committee + const activePath = join(this.circuitsDir, '.active-preset.json') + if (existsSync(activePath)) { + try { + const v = JSON.parse(readFileSync(activePath, 'utf-8')) as { committee?: string } + if (v.committee && (ALL_COMMITTEES as string[]).includes(v.committee)) { + return v.committee as CircuitCommittee + } + } catch { + // fall through + } + } + return CANONICAL_COMMITTEE } async generate(): Promise { @@ -133,18 +179,22 @@ class VerifierGenerator { const targetPreset = this.targetPreset() + const targetCommittee = this.targetCommittee() + if (!this.options.dryRun) { this.assertPresetBuilt(targetPreset) this.assertCircuitsBinActivePreset(targetPreset) + this.assertCircuitsBinActiveCommittee(targetCommittee) } - // Committed Honk `.sol` files are pinned to CANONICAL_PRESET only. Secure (and other) - // benchmark modes still need `circuits/bin/` aligned to their preset for integration + gas replay. - if (this.options.check && targetPreset !== CANONICAL_PRESET) { + // Committed Honk `.sol` files are pinned to (CANONICAL_PRESET, CANONICAL_COMMITTEE). Any other + // (preset, committee) is a per-deploy variant — generated under honk// (or skipped + // entirely in --check mode since there's no canonical to diff against). + if (this.options.check && (targetPreset !== CANONICAL_PRESET || targetCommittee !== CANONICAL_COMMITTEE)) { console.log( - `\n✅ Preset '${targetPreset}' is built and active in circuits/bin.\n` + - ` Committed Honk verifiers in git are pinned to '${CANONICAL_PRESET}' only; skipping .sol diff.\n` + - ` Benchmark gas replay deploys fresh aggregator verifiers from circuits/bin at runtime.\n`, + `\n✅ (preset=${targetPreset}, committee=${targetCommittee}) is built and active in circuits/bin.\n` + + ` Committed Honk verifiers are pinned to (${CANONICAL_PRESET}, ${CANONICAL_COMMITTEE}); skipping .sol diff.\n` + + ` Benchmark / deploy flows generate fresh aggregator verifiers under honk/${targetCommittee}/ at runtime.\n`, ) return } @@ -569,6 +619,34 @@ class VerifierGenerator { } console.log(` ✓ circuits/bin active preset matches '${preset}'.\n`) } + + /** + * Mirror of `assertCircuitsBinActivePreset` for the committee axis. When the active + * committee on disk doesn't match the one we're generating for, the resulting `.sol` + * verifiers would bake in the wrong H/T and silently disagree with on-chain calldata. + */ + private assertCircuitsBinActiveCommittee(committee: CircuitCommittee): void { + const activePath = join(this.circuitsDir, '.active-preset.json') + if (!existsSync(activePath)) return // already errored in preset check; nothing extra to say + let active: { committee?: string } = {} + try { + active = JSON.parse(readFileSync(activePath, 'utf-8')) + } catch { + return + } + if (!active.committee) { + console.warn(` ⚠️ ${activePath} has no \`committee\` field (older build). Skipping committee cross-check.\n`) + return + } + if (active.committee !== committee) { + throw new Error( + `circuits/bin was last built for committee '${active.committee}', but this run targets '${committee}'.\n` + + ` Rebuild with:\n` + + ` pnpm build:circuits --committee ${committee}`, + ) + } + console.log(` ✓ circuits/bin active committee matches '${committee}'.\n`) + } } // --------------------------------------------------------------------------- @@ -608,6 +686,17 @@ async function main() { process.exit(1) } options.preset = value + } else if (arg === '--committee') { + const value = args[++i] + if (!value || value.startsWith('--')) { + console.error(`Error: --committee requires a value (${ALL_COMMITTEES.join('|')})`) + process.exit(1) + } + if (!(ALL_COMMITTEES as readonly string[]).includes(value)) { + console.error(`Error: unknown committee '${value}'. Expected one of: ${ALL_COMMITTEES.join(', ')}`) + process.exit(1) + } + options.committee = value as CircuitCommittee } else if (arg === '--output-dir') { const value = args[++i] if (!value || value.startsWith('--')) { @@ -653,6 +742,9 @@ Options: --preset BFV preset for circuits/bin (insecure-512 | secure-8192). Defaults to insecure-512. With --check and a non-insecure preset, only verifies dist/ + circuits/bin alignment (no .sol diff). + --committee Committee size (micro | small | medium). When omitted, read from + circuits/bin/.active-preset.json. Non-canonical committees write + to honk// so committed canonical files are not clobbered. --output-dir Write generated verifiers here instead of the committed honk/ dir. --write Write/overwrite committed verifiers (this is the default when neither --check nor --write is passed).