11 #include "zecale_config.h"
13 #include <boost/program_options.hpp>
15 #include <grpc/grpc.h>
16 #include <grpcpp/security/server_credentials.h>
17 #include <grpcpp/server.h>
18 #include <grpcpp/server_builder.h>
19 #include <grpcpp/server_context.h>
21 #include <libsnark/common/data_structures/merkle_tree.hpp>
22 #include <libtool/tool_util.hpp>
23 #include <libzeth/circuits/circuit_types.hpp>
24 #include <libzeth/core/utils.hpp>
25 #include <libzeth/serialization/proto_utils.hpp>
26 #include <libzeth/serialization/r1cs_serialization.hpp>
27 #include <libzeth/zeth_constants.hpp>
32 #include <zecale/api/aggregator.grpc.pb.h>
34 namespace proto = google::protobuf;
35 namespace po = boost::program_options;
38 #if defined(ZECALE_CURVE_MNT6)
39 #include <libsnark/gadgetlib1/gadgets/pairing/mnt/mnt_pairing_params.hpp>
40 using wpp = libff::mnt6_pp;
41 #elif defined(ZECALE_CURVE_BW6_761)
42 #include <libsnark/gadgetlib1/gadgets/pairing/bw6_761_bls12_377/bw6_761_pairing_params.hpp>
43 using wpp = libff::bw6_761_pp;
45 #error "ZECALE_CURVE_* variable not set to supported curve"
49 using npp = libsnark::other_curve<wpp>;
52 #if defined(ZECALE_SNARK_PGHR13)
54 #include <libzeth/snarks/pghr13/pghr13_api_handler.hpp>
55 using wsnark = libzeth::pghr13_snark<wpp>;
56 using wapi_handler = libzeth::pghr13_api_handler<wpp>;
58 using napi_handler = libzeth::pghr13_api_handler<npp>;
59 #elif defined(ZECALE_SNARK_GROTH16)
61 #include <libzeth/snarks/groth16/groth16_api_handler.hpp>
62 using wsnark = libzeth::groth16_snark<wpp>;
63 using wapi_handler = libzeth::groth16_api_handler<wpp>;
65 using napi_handler = libzeth::groth16_api_handler<npp>;
67 #error "ZECALE_SNARK_* variable not set to supported ZK snark"
70 using nsnark =
typename nverifier::snark;
72 static const size_t batch_size = 2;
73 static const size_t num_inputs_per_nested_proof = 1;
89 const wsnark::keypair &keypair;
92 std::map<std::string, application_pool *> application_pools;
97 : aggregator(aggregator), keypair(keypair)
104 for (
const auto &entry : application_pools) {
107 application_pools.clear();
111 grpc::ServerContext * ,
112 const proto::Empty * ,
113 zecale_proto::AggregatorConfiguration *response)
override
115 std::cout <<
"[INFO] Request for configuration\n";
116 libzecale::aggregator_configuration_to_proto<npp, wpp, nsnark, wsnark>(
118 return grpc::Status::OK;
122 grpc::ServerContext * ,
123 const proto::Empty * ,
124 zeth_proto::VerificationKey *response)
override
126 std::cout <<
"[ACK] Received the request to get the verification key"
128 std::cout <<
"[DEBUG] Preparing verification key for response..."
131 wapi_handler::verification_key_to_proto(keypair.vk, response);
132 }
catch (
const std::exception &e) {
133 std::cout <<
"[ERROR] " << e.what() << std::endl;
135 grpc::StatusCode::INVALID_ARGUMENT, grpc::string(e.what()));
137 std::cout <<
"[ERROR] In catch all" << std::endl;
138 return grpc::Status(grpc::StatusCode::UNKNOWN,
"");
141 return grpc::Status::OK;
145 grpc::ServerContext * ,
146 const zeth_proto::VerificationKey *request,
147 zecale_proto::VerificationKeyHash *response)
override
149 typename nsnark::verification_key vk =
150 napi_handler::verification_key_from_proto(*request);
151 const libff::Fr<wpp> vk_hash =
154 const std::string vk_hash_str = libzeth::field_element_to_json(vk_hash);
155 response->set_hash(vk_hash_str);
157 std::cout <<
"[DEBUG] GetNestedVerificationKeyHash: "
159 nsnark::verification_key_write_json(vk, std::cout);
160 std::cout <<
"\n VK hash: " << vk_hash_str <<
"\n";
161 return grpc::Status::OK;
165 grpc::ServerContext * ,
166 const zecale_proto::ApplicationDescription *registration,
167 zecale_proto::VerificationKeyHash *response)
override
169 std::cout <<
"[ACK] Received 'register application' request"
171 std::cout <<
"[DEBUG] Registering application..." << std::endl;
175 const std::string &
name = registration->application_name();
176 if (application_pools.count(
name)) {
178 grpc::StatusCode::INVALID_ARGUMENT,
179 grpc::string(
"application already registered"));
184 const zeth_proto::VerificationKey &vk_proto = registration->vk();
185 typename nsnark::verification_key vk =
186 napi_handler::verification_key_from_proto(vk_proto);
188 const libff::Fr<wpp> vk_hash =
191 const std::string vk_hash_str =
192 libzeth::field_element_to_json(vk_hash);
193 response->set_hash(vk_hash_str);
195 std::cout <<
"[DEBUG] Registered application '" <<
name
197 nsnark::verification_key_write_json(vk, std::cout);
198 std::cout <<
"\n VK hash: " << vk_hash_str <<
"\n";
199 }
catch (
const std::exception &e) {
200 std::cout <<
"[ERROR] " << e.what() << std::endl;
202 grpc::StatusCode::INVALID_ARGUMENT, grpc::string(e.what()));
204 std::cout <<
"[ERROR] In catch all" << std::endl;
205 return grpc::Status(grpc::StatusCode::UNKNOWN,
"");
208 return grpc::Status::OK;
212 grpc::ServerContext * ,
213 const zecale_proto::NestedTransaction *transaction,
214 proto::Empty * )
override
219 const std::string &app_name = transaction->application_name();
220 std::cout <<
"[ACK] Received nested transaction, app name: "
221 << app_name << std::endl;
226 libzecale::nested_transaction_from_proto<npp, napi_handler>(
229 num_inputs_per_nested_proof) {
230 throw std::invalid_argument(
"invalid number of inputs");
236 std::cout <<
"[DEBUG] Registered tx with ext proof:\n";
239 std::cout <<
"[DEBUG] " << std::to_string(app_pool->
tx_pool_size())
241 }
catch (
const std::exception &e) {
242 std::cout <<
"[ERROR] " << e.what() << std::endl;
244 grpc::StatusCode::INVALID_ARGUMENT, grpc::string(e.what()));
246 std::cout <<
"[ERROR] In catch all" << std::endl;
247 return grpc::Status(grpc::StatusCode::UNKNOWN,
"");
250 return grpc::Status::OK;
254 grpc::ServerContext * ,
255 const zecale_proto::AggregatedTransactionRequest *request,
256 zecale_proto::AggregatedTransaction *response)
override
261 const std::string &app_name = request->application_name();
262 std::cout <<
"[ACK] Aggregation tx request, app name: " << app_name
267 std::array<libzecale::nested_transaction<npp, nsnark>, batch_size>
270 std::cout <<
"[DEBUG] Got batch of size "
271 << std::to_string(num_entries) <<
" from the pool\n";
272 if (num_entries == 0) {
273 throw std::runtime_error(
"insufficient entries in pool");
277 std::array<const libzeth::extended_proof<npp, nsnark> *, batch_size>
279 for (
size_t i = 0; i < batch_size; ++i) {
280 nested_proofs[i] = &batch[i].extended_proof();
282 std::cout <<
"[DEBUG] got tx " << std::to_string(i)
283 <<
" with ext proof:\n";
284 nested_proofs[i]->write_json(std::cout);
288 const nsnark::verification_key &nested_vk =
291 std::cout <<
"[DEBUG] Generating the batched proof...\n";
292 libzeth::extended_proof<wpp, wsnark> wrapping_proof =
293 aggregator.
prove(nested_vk, nested_proofs, keypair.pk);
295 std::cout <<
"[DEBUG] Generated extended proof:\n";
296 wrapping_proof.write_json(std::cout);
300 response->set_application_name(app_name);
301 zeth_proto::ExtendedProof *wrapping_proof_proto =
302 new zeth_proto::ExtendedProof();
303 wapi_handler::extended_proof_to_proto(
304 wrapping_proof, wrapping_proof_proto);
305 response->set_allocated_extended_proof(wrapping_proof_proto);
306 for (
size_t i = 0; i < batch_size; ++i) {
307 const std::vector<uint8_t> ¶meters = batch[i].parameters();
308 response->add_nested_parameters(
309 (
const char *)parameters.data(), parameters.size());
311 std::cout <<
"[DEBUG] Written to response" << std::endl;
312 }
catch (
const std::exception &e) {
313 std::cout <<
"[ERROR] " << e.what() << std::endl;
315 grpc::StatusCode::INVALID_ARGUMENT, grpc::string(e.what()));
317 std::cout <<
"[ERROR] In catch all" << std::endl;
318 return grpc::Status(grpc::StatusCode::UNKNOWN,
"");
321 return grpc::Status::OK;
334 ZECALE_VERSION_MAJOR,
335 ZECALE_VERSION_MINOR);
337 return "Version <Not specified>";
345 std::string copyright =
346 "Copyright (c) 2015-2022 Clearmatics Technologies Ltd";
347 std::string license =
"SPDX-License-Identifier: LGPL-3.0+";
348 std::string project =
"R&D Department: PoC for a privacy preserving "
349 "scalability solution on Ethereum";
351 std::string warning =
"**WARNING:** This code is a research-quality proof "
352 "of concept, DO NOT use in production!";
354 std::cout <<
"\n=====================================================\n";
355 std::cout << copyright <<
"\n";
356 std::cout << license <<
"\n";
357 std::cout << project <<
"\n";
359 std::cout << warning <<
"\n";
360 std::cout <<
"=====================================================\n"
364 static void RunServer(
369 std::string server_address(
"0.0.0.0:50052");
373 grpc::ServerBuilder builder;
376 builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
380 builder.RegisterService(&service);
383 std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
384 std::cout <<
"[DEBUG] Server listening on " << server_address << std::endl;
392 int main(
int argc,
char **argv)
395 po::options_description options(
"");
396 options.add_options()(
398 po::value<boost::filesystem::path>(),
399 "file to load keypair from");
401 options.add_options()(
403 po::value<boost::filesystem::path>(),
404 "file in which to export the r1cs in json format");
408 std::cout <<
"Usage:"
410 <<
" " << argv[0] <<
" [<options>]\n"
412 std::cout << options;
413 std::cout << std::endl;
416 boost::filesystem::path keypair_file;
417 boost::filesystem::path r1cs_file;
419 po::variables_map vm;
421 po::command_line_parser(argc, argv).options(options).run(), vm);
422 if (vm.count(
"help")) {
426 if (vm.count(
"keypair")) {
427 keypair_file = vm[
"keypair"].as<boost::filesystem::path>();
429 if (vm.count(
"r1cs")) {
430 r1cs_file = vm[
"r1cs"].as<boost::filesystem::path>();
432 }
catch (po::error &error) {
433 std::cerr <<
" ERROR: " << error.what() << std::endl;
439 if (keypair_file.empty()) {
440 boost::filesystem::path setup_dir =
441 libzeth::get_path_to_setup_directory();
442 if (!setup_dir.empty()) {
443 boost::filesystem::create_directories(setup_dir);
445 keypair_file = setup_dir /
"zecale_keypair.bin";
449 std::cout <<
"[INFO] Init params of both curves" << std::endl;
450 npp::init_public_params();
451 wpp::init_public_params();
457 wsnark::keypair keypair = [&keypair_file, &aggregator]() {
458 if (boost::filesystem::exists(keypair_file)) {
459 std::cout <<
"[INFO] Loading keypair: " << keypair_file <<
"\n";
460 wsnark::keypair keypair;
462 libtool::open_binary_input_file(keypair_file.c_str());
463 wsnark::keypair_read_bytes(keypair, in_s);
467 throw std::invalid_argument(
"invalid VK");
473 std::cout <<
"[INFO] No keypair file " << keypair_file
474 <<
". Generating.\n";
479 throw std::invalid_argument(
"invalid VK");
482 const size_t num_constraints =
484 std::cout <<
"[INFO] Circuit has " << std::to_string(num_constraints)
487 std::cout <<
"[INFO] Writing new keypair to " << keypair_file <<
"\n";
488 std::ofstream out_s =
489 libtool::open_binary_output_file(keypair_file.c_str());
490 wsnark::keypair_write_bytes(keypair, out_s);
496 if (!r1cs_file.empty()) {
497 std::cout <<
"[INFO] Writing R1CS to " << std::endl;
498 std::ofstream r1cs_stream(r1cs_file.c_str());
499 libzeth::r1cs_write_json(
504 std::cout <<
"[INFO] Setup successful, starting the server..." << std::endl;
505 RunServer(aggregator, keypair);