Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
cdd46b4
Turn on msgpack by default. Add Format::BincodeLegacy
aakoshh Mar 25, 2025
2ed3441
Update expected serialized bytes in tests to msgpack
aakoshh May 20, 2025
9a1db21
Update expected serialized witness data
aakoshh Mar 26, 2025
6e246f5
Try bincode first, the others might falsely pass
aakoshh Mar 26, 2025
3625ab7
Update insta formats to use msgpack
aakoshh May 20, 2025
e6679ec
Update insta snapshots to use msgpack
aakoshh May 20, 2025
6b4ab8f
Merge remote-tracking branch 'origin/master' into af/msgpack-default
aakoshh Dec 9, 2025
7326205
Test both legacy and default formats
aakoshh Dec 9, 2025
c2c1fc7
Fix merge
aakoshh Dec 9, 2025
f188383
Update the TS test to contain compressed msgpack
aakoshh Dec 9, 2025
01bd2cc
Update the expected compressed witness data
aakoshh Dec 9, 2025
763ff88
Use ByteMode::ForceIterables
aakoshh Dec 9, 2025
3e3fac0
First write the VK, then prove
aakoshh Dec 9, 2025
d5126b9
Update test vectors with ByteMode::ForceIterables
aakoshh Dec 9, 2025
ff2317c
Merge remote-tracking branch 'origin/master' into af/msgpack-default
aakoshh Dec 16, 2025
f45aaca
Update to bb version Adam pointed at, which still supports all kinds …
aakoshh Dec 18, 2025
7065876
Merge remote-tracking branch 'origin/master' into af/msgpack-default
aakoshh Dec 18, 2025
08f5e41
Remove the v prefix from the release tag
aakoshh Dec 18, 2025
7e9f48a
Print the circuit name in gates_report.sh
aakoshh Dec 18, 2025
7401bfe
Skip databus_composite_calldata in gates_report
aakoshh Dec 18, 2025
38b5fae
Skip a bunch more circuits with #[fold]
aakoshh Dec 18, 2025
eb0b035
Update bb version in integration tests
aakoshh Dec 18, 2025
d6f1945
Update name to verify_honk_proof
aakoshh Dec 18, 2025
3562959
feat: C++ codegen to support the `msgpack-compact` serialisation form…
aakoshh Dec 18, 2025
2580f0c
Update bb.js and remove fold_fibonacci
federicobarbacovi Dec 18, 2025
632479b
Update the BB version in other places
aakoshh Dec 18, 2025
6bc52f6
Merge branch 'af/msgpack-default' of github.com:noir-lang/noir into a…
aakoshh Dec 18, 2025
2a6e81b
Update yarn.lock
aakoshh Dec 18, 2025
a3d1cb8
Merge branch 'master' into af/msgpack-default
aakoshh Dec 19, 2025
2c9a55a
Merge branch 'master' into af/msgpack-default
TomAFrench Jan 5, 2026
8080de6
cleanup
TomAFrench Jan 5, 2026
235e07e
Apply suggestions from code review
TomAFrench Jan 5, 2026
d36f17f
Apply suggestion from @TomAFrench
TomAFrench Jan 5, 2026
771e326
Merge branch 'master' into af/msgpack-default
TomAFrench Jan 5, 2026
023e77e
chore(serialization): Use `msgpack-compact` by default (#11094)
aakoshh Jan 6, 2026
1cb59fe
Apply suggestion from @TomAFrench
TomAFrench Jan 6, 2026
48d0422
Apply suggestion from @TomAFrench
TomAFrench Jan 6, 2026
90aa4cb
Merge branch 'master' into af/msgpack-default
TomAFrench Jan 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,264 changes: 911 additions & 353 deletions acvm-repo/acir/codegen/acir.cpp

Large diffs are not rendered by default.

54 changes: 45 additions & 9 deletions acvm-repo/acir/codegen/witness.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include "serde.hpp"
#include "msgpack.hpp"
#include "barretenberg/serialize/msgpack_impl.hpp"
#include "bincode.hpp"

namespace Witnesses {
Expand All @@ -10,7 +10,7 @@ namespace Witnesses {
msgpack::object const& o,
std::string const& name
) {
if(o.type != msgpack::type::MAP) {
if (o.type != msgpack::type::MAP) {
std::cerr << o << std::endl;
throw_or_abort("expected MAP for " + name);
}
Expand All @@ -28,6 +28,7 @@ namespace Witnesses {
}
return kvmap;
}

template<typename T>
static void conv_fld_from_kvmap(
std::map<std::string, msgpack::object const*> const& kvmap,
Expand All @@ -48,6 +49,26 @@ namespace Witnesses {
throw_or_abort("missing field: " + struct_name + "::" + field_name);
}
}

template<typename T>
static void conv_fld_from_array(
msgpack::object_array const& array,
std::string const& struct_name,
std::string const& field_name,
T& field,
uint32_t index
) {
if (index >= array.size) {
throw_or_abort("index out of bounds: " + struct_name + "::" + field_name + " at " + std::to_string(index));
}
auto element = array.ptr[index];
try {
element.convert(field);
} catch (const msgpack::type_error&) {
std::cerr << element << std::endl;
throw_or_abort("error converting into field " + struct_name + "::" + field_name);
}
}
};
}

Expand Down Expand Up @@ -106,10 +127,18 @@ namespace Witnesses {
}

void msgpack_unpack(msgpack::object const& o) {
auto name = "StackItem";
auto kvmap = Helpers::make_kvmap(o, name);
Helpers::conv_fld_from_kvmap(kvmap, name, "index", index, false);
Helpers::conv_fld_from_kvmap(kvmap, name, "witness", witness, false);
std::string name = "StackItem";
if (o.type == msgpack::type::MAP) {
auto kvmap = Helpers::make_kvmap(o, name);
Helpers::conv_fld_from_kvmap(kvmap, name, "index", index, false);
Helpers::conv_fld_from_kvmap(kvmap, name, "witness", witness, false);
} else if (o.type == msgpack::type::ARRAY) {
auto array = o.via.array;
Helpers::conv_fld_from_array(array, name, "index", index, 0);
Helpers::conv_fld_from_array(array, name, "witness", witness, 1);
} else {
throw_or_abort("expected MAP or ARRAY for " + name);
}
}
};

