Skip to content

Commit c225327

Browse files
authored
feat: Streaming serialize / deserialize (WIP) (#20072)
Public dispatch performance was incredibly bad due to serialize/deserialize inefficiencies. This PR switches to a streaming (reader/writer) pattern to improve performance. Thanks @Thunkar as macro wizard for help navigating comptime problems
2 parents d076922 + 8a3f584 commit c225327

File tree

24 files changed

+1505
-1081
lines changed

24 files changed

+1505
-1081
lines changed

noir-projects/aztec-nr/aztec/src/macros/dispatch.nr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub comptime fn generate_public_dispatch(m: Module) -> Quoted {
5252
let param_name = f"arg{parameter_index_value}".quoted_contents();
5353
let param_type = param.1;
5454
let read = quote {
55-
let $param_name: $param_type = reader.read_struct(aztec::protocol::traits::Deserialize::deserialize);
55+
let $param_name: $param_type = aztec::protocol::traits::Deserialize::stream_deserialize(&mut reader);
5656
};
5757
*parameter_index += 1;
5858
quote { $read }

noir-projects/aztec-nr/aztec/src/test/mocks/mock_struct.nr

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use crate::protocol::traits::{Deserialize, Empty, Packable, Serialize};
44

5+
#[derive(Deserialize, Serialize)]
56
pub struct MockStruct {
67
pub a: Field,
78
pub b: Field,
@@ -25,22 +26,6 @@ impl Empty for MockStruct {
2526
}
2627
}
2728

28-
impl Serialize for MockStruct {
29-
let N: u32 = 2;
30-
31-
fn serialize(self) -> [Field; Self::N] {
32-
[self.a, self.b]
33-
}
34-
}
35-
36-
impl Deserialize for MockStruct {
37-
let N: u32 = 2;
38-
39-
fn deserialize(fields: [Field; Self::N]) -> Self {
40-
Self { a: fields[0], b: fields[1] }
41-
}
42-
}
43-
4429
impl Packable for MockStruct {
4530
let N: u32 = 2;
4631

noir-projects/noir-protocol-circuits/Nargo.template.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,5 @@ members = [
4646
"crates/rollup-checkpoint-padding",
4747
"crates/rollup-checkpoint-merge",
4848
"crates/rollup-root",
49+
"crates/serde"
4950
]

noir-projects/noir-protocol-circuits/crates/blob/src/abis/blob_accumulator.nr

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use types::{
1010
constants::BLOB_ACCUMULATOR_LENGTH,
1111
hash::{poseidon2_hash, sha256_to_field},
1212
traits::{Deserialize, Empty, Serialize},
13-
utils::reader::Reader,
13+
utils::{reader::Reader, writer::Writer},
1414
};
1515

1616
/**
@@ -180,17 +180,22 @@ impl Eq for BlobAccumulator {
180180
impl Serialize for BlobAccumulator {
181181
let N: u32 = BLOB_ACCUMULATOR_LENGTH;
182182

183-
fn serialize(self) -> [Field; BLOB_ACCUMULATOR_LENGTH] {
184-
let mut fields: BoundedVec<Field, BLOB_ACCUMULATOR_LENGTH> = BoundedVec::new();
185-
fields.push(self.blob_commitments_hash_acc);
186-
fields.push(self.z_acc);
187-
fields.extend_from_array(self.y_acc.get_limbs().map(|l| l as Field));
188-
fields.extend_from_array(self.c_acc.x.get_limbs().map(|l| l as Field));
189-
fields.extend_from_array(self.c_acc.y.get_limbs().map(|l| l as Field));
190-
fields.push(self.c_acc.is_infinity as Field);
191-
fields.push(self.gamma_acc);
192-
fields.extend_from_array(self.gamma_pow_acc.get_limbs().map(|l| l as Field));
193-
fields.storage()
183+
fn serialize(self) -> [Field; Self::N] {
184+
let mut writer: Writer<Self::N> = Writer::new();
185+
self.stream_serialize(&mut writer);
186+
writer.finish()
187+
}
188+
189+
#[inline_always]
190+
fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
191+
writer.write(self.blob_commitments_hash_acc);
192+
writer.write(self.z_acc);
193+
writer.write_array(self.y_acc.get_limbs().map(|l| l as Field));
194+
writer.write_array(self.c_acc.x.get_limbs().map(|l| l as Field));
195+
writer.write_array(self.c_acc.y.get_limbs().map(|l| l as Field));
196+
writer.write(self.c_acc.is_infinity as Field);
197+
writer.write(self.gamma_acc);
198+
writer.write_array(self.gamma_pow_acc.get_limbs().map(|l| l as Field));
194199
}
195200
}
196201

@@ -201,7 +206,14 @@ impl Deserialize for BlobAccumulator {
201206

202207
fn deserialize(fields: [Field; Self::N]) -> Self {
203208
let mut reader = Reader::new(fields);
204-
let mut item = Self {
209+
let result = Self::stream_deserialize(&mut reader);
210+
reader.finish();
211+
result
212+
}
213+
214+
#[inline_always]
215+
fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
216+
Self {
205217
blob_commitments_hash_acc: reader.read(),
206218
z_acc: reader.read(),
207219
y_acc: BLS12_381_Fr::from_limbs(reader.read_array().map(|e| e as u128)),
@@ -212,7 +224,26 @@ impl Deserialize for BlobAccumulator {
212224
},
213225
gamma_acc: reader.read(),
214226
gamma_pow_acc: BLS12_381_Fr::from_limbs(reader.read_array().map(|e| e as u128)),
215-
};
216-
item
227+
}
217228
}
218229
}
230+
231+
#[test]
232+
fn serde_test() {
233+
let blob_accumulator = BlobAccumulator {
234+
blob_commitments_hash_acc: 1,
235+
z_acc: 2,
236+
y_acc: BLS12_381_Fr::from_limbs([3, 4, 5]),
237+
c_acc: BLSPoint {
238+
x: BLS12_381_Fq::from_limbs([6, 7, 8, 0]),
239+
y: BLS12_381_Fq::from_limbs([10, 11, 12, 13]),
240+
is_infinity: false,
241+
},
242+
gamma_acc: 42,
243+
gamma_pow_acc: BLS12_381_Fr::from_limbs([14, 15, 16]),
244+
};
245+
246+
let serialized = blob_accumulator.serialize();
247+
let deserialized = BlobAccumulator::deserialize(serialized);
248+
assert_eq(blob_accumulator, deserialized);
249+
}

noir-projects/noir-protocol-circuits/crates/blob/src/abis/final_blob_batching_challenges.nr

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use bignum::{BigNum, BLS12_381_Fr};
22
use types::{
33
constants::BLS12_FR_LIMBS,
44
traits::{Deserialize, Empty, Serialize},
5-
utils::reader::Reader,
5+
utils::{reader::Reader, writer::Writer},
66
};
77

88
/**
@@ -41,10 +41,15 @@ impl Serialize for FinalBlobBatchingChallenges {
4141
let N: u32 = BLS12_FR_LIMBS + 1;
4242

4343
fn serialize(self) -> [Field; Self::N] {
44-
let mut fields: BoundedVec<Field, BLS12_FR_LIMBS + 1> = BoundedVec::new();
45-
fields.push(self.z);
46-
fields.extend_from_array(self.gamma.get_limbs().map(|l| l as Field));
47-
fields.storage()
44+
let mut writer: Writer<Self::N> = Writer::new();
45+
self.stream_serialize(&mut writer);
46+
writer.finish()
47+
}
48+
49+
#[inline_always]
50+
fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
51+
writer.write(self.z);
52+
writer.write_array(self.gamma.get_limbs().map(|l| l as Field));
4853
}
4954
}
5055

@@ -53,10 +58,25 @@ impl Deserialize for FinalBlobBatchingChallenges {
5358

5459
fn deserialize(fields: [Field; Self::N]) -> Self {
5560
let mut reader = Reader::new(fields);
56-
let mut item = Self {
61+
let result = Self::stream_deserialize(&mut reader);
62+
reader.finish();
63+
result
64+
}
65+
66+
#[inline_always]
67+
fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
68+
Self {
5769
z: reader.read(),
5870
gamma: BLS12_381_Fr::from_limbs(reader.read_array().map(|e| e as u128)),
59-
};
60-
item
71+
}
6172
}
6273
}
74+
75+
#[test]
76+
fn serde_test() {
77+
let final_blob_batching_challenges =
78+
FinalBlobBatchingChallenges { z: 1, gamma: BLS12_381_Fr::from_limbs([2, 3, 4]) };
79+
let serialized = final_blob_batching_challenges.serialize();
80+
let deserialized = FinalBlobBatchingChallenges::deserialize(serialized);
81+
assert_eq(final_blob_batching_challenges, deserialized);
82+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "serde"
3+
type = "lib"
4+
authors = [""]
5+
compiler_version = ">=0.18.0"
6+
7+
[dependencies]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pub mod reader;
2+
pub mod writer;
3+
pub mod serialization;
4+
pub mod type_impls;
5+
mod tests;

noir-projects/noir-protocol-circuits/crates/types/src/utils/reader.nr renamed to noir-projects/noir-protocol-circuits/crates/serde/src/reader.nr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ impl<let N: u32> Reader<N> {
5151
result
5252
}
5353

54+
pub fn peek_offset(&mut self, offset: u32) -> Field {
55+
self.data[self.offset + offset]
56+
}
57+
58+
pub fn advance_offset(&mut self, offset: u32) {
59+
self.offset += offset;
60+
}
61+
5462
pub fn finish(self) {
5563
assert_eq(self.offset, self.data.len(), "Reader did not read all data");
5664
}

0 commit comments

Comments
 (0)