Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
msgpack.hpp
Go to the documentation of this file.
1#pragma once
2/* Minimal header for declaring msgpack fields.
3This should be included as "barretenberg/serialize/msgpack.hpp" unless a translation wants
4to use msgpack for bindings, then "barretenberg/serialize/cbind.hpp" should be included.
5
6## Overview
7
8The Msgpack module allows for efficient serialization and deserialization of data structures. It can be applied to
9map-like objects, array-like objects, and custom serialization/deserialization logic.
10
11## Binding objects
12
13Marking structs/classes with their fields for msgpack allows you to pack and unpack the class.
14
151. All objects bound should have a default constructor
162. Objects can be tightly packed as binary (see field_impl.hpp), array-like, or map-like. See below
173. You should list all fields of a class in the below methods, or use the custom method.
18
19### Typical Objects
20
21To make objects serializable as a map-like format, define the `msgpack` method in your class as follows:
22
23```cpp
24void msgpack(auto ar) {
25 ar(NVP(circuit_type, circuit_size, num_public_inputs, commitments, contains_pairing_point_accumulator,
26pairing_point_accumulator_public_input_indices));
27}
28or
29MSGPACK_FIELDS(circuit_type, circuit_size, num_public_inputs, commitments, contains_pairing_point_accumulator,
30pairing_point_accumulator_public_input_indices);
31```
32
33This approach assumes 1. all members are default constructible 2. you give it all members 3. all members are writable
34references
35
36This method maps the object's properties (e.g., `circuit_type`, `circuit_size`, etc.) to their respective keys in the
37serialized data.
38
39
40### Custom Serialization and Deserialization
41
42For custom serialization and deserialization, define `msgpack_pack` and `msgpack_unpack` methods in your class:
43
44```cpp
45// For serialization
46template <class Params> void field<Params>::msgpack_pack(auto& packer) const
47{
48 auto adjusted = from_montgomery_form();
49 uint64_t bin_data[4] = {
50 htonll(adjusted.data[3]), htonll(adjusted.data[2]), htonll(adjusted.data[1]), htonll(adjusted.data[0])
51 };
52 packer.pack_bin(sizeof(bin_data));
53 packer.pack_bin_body((const char*)bin_data, sizeof(bin_data));
54}
55
56// For deserialization
57template <class Params> void field<Params>::msgpack_unpack(auto o)
58{
59 msgpack::read_bin64(o, data, 4);
60 uint64_t reversed[] = {data[3], data[2], data[1], data[0]};
61 for (int i = 0; i < 4; i++) {
62 data[i] = reversed[i];
63 }
64 *this = to_montgomery_form();
65}
66```
67
68These methods allow you to implement custom logic for the serialization and deserialization processes.
69
70
71## Packing/Unpacking
72
73Only when actually using msgpack to write or read data, include "barretenberg/serialize/cbind.hpp".
74You can then use msgpack library features to serialize and deserialize C++ objects.
75
76e.g. packing
77```
78 // Create a buffer to store the encoded data
79 msgpack::sbuffer buffer;
80 msgpack::pack(buffer, obj);
81
82 uint8_t* output = (uint8_t*)aligned_alloc(64, buffer.size());
83 memcpy(output, buffer.data(), buffer.size());
84 // Convert the buffer data to a string and return it
85 return { output, buffer.size() };
86```
87
88e.g. unpacking
89
90```
91 msgpack::unpack((const char*)encoded_data, encoded_data_size).get().convert(*value);
92```
93
94Note that `msgpack::unpack` returns a `msgpack::object_handle` which controls the lifetime
95of the `msgpack::object` returned by `msgpack::object_handle::get`, so if you need access
96to the object itself, do break up the above to keep a reference to the handle, for example:
97
98```
99 msgpack::object_handle oh = msgpack::unpack((const char*)encoded_data, encoded_data_size);
100 msgpack::object o = oh.get();
101 try {
102 o.convert(*value);
103 } catch (const msgpack::type_error&) {
104 std::cerr << "failed to unpack: " << o << std::endl;
105 throw;
106 }
107```
108*/
109// For sbuffer forward declaration:
112#include <msgpack/sbuffer_decl.hpp>
113
114#include <string>
115#include <string_view>
116#include <type_traits>
117
118// Helper for above documented syntax
119// Define a macro that takes any amount of parameters and expands to a msgpack method definition
120// __VA__ARGS__ expands to the parmeters, comma separated.
121#define MSGPACK_FIELDS(...) \
122 void msgpack(auto pack_fn) \
123 { \
124 pack_fn(NVP(__VA_ARGS__)); \
125 }
126
127namespace msgpack_detail {
128
129// A constexpr function to convert a snake_case string to a camelCase string.
130inline constexpr std::string camel_case(std::string_view name)
131{
132 std::string result;
133 bool to_upper = false;
134 for (char c : name) {
135 if (c == '_') {
136 to_upper = true;
137 } else {
138 if (to_upper && c >= 'a' && c <= 'z') {
139 result += static_cast<char>(c - 'a' + 'A');
140 to_upper = false;
141 } else {
142 result += c;
143 to_upper = false;
144 }
145 }
146 }
147 return result;
148}
149
150// Helper to unwrap reference_wrappers or pass through values
151template <typename T> constexpr decltype(auto) unwrap_ref(T& t)
152{
153 if constexpr (requires { t.get(); }) {
154 return t.get();
155 } else {
156 return t;
157 }
158}
159
160} // namespace msgpack_detail
161
162// Same as MSGPACK_FIELDS but expecting the serialized names to be in camelCase.
163// NOTE: We use std::ref for fields to preserve references, store strings as values,
164// then unwrap reference_wrappers to get actual references while keeping strings as-is.
165#define MSGPACK_CAMEL_CASE_FIELDS(...) \
166 void msgpack(auto pack_fn) \
167 { \
168 auto temp_args = std::make_tuple(NVPFG(::msgpack_detail::camel_case, std::ref, __VA_ARGS__)); \
169 std::apply([&](auto&... args) { pack_fn(::msgpack_detail::unwrap_ref(args)...); }, temp_args); \
170 }
constexpr decltype(auto) unwrap_ref(T &t)
Definition msgpack.hpp:151
constexpr std::string camel_case(std::string_view name)
Definition msgpack.hpp:130