Skip to content

Commit a7e25ce

Browse files
committed
fix: started to replace borsh with bincode serialization, verify commitment consistency in SP1 proofs and FinalizedEpoch
1 parent 0f0c02a commit a7e25ce

File tree

12 files changed

+111
-43
lines changed

12 files changed

+111
-43
lines changed

Cargo.lock

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

crates/common/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ serde.workspace = true
1515
hex.workspace = true
1616
sha2.workspace = true
1717
celestia-types.workspace = true
18+
bincode.workspace = true

crates/common/src/hashchain.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use anyhow::{bail, Result};
2-
use borsh::{BorshDeserialize, BorshSerialize};
32
use jmt::KeyHash;
43
use serde::{Deserialize, Serialize};
54
use std::ops::{Deref, DerefMut};
@@ -9,7 +8,7 @@ use crate::{
98
tree::{hash, Digest, Hasher},
109
};
1110

12-
#[derive(Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, Debug, PartialEq)]
11+
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
1312
pub struct Hashchain {
1413
pub id: String,
1514
pub entries: Vec<HashchainEntry>,
@@ -129,9 +128,17 @@ impl Hashchain {
129128
pub fn len(&self) -> usize {
130129
self.entries.len()
131130
}
131+
132+
pub fn serialize(&self) -> Result<Vec<u8>> {
133+
bincode::serialize(self).map_err(anyhow::Error::from)
134+
}
135+
136+
pub fn deserialize(data: &[u8]) -> Result<Self> {
137+
bincode::deserialize(data).map_err(anyhow::Error::from)
138+
}
132139
}
133140

134-
#[derive(Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, Debug, PartialEq)]
141+
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
135142
// A [`HashchainEntry`] represents a single entry in an account's hashchain.
136143
// The value in the leaf of the corresponding account's node in the IMT is the hash of the last node in the hashchain.
137144
pub struct HashchainEntry {
@@ -155,4 +162,12 @@ impl HashchainEntry {
155162
operation,
156163
}
157164
}
165+
166+
pub fn serialize(&self) -> Result<Vec<u8>> {
167+
bincode::serialize(self).map_err(anyhow::Error::from)
168+
}
169+
170+
pub fn deserialize(data: &[u8]) -> Result<Self> {
171+
bincode::deserialize(data).map_err(anyhow::Error::from)
172+
}
158173
}

crates/common/src/operation.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
use anyhow::{Context, Result};
2-
use borsh::{BorshDeserialize, BorshSerialize};
32
use celestia_types::Blob;
43
use serde::{Deserialize, Serialize};
54
use std::fmt::Display;
65

7-
#[derive(Clone, BorshDeserialize, BorshSerialize, Serialize, Deserialize, Debug, PartialEq)]
6+
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
87
// An [`Operation`] represents a state transition in the system.
98
// In a blockchain analogy, this would be the full set of our transaction types.
109
pub enum Operation {
@@ -26,7 +25,7 @@ pub enum Operation {
2625
},
2726
}
2827

29-
#[derive(Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, Debug, PartialEq)]
28+
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
3029
// An [`AccountSource`] represents the source of an account. See adr-002 for more information.
3130
pub enum AccountSource {
3231
SignedBySequencer { signature: String },
@@ -61,7 +60,7 @@ impl TryFrom<&Blob> for Operation {
6160
type Error = anyhow::Error;
6261

6362
fn try_from(value: &Blob) -> Result<Self, Self::Error> {
64-
borsh::from_slice::<Self>(&value.data)
63+
bincode::deserialize(&value.data)
6564
.context(format!("Failed to decode blob into Operation: {value:?}"))
6665
}
6766
}

crates/common/src/tree.rs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use anyhow::{anyhow, bail, Context, Result};
2+
use bincode;
23
use bls12_381::Scalar;
3-
use borsh::{from_slice, to_vec, BorshDeserialize, BorshSerialize};
44
use jmt::{
55
proof::{SparseMerkleProof, UpdateMerkleProof},
66
storage::{NodeBatch, TreeReader, TreeUpdateBatch, TreeWriter},
@@ -22,9 +22,7 @@ pub fn hash(data: &[u8]) -> Digest {
2222
Digest(hasher.finalize())
2323
}
2424

25-
#[derive(
26-
Debug, Clone, BorshSerialize, BorshDeserialize, Serialize, Deserialize, PartialEq, Eq, Copy,
27-
)]
25+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Copy)]
2826
pub struct Digest([u8; 32]);
2927

