Skip to content

Commit

Permalink
Range proof batch verification
Browse files Browse the repository at this point in the history
  • Loading branch information
AaronFeickert committed May 17, 2021
1 parent 677b54c commit f6aa87a
Show file tree
Hide file tree
Showing 11 changed files with 558 additions and 192 deletions.
4 changes: 2 additions & 2 deletions src/liblelantus/innerproduct_proof_verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,14 @@ bool InnerProductProofVerifier::verify_util(
return InnerProductProofVerifier(g_p, h_p, u_, p_p, version_).verify_util(proof, itr_l + 1, itr_r + 1, challengeGenerator);
}

bool InnerProductProofVerifier::verify_fast(uint64_t n, const Scalar& x, const InnerProductProof& proof, unique_ptr<ChallengeGenerator>& challengeGenerator) {
bool InnerProductProofVerifier::verify_fast(std::size_t n, const Scalar& x, const InnerProductProof& proof, unique_ptr<ChallengeGenerator>& challengeGenerator) {
u_ *= x;
P_ += u_ * proof.c_;
return verify_fast_util(n, proof, challengeGenerator);
}

bool InnerProductProofVerifier::verify_fast_util(
uint64_t n,
std::size_t n,
const InnerProductProof& proof,
unique_ptr<ChallengeGenerator>& challengeGenerator){
std::size_t log_n = proof.L_.size();
Expand Down
4 changes: 2 additions & 2 deletions src/liblelantus/innerproduct_proof_verifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class InnerProductProofVerifier {
int version); // if(version >= 2) we should pass CHash256 in verify

bool verify(const Scalar& x, const InnerProductProof& proof, unique_ptr<ChallengeGenerator>& challengeGenerator);
bool verify_fast(uint64_t n, const Scalar& x, const InnerProductProof& proof, unique_ptr<ChallengeGenerator>& challengeGenerator);
bool verify_fast(std::size_t n, const Scalar& x, const InnerProductProof& proof, unique_ptr<ChallengeGenerator>& challengeGenerator);

private:
bool verify_util(
Expand All @@ -27,7 +27,7 @@ class InnerProductProofVerifier {
typename std::vector<GroupElement>::const_iterator itr_r,
unique_ptr<ChallengeGenerator>& challengeGenerator);

bool verify_fast_util(uint64_t n, const InnerProductProof& proof, unique_ptr<ChallengeGenerator>& challengeGenerator);
bool verify_fast_util(std::size_t n, const InnerProductProof& proof, unique_ptr<ChallengeGenerator>& challengeGenerator);

private:
const std::vector<GroupElement>& g_;
Expand Down
33 changes: 32 additions & 1 deletion src/liblelantus/lelantus_primitives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,37 @@
namespace lelantus {

static std::string lts("LELANTUS_SIGMA");

// Invert a vector of scalars
//
// This _requires_ that all scalars be nonzero!
std::vector<Scalar> LelantusPrimitives::invert(const std::vector<Scalar>& scalars) {
std::size_t n = scalars.size();

std::vector<Scalar> result;
result.reserve(n);
result.resize(n);
std::vector<Scalar> scratch;
scratch.reserve(n);
Scalar acc(uint64_t(1));
Scalar temp;

for (std::size_t i = 0; i < n; i++) {
if (scalars[i] == Scalar(uint64_t(0))) {
throw std::runtime_error("Cannot invert a zero scalar");
}
scratch.emplace_back(acc);
acc *= scalars[i];
}
acc = acc.inverse();
for (std::size_t i = n; i > 0; i--) {
temp = acc * scalars[i - 1];
result[i - 1] = acc * scratch[i - 1];
acc = temp;
}

return result;
}

void LelantusPrimitives::generate_challenge(
const std::vector<GroupElement>& group_elements,
Expand Down Expand Up @@ -212,7 +243,7 @@ GroupElement LelantusPrimitives::p_prime(
return L * x_square + P_ + R * (x_square.inverse());
}

Scalar LelantusPrimitives::delta(const Scalar& y, const Scalar& z, uint64_t n, uint64_t m){
Scalar LelantusPrimitives::delta(const Scalar& y, const Scalar& z, std::size_t n, std::size_t m){
Scalar y_;
Scalar two_;
NthPower y_n(y);
Expand Down
4 changes: 3 additions & 1 deletion src/liblelantus/lelantus_primitives.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class LelantusPrimitives {

public:
////common functions
static std::vector<Scalar> invert(const std::vector<Scalar>& scalars);

static void generate_challenge(
const std::vector<GroupElement>& group_elements,
const std::string& domain_separator,
Expand Down Expand Up @@ -112,7 +114,7 @@ class LelantusPrimitives {
const GroupElement& R,
const Scalar& x);

static Scalar delta(const Scalar& y, const Scalar& z, uint64_t n, uint64_t m);
static Scalar delta(const Scalar& y, const Scalar& z, std::size_t n, std::size_t m);

};

Expand Down
8 changes: 5 additions & 3 deletions src/liblelantus/lelantus_prover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,11 +203,13 @@ void LelantusProver::generate_bulletproofs(
v_s.reserve(m);
serials.reserve(m);
randoms.reserve(m);
// NOTE: this prepends zero-value group elements, apparently as an earlier coding error
// This doesn't hurt anything, and so is retained here for compatibility reasons
std::vector<GroupElement> commitments(Cout.size());
for (std::size_t i = 0; i < Cout.size(); ++i)
{
v_s.push_back(Cout[i].getV());
v_s.push_back(Cout[i].getVScalar() + params->get_limit_range());
v_s.push_back(Cout[i].getV()); // Ensure that v >= 0
v_s.push_back(Cout[i].getVScalar() + params->get_limit_range()); // Ensure that v <= ZC_LELANTUS_MAX_MINT
serials.insert(serials.end(), 2, Cout[i].getSerialNumber());
randoms.insert(randoms.end(), 2, Cout[i].getRandomness());
commitments.emplace_back(Cout[i].getPublicCoin().getValue());
Expand All @@ -226,7 +228,7 @@ void LelantusProver::generate_bulletproofs(
h_.insert(h_.end(), params->get_bulletproofs_h().begin(), params->get_bulletproofs_h().begin() + (n * m));

RangeProver rangeProver(params->get_h1(), params->get_h0(), params->get_g(), g_, h_, n, version);
rangeProver.batch_proof(v_s, serials, randoms, commitments, bulletproofs);
rangeProver.proof(v_s, serials, randoms, commitments, bulletproofs);

}

Expand Down
30 changes: 21 additions & 9 deletions src/liblelantus/lelantus_verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ bool LelantusVerifier::verify_sigma(

bool LelantusVerifier::verify_rangeproof(
const std::vector<PublicCoin>& Cout,
const RangeProof& bulletproofs) {
const RangeProof& bulletproof) {
if (Cout.empty())
return true;

Expand All @@ -191,26 +191,38 @@ bool LelantusVerifier::verify_rangeproof(
while (m & (m - 1))
m++;

// NOTE: for actual deployment, need to ensure this vector is constructed to accommodate the largest proof
std::vector<GroupElement> g_, h_;
g_.reserve(n * m);
h_.reserve(n * m);
g_.insert(g_.end(), params->get_bulletproofs_g().begin(), params->get_bulletproofs_g().begin() + (n * m));
h_.insert(h_.end(), params->get_bulletproofs_h().begin(), params->get_bulletproofs_h().begin() + (n * m));

std::vector<GroupElement> V;
V.reserve(m);
std::vector<GroupElement> commitments(Cout.size());
std::vector<std::vector<GroupElement> > V;
V.reserve(1); // size of batch
V.resize(1);
V[0].reserve(m); // aggregation size
std::vector<std::vector<GroupElement> > commitments;
commitments.reserve(1); // size of batch
commitments.resize(1);
commitments[0].reserve(2 * Cout.size());
commitments[0].resize(Cout.size()); // prepend zero elements, to match the prover's behavior
for (std::size_t i = 0; i < Cout.size(); ++i) {
V.push_back(Cout[i].getValue());
V.push_back(Cout[i].getValue() + params->get_h1_limit_range());
commitments.emplace_back(Cout[i].getValue());
V[0].push_back(Cout[i].getValue());
V[0].push_back(Cout[i].getValue() + params->get_h1_limit_range());
commitments[0].emplace_back(Cout[i].getValue());
}

std:vector<RangeProof> proofs;
proofs.reserve(1); // size of batch
proofs.emplace_back(bulletproof);

// Pad with zero elements
for (std::size_t i = Cout.size() * 2; i < m; ++i)
V.push_back(GroupElement());
V[0].push_back(GroupElement());

RangeVerifier rangeVerifier(params->get_h1(), params->get_h0(), params->get_g(), g_, h_, n, version);
if (!rangeVerifier.verify_batch(V, commitments, bulletproofs)) {
if (!rangeVerifier.verify(V, commitments, proofs)) {
LogPrintf("Lelantus verification failed due range proof verification failed.");
return false;
}
Expand Down
20 changes: 17 additions & 3 deletions src/liblelantus/range_prover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ RangeProver::RangeProver(
const GroupElement& h2,
const std::vector<GroupElement>& g_vector,
const std::vector<GroupElement>& h_vector,
uint64_t n,
std::size_t n,
unsigned int v)
: g (g)
, h1 (h1)
Expand All @@ -20,13 +20,27 @@ RangeProver::RangeProver(
, version (v)
{}

void RangeProver::batch_proof(
void RangeProver::proof(
const std::vector<Scalar>& v,
const std::vector<Scalar>& serialNumbers,
const std::vector<Scalar>& randomness,
const std::vector<GroupElement>& commitments,
RangeProof& proof_out) {
// Size checks
std::size_t m = v.size();
if (m == 0) {
throw std::invalid_argument("Range proof cannot use zero inputs");
}
if ((m & (m - 1)) != 0) {
throw std::invalid_argument("Range proof requires a power-of-two number of aggregated inputs");
}
if (v.size() != serialNumbers.size() || v.size() != randomness.size()) {
throw std::invalid_argument("Range proof input vector sizes do not match");
}
if (g_.size() != n * m || h_.size() != n * m) {
throw std::invalid_argument("Range proof generator vector has incorrect size");
}

std::vector<std::vector<bool>> bits;
bits.resize(m);
for (std::size_t i = 0; i < v.size(); i++)
Expand Down Expand Up @@ -90,7 +104,7 @@ void RangeProver::batch_proof(
NthPower two_n_(uint64_t(2));
std::vector<Scalar> two_n;
two_n.reserve(n);
for (uint64_t k = 0; k < n; ++k)
for (std::size_t k = 0; k < n; ++k)
{
two_n.emplace_back(two_n_.pow);
two_n_.go_next();
Expand Down
6 changes: 3 additions & 3 deletions src/liblelantus/range_prover.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ class RangeProver {
, const GroupElement& h2
, const std::vector<GroupElement>& g_vector
, const std::vector<GroupElement>& h_vector
, uint64_t n
, std::size_t n
, unsigned int v);

// commitments are included into transcript if version >= LELANTUS_TX_VERSION_4_5
void batch_proof(
void proof(
const std::vector<Scalar>& v
, const std::vector<Scalar>& serialNumbers
, const std::vector<Scalar>& randomness
Expand All @@ -30,7 +30,7 @@ class RangeProver {
GroupElement h2;
std::vector<GroupElement> g_;
std::vector<GroupElement> h_;
uint64_t n;
std::size_t n;
unsigned int version;

};
Expand Down
Loading

0 comments on commit f6aa87a

Please sign in to comment.