11#pragma once
22
33#include " barretenberg/api/api.hpp"
4+ #include " barretenberg/common/throw_or_abort.hpp"
45#include " barretenberg/common/version.hpp"
6+ #include " barretenberg/numeric/uint256/uint256.hpp"
57#include " barretenberg/serialize/msgpack.hpp"
68#include " barretenberg/serialize/msgpack_impl.hpp"
79#include < iomanip>
10+ #include < optional>
811#include < sstream>
912#include < string>
1013#include < vector>
1114
15+ // nlohmann/json has sign-conversion warnings that fail with -Werror in WASM builds
16+ #ifdef __clang__
17+ #pragma clang diagnostic push
18+ #pragma clang diagnostic ignored "-Wsign-conversion"
19+ #endif
20+ #include < nlohmann/json.hpp>
21+ #ifdef __clang__
22+ #pragma clang diagnostic pop
23+ #endif
24+
1225namespace bb {
1326
1427/* *
@@ -25,59 +38,195 @@ inline std::string bytes_to_hex_string(const std::vector<uint8_t>& bytes)
2538}
2639
2740/* *
28- * @brief Serializable structure for JSON output (msgpack-compatible)
41+ * @brief Try to parse file content as JSON
42+ *
43+ * @details Attempts to parse the content as JSON.
44+ * Returns nullopt if parsing fails, allowing fallback to binary format.
45+ */
46+ inline std::optional<nlohmann::json> try_parse_json (const std::vector<uint8_t >& content)
47+ {
48+ // Quick check: JSON objects must start with '{' (after whitespace)
49+ for (const auto & byte : content) {
50+ if (std::isspace (static_cast <unsigned char >(byte)) != 0 ) {
51+ continue ;
52+ }
53+ if (byte != ' {' ) {
54+ return std::nullopt ;
55+ }
56+ break ;
57+ }
58+
59+ // Try to parse as JSON
60+ try {
61+ std::string str (content.begin (), content.end ());
62+ return nlohmann::json::parse (str);
63+ } catch (...) {
64+ return std::nullopt ;
65+ }
66+ }
67+
68+ /* *
69+ * @brief Parse a hex string (with or without 0x prefix) to uint256_t
70+ */
71+ inline uint256_t hex_string_to_uint256 (const std::string& hex_str)
72+ {
73+ std::string str = hex_str;
74+ // Remove 0x prefix if present
75+ if (str.size () >= 2 && str[0 ] == ' 0' && (str[1 ] == ' x' || str[1 ] == ' X' )) {
76+ str = str.substr (2 );
77+ }
78+ // Pad to 64 characters (32 bytes) if needed
79+ if (str.size () < 64 ) {
80+ str.insert (0 , 64 - str.size (), ' 0' );
81+ }
82+ return uint256_t (str);
83+ }
84+
85+ /* *
86+ * @brief Serializable structure for VK JSON output (msgpack-compatible)
2987 */
30- struct JsonOutput {
31- std::vector<std::string> fields;
32- std::string vk_hash; // Only for VK and proof (hash of VK the proof targets)
33- std::string file_kind; // "vk", "proof", or "public_inputs"
88+ struct VkJson {
89+ std::vector<std::string> vk;
90+ std::string hash;
3491 std::string bb_version;
3592 std::string scheme;
36- std::string verifier_target; // Optional
3793
38- MSGPACK_FIELDS (fields, vk_hash, file_kind, bb_version, scheme, verifier_target);
94+ MSGPACK_FIELDS (vk, hash, bb_version, scheme);
95+
96+ template <typename T>
97+ static std::string build (const std::vector<T>& fields, const std::string& hash, const std::string& scheme)
98+ {
99+ std::vector<std::string> hex_fields;
100+ hex_fields.reserve (fields.size ());
101+ for (const auto & field : fields) {
102+ std::stringstream ss;
103+ ss << field;
104+ hex_fields.push_back (ss.str ());
105+ }
106+
107+ VkJson output{ .vk = std::move (hex_fields), .hash = hash, .bb_version = BB_VERSION, .scheme = scheme };
108+
109+ msgpack::sbuffer buffer;
110+ msgpack::pack (buffer, output);
111+ msgpack::object_handle oh = msgpack::unpack (buffer.data (), buffer.size ());
112+
113+ std::stringstream ss;
114+ ss << oh.get ();
115+ return ss.str ();
116+ }
117+
118+ static std::vector<uint8_t > parse_to_bytes (const nlohmann::json& json)
119+ {
120+ if (!json.contains (" vk" ) || !json[" vk" ].is_array ()) {
121+ throw_or_abort (" JSON missing 'vk' array" );
122+ }
123+ std::vector<uint8_t > result;
124+ result.reserve (json[" vk" ].size () * 32 );
125+ for (const auto & field : json[" vk" ]) {
126+ auto value = hex_string_to_uint256 (field.get <std::string>());
127+ for (int i = 3 ; i >= 0 ; --i) {
128+ uint64_t limb = value.data [i];
129+ for (int j = 7 ; j >= 0 ; --j) {
130+ result.push_back (static_cast <uint8_t >((limb >> (j * 8 )) & 0xFF ));
131+ }
132+ }
133+ }
134+ return result;
135+ }
39136};
40137
41138/* *
42- * @brief Build JSON output string using msgpack serialization
43- *
44- * @tparam T Field element type (must have operator<< that outputs 0x-prefixed hex)
45- * @param fields Vector of field elements to serialize
46- * @param file_kind Type identifier: "vk", "proof", or "public_inputs"
47- * @param flags API flags containing scheme and verifier_target
48- * @param vk_hash Optional hash string for VK or proof files
49- * @return JSON string
139+ * @brief Serializable structure for proof JSON output (msgpack-compatible)
50140 */
51- template <typename T>
52- std::string build_json_output (const std::vector<T>& fields,
53- const std::string& file_kind,
54- const API::Flags& flags,
55- const std::string& vk_hash = " " )
56- {
57- std::vector<std::string> hex_fields;
58- hex_fields.reserve (fields.size ());
59- for (const auto & field : fields) {
141+ struct ProofJson {
142+ std::vector<std::string> proof;
143+ std::string vk_hash;
144+ std::string bb_version;
145+ std::string scheme;
146+
147+ MSGPACK_FIELDS (proof, vk_hash, bb_version, scheme);
148+
149+ template <typename T>
150+ static std::string build (const std::vector<T>& fields, const std::string& vk_hash, const std::string& scheme)
151+ {
152+ std::vector<std::string> hex_fields;
153+ hex_fields.reserve (fields.size ());
154+ for (const auto & field : fields) {
155+ std::stringstream ss;
156+ ss << field;
157+ hex_fields.push_back (ss.str ());
158+ }
159+
160+ ProofJson output{
161+ .proof = std::move (hex_fields), .vk_hash = vk_hash, .bb_version = BB_VERSION, .scheme = scheme
162+ };
163+
164+ msgpack::sbuffer buffer;
165+ msgpack::pack (buffer, output);
166+ msgpack::object_handle oh = msgpack::unpack (buffer.data (), buffer.size ());
167+
60168 std::stringstream ss;
61- ss << field; // T's operator<< outputs "0x" prefix
62- hex_fields.push_back (ss.str ());
169+ ss << oh.get ();
170+ return ss.str ();
171+ }
172+
173+ static std::vector<uint256_t > parse (const nlohmann::json& json)
174+ {
175+ if (!json.contains (" proof" ) || !json[" proof" ].is_array ()) {
176+ throw_or_abort (" JSON missing 'proof' array" );
177+ }
178+ std::vector<uint256_t > result;
179+ result.reserve (json[" proof" ].size ());
180+ for (const auto & field : json[" proof" ]) {
181+ result.push_back (hex_string_to_uint256 (field.get <std::string>()));
182+ }
183+ return result;
63184 }
185+ };
186+
187+ /* *
188+ * @brief Serializable structure for public inputs JSON output (msgpack-compatible)
189+ */
190+ struct PublicInputsJson {
191+ std::vector<std::string> public_inputs;
192+ std::string bb_version;
193+ std::string scheme;
64194
65- JsonOutput output{
66- .fields = std::move (hex_fields),
67- .vk_hash = vk_hash,
68- .file_kind = file_kind,
69- .bb_version = BB_VERSION,
70- .scheme = flags.scheme ,
71- .verifier_target = flags.verifier_target ,
72- };
195+ MSGPACK_FIELDS (public_inputs, bb_version, scheme);
73196
74- msgpack::sbuffer buffer;
75- msgpack::pack (buffer, output);
76- msgpack::object_handle oh = msgpack::unpack (buffer.data (), buffer.size ());
197+ template <typename T> static std::string build (const std::vector<T>& fields, const std::string& scheme)
198+ {
199+ std::vector<std::string> hex_fields;
200+ hex_fields.reserve (fields.size ());
201+ for (const auto & field : fields) {
202+ std::stringstream ss;
203+ ss << field;
204+ hex_fields.push_back (ss.str ());
205+ }
77206
78- std::stringstream ss;
79- ss << oh.get ();
80- return ss.str ();
81- }
207+ PublicInputsJson output{ .public_inputs = std::move (hex_fields), .bb_version = BB_VERSION, .scheme = scheme };
208+
209+ msgpack::sbuffer buffer;
210+ msgpack::pack (buffer, output);
211+ msgpack::object_handle oh = msgpack::unpack (buffer.data (), buffer.size ());
212+
213+ std::stringstream ss;
214+ ss << oh.get ();
215+ return ss.str ();
216+ }
217+
218+ static std::vector<uint256_t > parse (const nlohmann::json& json)
219+ {
220+ if (!json.contains (" public_inputs" ) || !json[" public_inputs" ].is_array ()) {
221+ throw_or_abort (" JSON missing 'public_inputs' array" );
222+ }
223+ std::vector<uint256_t > result;
224+ result.reserve (json[" public_inputs" ].size ());
225+ for (const auto & field : json[" public_inputs" ]) {
226+ result.push_back (hex_string_to_uint256 (field.get <std::string>()));
227+ }
228+ return result;
229+ }
230+ };
82231
83232} // namespace bb
0 commit comments