Zeth - Zerocash on Ethereum  0.8
Reference implementation of the Zeth protocol by Clearmatics
mpc_phase2_verify_transcript.cpp
Go to the documentation of this file.
1 // Copyright (c) 2015-2022 Clearmatics Technologies Ltd
2 //
3 // SPDX-License-Identifier: LGPL-3.0+
4 
6 #include "mpc_common.hpp"
7 
8 #include <boost/program_options.hpp>
9 #include <fstream>
10 
11 using namespace libzeth;
12 using pp = defaults::pp;
13 namespace po = boost::program_options;
14 
15 namespace
16 {
17 
18 // Usage:
19 // $0 phase2-verify-transcript [<options>]
20 // <challenge_0_file> <transcript_file> <final_challenge_file>
21 //
22 // Options:
23 // --digest <file> Confirm that a contribution with the given digest is
24 // included in the transcript.
25 class mpc_phase2_verify_transcript : public mpc_subcommand
26 {
27 private:
28  std::string challenge_0_file;
29  std::string transcript_file;
30  std::string final_challenge_file;
31  std::string digest;
32 
33 public:
34  mpc_phase2_verify_transcript()
36  "phase2-verify-transcript",
37  "Verify full transcript, check specific contribution")
38  , challenge_0_file()
39  , transcript_file()
40  , final_challenge_file()
41  , digest()
42  {
43  }
44 
45 private:
46  void initialize_suboptions(
47  po::options_description &options,
48  po::options_description &all_options,
49  po::positional_options_description &pos) override
50  {
51  options.add_options()(
52  "digest",
53  po::value<std::string>(),
54  "Check that transcript includes contribution digest");
55  all_options.add(options).add_options()(
56  "challenge_0_file", po::value<std::string>(), "challenge file")(
57  "transcript_file", po::value<std::string>(), "transcript file")(
58  "final_challenge_file",
59  po::value<std::string>(),
60  "final challenge file");
61  pos.add("challenge_0_file", 1)
62  .add("transcript_file", 1)
63  .add("final_challenge_file", 1);
64  }
65 
66  void parse_suboptions(const po::variables_map &vm) override
67  {
68  if (0 == vm.count("challenge_0_file")) {
69  throw po::error("challenge_0_file not specified");
70  }
71  if (0 == vm.count("transcript_file")) {
72  throw po::error("transcript_file not specified");
73  }
74  if (0 == vm.count("final_challenge_file")) {
75  throw po::error("final_challenge_file not specified");
76  }
77  challenge_0_file = vm["challenge_0_file"].as<std::string>();
78  transcript_file = vm["transcript_file"].as<std::string>();
79  final_challenge_file = vm["final_challenge_file"].as<std::string>();
80  digest = vm.count("digest") ? vm["digest"].as<std::string>() : "";
81  }
82 
83  void subcommand_usage(const char *argv0) override
84  {
85  std::cout << "Usage:\n " << argv0 << " " << subcommand_name
86  << " \\\n <challenge_0_file> <transcript_file> "
87  "<final_challenge_file>\n\n";
88  }
89 
90  int execute_subcommand(const global_options &options) override
91  {
92  if (options.verbose) {
93  std::cout << "challenge_0: " << challenge_0_file << "\n"
94  << "transcript: " << transcript_file << "\n"
95  << "final_challenge: " << final_challenge_file
96  << std::endl;
97  }
98 
99  // Load the initial challenge
100  libff::enter_block("Load challenge_0 file");
101  const srs_mpc_phase2_challenge<pp> challenge_0 =
102  read_from_file<const srs_mpc_phase2_challenge<pp>>(
103  challenge_0_file);
104  libff::leave_block("Load challenge_0 file");
105 
106  // Simple sanity check on challenge.0. The initial transcript digest
107  // should be based on the cs_hash for this MPC.
108  {
109  mpc_hash_t init_transcript_digest;
111  init_transcript_digest,
112  challenge_0.accumulator.cs_hash,
113  sizeof(mpc_hash_t));
114  if (0 != memcmp(
115  init_transcript_digest,
116  challenge_0.transcript_digest,
117  sizeof(mpc_hash_t))) {
118  throw std::invalid_argument(
119  "transcript digest does not match starting challenge");
120  }
121  }
122 
123  bool check_for_contribution = false;
124 
125  // If required, load a contribution hash and set the
126  // `check_for_contribution` flag.
127  mpc_hash_t check_contribution_digest;
128  if (!digest.empty()) {
129  std::ifstream in(digest, std::ios_base::in);
130  in.exceptions(
131  std::ios_base::eofbit | std::ios_base::badbit |
132  std::ios_base::failbit);
133  if (!mpc_hash_read(check_contribution_digest, in)) {
134  throw std::invalid_argument(
135  "could not parse contribution digest");
136  }
137 
138  check_for_contribution = true;
139  }
140 
141  // Verify transcript based on the initial challenge
142  libff::enter_block("Verify transcript");
143  libff::G1<pp> final_delta;
144  mpc_hash_t final_transcript_digest{};
145  {
146  std::ifstream in(
147  transcript_file, std::ios_base::binary | std::ios_base::in);
148  bool transcript_valid = false;
149  bool contribution_found = false;
150  if (check_for_contribution) {
151  transcript_valid = srs_mpc_phase2_verify_transcript<pp>(
152  challenge_0.transcript_digest,
153  challenge_0.accumulator.delta_g1,
154  check_contribution_digest,
155  in,
156  final_delta,
157  final_transcript_digest,
158  contribution_found);
159  } else {
160  contribution_found = true;
161  transcript_valid = srs_mpc_phase2_verify_transcript<pp>(
162  challenge_0.transcript_digest,
163  challenge_0.accumulator.delta_g1,
164  in,
165  final_delta,
166  final_transcript_digest);
167  }
168 
169  if (!transcript_valid) {
170  std::cerr << "Transcript was invalid" << std::endl;
171  return 1;
172  }
173 
174  if (!contribution_found) {
175  std::cerr << "Specified contribution digest was not found"
176  << std::endl;
177  return 1;
178  }
179  }
180  libff::leave_block("Verify transcript");
181 
182  // Load and check the final challenge
183  libff::enter_block("Load phase2 output");
184  const srs_mpc_phase2_challenge<pp> final_challenge =
185  read_from_file<const srs_mpc_phase2_challenge<pp>>(
186  final_challenge_file);
187  libff::leave_block("Load phase2 output");
188 
189  libff::enter_block("Verify final output");
190  if (0 != memcmp(
191  final_challenge.transcript_digest,
192  final_transcript_digest,
193  sizeof(mpc_hash_t))) {
194  throw std::invalid_argument(
195  "invalid transcript digest in final accumulator");
196  }
197  if (final_challenge.accumulator.delta_g1 != final_delta) {
198  throw std::invalid_argument(
199  "invalid delta_g1 in final accumulator");
200  }
202  challenge_0.accumulator, final_challenge.accumulator)) {
203  throw std::invalid_argument("accumlators are inconsistent");
204  }
205  libff::leave_block("Verify final output");
206 
207  std::cout << "Transcript OK!" << std::endl;
208  return 0;
209  }
210 };
211 
212 } // namespace
213 
215  new mpc_phase2_verify_transcript();
mpc_common.hpp
mpc_phase2_verify_transcript_cmd
mpc_subcommand * mpc_phase2_verify_transcript_cmd
Definition: mpc_phase2_verify_transcript.cpp:214
pp
defaults::pp pp
Definition: mpc_phase2_verify_transcript.cpp:12
libzeth::srs_mpc_phase2_challenge::accumulator
srs_mpc_phase2_accumulator< ppT > accumulator
Definition: phase2.hpp:114
libzeth
Definition: binary_operation.hpp:15
global_options::verbose
bool verbose
Definition: mpc_subcommand.hpp:19
libzeth::srs_mpc_phase2_challenge
Definition: phase2.hpp:110
global_options
Definition: mpc_subcommand.hpp:15
mpc_subcommand
libtool::subcommand< global_options > mpc_subcommand
Definition: mpc_subcommand.hpp:22
libzeth::mpc_hash_t
size_t[MPC_HASH_ARRAY_LENGTH] mpc_hash_t
Definition: mpc_hash.hpp:21
pp
defaults::pp pp
Definition: mpc_create_keypair.cpp:14
libzeth::srs_mpc_phase2_challenge::transcript_digest
mpc_hash_t transcript_digest
Definition: phase2.hpp:113
libzeth::mpc_hash_read
bool mpc_hash_read(mpc_hash_t out_hash, std::istream &in)
Definition: mpc_hash.cpp:63
phase2.hpp
libzeth::mpc_compute_hash
void mpc_compute_hash(mpc_hash_t out_hash, const void *data, size_t data_size)
Definition: mpc_hash.cpp:40
libtool::subcommand
Class representing a tool subcommand.
Definition: subcommand.hpp:18
libzeth::srs_mpc_phase2_update_is_consistent
bool srs_mpc_phase2_update_is_consistent(const srs_mpc_phase2_accumulator< ppT > &last, const srs_mpc_phase2_accumulator< ppT > &updated)