diff --git a/core/src/io.rs b/core/src/io.rs index 2ed4489272..4dc4473de8 100644 --- a/core/src/io.rs +++ b/core/src/io.rs @@ -1,8 +1,6 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use crate::stark::StarkGenericConfig; use crate::utils::Buffer; -use crate::Proof; /// Standard input for the prover. #[derive(Serialize, Deserialize)] @@ -88,14 +86,71 @@ impl SP1Stdout { } } -pub fn serialize_proof( - proof: &Proof, - serializer: S, -) -> Result -where - S: serde::Serializer, -{ - let bytes = bincode::serialize(proof).unwrap(); - let hex_bytes = hex::encode(bytes); - serializer.serialize_str(&hex_bytes) +pub mod proof_serde { + use serde::{de::DeserializeOwned, Deserialize, Deserializer, Serialize}; + + use crate::stark::{Proof, StarkGenericConfig}; + + pub fn serialize( + proof: &Proof, + serializer: S, + ) -> Result + where + S: serde::Serializer, + { + if serializer.is_human_readable() { + let bytes = bincode::serialize(proof).unwrap(); + let hex_bytes = hex::encode(bytes); + serializer.serialize_str(&hex_bytes) + } else { + proof.serialize(serializer) + } + } + + pub fn deserialize<'de, D, SC: StarkGenericConfig + DeserializeOwned>( + deserializer: D, + ) -> Result, D::Error> + where + D: Deserializer<'de>, + { + if deserializer.is_human_readable() { + let hex_bytes = String::deserialize(deserializer).unwrap(); + let bytes = hex::decode(hex_bytes).unwrap(); + let proof = bincode::deserialize(&bytes).map_err(serde::de::Error::custom)?; + Ok(proof) + } else { + Proof::::deserialize(deserializer) + } + } + + #[cfg(test)] + mod tests { + use crate::{ + utils::{tests::FIBONACCI_IO_ELF, BabyBearBlake3}, + SP1ProofWithIO, SP1Prover, SP1Stdin, SP1Verifier, + }; + + /// Tests serialization with a human-readable encoding + #[test] + fn test_json_roundtrip() { + let mut stdin = SP1Stdin::new(); + stdin.write(&3u32); + let proof = SP1Prover::prove(FIBONACCI_IO_ELF, stdin).unwrap(); + let json = serde_json::to_string(&proof).unwrap(); + let output = serde_json::from_str::>(&json).unwrap(); + SP1Verifier::verify(FIBONACCI_IO_ELF, &output).unwrap(); + } + + /// Tests serialization with a binary encoding + #[test] + fn test_bincode_roundtrip() { + let mut stdin = SP1Stdin::new(); + stdin.write(&3u32); + let proof = SP1Prover::prove(FIBONACCI_IO_ELF, stdin).unwrap(); + let serialized = bincode::serialize(&proof).unwrap(); + let output = + bincode::deserialize::>(&serialized).unwrap(); + SP1Verifier::verify(FIBONACCI_IO_ELF, &output).unwrap(); + } + } } diff --git a/core/src/lib.rs b/core/src/lib.rs index 509c0d803a..786c7980c0 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -50,8 +50,8 @@ pub struct SP1Verifier; /// A proof of a RISCV ELF execution with given inputs and outputs. #[derive(Serialize, Deserialize)] -pub struct SP1ProofWithIO { - #[serde(serialize_with = "serialize_proof")] +pub struct SP1ProofWithIO { + #[serde(with = "proof_serde")] pub proof: Proof, pub stdin: SP1Stdin, pub stdout: SP1Stdout, @@ -91,7 +91,7 @@ impl SP1Prover { config: SC, ) -> Result> where - SC: StarkUtils + Send + Sync + Serialize + Clone, + SC: StarkUtils + Send + Sync + Serialize + DeserializeOwned + Clone, SC::Challenger: Clone, OpeningProof: Send + Sync, >>::Commitment: Send + Sync, @@ -134,7 +134,7 @@ impl SP1Verifier { config: SC, ) -> Result<(), ProgramVerificationError> where - SC: StarkUtils + Send + Sync + Serialize, + SC: StarkUtils + Send + Sync + Serialize + DeserializeOwned, SC::Challenger: Clone, OpeningProof: Send + Sync, >>::Commitment: Send + Sync, @@ -150,7 +150,7 @@ impl SP1Verifier { } } -impl SP1ProofWithIO { +impl SP1ProofWithIO { /// Saves the proof as a JSON to the given path. pub fn save(&self, path: &str) -> Result<()> { let data = serde_json::to_string(self).unwrap();