Skip to content

Commit fcbb881

Browse files
readding groth16 as new crate
1 parent b03b8eb commit fcbb881

File tree

15 files changed

+1249
-29
lines changed

15 files changed

+1249
-29
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/errors/Cargo.toml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
[package]
2+
name = "prism-errors"
3+
version.workspace = true
4+
edition.workspace = true
5+
license.workspace = true
6+
homepage.workspace = true
7+
repository.workspace = true
8+
9+
[dependencies]
10+
axum = { workspace = true }
11+
borsh = { workspace = true }
12+
tower-http = { workspace = true }
13+
utoipa = { workspace = true }
14+
utoipa-swagger-ui = { workspace = true }
15+
async-trait = { workspace = true }
16+
serde = { workspace = true }
17+
serde_json = { workspace = true }
18+
redis = { workspace = true }
19+
ed25519-dalek = { workspace = true }
20+
ed25519 = { workspace = true }
21+
base64 = { workspace = true }
22+
tokio = { workspace = true }
23+
bellman = { workspace = true }
24+
bls12_381 = { workspace = true }
25+
rand = { workspace = true }
26+
hex = { workspace = true }
27+
ff = { workspace = true }
28+
log = { workspace = true }
29+
pretty_env_logger = { workspace = true }
30+
clap = { workspace = true }
31+
config = { workspace = true }
32+
thiserror = { workspace = true }
33+
indexed-merkle-tree = { workspace = true }
34+
dotenvy = { workspace = true }
35+
celestia-rpc = { workspace = true }
36+
celestia-types = { workspace = true }
37+
mockall = { workspace = true }
38+
keystore-rs = { workspace = true }
39+
toml = { workspace = true }
40+
dirs = { workspace = true }
41+
anyhow = { workspace = true }
42+
jmt = { workspace = true, path = "../jmt", features = ["mocks"] }
43+
sha2 = { workspace = true }
44+
auto_impl = { workspace = true }
45+
prism-common = { workspace = true }
46+
47+
[patch.crates-io]
48+
sha2-v0-9-8 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", branch = "patch-sha2-v0.9.8" }
49+
sha2-v0-10-6 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", branch = "patch-sha2-v0.10.6" }
50+
sha2-v0-10-8 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", branch = "patch-sha2-v0.10.8" }
51+
52+
[dev-dependencies]
53+
serial_test = "3.1.1"
54+
criterion = "0.5.1"
55+
56+
# [[bench]]
57+
# name = "zk_benchmarks"
58+
# harness = false

