// TODO: get parameters from the commitment group CommitmentProofOfKnowledge::CommitmentProofOfKnowledge(const IntegerGroupParams* aParams, const IntegerGroupParams* bParams, const Commitment& a, const Commitment& b): ap(aParams),bp(bParams) { CBigNum r1, r2, r3; // First: make sure that the two commitments have the // same contents. if (a.getContents() != b.getContents()) { throw std::runtime_error("Both commitments must contain the same value"); } // Select three random values "r1, r2, r3" in the range 0 to (2^l)-1 where l is: // length of challenge value + max(modulus 1, modulus 2, order 1, order 2) + margin. // We set "margin" to be a relatively generous security parameter. // // We choose these large values to ensure statistical zero knowledge. uint32_t randomSize = COMMITMENT_EQUALITY_CHALLENGE_SIZE + COMMITMENT_EQUALITY_SECMARGIN + std::max(std::max(this->ap->modulus.bitSize(), this->bp->modulus.bitSize()), std::max(this->ap->groupOrder.bitSize(), this->bp->groupOrder.bitSize())); CBigNum maxRange = (CBigNum(2).pow(randomSize) - CBigNum(1)); r1 = CBigNum::randBignum(maxRange); r2 = CBigNum::randBignum(maxRange); r3 = CBigNum::randBignum(maxRange); // Generate two random, ephemeral commitments "T1, T2" // of the form: // T1 = g1^r1 * h1^r2 mod p1 // T2 = g2^r1 * h2^r3 mod p2 // // Where (g1, h1, p1) are from "aParams" and (g2, h2, p2) are from "bParams". CBigNum T1 = this->ap->g.pow_mod(r1, this->ap->modulus).mul_mod((this->ap->h.pow_mod(r2, this->ap->modulus)), this->ap->modulus); CBigNum T2 = this->bp->g.pow_mod(r1, this->bp->modulus).mul_mod((this->bp->h.pow_mod(r3, this->bp->modulus)), this->bp->modulus); // Now hash commitment "A" with commitment "B" as well as the // parameters and the two ephemeral commitments "T1, T2" we just generated this->challenge = calculateChallenge(a.getCommitmentValue(), b.getCommitmentValue(), T1, T2); // Let "m" be the contents of the commitments "A, B". We have: // A = g1^m * h1^x mod p1 // B = g2^m * h2^y mod p2 // T1 = g1^r1 * h1^r2 mod p1 // T2 = g2^r1 * h2^r3 mod p2 // // Now compute: // S1 = r1 + (m * challenge) -- note, not modular arithmetic // S2 = r2 + (x * challenge) -- note, not modular arithmetic // S3 = r3 + (y * challenge) -- note, not modular arithmetic this->S1 = r1 + (a.getContents() * this->challenge); this->S2 = r2 + (a.getRandomness() * this->challenge); this->S3 = r3 + (b.getRandomness() * this->challenge); // We're done. The proof is S1, S2, S3 and "challenge", all of which // are stored in member variables. }
// TODO: get parameters from the commitment group CommitmentProofOfKnowledge::CommitmentProofOfKnowledge(const IntegerGroupParams* aParams, const IntegerGroupParams* bParams, const Commitment& a, const Commitment& b): ap(aParams),bp(bParams) { Bignum r1; // First: make sure that the two commitments have the // same contents. if(a.getContents() != b.getContents()){ throw std::invalid_argument("Both commitments must contain the same value"); } // In order to ensure statistical zero knowledge, we pick "r1" out of the // largest possible range. In this case, the smaller of the two group orders. if(this->ap->groupOrder < this->bp->groupOrder){ r1 = Bignum::randBignum(ap->groupOrder); }else{ r1 = Bignum::randBignum(bp->groupOrder); } // Generate two random, ephemeral commitments "T1, T2" to "r1" under the two different // sets of commitment parameters. Commitment t1(aParams, r1); Commitment t2(bParams, r1); Bignum T1 = t1.getCommitmentValue(); Bignum T2 = t2.getCommitmentValue(); // Now hash commitment "A" with commitment "B" as well as the // parameters and the two ephemeral commitments "T1, T2" we just generated this->challenge = calculateChallenge(a.getCommitmentValue(), b.getCommitmentValue(), T1, T2); // Let "m" be the contents of the commitments. We'll implicitly define // A = g1^m * h1^x mod p1 // B = g2^m * h2^y mod p2 // T1 = g1^r1 * h1^r2 mod p1 // T2 = g2^r1 * h2^r3 mod p2 // // Now compute: // S1 = r1 + (m * challenge) // S2 = r2 + (x * challenge) // S3 = r3 + (y * challenge) S1 = t1.getContents() + (a.getContents() * challenge); S2 = t1.getRandomness() + (a.getRandomness() * challenge); S3 = t2.getRandomness() + (b.getRandomness() * challenge); // We're done. The proof is S1, S2, S3 and "challenge". }
AccumulatorProofOfKnowledge::AccumulatorProofOfKnowledge(const AccumulatorAndProofParams* p, const Commitment& commitmentToCoin, const AccumulatorWitness& witness, Accumulator& a): params(p) { Bignum sg = params->accumulatorPoKCommitmentGroup.g; Bignum sh = params->accumulatorPoKCommitmentGroup.h; Bignum g_n = params->accumulatorQRNCommitmentGroup.g; Bignum h_n = params->accumulatorQRNCommitmentGroup.h; Bignum e = commitmentToCoin.getContents(); Bignum r = commitmentToCoin.getRandomness(); Bignum r_1 = Bignum::randBignum(params->accumulatorModulus/4); Bignum r_2 = Bignum::randBignum(params->accumulatorModulus/4); Bignum r_3 = Bignum::randBignum(params->accumulatorModulus/4); this->C_e = g_n.pow_mod(e, params->accumulatorModulus) * h_n.pow_mod(r_1, params->accumulatorModulus); this->C_u = witness.getValue() * h_n.pow_mod(r_2, params->accumulatorModulus); this->C_r = g_n.pow_mod(r_2, params->accumulatorModulus) * h_n.pow_mod(r_3, params->accumulatorModulus); Bignum r_alpha = Bignum::randBignum(params->maxCoinValue * Bignum(2).pow(params->k_prime + params->k_dprime)); if(!(Bignum::randBignum(Bignum(3)) % 2)) { r_alpha = 0-r_alpha; } Bignum r_gamma = Bignum::randBignum(params->accumulatorPoKCommitmentGroup.modulus); Bignum r_phi = Bignum::randBignum(params->accumulatorPoKCommitmentGroup.modulus); Bignum r_psi = Bignum::randBignum(params->accumulatorPoKCommitmentGroup.modulus); Bignum r_sigma = Bignum::randBignum(params->accumulatorPoKCommitmentGroup.modulus); Bignum r_xi = Bignum::randBignum(params->accumulatorPoKCommitmentGroup.modulus); Bignum r_epsilon = Bignum::randBignum((params->accumulatorModulus/4) * Bignum(2).pow(params->k_prime + params->k_dprime)); if(!(Bignum::randBignum(Bignum(3)) % 2)) { r_epsilon = 0-r_epsilon; } Bignum r_eta = Bignum::randBignum((params->accumulatorModulus/4) * Bignum(2).pow(params->k_prime + params->k_dprime)); if(!(Bignum::randBignum(Bignum(3)) % 2)) { r_eta = 0-r_eta; } Bignum r_zeta = Bignum::randBignum((params->accumulatorModulus/4) * Bignum(2).pow(params->k_prime + params->k_dprime)); if(!(Bignum::randBignum(Bignum(3)) % 2)) { r_zeta = 0-r_zeta; } Bignum r_beta = Bignum::randBignum((params->accumulatorModulus/4) * params->accumulatorPoKCommitmentGroup.modulus * Bignum(2).pow(params->k_prime + params->k_dprime)); if(!(Bignum::randBignum(Bignum(3)) % 2)) { r_beta = 0-r_beta; } Bignum r_delta = Bignum::randBignum((params->accumulatorModulus/4) * params->accumulatorPoKCommitmentGroup.modulus * Bignum(2).pow(params->k_prime + params->k_dprime)); if(!(Bignum::randBignum(Bignum(3)) % 2)) { r_delta = 0-r_delta; } this->st_1 = (sg.pow_mod(r_alpha, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(r_phi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; this->st_2 = (((commitmentToCoin.getCommitmentValue() * sg.inverse(params->accumulatorPoKCommitmentGroup.modulus)).pow_mod(r_gamma, params->accumulatorPoKCommitmentGroup.modulus)) * sh.pow_mod(r_psi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; this->st_3 = ((sg * commitmentToCoin.getCommitmentValue()).pow_mod(r_sigma, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(r_xi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; this->t_1 = (h_n.pow_mod(r_zeta, params->accumulatorModulus) * g_n.pow_mod(r_epsilon, params->accumulatorModulus)) % params->accumulatorModulus; this->t_2 = (h_n.pow_mod(r_eta, params->accumulatorModulus) * g_n.pow_mod(r_alpha, params->accumulatorModulus)) % params->accumulatorModulus; this->t_3 = (C_u.pow_mod(r_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(r_beta, params->accumulatorModulus))) % params->accumulatorModulus; this->t_4 = (C_r.pow_mod(r_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(r_delta, params->accumulatorModulus)) * ((g_n.inverse(params->accumulatorModulus)).pow_mod(r_beta, params->accumulatorModulus))) % params->accumulatorModulus; CHashWriter hasher(0,0); hasher << *params << sg << sh << g_n << h_n << commitmentToCoin.getCommitmentValue() << C_e << C_u << C_r << st_1 << st_2 << st_3 << t_1 << t_2 << t_3 << t_4; //According to the proof, this hash should be of length k_prime bits. It is currently greater than that, which should not be a problem, but we should check this. Bignum c = Bignum(hasher.GetHash()); this->s_alpha = r_alpha - c*e; this->s_beta = r_beta - c*r_2*e; this->s_zeta = r_zeta - c*r_3; this->s_sigma = r_sigma - c*((e+1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder)); this->s_eta = r_eta - c*r_1; this->s_epsilon = r_epsilon - c*r_2; this->s_delta = r_delta - c*r_3*e; this->s_xi = r_xi + c*r*((e+1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder)); this->s_phi = (r_phi - c*r) % params->accumulatorPoKCommitmentGroup.groupOrder; this->s_gamma = r_gamma - c*((e-1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder)); this->s_psi = r_psi + c*r*((e-1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder)); }