All Classes Namespaces Files Functions Variables Macros Pages
main.cpp
Go to the documentation of this file.
1 
10 #include <cstring>
11 #include <cstdlib>
12 #include <cstdint>
13 #include <string>
14 #include <vector>
15 #include <iostream>
16 #include <iomanip>
17 
20 #include "arithm/arithm.hpp"
21 #include "elgamal/elgamal.hpp"
22 #include "xmlconfig/xmlconfig.hpp"
23 #include "proofs/proofs.hpp"
24 
25 
30 {
31  std::cout<<"\n c++ verificatum verifier\n\n"
32  <<"To use this software, use the following line:\n\n"
33  <<"./cppverifier <protInfo.xml> <roProof>\n\n"
34  <<"Where <protInfo.xml> is an xml file desciring the "
35  <<"protocol info and <roProof> is the path to the "
36  <<"proof directory.\n"
37  <<std::endl;
38 }
39 
40 
51 std::string concatenation(std::string str1, char separator,
52  std::string str2)
53 {
54  std::string res = str1;
55  res.push_back(separator);
56  res.insert(res.end(),str2.begin(),str2.end());
57  return res;
58 }
59 
60 
71 std::string getPath(std::string dir, std::string type, unsigned int l)
72 {
73  std::string res;
74  res = concatenation(dir,'/',type);
75  res.push_back('0' + l/10);
76  res.push_back('0' + l%10);
77  res = concatenation(res,'.',"bt");
78  return res;
79 }
80 
81 
96 void preprocessArgs(int argc,
97  char ** argv,
98  std::string &configFile,
99  std::string &path2roDir)
100 {
101  if (argc < 3)
102  // Too few cli arguments
103  {
104  displayHelp();
105  exit(1);
106  }
107  else
108  {
109  configFile.assign(argv[1]);
110  path2roDir.assign(argv[2]);
111  }
112 }
113 
114 
115 
116 
127 int main(int argc, char ** argv)
128 {
129  bool readingWasOK; // to know if proofs are well initialized
130 
131  // 1- done by hand
132 
133  /* NOTHING */
134  std::cout<<"1. Must be done by hand."<<std::endl;
135 
136 
137  // 2- Public parameters
138 
139  std::cout<<"2. Initialising public parameters"<<std::endl;
140  std::string protInfo, roProof;
141  preprocessArgs(argc,argv,protInfo,roProof);
142  XmlConfig * config = new XmlConfig(protInfo);
143  arithm::Group * gq = config->getPgroup();
144  arithm::Group * M = gq;
146  elGamal::CipherGroup c(gq);
147 
148 
149  // 3- prefix to random oracles
150 
151  std::cout<<"3. Setting up the prefix for the RO"<<std::endl;
152  std::vector<uint8_t> content, rho;
154  content = verifierUtils::file2bytes(protInfo);
155  H->hash(content);
156  rho = H->getHash();
157 
158 
159  // 4- joint public key
160 
161  std::cout<<"4. Reading the joint public key"<<std::endl;
162  verifierUtils::ByteTree * btPublicKey = verifierUtils::ByteTree::parseFile(concatenation(roProof,'/',"FullPublicKey.bt"));
163  arithm::Elmt pk = gq->getElmt(btPublicKey->getChild(1)->getChild(1));
164 
165 
166  // 5- individual public keys
167 
168  std::cout<<"5. Reading individual public keys"<<std::endl;
169  unsigned int k = config->getNopart();
171  for (unsigned int l=1; l<=k; l++)
172  {
173  std::cout<<" reading key #"<<l<<std::endl;
174  verifierUtils::ByteTree * btIndKey = verifierUtils::ByteTree::parseFile(getPath(roProof,"PublicKey",l));
175  y.addElmt(gq->getElmt(btIndKey));
176  }
177  arithm::Elmt prod = gq->product(y);
178  if (!gq->compare(prod,pk))
179  {
180  std::cout<<"\nREJECT: $\\prod_{l=1}^{k} y_l \\noteq pk$"<<std::endl;
181  return 1;
182  }
183  else
184  std::cout<<" We do have $\\prod_{l=1}^{k} y_l \\eq pk$"<<std::endl;
185 
186 
187  // 6- Array of Input Ciphertexts
188 
189  std::cout<<"6. Reading the 0th array of input ciphertexts"<<std::endl;
190  elGamal::CipherGroup C(gq);
191  std::cout<<" reading cipher text #0"<<std::endl;
192  verifierUtils::ByteTree * btArrayCipherText = verifierUtils::ByteTree::parseFile(getPath(roProof,"CiphertextList",0));
193  elGamal::ArrayOfCiphers LlMinus1(btArrayCipherText,C);
194  unsigned int N = LlMinus1.size();
195  unsigned int N0 = (config->getMaxciph() != 0)? config->getMaxciph() : N;
196  std::cout<<" N="<<N<<", N_0="<<N0<<std::endl;
197 
198 
199  // 7- Proofs of shuffle
200 
201  unsigned int lambda = config->getThres();
202  std::cout<<"7. PROOFS OF SHUFFLE for l=1.."<<lambda<<std::endl;
203  for (unsigned int l=1; l<=lambda; l++)
204  {
205  std::cout<<" l="<<l<<std::endl;
206  // a) Verify Proof of Shuffle of Commitments
207  verifierUtils::ByteTree * btUl = verifierUtils::ByteTree::parseFile(getPath(roProof,"PermutationCommitment",l));
208  verifierUtils::ByteTree * tauPos = verifierUtils::ByteTree::parseFile(getPath(roProof,"PoSCommitment",l));
209  verifierUtils::ByteTree * sigmaPos = verifierUtils::ByteTree::parseFile(getPath(roProof,"PoSReply",l));
210  arithm::ArrayOfElmts ul = gq->getArray(btUl);
211 
212  proofs::ProofOfShuffleOfCommitments shuffleOfCommitments(
213  readingWasOK, config, rho, N0, ul, tauPos, sigmaPos);
214  if (!readingWasOK)
215  {
216  std::cout<<" a) Proof of shuffle of commitments could not be initialized."<<std::endl;
217  ul = shuffleOfCommitments.getGenerators();
218  }
219  else if (!shuffleOfCommitments.isEverythingOK())
220  {
221  std::cout<<" a) Proof of shuffle of commitments went wrong so ul=h"<<std::endl;
222  ul = shuffleOfCommitments.getGenerators();
223  }
224  else
225  std::cout<<" a) Proof of shuffle of commitments passed."<<std::endl;
226 
227  // b) Shrink Permutation Commitment
228  verifierUtils::ByteTree * keepList = verifierUtils::ByteTree::parseFile(getPath(roProof,"KeepList",l));
229  std::vector<bool> tl = keepList->toBoolArray();
230  if (tl.size() != N0)
231  {
232  tl.assign(N0, false);
233  for (unsigned int i=0; i<N; i++)
234  tl[i] = true;
235  }
236  else
237  {
238  unsigned int hammingWeight = 0;
239  for (unsigned int i=0; i<N0; i++)
240  if (tl[i])
241  hammingWeight++;
242  if (hammingWeight != N)
243  {
244  tl.assign(N0, false);
245  for (unsigned int i=0; i<N; i++)
246  tl[i] = true;
247  }
248  }
249  ul = ul.subArray(tl);
250  std::cout<<" b) Keep list parsed."<<std::endl;
251 
252  // c) Array of CipherTexts
253  btArrayCipherText = verifierUtils::ByteTree::parseFile(getPath(roProof,"CiphertextList",l));
254  elGamal::ArrayOfCiphers Ll(btArrayCipherText,C);
255  std::cout<<" c) array of ciphertext L_"<<l<<" read."<<std::endl;
256 
257  // d) Verify Commitment-Consistent Proof of Shuffle
258  verifierUtils::ByteTree * tauCCPos = verifierUtils::ByteTree::parseFile(getPath(roProof,"CCPoSCommitment",l));
259  verifierUtils::ByteTree * sigmaCCPos = verifierUtils::ByteTree::parseFile(getPath(roProof,"CCPoSReply",l));
260  proofs::ProofOfShuffleOfCiphers commitmentConsistent(
261  readingWasOK, config, rho, ul, N, R, C, pk, LlMinus1, Ll, tauCCPos, sigmaCCPos);
262  if ( (!readingWasOK) || (!commitmentConsistent.isEverythingOK()) )
263  {
264  std::cout<<" d) Proof of commitment consistent shuffle went wrong..."<<std::endl;
265  if ( !C.compare(LlMinus1,Ll) )
266  {
267  std::cout<<"\nREJECT: Algorithm 18 rejected and $L_{l-1} \\neq L_l$ "<<std::endl;
268  return 1;
269  }
270  std::cout<<" ... but L_{l-1} \\eq L_l$"<<std::endl;
271  }
272  else
273  {
274  std::cout<<" d) Proof of commitment consistent shuffle passed."<<std::endl;
275  }
276 
277  LlMinus1 = Ll;
278  }
279 
280 
281  // 8- Proof of decryption
282 
283  std::cout<<"8. PROOF OF DECRYPTION for l=1.."<<k<<std::endl;
284  arithm::ArrayOfElmts f = gq->getOne(N);
285  for (unsigned int l=1; l<=k; l++)
286  {
287  // 0) trying to read x_l
288  verifierUtils::ByteTree * secretKey = verifierUtils::ByteTree::parseFile(getPath(roProof,"SecretKey",l));
290  if (
291  (secretKey != NULL)
292  && (gq->compare(
293  gq->exponentiation(gq->getGenerator(),arithm::Elmt (secretKey->getChild(1),NULL)),
294  y.getElmt(l)))
295  )
296  {
297  // a) x_l can be read and y_l == g^{x_l}
298  std::cout<<" a-case) x_l could be read and $y_l \\eq g^{x_l}$"<<std::endl;
299  arithm::Elmt xl(secretKey->getChild(1),NULL);
300  fl = C.pdec(xl,LlMinus1);
301  std::cout<<" f_l set to $PDec_{x_l}(L_{l-1})"<<std::endl;
302  }
303  else
304  {
305  // b) x_l can NOT be read
306  std::cout<<" b-case) x_l could not be read or $y_l \\noteq g^{x_l}$"<<std::endl;
307  verifierUtils::ByteTree * decFactor = verifierUtils::ByteTree::parseFile(getPath(roProof,"DecryptionFactors",l));
308  fl = gq->getArray(decFactor->getChild(1));
309 
310  // running the proof of correct decryption
311  verifierUtils::ByteTree * taul = verifierUtils::ByteTree::parseFile(getPath(roProof,"DecrFactCommitment",l));
312  verifierUtils::ByteTree * sigmal = verifierUtils::ByteTree::parseFile(getPath(roProof,"DecrFactReply",l));
313  btArrayCipherText = verifierUtils::ByteTree::parseFile(getPath(roProof,"CiphertextList",lambda));
314  elGamal::ArrayOfCiphers Llambda(btArrayCipherText,C);
315  proofs::ProofOfCorrectDecryption correctDecryption(
316  readingWasOK, config, rho, N, y.getElmt(l-1), C, M, Llambda, fl, taul, sigmal);
317  if (!readingWasOK)
318  {
319  std::cout<<"\nREJECT: Algorithm 18 rejected because it could not read the data it needed."
320  <<std::endl;
321  return 1;
322  }
323  else if (!correctDecryption.isEverythingOK())
324  {
325  std::cout<<"\nREJECT: Algorithm 18 rejected because $y^v y' \\noteq g^{k_x}$ or $PDec_{k_x}(A) \\noteq B^v B'."
326  <<std::endl;
327  return 1;
328  }
329  else
330  std::cout<<" Proof of correct decryption was OK for l="<<l<<std::endl;
331  }
332  f = gq->multiplication(f,fl);
333  }
334 
335 
336  // 9- verify output
337 
338  std::cout<<"9. Verifying output"<<std::endl;
339  verifierUtils::ByteTree * btPlaintext = verifierUtils::ByteTree::parseFile(concatenation(roProof,'/',"PlaintextElements.bt"));
340  arithm::ArrayOfElmts m = M->getArray(btPlaintext);
341  verifierUtils::ByteTree * btArrayCipherTextLambda = verifierUtils::ByteTree::parseFile(getPath(roProof,"CiphertextList",lambda));
342  elGamal::ArrayOfCiphers Llambda(btArrayCipherTextLambda,C);
343  if ( !gq->compare(m,C.tdec(Llambda,f)) )
344  {
345  std::cout<<"\nREJECT: $m \\noteq TDec(L_{\\lambda}), \\prod_{l=1}^k f_l$"<<std::endl;
346  return 1;
347  }
348  else
349  std::cout<<" ... Output correct!"<<std::endl;
350 
351 
352  // If we reached this point then nothing was wrong. So it's great (\o/) and we return 0
353  std::cout<<"\nACCEPT"<<std::endl;
354  return 0;
355 }