Expand All @@ -126,9 +155,16 @@ namespace Witnesses {
}

void msgpack_unpack(msgpack::object const& o) {
auto name = "WitnessStack";
auto kvmap = Helpers::make_kvmap(o, name);
Helpers::conv_fld_from_kvmap(kvmap, name, "stack", stack, false);
std::string name = "WitnessStack";
if (o.type == msgpack::type::MAP) {
auto kvmap = Helpers::make_kvmap(o, name);
Helpers::conv_fld_from_kvmap(kvmap, name, "stack", stack, false);
} else if (o.type == msgpack::type::ARRAY) {
auto array = o.via.array;
Helpers::conv_fld_from_array(array, name, "stack", stack, 0);
} else {
throw_or_abort("expected MAP or ARRAY for " + name);
}
}
};

Expand Down
29 changes: 18 additions & 11 deletions acvm-repo/acir/src/circuit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ pub mod brillig;
pub mod opcodes;

use crate::{
SerializationFormat,
circuit::opcodes::display_opcode,
native_types::{Expression, Witness},
serialization::{deserialize_any_format, serialize_with_format_from_env},
serialization::{self, deserialize_any_format, serialize_with_format},
};
use acir_field::AcirField;
pub use opcodes::Opcode;
Expand Down Expand Up @@ -266,24 +267,30 @@ impl<F: AcirField> Circuit<F> {
}

