Skip to content

Commit 122119b

Browse files
authored
chore!: Move circuit serialization circuit into acir (#3345)
1 parent 4e2d35f commit 122119b

16 files changed

Lines changed: 78 additions & 107 deletions

File tree

Cargo.lock

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

acvm-repo/acir/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ serde.workspace = true
1919
thiserror.workspace = true
2020
flate2 = "1.0.24"
2121
bincode.workspace = true
22+
base64.workspace = true
2223

2324
[dev-dependencies]
2425
serde_json = "1.0"

acvm-repo/acir/src/circuit/mod.rs

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ use thiserror::Error;
99

1010
use std::{io::prelude::*, num::ParseIntError, str::FromStr};
1111

12+
use base64::Engine;
1213
use flate2::Compression;
14+
use serde::{de::Error as DeserializationError, Deserialize, Deserializer, Serialize, Serializer};
1315

14-
use serde::{Deserialize, Serialize};
1516
use std::collections::BTreeSet;
1617

1718
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
@@ -125,21 +126,54 @@ impl Circuit {
125126
PublicInputs(public_inputs)
126127
}
127128

128-
pub fn write<W: std::io::Write>(&self, writer: W) -> std::io::Result<()> {
129+
fn write<W: std::io::Write>(&self, writer: W) -> std::io::Result<()> {
129130
let buf = bincode::serialize(self).unwrap();
130131
let mut encoder = flate2::write::GzEncoder::new(writer, Compression::default());
131132
encoder.write_all(&buf)?;
132133
encoder.finish()?;
133134
Ok(())
134135
}
135136

136-
pub fn read<R: std::io::Read>(reader: R) -> std::io::Result<Self> {
137+
fn read<R: std::io::Read>(reader: R) -> std::io::Result<Self> {
137138
let mut gz_decoder = flate2::read::GzDecoder::new(reader);
138139
let mut buf_d = Vec::new();
139140
gz_decoder.read_to_end(&mut buf_d)?;
140141
bincode::deserialize(&buf_d)
141142
.map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidInput, err))
142143
}
144+
145+
pub fn serialize_circuit(circuit: &Circuit) -> Vec<u8> {
146+
let mut circuit_bytes: Vec<u8> = Vec::new();
147+
circuit.write(&mut circuit_bytes).expect("expected circuit to be serializable");
148+
circuit_bytes
149+
}
150+
151+
pub fn deserialize_circuit(serialized_circuit: &[u8]) -> std::io::Result<Self> {
152+
Circuit::read(serialized_circuit)
153+
}
154+
155+
// Serialize and base64 encode circuit
156+
pub fn serialize_circuit_base64<S>(circuit: &Circuit, s: S) -> Result<S::Ok, S::Error>
157+
where
158+
S: Serializer,
159+
{
160+
let circuit_bytes = Circuit::serialize_circuit(circuit);
161+
let encoded_b64 = base64::engine::general_purpose::STANDARD.encode(circuit_bytes);
162+
s.serialize_str(&encoded_b64)
163+
}
164+
165+
// Deserialize and base64 decode circuit
166+
pub fn deserialize_circuit_base64<'de, D>(deserializer: D) -> Result<Circuit, D::Error>
167+
where
168+
D: Deserializer<'de>,
169+
{
170+
let bytecode_b64: String = serde::Deserialize::deserialize(deserializer)?;
171+
let circuit_bytes = base64::engine::general_purpose::STANDARD
172+
.decode(bytecode_b64)
173+
.map_err(D::Error::custom)?;
174+
let circuit = Self::deserialize_circuit(&circuit_bytes).map_err(D::Error::custom)?;
175+
Ok(circuit)
176+
}
143177
}
144178

145179
impl std::fmt::Display for Circuit {
@@ -229,9 +263,8 @@ mod tests {
229263
};
230264

231265
fn read_write(circuit: Circuit) -> (Circuit, Circuit) {
232-
let mut bytes = Vec::new();
233-
circuit.write(&mut bytes).unwrap();
234-
let got_circuit = Circuit::read(&*bytes).unwrap();
266+
let bytes = Circuit::serialize_circuit(&circuit);
267+
let got_circuit = Circuit::deserialize_circuit(&bytes).unwrap();
235268
(circuit, got_circuit)
236269
}
237270

@@ -277,7 +310,7 @@ mod tests {
277310
encoder.write_all(bad_circuit).unwrap();
278311
encoder.finish().unwrap();
279312

280-
let deserialization_result = Circuit::read(&*zipped_bad_circuit);
313+
let deserialization_result = Circuit::deserialize_circuit(&zipped_bad_circuit);
281314
assert!(deserialization_result.is_err());
282315
}
283316
}

acvm-repo/acir/tests/test_program_serialization.rs

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ fn addition_circuit() {
4242
..Circuit::default()
4343
};
4444

45-
let mut bytes = Vec::new();
46-
circuit.write(&mut bytes).unwrap();
45+
let bytes = Circuit::serialize_circuit(&circuit);
4746

