diff --git a/packages/compute_provider/.gitignore b/packages/compute_provider/.gitignore new file mode 100644 index 00000000..9f970225 --- /dev/null +++ b/packages/compute_provider/.gitignore @@ -0,0 +1 @@ +target/ \ No newline at end of file diff --git a/packages/compute_provider/Cargo.lock b/packages/compute_provider/Cargo.lock new file mode 100644 index 00000000..cddfd1c0 --- /dev/null +++ b/packages/compute_provider/Cargo.lock @@ -0,0 +1,572 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "ark-bn254" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown", + "itertools", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "compute-provider" +version = "0.1.0" +dependencies = [ + "ark-bn254", + "ark-ff", + "hex", + "lean-imt", + "light-poseidon", + "num-bigint", + "num-traits", + "rayon", + "serde", + "sha3", +] + +[[package]] +name = "cpufeatures" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lean-imt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e72b0683df18378c72877bfc0a1befc69b009f43e8f0ef3689f0cc98f067222" + +[[package]] +name = "libc" +version = "0.2.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "light-poseidon" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" +dependencies = [ + "ark-bn254", + "ark-ff", + "num-bigint", + "thiserror", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] diff --git a/packages/compute_provider/Cargo.toml b/packages/compute_provider/Cargo.toml new file mode 100644 index 00000000..6b2a6b19 --- /dev/null +++ b/packages/compute_provider/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "compute-provider" +version = "0.1.0" +edition = "2021" + +[dependencies] +serde = { version = "1.0", features = ["derive", "std"] } +lean-imt = "0.1.0" +sha3 = "0.10.8" +num-bigint = "0.4" +num-traits = "0.2" +hex = "0.4" +light-poseidon = "0.2.0" +ark-ff = "0.4.2" +ark-bn254 = "0.4.0" +rayon = "1.10.0" diff --git a/packages/compute_provider/Readme.md b/packages/compute_provider/Readme.md new file mode 100644 index 00000000..c8c60508 --- /dev/null +++ b/packages/compute_provider/Readme.md @@ -0,0 +1,87 @@ +# FHE Compute Manager + +This project provides a flexible and efficient framework for managing Secure Programs (SP) of the [Enclave Protocol](enclave.gg). It supports both sequential and parallel processing, with the ability to integrate various compute providers. + +## Features + +- Support for both sequential and parallel FHE computations +- Flexible integration of different compute providers +- Merkle tree generation for input verification +- Ciphertext hashing for output verification + +## Installation + +To use this library, add it to your `Cargo.toml`: + +```toml +[dependencies] +compute-provider = { git = "https://github.com/gnosisguild/enclave.git", path = "packages/compute_provider"} +``` + +## Usage + +To use the library, follow these steps: + +1. Create an instance of the `ComputeManager` with your desired configuration. +2. Call the `start` method to begin the computation process. +3. The method will return the computed ciphertext and the corresponding proof. + +```rust +use anyhow::Result; +use compute_provider::{ComputeInput, ComputeManager, ComputeProvider, ComputeResult, FHEInputs}; +use voting_core::fhe_processor; + +// Define your Risc0Provider struct and implement the ComputeProvider trait +pub fn run_compute(params: FHEInputs) -> Result<(Risc0Output, Vec)> { + let risc0_provider = Risc0Provider; + let mut provider = ComputeManager::new(risc0_provider, params, fhe_processor, false, None); + let output = provider.start(); + Ok(output) +} +``` + + +## Risc0 Example + +Here's a more detailed example of how to use the Compute Manager with Risc0: + +```rust +use compute_provider::{ComputeInput, ComputeManager, ComputeProvider, ComputeResult, FHEInputs}; +use methods::VOTING_ELF; +use risc0_ethereum_contracts::groth16; +use risc0_zkvm::{default_prover, ExecutorEnv, ProverOpts, VerifierContext}; +use serde::{Deserialize, Serialize}; + +pub struct Risc0Provider; +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Risc0Output { + pub result: ComputeResult, + pub seal: Vec, +} + +impl ComputeProvider for Risc0Provider { + type Output = Risc0Output; + fn prove(&self, input: &ComputeInput) -> Self::Output { + // Implementation details + } +} +pub fn run_compute(params: FHEInputs) -> Result<(Risc0Output, Vec)> { + let risc0_provider = Risc0Provider; + let mut provider = ComputeManager::new(risc0_provider, params, fhe_processor, false, None); + let output: (Risc0Output, Vec) = provider.start(); + Ok(output) +} +``` + + +This example demonstrates how to create a Risc0Provider, use it with the ComputeManager, and measure the execution time of the computation. + +## Configuration + +The `ComputeManager::new()` function takes several parameters: + +- `provider`: An instance of your compute provider (e.g., `Risc0Provider`) +- `fhe_inputs`: The FHE inputs for the computation +- `fhe_processor`: A function to process the FHE inputs +- `use_parallel`: A boolean indicating whether to use parallel processing +- `batch_size`: An optional batch size for parallel processing, must be a power of 2 \ No newline at end of file diff --git a/packages/compute_provider/src/ciphertext_output.rs b/packages/compute_provider/src/ciphertext_output.rs new file mode 100644 index 00000000..1f32758f --- /dev/null +++ b/packages/compute_provider/src/ciphertext_output.rs @@ -0,0 +1,18 @@ +use crate::compute_input::ComputeInput; + +pub trait ComputeProvider { + type Output: Send + Sync; + + fn prove( + &self, + input: &ComputeInput + ) -> Self::Output; +} + + +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] +pub struct ComputeResult { + pub ciphertext_hash: Vec, + pub params_hash: Vec, + pub merkle_root: Vec, +} \ No newline at end of file diff --git a/packages/compute_provider/src/compute_input.rs b/packages/compute_provider/src/compute_input.rs new file mode 100644 index 00000000..6d43864a --- /dev/null +++ b/packages/compute_provider/src/compute_input.rs @@ -0,0 +1,41 @@ +use crate::ciphertext_output::ComputeResult; +use crate::merkle_tree::MerkleTree; +use sha3::{Digest, Keccak256}; + +pub type FHEProcessor = fn(&FHEInputs) -> Vec; + +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] +pub struct FHEInputs { + pub ciphertexts: Vec<(Vec, u64)>, + pub params: Vec, +} + +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] +pub struct ComputeInput { + pub fhe_inputs: FHEInputs, + pub ciphertext_hash: Vec, + pub leaf_hashes: Vec, +} + +impl ComputeInput { + pub fn process(&self, fhe_processor: FHEProcessor) -> ComputeResult { + let processed_ciphertext = (fhe_processor)(&self.fhe_inputs); + let processed_hash = Keccak256::digest(&processed_ciphertext).to_vec(); + let params_hash = Keccak256::digest(&self.fhe_inputs.params).to_vec(); + + assert_eq!(processed_hash, self.ciphertext_hash, "Ciphertext hash mismatch"); + + let merkle_root = MerkleTree { + leaf_hashes: self.leaf_hashes.clone(), + } + .build_tree() + .root() + .unwrap(); + + ComputeResult { + ciphertext_hash: processed_hash, + params_hash, + merkle_root: hex::decode(merkle_root).unwrap(), + } + } +} diff --git a/packages/compute_provider/src/compute_manager.rs b/packages/compute_provider/src/compute_manager.rs new file mode 100644 index 00000000..3e2a37dc --- /dev/null +++ b/packages/compute_provider/src/compute_manager.rs @@ -0,0 +1,127 @@ +use crate::ciphertext_output::ComputeProvider; +use crate::compute_input::{ComputeInput, FHEInputs}; +use crate::merkle_tree::MerkleTree; +use crate::FHEProcessor; +use rayon::prelude::*; +use sha3::{Digest, Keccak256}; +use std::sync::Arc; + +pub struct ComputeManager

