Skip to content

Commit

Permalink
refactor: refactoring into crates and adding nova, sp1 (#115)
Browse files Browse the repository at this point in the history
* feat(WIP): nova

* fix: not using struct variants in step enum

* removing dead code

* fuck this man what am i even doing

* feat: beginning of migration to jmt

* refactor: redis as JMT backend (temporarily)

* progress on JMT migration: removing lifetime annotations to own TreeReader

* build errors

* supernova

* fix some things

* write_batch

* failing test

* nova batch updates

* cargo fix imports

* removing unused deps

* adding pp serde

* updating cargo toml

* feat: playing around with supernova rehashing

* membership proof

* invalid witness length

* i give up

* restructuring to crates

* readding groth16 as new crate

* readding groth16 as new crate

* adding sp1 crate

* trimming deps

* readmes

* clippy

* readmes and clippy

* debugging storage.rs for jmt

* fixing tests

* patches

* clippy

---------

Co-authored-by: sebasti810 <spusch@outlook.de>
  • Loading branch information
distractedm1nd and sebasti810 authored Sep 11, 2024
1 parent d8e74ea commit 2967421
Show file tree
Hide file tree
Showing 48 changed files with 3,525 additions and 2,757 deletions.
3,069 changes: 1,039 additions & 2,030 deletions Cargo.lock

Large diffs are not rendered by default.

76 changes: 48 additions & 28 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[package]
[workspace.package]
name = "prism"
version = "0.1.0"
authors = [
Expand All @@ -13,66 +13,86 @@ license = "MIT"
keywords = ["crypto", "key-transparency"]
readme = "README.md"

[features]
default = []
key_transparency = []
[workspace]
members = [
"crates/prism",
"crates/common",
"crates/nova",
"crates/groth16",
"crates/errors",
"crates/sp1",
]
default-members = [
"crates/prism",
"crates/common",
"crates/nova",
"crates/groth16",
"crates/errors",
]
resolver = "2"

[dependencies]
[workspace.dependencies]
axum = "0.6"
borsh = { version = "1.5.1", features = ["derive"] }
tower-http = { version = "0.4", features = ["cors"] }
utoipa = { version = "3.3", features = ["axum_extras"] }
utoipa-swagger-ui = { version = "3.1", features = ["axum"] }
crypto-hash = "0.3.4"
async-trait = "0.1.68"
serde = { version = "1.0.151", features = ["derive"] }
serde_json = "1.0.79"
redis = "0.24.0"
actix-web = { version = "4.4.1" }
actix-cors = "0.7.0"
async-redis-session = "0.2.2"
ed25519-dalek = "2.1.0"
ed25519 = "2.2.0"
base64 = "0.22.0"
tokio = { version = "1.16.1", features = ["full"] }
reqwest = { version = "0.11.23", features = ["json"] }
ctrlc = "3.1.5"
num = "0.4.0"
bellman = "0.14.0"
pairing = "0.23.0"
jsonrpsee = { version = "0.22.2", features = ["ws-client"] }
bls12_381 = "0.8.0"
rand = "0.8.5"
rand07 = { package = "rand", version = "0.7.0" }
hex = "0.4.3"
ff = "0.13.0"
openssl = "0.10.66"
futures = "0.3"
lazy_static = "1.4"
colored = "2.0.0"
log = "0.4"
pretty_env_logger = "0.5.0"
clap = { version = "4.3.2", features = ["derive"] }
config = "0.14.0"
fs2 = "0.4.3"
thiserror = "1.0.62"
indexed-merkle-tree = "0.6.2"
dotenvy = "0.15.7"
ahash = "0.8.7"
celestia-rpc = "0.2.0"
celestia-types = "0.2.0"
mockall = "0.12.1"
keystore-rs = "0.1.0"
pyroscope = "0.5.7"
pyroscope_pprofrs = "0.2.7"
toml = "0.8.14"
dirs = "5.0.1"
anyhow = "1.0.44"
jmt = { version = "0.10.0", features = ["mocks"] }
bellpepper-core = { version = "0.4.0", default-features = false }
bellpepper = "0.4.1"
itertools = "0.13.0" # zip_eq
arecibo = "0.2.0"
sha2 = "0.10.8"
auto_impl = "1.2.0"
bincode = "1.3.3"
blake2 = "0.10.6"
sp1-zkvm = { version = "1.2.0" }
prism-common = { path = "crates/common" }
prism-nova = { path = "crates/nova" }
prism-errors = { path = "crates/errors" }
prism-main = { path = "crates/prism" }
prism-groth16 = { path = "crates/groth16" }
sp1-helper = "1.2.0"

[patch.crates-io]
sha2-v0-10-8 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", branch = "patch-sha2-v0.10.8" }
arecibo = { git = "https://github.com/deltadevsde/arecibo" }
jmt = { git = "https://github.com/deltadevsde/jmt", branch = "rehashing-circuit", features = [
"mocks",
] }

[dev-dependencies]
serial_test = "3.1.1"
criterion = "0.5.1"
# [workspace.dev-dependencies]
# serial_test = "3.1.1"
# criterion = "0.5.1"

[[bench]]
name = "zk_benchmarks"
harness = false
# [[bench]]
# name = "zk_benchmarks"
# harness = false
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

## What is Prism?

Prism is a decentralized key transparency protocol, strongly inspired by the paper [Tzialla et. al](https://eprint.iacr.org/2021/1263.pdf), leveraging zkSNARKs to enable trust-minimized verification of E2EE services via WASM light clients. This eliminates the possibility for hidden backdoors in E2EE services through a user-verifiable key management system. It uses transparency dictionaries under the hood, offering a generalized solution for managing a label-value map in environments where the service maintaining the map is not completely trusted.
Prism is a decentralized key transparency protocol, first inspired by the paper [Tzialla et. al](https://eprint.iacr.org/2021/1263.pdf), leveraging zkSNARKs to enable trust-minimized verification of E2EE services via WASM light clients. This eliminates the possibility for hidden backdoors in E2EE services through a user-verifiable key management system. It uses transparency dictionaries under the hood, offering a generalized solution for managing a label-value map in environments where the service maintaining the map is not completely trusted.

Prism provides the first key-transparency solution to enable automatic verification of the service provider. This is achieved by providing constant size succinct proofs to WASM light clients over a data availbility layer. The system is designed to be efficient, scalable and secure, making it suitable for a wide range of applications.

Expand All @@ -30,6 +30,9 @@ The project is still in the early development phase, has not been audited, and i

Due to this ongoing development work, changes are still being made that may affect existing functionalities.

## Circuits
We are currently experimenting with various proof systems and have handwritten groth16 and supernova circuits to handle the epoch proofs. We are also experimenting with SP1 as an alternative, which you can find in the `prism-sp1` crate.

## Installation

### Prerequisites
Expand Down
27 changes: 13 additions & 14 deletions benches/zk_benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use indexed_merkle_tree::{
tree::{IndexedMerkleTree, Proof},
Hash,
};
use prism::{circuits::BatchMerkleProofCircuit, utils::validate_epoch};
use rand::Rng;
use std::time::Duration;

Expand Down Expand Up @@ -56,13 +55,13 @@ fn bench_proof_generation(c: &mut Criterion) {
let (_, proofs, prev_commitment, current_commitment) =
setup_tree_and_proofs(*tree_size, *batch_size);
b.iter(|| {
let circuit = BatchMerkleProofCircuit::new(
black_box(&prev_commitment),
black_box(&current_commitment),
black_box(proofs.clone()),
)
.unwrap();
let _ = circuit.create_and_verify_snark();
// let circuit = BatchMerkleProofCircuit::new(
// black_box(&prev_commitment),
// black_box(&current_commitment),
// black_box(proofs.clone()),
// )
// .unwrap();
// let _ = circuit.create_and_verify_snark();
});
},
);
Expand All @@ -85,17 +84,17 @@ fn bench_proof_verification(c: &mut Criterion) {
|b, &(tree_size, batch_size)| {
let (_, proofs, prev_commitment, current_commitment) =
setup_tree_and_proofs(*tree_size, *batch_size);
let circuit =
BatchMerkleProofCircuit::new(&prev_commitment, &current_commitment, proofs)
.unwrap();
let (proof, verifying_key) = circuit.create_and_verify_snark().unwrap();
// let circuit =
// BatchMerkleProofCircuit::new(&prev_commitment, &current_commitment, proofs)
// .unwrap();
// let (proof, verifying_key) = circuit.create_and_verify_snark().unwrap();
b.iter(|| {
let _ = validate_epoch(
/* let _ = validate_epoch(
black_box(&prev_commitment),
black_box(&current_commitment),
black_box(proof.clone()),
black_box(verifying_key.clone()),
);
); */
});
},
);
Expand Down
18 changes: 18 additions & 0 deletions crates/common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "prism-common"
version.workspace = true
edition.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true

[dependencies]
anyhow.workspace = true
bls12_381.workspace = true
borsh.workspace = true
jmt.workspace = true
serde.workspace = true
hex.workspace = true
sha2.workspace = true
blake2.workspace = true
celestia-types.workspace = true
158 changes: 158 additions & 0 deletions crates/common/src/hashchain.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
use anyhow::{bail, Result};
use borsh::{BorshDeserialize, BorshSerialize};
use jmt::KeyHash;
use serde::{Deserialize, Serialize};
use std::ops::{Deref, DerefMut};

use crate::{
operation::{AccountSource, Operation},
tree::{hash, Digest, Hasher},
};

#[derive(Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, Debug, PartialEq)]
pub struct Hashchain {
pub id: String,
pub entries: Vec<HashchainEntry>,
}

impl IntoIterator for Hashchain {
type Item = HashchainEntry;
type IntoIter = std::vec::IntoIter<Self::Item>;

fn into_iter(self) -> Self::IntoIter {
self.entries.into_iter()
}
}

impl<'a> IntoIterator for &'a Hashchain {
type Item = &'a HashchainEntry;
type IntoIter = std::slice::Iter<'a, HashchainEntry>;

fn into_iter(self) -> Self::IntoIter {
self.entries.iter()
}
}

impl<'a> IntoIterator for &'a mut Hashchain {
type Item = &'a mut HashchainEntry;
type IntoIter = std::slice::IterMut<'a, HashchainEntry>;

fn into_iter(self) -> Self::IntoIter {
self.entries.iter_mut()
}
}

impl Deref for Hashchain {
type Target = Vec<HashchainEntry>;

fn deref(&self) -> &Self::Target {
&self.entries
}
}

impl DerefMut for Hashchain {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.entries
}
}

impl Hashchain {
pub fn new(id: String) -> Self {
Self {
id,
entries: Vec::new(),
}
}

pub fn iter(&self) -> std::slice::Iter<'_, HashchainEntry> {
self.entries.iter()
}

pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, HashchainEntry> {
self.entries.iter_mut()
}

pub fn create_account(&mut self, value: String, source: AccountSource) -> Result<Digest> {
let operation = Operation::CreateAccount {
id: self.id.clone(),
value,
source,
};
self.push(operation)
}

pub fn get(&self, idx: usize) -> &HashchainEntry {
&self.entries[idx]
}

pub fn push(&mut self, operation: Operation) -> Result<Digest> {
if operation.id() != self.id {
bail!("Operation ID does not match Hashchain ID");
}

let previous_hash = self
.entries
.last()
.map_or(Digest::new([0u8; 32]), |entry| entry.hash);

let entry = HashchainEntry::new(operation, previous_hash);
self.entries.push(entry.clone());

Ok(entry.hash)
}

// TODO: Obviously, this needs to be authenticated by an existing key.
pub fn add(&mut self, value: String) -> Result<Digest> {
let operation = Operation::Add {
id: self.id.clone(),
value,
};
self.push(operation)
}

pub fn revoke(&mut self, value: String) -> Result<Digest> {
let operation = Operation::Revoke {
id: self.id.clone(),
value,
};
self.push(operation)
}

pub fn get_keyhash(&self) -> KeyHash {
KeyHash::with::<Hasher>(self.id.clone())
}

pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}

pub fn len(&self) -> usize {
self.entries.len()
}
}

#[derive(Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, Debug, PartialEq)]
// A [`HashchainEntry`] represents a single entry in an account's hashchain.
// The value in the leaf of the corresponding account's node in the IMT is the hash of the last node in the hashchain.
pub struct HashchainEntry {
pub hash: Digest,
pub previous_hash: Digest,
pub operation: Operation,
}

impl HashchainEntry {
pub fn new(operation: Operation, previous_hash: Digest) -> Self {
let hash = {
let mut data = Vec::new();
data.extend_from_slice(operation.to_string().as_bytes());
data.extend_from_slice(previous_hash.as_ref());
// TODO: replace with sha256 after JMT complete
hash(&data)
};
Self {
hash,
previous_hash,
operation,
}
}
}
3 changes: 3 additions & 0 deletions crates/common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod hashchain;
pub mod operation;
pub mod tree;
Loading

0 comments on commit 2967421

Please sign in to comment.