3028
impl Digest {
@@ -116,7 +114,7 @@ impl Serialize for Proof {
116114
where
117115
S: serde::Serializer,
118116
{
119-
let bytes = borsh::to_vec(self).map_err(serde::ser::Error::custom)?;
117+
let bytes = bincode::serialize(self).map_err(serde::ser::Error::custom)?;
120118
serializer.serialize_bytes(&bytes)
121119
}
122120
}
@@ -132,28 +130,28 @@ impl<'de> Deserialize<'de> for Proof {
132130
type Value = Proof;
133131

134132
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
135-
formatter.write_str("a byte array containing Borsh-serialized Proof")
133+
formatter.write_str("a byte array containing serialized Proof")
136134
}
137135

138136
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
139137
where
140138
E: serde::de::Error,
141139
{
142-
Proof::try_from_slice(v).map_err(serde::de::Error::custom)
140+
bincode::deserialize(v).map_err(serde::de::Error::custom)
143141
}
144142
}
145143

146144
deserializer.deserialize_bytes(ProofVisitor)
147145
}
148146
}
149147

150-
#[derive(BorshSerialize, BorshDeserialize, Debug, Clone)]
148+
#[derive(Debug, Clone)]
151149
pub enum Proof {
152150
Update(UpdateProof),
153151
Insert(InsertProof),
154152
}
155153

156-
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)]
154+
#[derive(Debug, Clone)]
157155
pub struct NonMembershipProof {
158156
pub root: Digest,
159157
pub proof: SparseMerkleProof<Hasher>,
@@ -166,7 +164,7 @@ impl NonMembershipProof {
166164
}
167165
}
168166