impl<F: Serialize + AcirField> Program<F> {
/// Serialize and compress the [Program] into bytes.
fn write<W: Write>(&self, writer: W) -> std::io::Result<()> {
let buf = serialize_with_format_from_env(self)?;

/// Compress a serialized [Program].
fn compress(buf: Vec<u8>) -> std::io::Result<Vec<u8>> {
let mut compressed: Vec<u8> = Vec::new();
// Compress the data, which should help with formats that uses field names.
let mut encoder = flate2::write::GzEncoder::new(writer, Compression::default());
let mut encoder = flate2::write::GzEncoder::new(&mut compressed, Compression::default());
encoder.write_all(&buf)?;
encoder.finish()?;
Ok(())
Ok(compressed)
}

/// Serialize and compress a [Program] into bytes, using the given format.
pub fn serialize_program_with_format(program: &Self, format: serialization::Format) -> Vec<u8> {
let program_bytes =
serialize_with_format(program, format).expect("expected circuit to be serializable");
Self::compress(program_bytes).expect("expected circuit to compress")
}

/// Serialize and compress a [Program] into bytes, using the format from the environment, or the default format.
pub fn serialize_program(program: &Self) -> Vec<u8> {
let mut program_bytes: Vec<u8> = Vec::new();
program.write(&mut program_bytes).expect("expected circuit to be serializable");
program_bytes
let format = SerializationFormat::from_env().expect("invalid format");
Self::serialize_program_with_format(program, format.unwrap_or_default())
}

/// Serialize and base64 encode program
/// Serialize, compress then base64 encode a [Program], using the format from the environment, or the default format,
pub fn serialize_program_base64<S>(program: &Self, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
Expand Down
89 changes: 79 additions & 10 deletions acvm-repo/acir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub use brillig;
pub use circuit::black_box_functions::BlackBoxFunc;
pub use circuit::opcodes::InvalidInputBitSize;
pub use parser::parse_opcodes;
pub use serialization::Format as SerializationFormat;

#[cfg(test)]
mod reflection {
Expand Down Expand Up @@ -75,6 +76,11 @@ mod reflection {
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Default, Hash)]
struct ProgramWithoutBrillig<F: AcirField> {
pub functions: Vec<Circuit<F>>,
/// We want to ignore this field. By setting its type as `unit`
/// it will not be deserialized, but it will correctly maintain
/// the position of the others (although in this case it doesn't)
/// matter since it's the last field.
pub unconstrained_functions: (),
}

#[test]
Expand Down Expand Up @@ -225,7 +231,10 @@ mod reflection {
fn add_preamble(source: &mut String) {
let inc = r#"#include "serde.hpp""#;
let pos = source.find(inc).expect("serde.hpp missing");
source.insert_str(pos + inc.len(), "\n#include \"msgpack.hpp\"");
source.insert_str(
pos + inc.len(),
"\n#include \"barretenberg/serialize/msgpack_impl.hpp\"",
);
}

/// Add helper functions to cut down repetition in the generated code.
Expand All @@ -239,7 +248,7 @@ mod reflection {
msgpack::object const& o,
std::string const& name
) {
if(o.type != msgpack::type::MAP) {
if (o.type != msgpack::type::MAP) {
std::cerr << o << std::endl;
throw_or_abort("expected MAP for " + name);
}
Expand All @@ -257,6 +266,7 @@ mod reflection {
}
return kvmap;
}

template<typename T>
static void conv_fld_from_kvmap(
std::map<std::string, msgpack::object const*> const& kvmap,
Expand All @@ -277,6 +287,26 @@ mod reflection {
throw_or_abort("missing field: " + struct_name + "::" + field_name);
}
}

template<typename T>
static void conv_fld_from_array(
msgpack::object_array const& array,
std::string const& struct_name,
std::string const& field_name,
T& field,
uint32_t index
) {
if (index >= array.size) {
throw_or_abort("index out of bounds: " + struct_name + "::" + field_name + " at " + std::to_string(index));
}
auto element = array.ptr[index];
try {
element.convert(field);
} catch (const msgpack::type_error&) {
std::cerr << element << std::endl;
throw_or_abort("error converting into field " + struct_name + "::" + field_name);
}
}
};
"#;
// cSpell:enable
Expand Down Expand Up @@ -361,13 +391,24 @@ mod reflection {
// or we could reject the data if there was a new field we could
// not recognize, or we could even handle aliases.

// We treat unit fields as special, using them to ignore fields during deserialization:
// * in 'map' format we skip over them, never try to deserialize them from the map
// * in 'tuple' format we jump over their index, ignoring whatever is in that position
fn is_unit(field: &Named<Format>) -> bool {
matches!(field.value, Format::Unit)
}

let non_unit_field_count = fields.iter().filter(|f| !is_unit(f)).count();

self.msgpack_pack(name, &{
let mut body = format!(
"
packer.pack_map({});",
fields.len()
packer.pack_map({non_unit_field_count});",
);
for field in fields {
if is_unit(field) {
continue;
}
let field_name = &field.name;
body.push_str(&format!(
r#"
Expand All @@ -383,20 +424,48 @@ mod reflection {
// cSpell:disable
let mut body = format!(
r#"
auto name = "{name}";
auto kvmap = Helpers::make_kvmap(o, name);"#
std::string name = "{name}";
if (o.type == msgpack::type::MAP) {{
auto kvmap = Helpers::make_kvmap(o, name);"#
);
// cSpell:enable
for field in fields {
if is_unit(field) {
continue;
}
let field_name = &field.name;
let is_optional = matches!(field.value, Format::Option(_));
// cSpell:disable
body.push_str(&format!(
r#"
Helpers::conv_fld_from_kvmap(kvmap, name, "{field_name}", {field_name}, {is_optional});"#
Helpers::conv_fld_from_kvmap(kvmap, name, "{field_name}", {field_name}, {is_optional});"#
));
// cSpell:enable
}
body.push_str(
"
} else if (o.type == msgpack::type::ARRAY) {
auto array = o.via.array; ",
);
for (index, field) in fields.iter().enumerate() {
if is_unit(field) {
continue;
}
let field_name = &field.name;
// cSpell:disable
body.push_str(&format!(
r#"
Helpers::conv_fld_from_array(array, name, "{field_name}", {field_name}, {index});"#
));
// cSpell:enable
}

body.push_str(
r#"
} else {
throw_or_abort("expected MAP or ARRAY for " + name);
}"#,
);
body
});
}
Expand Down Expand Up @@ -466,9 +535,9 @@ mod reflection {
packer.pack(tag);
}} else {{
std::visit([&packer, tag](const auto& arg) {{
std::map<std::string, msgpack::object> data;
data[tag] = msgpack::object(arg);
packer.pack(data);
packer.pack_map(1);
packer.pack(tag);
arg.msgpack_pack(packer);
}}, value);
}}"#
)
Expand Down
14 changes: 12 additions & 2 deletions acvm-repo/acir/src/native_types/witness_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use flate2::bufread::GzEncoder;
use serde::{Deserialize, Serialize};
use thiserror::Error;

use crate::{native_types::Witness, serialization};
use crate::{SerializationFormat, native_types::Witness, serialization};

#[derive(Debug, Error)]
enum SerializationError {
Expand Down Expand Up @@ -91,7 +91,17 @@ impl<F> From<BTreeMap<Witness, F>> for WitnessMap<F> {
impl<F: AcirField + Serialize> WitnessMap<F> {
/// Serialize and compress.
pub fn serialize(&self) -> Result<Vec<u8>, WitnessMapError> {
let buf = serialization::serialize_with_format_from_env(self)
let format = SerializationFormat::from_env()
.map_err(|err| SerializationError::Serialize(std::io::Error::other(err)))?;
self.serialize_with_format(format.unwrap_or_default())
}

/// Serialize and compress with a given format.
pub fn serialize_with_format(
&self,
format: SerializationFormat,
) -> Result<Vec<u8>, WitnessMapError> {
let buf = serialization::serialize_with_format(self, format)
.map_err(|e| WitnessMapError(SerializationError::Serialize(e)))?;

let mut deflater = GzEncoder::new(buf.as_slice(), Compression::best());
Expand Down
13 changes: 12 additions & 1 deletion acvm-repo/acir/src/native_types/witness_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use flate2::bufread::GzEncoder;
use serde::{Deserialize, Serialize};
use thiserror::Error;

use crate::SerializationFormat;
use crate::serialization;

use super::WitnessMap;
Expand Down Expand Up @@ -72,7 +73,17 @@ impl<F> WitnessStack<F> {
impl<F: AcirField + Serialize> WitnessStack<F> {
/// Serialize and compress.
pub fn serialize(&self) -> Result<Vec<u8>, WitnessStackError> {
let buf = serialization::serialize_with_format_from_env(self)
let format = SerializationFormat::from_env()
.map_err(|err| SerializationError::Serialize(std::io::Error::other(err)))?;
self.serialize_with_format(format.unwrap_or_default())
}

/// Serialize and compress with a given format.
pub fn serialize_with_format(
&self,
format: SerializationFormat,
) -> Result<Vec<u8>, WitnessStackError> {
let buf = serialization::serialize_with_format(self, format)
.map_err(|e| WitnessStackError(SerializationError::Serialize(e)))?;

let mut deflater = GzEncoder::new(buf.as_slice(), Compression::best());
Expand Down
Loading
Loading