+where + P: ComputeProvider + Send + Sync, +{ + input: ComputeInput, + provider: P, + processor: FHEProcessor, + use_parallel: bool, + batch_size: Option, +} + +impl

ComputeManager

+where + P: ComputeProvider + Send + Sync, +{ + pub fn new( + provider: P, + fhe_inputs: FHEInputs, + fhe_processor: FHEProcessor, + use_parallel: bool, + batch_size: Option, + ) -> Self { + Self { + provider, + input: ComputeInput { + fhe_inputs, + ciphertext_hash: Vec::new(), + leaf_hashes: Vec::new(), + }, + processor: fhe_processor, + use_parallel, + batch_size, + } + } + + pub fn start(&mut self) -> (P::Output, Vec) { + if self.use_parallel { + self.start_parallel() + } else { + self.start_sequential() + } + } + + fn start_sequential(&mut self) -> (P::Output, Vec) { + let mut tree_handler = MerkleTree::new(); + tree_handler.compute_leaf_hashes(&self.input.fhe_inputs.ciphertexts); + self.input.leaf_hashes = tree_handler.leaf_hashes.clone(); + + // Compute the ciphertext + let ciphertext = (self.processor)(&self.input.fhe_inputs); + + // Compute the hash of the ciphertext + self.input.ciphertext_hash = Keccak256::digest(&ciphertext).to_vec(); + + (self.provider.prove(&self.input), ciphertext) + } + + fn start_parallel(&self) -> (P::Output, Vec) { + let batch_size = self.batch_size.unwrap_or(2); + + let ciphertexts = Arc::new(self.input.fhe_inputs.ciphertexts.clone()); + let params = Arc::new(self.input.fhe_inputs.params.clone()); + + let chunks: Vec, u64)>> = ciphertexts + .chunks(batch_size) + .map(|chunk| chunk.to_vec()) + .collect(); + + let tally_results: Vec<(P::Output, Vec, String)> = chunks + .into_par_iter() + .map(|chunk| { + let mut tree_handler = MerkleTree::new(); + tree_handler.compute_leaf_hashes(&chunk); + let merkle_root = tree_handler.build_tree().root().unwrap(); + + let fhe_inputs = FHEInputs { + ciphertexts: chunk.clone(), + params: params.to_vec(), + }; + + let ciphertext = (self.processor)(&fhe_inputs); + let ciphertext_hash = Keccak256::digest(&ciphertext).to_vec(); + + let input = ComputeInput { + fhe_inputs, + ciphertext_hash, + leaf_hashes: tree_handler.leaf_hashes.clone(), + }; + + (self.provider.prove(&input), ciphertext, merkle_root) + }) + .collect(); + + // The leaf hashes are the hashes of the merkle roots of the parallel trees + let leaf_hashes: Vec = tally_results + .iter() + .map(|result| result.2.clone()) + .collect(); + + let fhe_inputs = FHEInputs { + ciphertexts: tally_results + .iter() + .map(|result| (result.1.clone(), 0 as u64)) // The index is not used for the final computation in the parallel case + .collect(), + params: params.to_vec(), + }; + + let ciphertext = (self.processor)(&fhe_inputs); + let ciphertext_hash = Keccak256::digest(&ciphertext).to_vec(); + + let final_input = ComputeInput { + fhe_inputs, + ciphertext_hash, + leaf_hashes: leaf_hashes.clone(), + }; + + (self.provider.prove(&final_input), ciphertext) + } +} diff --git a/packages/compute_provider/src/lib.rs b/packages/compute_provider/src/lib.rs new file mode 100644 index 00000000..1360e93d --- /dev/null +++ b/packages/compute_provider/src/lib.rs @@ -0,0 +1,8 @@ +mod compute_input; +mod compute_manager; +mod merkle_tree; +mod ciphertext_output; + +pub use compute_manager::*; +pub use compute_input::*; +pub use ciphertext_output::*; \ No newline at end of file diff --git a/packages/compute_provider/src/merkle_tree.rs b/packages/compute_provider/src/merkle_tree.rs new file mode 100644 index 00000000..9b759aef --- /dev/null +++ b/packages/compute_provider/src/merkle_tree.rs @@ -0,0 +1,62 @@ +use sha3::{Digest, Keccak256}; +use num_bigint::BigUint; +use num_traits::Num; +use ark_bn254::Fr; +use ark_ff::{BigInt, BigInteger}; +use light_poseidon::{Poseidon, PoseidonHasher}; +use lean_imt::LeanIMT; +use std::str::FromStr; + +pub struct MerkleTree { + pub leaf_hashes: Vec, +} + +impl MerkleTree { + pub fn new() -> Self { + Self { + leaf_hashes: Vec::new(), + } + } + + pub fn compute_leaf_hashes(&mut self, data: &[(Vec, u64)]) { + for item in data { + let hex_output = hex::encode(Keccak256::digest(&item.0)); + let sanitized_hex = hex_output.trim_start_matches("0x"); + let numeric_value = BigUint::from_str_radix(sanitized_hex, 16) + .unwrap() + .to_string(); + let fr_element = Fr::from_str(&numeric_value).unwrap(); + let index_element = Fr::from_str(&item.1.to_string()).unwrap(); + let mut poseidon_instance = Poseidon::::new_circom(2).unwrap(); + let hash_bigint: BigInt<4> = poseidon_instance + .hash(&[fr_element, index_element]) + .unwrap() + .into(); + let hash = hex::encode(hash_bigint.to_bytes_be()); + self.leaf_hashes.push(hash); + } + } + + fn poseidon_hash(nodes: Vec) -> String { + let mut poseidon = Poseidon::::new_circom(2).unwrap(); + let mut field_elements = Vec::new(); + + for node in nodes { + let sanitized_node = node.trim_start_matches("0x"); + let numeric_str = BigUint::from_str_radix(sanitized_node, 16) + .unwrap() + .to_string(); + let field_repr = Fr::from_str(&numeric_str).unwrap(); + field_elements.push(field_repr); + } + + let result_hash: BigInt<4> = poseidon.hash(&field_elements).unwrap().into(); + hex::encode(result_hash.to_bytes_be()) + } + + pub fn build_tree(&self) -> LeanIMT { + let mut tree = LeanIMT::new(Self::poseidon_hash); + tree.insert_many(self.leaf_hashes.clone()).unwrap(); + tree + } +}