2 * @file SerialNumberSignatureOfKnowledge.cpp
4 * @brief SerialNumberSignatureOfKnowledge class for the Zerocoin library.
6 * @author Ian Miers, Christina Garman and Matthew Green
9 * @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green
10 * @license This project is released under the MIT license.
15 namespace libzerocoin {
17 SerialNumberSignatureOfKnowledge::SerialNumberSignatureOfKnowledge(const Params* p): params(p) { }
19 SerialNumberSignatureOfKnowledge::SerialNumberSignatureOfKnowledge(const
20 Params* p, const PrivateCoin& coin, const Commitment& commitmentToCoin,
21 uint256 msghash):params(p),
22 s_notprime(p->zkp_iterations),
23 sprime(p->zkp_iterations) {
25 // Sanity check: verify that the order of the "accumulatedValueCommitmentGroup" is
26 // equal to the modulus of "coinCommitmentGroup". Otherwise we will produce invalid
28 if (params->coinCommitmentGroup.modulus != params->serialNumberSoKCommitmentGroup.groupOrder) {
29 throw ZerocoinException("Groups are not structured correctly.");
32 Bignum a = params->coinCommitmentGroup.g;
33 Bignum b = params->coinCommitmentGroup.h;
34 Bignum g = params->serialNumberSoKCommitmentGroup.g;
35 Bignum h = params->serialNumberSoKCommitmentGroup.h;
37 CHashWriter hasher(0,0);
38 hasher << *params << commitmentToCoin.getCommitmentValue() << coin.getSerialNumber();
40 vector<Bignum> r(params->zkp_iterations);
41 vector<Bignum> v(params->zkp_iterations);
42 vector<Bignum> c(params->zkp_iterations);
45 for(uint32_t i=0; i < params->zkp_iterations; i++) {
46 //FIXME we really ought to use one BN_CTX for all of these
47 // operations for performance reasons, not the one that
48 // is created individually by the wrapper
49 r[i] = Bignum::randBignum(params->coinCommitmentGroup.groupOrder);
50 v[i] = Bignum::randBignum(params->serialNumberSoKCommitmentGroup.groupOrder);
53 // Openssl's rng is not thread safe, so we don't call it in a parallel loop,
54 // instead we generate the random values beforehand and run the calculations
55 // based on those values in parallel.
56 #ifdef ZEROCOIN_THREADING
57 #pragma omp parallel for
59 for(uint32_t i=0; i < params->zkp_iterations; i++) {
60 // compute g^{ {a^x b^r} h^v} mod p2
61 c[i] = challengeCalculation(coin.getSerialNumber(), r[i], v[i]);
64 // We can't hash data in parallel either
65 // because OPENMP cannot not guarantee loops
67 for(uint32_t i=0; i < params->zkp_iterations; i++) {
70 this->hash = hasher.GetHash();
71 unsigned char *hashbytes = (unsigned char*) &hash;
73 #ifdef ZEROCOIN_THREADING
74 #pragma omp parallel for
76 for(uint32_t i = 0; i < params->zkp_iterations; i++) {
80 bool challenge_bit = ((hashbytes[byte] >> bit) & 0x01);
85 s_notprime[i] = r[i] - coin.getRandomness();
86 sprime[i] = v[i] - (commitmentToCoin.getRandomness() *
87 b.pow_mod(r[i] - coin.getRandomness(), params->serialNumberSoKCommitmentGroup.groupOrder));
92 inline Bignum SerialNumberSignatureOfKnowledge::challengeCalculation(const Bignum& a_exp,const Bignum& b_exp,
93 const Bignum& h_exp) const {
95 Bignum a = params->coinCommitmentGroup.g;
96 Bignum b = params->coinCommitmentGroup.h;
97 Bignum g = params->serialNumberSoKCommitmentGroup.g;
98 Bignum h = params->serialNumberSoKCommitmentGroup.h;
100 Bignum exponent = (a.pow_mod(a_exp, params->serialNumberSoKCommitmentGroup.groupOrder)
101 * b.pow_mod(b_exp, params->serialNumberSoKCommitmentGroup.groupOrder)) % params->serialNumberSoKCommitmentGroup.groupOrder;
103 return (g.pow_mod(exponent, params->serialNumberSoKCommitmentGroup.modulus) * h.pow_mod(h_exp, params->serialNumberSoKCommitmentGroup.modulus)) % params->serialNumberSoKCommitmentGroup.modulus;
106 bool SerialNumberSignatureOfKnowledge::Verify(const Bignum& coinSerialNumber, const Bignum& valueOfCommitmentToCoin,
107 const uint256 msghash) const {
108 Bignum a = params->coinCommitmentGroup.g;
109 Bignum b = params->coinCommitmentGroup.h;
110 Bignum g = params->serialNumberSoKCommitmentGroup.g;
111 Bignum h = params->serialNumberSoKCommitmentGroup.h;
112 CHashWriter hasher(0,0);
113 hasher << *params << valueOfCommitmentToCoin <<coinSerialNumber;
115 vector<CBigNum> tprime(params->zkp_iterations);
116 unsigned char *hashbytes = (unsigned char*) &this->hash;
117 #ifdef ZEROCOIN_THREADING
118 #pragma omp parallel for
120 for(uint32_t i = 0; i < params->zkp_iterations; i++) {
123 bool challenge_bit = ((hashbytes[byte] >> bit) & 0x01);
125 tprime[i] = challengeCalculation(coinSerialNumber, s_notprime[i], sprime[i]);
127 Bignum exp = b.pow_mod(s_notprime[i], params->serialNumberSoKCommitmentGroup.groupOrder);
128 tprime[i] = ((valueOfCommitmentToCoin.pow_mod(exp, params->serialNumberSoKCommitmentGroup.modulus) % params->serialNumberSoKCommitmentGroup.modulus) *
129 (h.pow_mod(sprime[i], params->serialNumberSoKCommitmentGroup.modulus) % params->serialNumberSoKCommitmentGroup.modulus)) %
130 params->serialNumberSoKCommitmentGroup.modulus;
133 for(uint32_t i = 0; i < params->zkp_iterations; i++) {
136 return hasher.GetHash() == hash;
139 } /* namespace libzerocoin */