169-
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)]
167+
#[derive(Debug, Clone)]
170168
pub struct InsertProof {
171169
pub non_membership_proof: NonMembershipProof,
172170

@@ -181,7 +179,7 @@ impl InsertProof {
181179
.verify()
182180
.context("Invalid NonMembershipProof")?;
183181

184-
let value = to_vec(&self.value).unwrap();
182+
let value = bincode::serialize(&self.value).unwrap();
185183

186184
self.membership_proof.clone().verify_existence(
187185
self.new_root.into(),
@@ -193,7 +191,7 @@ impl InsertProof {
193191
}
194192
}
195193

196-
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)]
194+
#[derive(Debug, Clone)]
197195
pub struct UpdateProof {
198196
pub old_root: RootHash,
199197
pub new_root: RootHash,
@@ -206,7 +204,7 @@ pub struct UpdateProof {
206204

207205
impl UpdateProof {
208206
pub fn verify(&self) -> Result<()> {
209-
let new_value = to_vec(&self.new_value).unwrap();
207+
let new_value = bincode::serialize(&self.new_value).unwrap();
210208

211209
self.proof.clone().verify_update(
212210
self.old_root,
@@ -278,11 +276,12 @@ where
278276
}
279277

280278
fn serialize_value(value: &Hashchain) -> Result<Vec<u8>> {
281-
to_vec(value).map_err(|e| anyhow!("Failed to serialize value: {}", e))
279+
bincode::serialize(value).map_err(|e| anyhow!("Failed to serialize value: {}", e))
282280
}
283281

284282
fn deserialize_value(bytes: &[u8]) -> Result<Hashchain> {
285-
from_slice::<Hashchain>(bytes).map_err(|e| anyhow!("Failed to deserialize value: {}", e))
283+
bincode::deserialize::<Hashchain>(bytes)
284+
.map_err(|e| anyhow!("Failed to deserialize value: {}", e))
286285
}
287286
}
288287

crates/groth16/src/lib.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use anyhow::{anyhow, Context, Result};
22
use bellman::{groth16, Circuit, ConstraintSystem, SynthesisError};
33
use bls12_381::{Bls12, G1Affine, G2Affine, Scalar};
4-
use borsh::{BorshDeserialize, BorshSerialize};
54
use prism_errors::{GeneralError, PrismError};
65
use std::fmt;
76

@@ -38,11 +37,11 @@ impl Circuit<Scalar> for ProofVariantCircuit {
3837
}
3938

4039
/// G1 represents a compressed [`bls12_381::G1Affine`]
41-
#[derive(BorshSerialize, BorshDeserialize, Clone)]
40+
#[derive(Clone)]
4241
pub struct G1([u8; 48]);
4342

4443
/// G2 represents a compressed [`bls12_381::G2Affine`]
45-
#[derive(BorshSerialize, BorshDeserialize, Clone)]
44+
#[derive(Clone)]
4645
pub struct G2([u8; 96]);
4746

4847
// Debug impls for the Affines print their hex representation
@@ -84,7 +83,7 @@ impl TryFrom<G2> for bls12_381::G2Affine {
8483
}
8584
}
8685

87-
#[derive(Clone, BorshSerialize, BorshDeserialize, Debug)]
86+
#[derive(Clone, Debug)]
8887
pub struct Bls12Proof {
8988
pub a: G1,
9089
pub b: G2,
@@ -113,7 +112,7 @@ impl From<groth16::Proof<Bls12>> for Bls12Proof {
113112
}
114113
}
115114

116-
#[derive(Clone, BorshSerialize, BorshDeserialize, Debug)]
115+
#[derive(Clone, Debug)]
117116
pub struct VerifyingKey {
118117
pub alpha_g1: G1,
119118
pub beta_g1: G1,

crates/prism/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ ed25519 = { workspace = true }
2121
base64 = { workspace = true }
2222
tokio = { workspace = true }
2323
bellman = { workspace = true }
24+
bincode = { workspace = true }
2425
bls12_381 = { workspace = true }
2526
rand = { workspace = true }
2627
hex = { workspace = true }

crates/prism/src/da/celestia.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@ use crate::{
33
consts::CHANNEL_BUFFER_SIZE,
44
da::{DataAvailabilityLayer, FinalizedEpoch},
55
};
6-
use prism_errors::{DataAvailabilityError, GeneralError};
76
use anyhow::{anyhow, bail, Context, Result};
87
use async_trait::async_trait;
9-
use borsh::from_slice;
108
use celestia_rpc::{BlobClient, Client, HeaderClient};
119
use celestia_types::{blob::GasPrice, nmt::Namespace, Blob};
1210
use prism_common::operation::Operation;
11+
use prism_errors::{DataAvailabilityError, GeneralError};
1312
use std::{self, sync::Arc};
1413
use tokio::{
1514
sync::{
@@ -19,11 +18,13 @@ use tokio::{
1918
task::spawn,
2019
};
2120

21+
use bincode;
22+
2223
impl TryFrom<&Blob> for FinalizedEpoch {
2324
type Error = anyhow::Error;
2425

2526
fn try_from(value: &Blob) -> Result<Self, Self::Error> {
26-
from_slice::<Self>(&value.data).context(format!(
27+
bincode::deserialize(&value.data).context(format!(
2728
"Failed to decode blob into FinalizedEpoch: {value:?}"
2829
))
2930
}
@@ -140,7 +141,7 @@ impl DataAvailabilityLayer for CelestiaConnection {
140141
let blobs: Result<Vec<Blob>, DataAvailabilityError> = epochs
141142
.iter()
142143
.map(|epoch| {
143-
let data = borsh::to_vec(epoch).map_err(|e| {
144+
let data = bincode::serialize(epoch).map_err(|e| {
144145
DataAvailabilityError::GeneralError(GeneralError::ParsingError(format!(
145146
"serializing epoch {}: {}",
146147
epoch.height, e
@@ -199,7 +200,7 @@ impl DataAvailabilityLayer for CelestiaConnection {
199200
let blobs: Result<Vec<Blob>, _> = operations
200201
.iter()
201202
.map(|operation| {
202-
let data = borsh::to_vec(operation)
203+
let data = bincode::serialize(operation)
203204
.context(format!("Failed to serialize operation {}", operation))
204205
.map_err(|e| {
205206
DataAvailabilityError::GeneralError(GeneralError::ParsingError(

crates/prism/src/da/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::utils::SignedContent;
22
use anyhow::Result;
33
use async_trait::async_trait;
4-
use borsh::{BorshDeserialize, BorshSerialize};
4+
use bincode;
55
use ed25519::Signature;
66
use prism_common::{operation::Operation, tree::Digest};
77
use prism_errors::GeneralError;
@@ -13,7 +13,7 @@ pub mod celestia;
1313
pub mod memory;
1414

1515
// FinalizedEpoch is the data structure that represents the finalized epoch data, and is posted to the DA layer.
16-
#[derive(BorshSerialize, BorshDeserialize, Clone, Debug)]
16+
#[derive(Serialize, Deserialize, Clone, Debug)]
1717
pub struct FinalizedEpoch {
1818
pub height: u64,
1919
pub prev_commitment: Digest,
@@ -34,7 +34,7 @@ impl SignedContent for FinalizedEpoch {
3434
fn get_plaintext(&self) -> Result<Vec<u8>> {
3535
let mut copy = self.clone();
3636
copy.signature = None;
37-
borsh::to_vec(&copy).map_err(|e| GeneralError::EncodingError(e.to_string()).into())
37+
bincode::serialize(&copy).map_err(|e| GeneralError::EncodingError(e.to_string()).into())
3838
}
3939

4040
fn get_public_key(&self) -> Result<String> {

crates/prism/src/node_types/lightclient.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::cfg::CelestiaConfig;
22
use anyhow::{Context, Result};
33
use async_trait::async_trait;
4+
use prism_common::tree::Digest;
45
use prism_errors::{DataAvailabilityError, GeneralError};
56
use sp1_sdk::{ProverClient, SP1VerifyingKey};
67
use std::{self, sync::Arc, time::Duration};
@@ -99,7 +100,27 @@ impl LightClient {
99100
}
100101
}
101102

102-
// TODO: compare commitment to epoch_json.proof.public_values
103+
let prev_commitment = &epoch_json.prev_commitment;
104+
let current_commitment = &epoch_json.current_commitment;
105+
106+
let mut public_values = epoch_json.proof.public_values.clone();
107+
let proof_prev_commitment: Digest = public_values.read();
108+
let proof_current_commitment: Digest = public_values.read();
109+
110+
if prev_commitment != &proof_prev_commitment
111+
|| current_commitment != &proof_current_commitment
112+
{
113+
error!(
114+
"Commitment mismatch:
115+
prev_commitment: {:?}, proof_prev_commitment: {:?},
116+
current_commitment: {:?}, proof_current_commitment: {:?}",
117+
prev_commitment,
118+
proof_prev_commitment,
119+
current_commitment,
120+
proof_current_commitment
121+
);
122+
panic!("Commitment mismatch in epoch {}", epoch_json.height);
123+
}
103124

104125
match self.client.verify(&epoch_json.proof, &self.verifying_key) {
105126
Ok(_) => {

0 commit comments

Comments
 (0)