4847
let expected_serialization: Vec<u8> = vec![
4948
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 187, 13, 192, 32, 12, 68, 249, 100, 32, 27,
@@ -73,8 +72,7 @@ fn fixed_base_scalar_mul_circuit() {
7372
..Circuit::default()
7473
};
7574

76-
let mut bytes = Vec::new();
77-
circuit.write(&mut bytes).unwrap();
75+
let bytes = Circuit::serialize_circuit(&circuit);
7876

7977
let expected_serialization: Vec<u8> = vec![
8078
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 48, 12, 194, 178, 215, 215, 46, 189,
@@ -101,8 +99,7 @@ fn pedersen_circuit() {
10199
..Circuit::default()
102100
};
103101

104-
let mut bytes = Vec::new();
105-
circuit.write(&mut bytes).unwrap();
102+
let bytes = Circuit::serialize_circuit(&circuit);
106103

107104
let expected_serialization: Vec<u8> = vec![
108105
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 138, 9, 10, 0, 64, 8, 2, 103, 15, 250, 255, 139,
@@ -143,8 +140,7 @@ fn schnorr_verify_circuit() {
143140
..Circuit::default()
144141
};
145142

146-
let mut bytes = Vec::new();
147-
circuit.write(&mut bytes).unwrap();
143+
let bytes = Circuit::serialize_circuit(&circuit);
148144

149145
let expected_serialization: Vec<u8> = vec![
150146
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 87, 78, 2, 1, 20, 134, 209, 177, 247, 222, 123,
@@ -197,8 +193,7 @@ fn simple_brillig_foreign_call() {
197193
..Circuit::default()
198194
};
199195

200-
let mut bytes = Vec::new();
201-
circuit.write(&mut bytes).unwrap();
196+
let bytes = Circuit::serialize_circuit(&circuit);
202197

203198
let expected_serialization: Vec<u8> = vec![
204199
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 49, 10, 64, 33, 12, 67, 99, 63, 124, 60, 142,
@@ -271,8 +266,7 @@ fn complex_brillig_foreign_call() {
271266
..Circuit::default()
272267
};
273268

274-
let mut bytes = Vec::new();
275-
circuit.write(&mut bytes).unwrap();
269+
let bytes = Circuit::serialize_circuit(&circuit);
276270

277271
let expected_serialization: Vec<u8> = vec![
278272
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 83, 219, 10, 128, 48, 8, 117, 174, 139, 159, 179,
@@ -310,8 +304,7 @@ fn memory_op_circuit() {
310304
return_values: PublicInputs([Witness(4)].into()),
311305
..Circuit::default()
312306
};
313-
let mut bytes = Vec::new();
314-
circuit.write(&mut bytes).unwrap();
307+
let bytes = Circuit::serialize_circuit(&circuit);
315308

316309
let expected_serialization: Vec<u8> = vec![
317310
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 146, 49, 14, 0, 32, 8, 3, 139, 192, 127, 240, 7,

acvm-repo/acvm_js/src/execute.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ pub async fn execute_circuit_with_black_box_solver(
6464
foreign_call_handler: ForeignCallHandler,
6565
) -> Result<JsWitnessMap, Error> {
6666
console_error_panic_hook::set_once();
67-
let circuit: Circuit = Circuit::read(&*circuit).expect("Failed to deserialize circuit");
67+
let circuit: Circuit =
68+
Circuit::deserialize_circuit(&circuit).expect("Failed to deserialize circuit");
6869

6970
let mut acvm = ACVM::new(&solver.0, &circuit.opcodes, initial_witness.into());
7071

acvm-repo/acvm_js/src/public_witness.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ pub fn get_return_witness(
3030
witness_map: JsWitnessMap,
3131
) -> Result<JsWitnessMap, JsString> {
3232
console_error_panic_hook::set_once();
33-
let circuit: Circuit = Circuit::read(&*circuit).expect("Failed to deserialize circuit");
33+
let circuit: Circuit =
34+
Circuit::deserialize_circuit(&circuit).expect("Failed to deserialize circuit");
3435
let witness_map = WitnessMap::from(witness_map);
3536

3637
let return_witness =
@@ -50,7 +51,8 @@ pub fn get_public_parameters_witness(
5051
solved_witness: JsWitnessMap,
5152
) -> Result<JsWitnessMap, JsString> {
5253
console_error_panic_hook::set_once();
53-
let circuit: Circuit = Circuit::read(&*circuit).expect("Failed to deserialize circuit");
54+
let circuit: Circuit =
55+
Circuit::deserialize_circuit(&circuit).expect("Failed to deserialize circuit");
5456
let witness_map = WitnessMap::from(solved_witness);
5557

5658
let public_params_witness =
@@ -70,7 +72,8 @@ pub fn get_public_witness(
7072
solved_witness: JsWitnessMap,
7173
) -> Result<JsWitnessMap, JsString> {
7274
console_error_panic_hook::set_once();
73-
let circuit: Circuit = Circuit::read(&*circuit).expect("Failed to deserialize circuit");
75+
let circuit: Circuit =
76+
Circuit::deserialize_circuit(&circuit).expect("Failed to deserialize circuit");
7477
let witness_map = WitnessMap::from(solved_witness);
7578

7679
let public_witness =

compiler/noirc_driver/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,4 @@ acvm.workspace = true
2020
iter-extended.workspace = true
2121
fm.workspace = true
2222
serde.workspace = true
23-
base64.workspace = true
2423
fxhash.workspace = true

compiler/noirc_driver/src/contract.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use noirc_errors::debug_info::DebugInfo;
88
use noirc_evaluator::errors::SsaReport;
99

1010
use super::debug::DebugFile;
11-
use crate::program::{deserialize_circuit, serialize_circuit};
1211

1312
/// Describes the types of smart contract functions that are allowed.
1413
/// Unlike the similar enum in noirc_frontend, 'open' and 'unconstrained'
@@ -62,7 +61,10 @@ pub struct ContractFunction {
6261

6362
pub abi: Abi,
6463

65-
#[serde(serialize_with = "serialize_circuit", deserialize_with = "deserialize_circuit")]
64+
#[serde(
65+
serialize_with = "Circuit::serialize_circuit_base64",
66+
deserialize_with = "Circuit::deserialize_circuit_base64"
67+
)]
6668
pub bytecode: Circuit,
6769

6870
pub debug: DebugInfo,

compiler/noirc_driver/src/program.rs

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@ use std::collections::BTreeMap;
33
use acvm::acir::circuit::Circuit;
44
use fm::FileId;
55

6-
use base64::Engine;
76
use noirc_errors::debug_info::DebugInfo;
87
use noirc_evaluator::errors::SsaReport;
9-
use serde::{de::Error as DeserializationError, ser::Error as SerializationError};
10-
use serde::{Deserialize, Deserializer, Serialize, Serializer};
8+
use serde::{Deserialize, Serialize};
119

1210
use super::debug::DebugFile;
1311

@@ -20,32 +18,13 @@ pub struct CompiledProgram {
2018
/// Used to short-circuit compilation in the case of the source code not changing since the last compilation.
2119
pub hash: u64,
2220

23-
#[serde(serialize_with = "serialize_circuit", deserialize_with = "deserialize_circuit")]
21+
#[serde(
22+
serialize_with = "Circuit::serialize_circuit_base64",
23+
deserialize_with = "Circuit::deserialize_circuit_base64"
24+
)]
2425
pub circuit: Circuit,
2526
pub abi: noirc_abi::Abi,
2627
pub debug: DebugInfo,
2728
pub file_map: BTreeMap<FileId, DebugFile>,
2829
pub warnings: Vec<SsaReport>,
2930
}
30-
31-
pub(crate) fn serialize_circuit<S>(circuit: &Circuit, s: S) -> Result<S::Ok, S::Error>
32-
where
33-
S: Serializer,
34-
{
35-
let mut circuit_bytes: Vec<u8> = Vec::new();
36-
circuit.write(&mut circuit_bytes).map_err(S::Error::custom)?;
37-
38-
let encoded_b64 = base64::engine::general_purpose::STANDARD.encode(circuit_bytes);
39-
s.serialize_str(&encoded_b64)
40-
}
41-
42-
pub(crate) fn deserialize_circuit<'de, D>(deserializer: D) -> Result<Circuit, D::Error>
43-
where
44-
D: Deserializer<'de>,
45-
{
46-
let bytecode_b64: String = serde::Deserialize::deserialize(deserializer)?;
47-
let circuit_bytes =
48-
base64::engine::general_purpose::STANDARD.decode(bytecode_b64).map_err(D::Error::custom)?;
49-
let circuit = Circuit::read(&*circuit_bytes).map_err(D::Error::custom)?;
50-
Ok(circuit)
51-
}

compiler/wasm/src/circuit.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,13 @@ use wasm_bindgen::prelude::*;
66
#[wasm_bindgen]
77
pub fn acir_read_bytes(bytes: Vec<u8>) -> JsValue {
88
console_error_panic_hook::set_once();
9-
let circuit = Circuit::read(&*bytes).unwrap();
9+
let circuit = Circuit::deserialize_circuit(&bytes).unwrap();
1010
<JsValue as JsValueSerdeExt>::from_serde(&circuit).unwrap()
1111
}
1212

1313
#[wasm_bindgen]
1414
pub fn acir_write_bytes(acir: JsValue) -> Vec<u8> {
1515
console_error_panic_hook::set_once();
1616
let circuit: Circuit = JsValueSerdeExt::into_serde(&acir).unwrap();
17-
let mut bytes = Vec::new();
18-
circuit.write(&mut bytes).unwrap();
19-
bytes
17+
Circuit::serialize_circuit(&circuit)
2018
}

0 commit comments

Comments
 (0)