crates/errors/src/lib.rs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
use anyhow::Error as AnyhowError;
2+
use ed25519_dalek::SignatureError;
3+
use thiserror::Error;
4+
5+
#[derive(Error, Debug)]
6+
pub enum PrismError {
7+
#[error(transparent)]
8+
General(#[from] GeneralError),
9+
#[error(transparent)]
10+
Database(#[from] DatabaseError),
11+
#[error(transparent)]
12+
DataAvailability(#[from] DataAvailabilityError),
13+
#[error(transparent)]
14+
Proof(#[from] ProofError),
15+
#[error("config error: {0}")]
16+
ConfigError(String),
17+
#[error(transparent)]
18+
Other(#[from] AnyhowError),
19+
}
20+
21+
// general reusable errors
22+
#[derive(Error, Debug)]
23+
pub enum GeneralError {
24+
#[error("parsing: {0}")]
25+
ParsingError(String),
26+
#[error("creating blob object: {0}")]
27+
BlobCreationError(String),
28+
#[error("encoding: {0}")]
29+
EncodingError(String),
30+
#[error("decoding: {0}")]
31+
DecodingError(String),
32+
#[error("missing argument: {0}")]
33+
MissingArgumentError(String),
34+
#[error("invalid public key")]
35+
InvalidPublicKey,
36+
#[error(transparent)]
37+
InvalidSignature(#[from] SignatureError),
38+
#[error("starting webserver")]
39+
WebserverError,
40+
#[error("initializing service: {0}")]
41+
InitializationError(String),
42+
}
43+
44+
#[derive(Error, Debug)]
45+
pub enum DatabaseError {
46+
#[error("acquiring database lock")]
47+
LockError,
48+
#[error("retrieving keys from {0} dictionary")]
49+
KeysError(String),
50+
#[error("{0} not found")]
51+
NotFoundError(String),
52+
#[error("retreiving input order list")]
53+
GetInputOrderError,
54+
#[error("reading {0} from database")]
55+
ReadError(String),
56+
#[error("writing {0} to database")]
57+
WriteError(String),
58+
#[error("deleting {0} from database")]
59+
DeleteError(String),
60+
#[error(transparent)]
61+
GeneralError(#[from] GeneralError),
62+
#[error("connecting to database: {0}")]
63+
ConnectionError(String),
64+
#[error("initializing database: {0}")]
65+
InitializationError(String),
66+
}
67+
68+
#[derive(Error, Debug)]
69+
pub enum DataAvailabilityError {
70+
#[error("initializing: {0}")]
71+
InitializationError(String),
72+
#[error("data channel is closed")]
73+
ChannelClosed,
74+
#[error("da networking error: {0}")]
75+
NetworkError(String),
76+
#[error("retrieving data at height {0}: {1}")]
77+
DataRetrievalError(u64, String),
78+
#[error("submitting epoch to da layer: {0}")]
79+
SubmissionError(String),
80+
#[error("setting new sync target: {0}")]
81+
SyncTargetError(String),
82+
#[error("receiving message on channel")]
83+
ChannelReceiveError,
84+
#[error(transparent)]
85+
GeneralError(#[from] GeneralError),
86+
}
87+
88+
#[derive(Error, Debug)]
89+
pub enum ProofError {
90+
#[error("generating proof: {0}")]
91+
GenerationError(String),
92+
#[error("verifying proof: {0}")]
93+
VerificationError(String),
94+
#[error("deserializing G1Affine point")]
95+
G1AffineDeserializationError,
96+
#[error("unpacking proof components: {0}")]
97+
ProofUnpackError(String),
98+
#[error("invalid proof format")]
99+
InvalidFormatError,
100+
}

crates/groth16/Cargo.toml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
[package]
2+
name = "prism-groth16"
3+
version.workspace = true
4+
edition.workspace = true
5+
license.workspace = true
6+
homepage.workspace = true
7+
repository.workspace = true
8+
9+
[dependencies]
10+
axum = { workspace = true }
11+
borsh = { workspace = true }
12+
tower-http = { workspace = true }
13+
utoipa = { workspace = true }
14+
utoipa-swagger-ui = { workspace = true }
15+
async-trait = { workspace = true }
16+
serde = { workspace = true }
17+
serde_json = { workspace = true }
18+
redis = { workspace = true }
19+
ed25519-dalek = { workspace = true }
20+
ed25519 = { workspace = true }
21+
base64 = { workspace = true }
22+
tokio = { workspace = true }
23+
bellman = { workspace = true }
24+
bls12_381 = { workspace = true }
25+
rand = { workspace = true }
26+
hex = { workspace = true }
27+
ff = { workspace = true }
28+
log = { workspace = true }
29+
pretty_env_logger = { workspace = true }
30+
clap = { workspace = true }
31+
config = { workspace = true }
32+
thiserror = { workspace = true }
33+
indexed-merkle-tree = { workspace = true }
34+
dotenvy = { workspace = true }
35+
celestia-rpc = { workspace = true }
36+
celestia-types = { workspace = true }
37+
mockall = { workspace = true }
38+
keystore-rs = { workspace = true }
39+
toml = { workspace = true }
40+
dirs = { workspace = true }
41+
anyhow = { workspace = true }
42+
jmt = { workspace = true, path = "../jmt", features = ["mocks"] }
43+
sha2 = { workspace = true }
44+
auto_impl = { workspace = true }
45+
prism-common = { workspace = true }
46+
prism-errors = { workspace = true }
47+
48+
[patch.crates-io]
49+
sha2-v0-9-8 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", branch = "patch-sha2-v0.9.8" }
50+
sha2-v0-10-6 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", branch = "patch-sha2-v0.10.6" }
51+
sha2-v0-10-8 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", branch = "patch-sha2-v0.10.8" }
52+
53+
[dev-dependencies]
54+
serial_test = "3.1.1"
55+
criterion = "0.5.1"
56+
57+
# [[bench]]
58+
# name = "zk_benchmarks"
59+
# harness = false

crates/groth16/src/hashchain.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use anyhow::Result;
2+
use bellman::{Circuit, ConstraintSystem, SynthesisError};
3+
use bls12_381::Scalar;
4+
use indexed_merkle_tree::sha256_mod;
5+
use prism_common::hashchain::HashchainEntry;
6+
7+
/// HashChainEntryCircuit is a circuit that verifies that a given value is present in a hashchain.
8+
#[derive(Clone)]
9+
pub struct HashChainEntryCircuit {
10+
pub value: Scalar,
11+
/// Represents the hashchain in the form of a vector of Scalars.
12+
/// Each Scalar is sha256_mod(hashchain_entry.value())
13+
pub chain: Vec<Scalar>,
14+
}
15+
16+
impl HashChainEntryCircuit {
17+
pub fn create(value: &str, hashchain: Vec<HashchainEntry>) -> Result<HashChainEntryCircuit> {
18+
let hashed_value = sha256_mod(value.as_bytes());
19+
let parsed_value = hashed_value.try_into()?;
20+
let mut parsed_hashchain: Vec<Scalar> = vec![];
21+
for entry in hashchain {
22+
let hashed_entry_value = sha256_mod(entry.operation.value().as_bytes());
23+
parsed_hashchain.push(hashed_entry_value.try_into()?)
24+
}
25+
Ok(HashChainEntryCircuit {
26+
value: parsed_value,
27+
chain: parsed_hashchain,
28+
})
29+
}
30+
}
31+
32+
impl Circuit<Scalar> for HashChainEntryCircuit {
33+
fn synthesize<CS: ConstraintSystem<Scalar>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
34+
if self.chain.is_empty() {
35+
return Err(SynthesisError::AssignmentMissing);
36+
}
37+
38+
let provided_value = cs.alloc_input(|| "provided hashed value", || Ok(self.value))?;
39+
40+
for entry in self.chain {
41+
if entry == self.value {
42+
let found_value = cs.alloc(|| "found hashed value", || Ok(entry))?;
43+
// found_value * (1) = provided_value
44+
cs.enforce(
45+
|| "found value check",
46+
|lc| lc + found_value,
47+
|lc| lc + CS::one(),
48+
|lc| lc + provided_value,
49+
);
50+
return Ok(());
51+
}
52+
}
53+
Err(SynthesisError::Unsatisfiable)
54+
}
55+
}

crates/groth16/src/less_than.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use anyhow::Result;
2+
use bellman::{gadgets::boolean::Boolean, Circuit, ConstraintSystem, SynthesisError};
3+
use bls12_381::Scalar;
4+
use ff::PrimeFieldBits;
5+
6+
#[derive(Clone)]
7+
pub struct LessThanCircuit {
8+
a: Scalar,
9+
b: Scalar,
10+
}
11+
12+
impl LessThanCircuit {
13+
pub fn new(a: Scalar, b: Scalar) -> LessThanCircuit {
14+
LessThanCircuit { a, b }
15+
}
16+
}
17+
18+
impl Circuit<Scalar> for LessThanCircuit {
19+
fn synthesize<CS: ConstraintSystem<Scalar>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
20+
let a_bits = self.a.to_le_bits();
21+
let b_bits = self.b.to_le_bits();
22+
23+
let mut result = Boolean::constant(false);
24+
25+
// Iterate over the bits from most significant to least significant
26+
for i in (0..a_bits.len()).rev() {
27+
let a_val = Boolean::constant(a_bits[i]);
28+
let b_val = Boolean::constant(b_bits[i]);
29+
let not_a = a_val.not();
30+
let not_b = b_val.not();
31+
32+
// Check if bits are equal (both 1 or both 0)
33+
let a_and_b = Boolean::and(cs.namespace(|| format!("a_and_b_{}", i)), &a_val, &b_val)?;
34+
let not_a_and_not_b = Boolean::and(
35+
cs.namespace(|| format!("not_a_and_not_b_{}", i)),
36+
&not_a,
37+
&not_b,
38+
)?;
39+
40+
// If the bits are equal, continue to the next bit
41+
if not_a_and_not_b.get_value().unwrap() || a_and_b.get_value().unwrap() {
42+
continue;
43+
} else {
44+
// If bits differ: b > a if b_bit = 1 && a_bit = 0
45+
result = Boolean::and(
46+
cs.namespace(|| format!("b_and_not_a_{}", i)),
47+
&b_val,
48+
&not_a,
49+
)?;
50+
break;
51+
}
52+
}
53+
54+
// Enforce the constraint that the result is correct
55+
// If result is true, then a < b, otherwise a >= b
56+
// result * (1) = 1
57+
cs.enforce(
58+
|| "a < b",
59+
|_| result.lc(CS::one(), Scalar::one()),
60+
|lc| lc + CS::one(),
61+
|lc| lc + CS::one(),
62+
);
63+
64+
Ok(())
65+
}
66+
}

0 commit comments

Comments
 (0)