diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000000..830d3c82f5
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000000..31d0a43b42
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000000..94a25f7f4c
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000000..7aeb59971c
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1644842195939
+
+
+ 1644842195939
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/output.txt b/output.txt
new file mode 100644
index 0000000000..b38ad8b4d7
--- /dev/null
+++ b/output.txt
@@ -0,0 +1,5 @@
+Running 1 test case...
+PASSED
+PASSED
+PASSED
+PASSED
diff --git a/src/Makefile.am b/src/Makefile.am
index fdeab1406c..04e8c9b203 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -55,6 +55,7 @@ LIBBITCOIN_CONSENSUS=libbitcoin_consensus.a
LIBBITCOIN_CLI=libbitcoin_cli.a
LIBBITCOIN_UTIL=libbitcoin_util.a
LIBLELANTUS=liblelantus.a
+LIBAURA=libaura.a
LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a
LIBBITCOINQT=qt/libfiroqt.a
LIBSECP256K1=secp256k1/libsecp256k1.la
@@ -86,7 +87,8 @@ EXTRA_LIBRARIES += \
$(LIBBITCOIN_WALLET) \
$(LIBBITCOIN_ZMQ) \
$(LIBFIRO_SIGMA) \
- $(LIBLELANTUS)
+ $(LIBLELANTUS) \
+ $(LIBAURA)
lib_LTLIBRARIES = $(LIBBITCOINCONSENSUS)
@@ -691,6 +693,24 @@ libsigma_a_SOURCES = \
sigma/params.cpp \
sigma/openssl_context.h
+libaura_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -Werror
+libaura_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -Werror
+libaura_a_SOURCES = \
+ libaura/r1_proof.h \
+ libaura/r1_proof_generator.h \
+ libaura/r1_proof_generator.hpp \
+ libaura/r1_proof_verifier.h \
+ libaura/r1_proof_verifier.hpp \
+ libaura/sigmaplus_proof.h \
+ libaura/sigmaplus_prover.h \
+ libaura/sigmaplus_prover.hpp \
+ libaura/sigmaplus_verifier.h \
+ libaura/sigmaplus_verifier.hpp \
+ libaura/aura_primitives.h \
+ libaura/aura_primitives.hpp \
+ libaura/params.h\
+ libaura/params.cpp
+
if GLIBC_BACK_COMPAT
libbitcoin_util_a_SOURCES += compat/glibc_compat.cpp
AM_LDFLAGS += $(COMPAT_LDFLAGS)
@@ -729,6 +749,7 @@ firod_LDADD = \
$(LIBBITCOIN_WALLET) \
$(LIBFIRO_SIGMA) \
$(LIBLELANTUS) \
+ $(LIBAURA) \
$(LIBBITCOIN_ZMQ) \
$(LIBBITCOIN_CONSENSUS) \
$(LIBBITCOIN_CRYPTO) \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 2e1e951287..7801649d86 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -97,6 +97,8 @@ BITCOIN_TESTS = \
sigma/test/r1_test.cpp \
sigma/test/serialize_test.cpp \
sigma/test/sigma_primitive_types_test.cpp \
+ libaura/test/protocol_tests.cpp \
+ libaura/test/hoom_tests.cpp \
test/addrman_tests.cpp \
test/allocator_tests.cpp \
test/amount_tests.cpp \
@@ -198,8 +200,8 @@ endif
test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) -ltor
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
-test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS)
-test_test_bitcoin_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBFIRO_SIGMA) $(LIBLELANTUS) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \
+test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS) $(LIBBLSSIG_INCLUDES)
+test_test_bitcoin_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBFIRO_SIGMA) $(LIBAURA) $(LIBLELANTUS) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \
$(BACKTRACE_LIB) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_PTHREADS_LIBS) $(ZMQ_LIBS) $(ZLIB_LIBS)
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
if ENABLE_WALLET
diff --git a/src/libaura/aura_primitives.h b/src/libaura/aura_primitives.h
new file mode 100755
index 0000000000..f35717e285
--- /dev/null
+++ b/src/libaura/aura_primitives.h
@@ -0,0 +1,58 @@
+#ifndef FIRO_AURA_SIGMA_SIGMA_PRIMITIVES_H
+#define FIRO_AURA_SIGMA_SIGMA_PRIMITIVES_H
+
+#include "../secp256k1/include/MultiExponent.h"
+#include "../secp256k1/include/GroupElement.h"
+#include "../secp256k1/include/Scalar.h"
+
+#include
+#include
+
+namespace aura {
+
+template
+struct NthPower {
+ Exponent num;
+ Exponent pow;
+
+ NthPower(const Exponent& num_) : num(num_), pow(uint64_t(1)) {}
+ NthPower(const Exponent& num_, const Exponent& pow_) : num(num_), pow(pow_) {}
+
+ void go_next() {
+ pow *= num;
+ }
+};
+
+template
+class SigmaPrimitives {
+
+public:
+ static void commit(const GroupElement& g,
+ const std::vector& h,
+ const std::vector& exp,
+ const Exponent& r,
+ GroupElement& result_out);
+
+ static GroupElement commit(const GroupElement& g, const Exponent m, const GroupElement h, const Exponent r);
+
+ static void convert_to_sigma(uint64_t num, uint64_t n, uint64_t m, std::vector& out);
+
+ static std::vector convert_to_nal(uint64_t num, uint64_t n, uint64_t m);
+
+ static void generate_challenge(const std::vector& group_elements,
+ Exponent& result_out);
+
+ /** \brief Adds a factor of (x*x + a) to the given polynomial in coefficients.
+ * \param[in,out] coefficients Coefficients of the polynomial created.
+ */
+ static void new_factor(const Exponent& x, const Exponent& a, std::vector& coefficients);
+
+ static GroupElement HelperFunction(const std::vector& commits, const std::vector & x);
+
+ };
+
+} // namespace aura
+
+#include "aura_primitives.hpp"
+
+#endif // FIRO_AURA_SIGMA_SIGMA_PRIMITIVES_H
diff --git a/src/libaura/aura_primitives.hpp b/src/libaura/aura_primitives.hpp
new file mode 100755
index 0000000000..bf8c1d70ca
--- /dev/null
+++ b/src/libaura/aura_primitives.hpp
@@ -0,0 +1,103 @@
+#include "../../crypto/sha256.h"
+
+namespace aura {
+
+template
+void SigmaPrimitives::commit(const GroupElement& g,
+ const std::vector& h,
+ const std::vector& exp,
+ const Exponent& r,
+ GroupElement& result_out) {
+ secp_primitives::MultiExponent mult(h, exp);
+ result_out += g * r + mult.get_multiple();
+}
+
+template
+GroupElement SigmaPrimitives::commit(
+ const GroupElement& g,
+ const Exponent m,
+ const GroupElement h,
+ const Exponent r){
+ return g * m + h * r;
+}
+
+template
+void SigmaPrimitives::convert_to_sigma(
+ uint64_t num,
+ uint64_t n,
+ uint64_t m,
+ std::vector& out) {
+ uint64_t rem;
+ uint64_t j = 0;
+
+ for (j = 0; j < m; ++j)
+ {
+ rem = num % n;
+ num /= n;
+ for (uint64_t i = 0; i < n; ++i) {
+ if(i == rem)
+ out.push_back(Exponent(uint64_t(1)));
+ else
+ out.push_back(Exponent(uint64_t(0)));
+ }
+ }
+}
+
+template
+std::vector SigmaPrimitives::convert_to_nal(
+ uint64_t num,
+ uint64_t n,
+ uint64_t m) {
+ std::vector result;
+ uint64_t rem;
+ uint64_t j = 0;
+ while (num != 0)
+ {
+ rem = num % n;
+ num /= n;
+ result.push_back(rem);
+ j++;
+ }
+ result.resize(m);
+ return result;
+}
+
+template
+void SigmaPrimitives::generate_challenge(
+ const std::vector& group_elements,
+ Exponent& result_out) {
+ if (group_elements.empty())
+ throw std::runtime_error("Group elements empty while generating a challenge.");
+ CSHA256 hash;
+ std::vector data(group_elements.size() * group_elements[0].memoryRequired());
+ unsigned char* current = data.data();
+ for (size_t i = 0; i < group_elements.size(); ++i) {
+ current = group_elements[i].serialize(current);
+ }
+ hash.Write(data.data(), data.size());
+ unsigned char result_data[CSHA256::OUTPUT_SIZE];
+ hash.Finalize(result_data);
+ result_out = result_data;
+}
+
+template
+void SigmaPrimitives::new_factor(
+ const Exponent& x,
+ const Exponent& a,
+ std::vector& coefficients) {
+ std::size_t degree = coefficients.size();
+ coefficients.push_back(x * coefficients[degree-1]);
+ for (std::size_t d = degree-1; d >= 1; --d)
+ coefficients[d] = a * coefficients[d] + x * coefficients[d-1];
+ coefficients[0] *= a;
+}
+
+ template
+ GroupElement SigmaPrimitives::HelperFunction(
+ const std::vector& commits,
+ const std::vector & x) {
+ secp_primitives::MultiExponent mult(commits, x);
+ return mult.get_multiple();
+ }
+
+} // namespace aura
diff --git a/src/libaura/hoom_proof.h b/src/libaura/hoom_proof.h
new file mode 100755
index 0000000000..f8c1eac550
--- /dev/null
+++ b/src/libaura/hoom_proof.h
@@ -0,0 +1,75 @@
+#ifndef FIRO_AURA_HOOM_PROOF_H
+#define FIRO_AURA_HOOM_PROOF_H
+
+#include "params.h"
+#include "sigmaplus_proof.h"
+
+namespace aura {
+
+template
+class HOOMProof {
+public:
+ int t_n_;
+ int t_m_;
+ int m_n_;
+ int m_m_;
+ std::vector d_;
+ SigmaPlusProof d_Proof_;
+ SigmaPlusProof D_Proof_;
+
+public:
+ HOOMProof(int t_n_, int t_m_, int m_n_, int m_m_):
+ t_n_(t_n_), t_m_(t_m_), m_n_(m_n_), m_m_(m_m_), d_Proof_(m_n_, m_m_), D_Proof_(t_n_, t_m_) {};
+
+public:
+ bool operator==(const HOOMProof& other) const {
+ return t_n_ == other.t_n_ &&
+ t_m_ == other.t_m_ &&
+ m_n_ == other.t_n_ &&
+ m_m_ == other.t_m_ &&
+ d_ == other.d_ &&
+ d_Proof_ == other.d_Proof_ &&
+ D_Proof_ == other.D_Proof_;
+ }
+
+ bool operator!=(const HOOMProof& other) const {
+ return !(*this == other);
+ }
+
+public:
+ inline int memoryRequired() const {
+ return d_.memoryRequired()
+ + d_Proof_.memoryRequired(m_n_, m_m_)
+ + D_Proof_.memoryRequired(t_n_, t_m_);
+ }
+
+/* inline unsigned char* serialize(unsigned char* buffer) const {
+ unsigned char* current = B_.serialize(buffer);
+ current = r1Proof_.serialize(current);
+ for (std::size_t i = 0; i < Gk_.size(); ++i)
+ current = Gk_[i].serialize(current);
+ return z_.serialize(current);
+ }
+
+ inline unsigned const char* deserialize(unsigned const char* buffer) {
+ unsigned const char* current = B_.deserialize(buffer);
+ current = r1Proof_.deserialize(current, n, m);
+ Gk_.resize(m);
+ for(int i = 0; i < m; ++i)
+ current = Gk_[i].deserialize(current);
+ return z_.deserialize(current);
+ }
+
+ ADD_SERIALIZE_METHODS;
+ template
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ READWRITE(B_);
+ READWRITE(r1Proof_);
+ READWRITE(Gk_);
+ READWRITE(z_);
+ } */
+};
+
+} //namespace aura
+
+#endif // FIRO_AURA_HOOM_PROOF_H
diff --git a/src/libaura/hoom_prover.h b/src/libaura/hoom_prover.h
new file mode 100755
index 0000000000..72f6065780
--- /dev/null
+++ b/src/libaura/hoom_prover.h
@@ -0,0 +1,36 @@
+#ifndef FIRO_AURA_HOOM_PROVER_H
+#define FIRO_AURA_HOOM_PROVER_H
+
+#include "sigmaplus_prover.h"
+#include "hoom_proof.h"
+
+#include
+
+namespace aura {
+
+template
+class HOOMProver{
+
+public:
+ HOOMProver(const GroupElement& g,
+ const std::vector& h_gens,
+ int t_n, int t_m, int m_n, int m_m);
+ void proof(const std::vector& commits,
+ const int& l,
+ const Exponent& r,
+ HOOMProof& proof_out);
+
+private:
+ GroupElement g_;
+ std::vector h_;
+ int t_n_;
+ int t_m_;
+ int m_n_;
+ int m_m_;
+};
+
+} // namespace aura
+
+#include "hoom_prover.hpp"
+
+#endif // FIRO_AURA_SIGMA_SIGMAPLUS_PROVER_H
diff --git a/src/libaura/hoom_prover.hpp b/src/libaura/hoom_prover.hpp
new file mode 100755
index 0000000000..3c34bc3c5f
--- /dev/null
+++ b/src/libaura/hoom_prover.hpp
@@ -0,0 +1,73 @@
+#include
+#include
+
+namespace aura {
+
+ template
+ HOOMProver::HOOMProver(const GroupElement& g,
+ const std::vector& h_gens,
+ int t_n, int t_m, int m_n, int m_m)
+ : g_(g)
+ , h_(h_gens)
+ , t_n_(t_n)
+ , t_m_(t_m)
+ , m_n_(m_n)
+ , m_m_(m_m) {
+ }
+
+ template
+ void HOOMProver::proof(const std::vector& commits,
+ const int& l,
+ const Exponent& r,
+ HOOMProof& proof_out) {
+
+ int t_ = pow(t_n_, t_m_);
+ int m_ = pow(m_n_, m_m_);
+
+ //binds the commitments to the y challenge
+ Exponent y;
+ SigmaPrimitives::generate_challenge(commits, y);
+
+ //generates blinding keys and binds the correct subset
+ std::vector r_;
+ r_.resize(m_);
+ for (int k = 0; k < m_; ++k) {
+ r_[k].randomize();
+ }
+ proof_out.d_.resize(m_);
+ int ptr = l / m_ * m_;
+ for (int k = 0; k < m_; ++k) {
+ proof_out.d_[k] = commits[ptr + k] + h_[0] * r_[k];
+ }
+
+ //generates one out of many sigma proof for the blinded subset
+ aura::SigmaPlusProver d_prover(g_, h_, m_n_, m_m_);
+ d_prover.proof(proof_out.d_, l % m_, r_[l % m_] + r, true, y, proof_out.d_Proof_);
+
+ //generates x challenge using the y challenge calculated in the sigma
+ std::vector x;
+ x.resize(m_);
+ SigmaPrimitives::generate_challenge({h_[0] * y}, x[0]);
+ secp_primitives::Scalar xsum = r_[0] * x[0];
+ for (int k = 1; k < m_; ++k) {
+ SigmaPrimitives::generate_challenge({h_[0] * x[k - 1]}, x[k]);
+ xsum += r_[k] * x[k];
+ }
+
+ //creates digests of the subsets
+ std::vector D_;
+ D_.resize(t_);
+ GroupElement D;
+ D = SigmaPrimitives::HelperFunction(proof_out.d_, x);
+ for (int k = 0; k < t_; ++k) {
+ D_[k] = D + SigmaPrimitives::HelperFunction({commits.begin() + k * m_, commits.begin() + (k + 1) * m_}, x).inverse();
+ }
+
+ //generates proof that the digest of our blinded subset is a member of the digests of all subsets
+ aura::SigmaPlusProver D_prover(g_, h_, t_n_, t_m_);
+ D_prover.proof(D_, l / m_, xsum, true, x[m_ - 1], proof_out.D_Proof_);
+ }
+
+
+
+} // namespace aura
diff --git a/src/libaura/hoom_verifier.h b/src/libaura/hoom_verifier.h
new file mode 100755
index 0000000000..5112be7a56
--- /dev/null
+++ b/src/libaura/hoom_verifier.h
@@ -0,0 +1,37 @@
+#ifndef FIRO_AURA_HOOM_VERIFIER_H
+#define FIRO_AURA_HOOM_VERIFIER_H
+
+#include "sigmaplus_verifier.h"
+#include "util.h"
+
+namespace aura {
+template
+class HOOMVerifier{
+
+public:
+ HOOMVerifier(const GroupElement& g,
+ const std::vector& h_gens,
+ int t_n, int t_m, int m_n, int m_m);
+
+ bool verify(const std::vector& commits,
+ const HOOMProof& proof) const;
+
+ bool batch_verify(const std::vector& commits,
+ const std::vector& serials,
+ const std::vector>& proofs) const;
+
+
+private:
+ GroupElement g_;
+ std::vector h_;
+ int t_n_;
+ int t_m_;
+ int m_n_;
+ int m_m_;
+};
+
+} // namespace aura
+
+#include "hoom_verifier.hpp"
+
+#endif // FIRO_AURA_HOOM_VERIFIER_H
diff --git a/src/libaura/hoom_verifier.hpp b/src/libaura/hoom_verifier.hpp
new file mode 100755
index 0000000000..2b31487cc4
--- /dev/null
+++ b/src/libaura/hoom_verifier.hpp
@@ -0,0 +1,142 @@
+#include
+#include
+
+namespace aura {
+
+ template
+ HOOMVerifier::HOOMVerifier(const GroupElement &g,
+ const std::vector &h_gens,
+ int t_n, int t_m, int m_n, int m_m)
+ : g_(g), h_(h_gens), t_n_(t_n), t_m_(t_m), m_n_(m_n), m_m_(m_m) {
+ }
+
+ template
+ bool HOOMVerifier::verify(const std::vector &commits,
+ const HOOMProof &proof) const {
+
+
+ int t_ = pow(t_n_, t_m_);
+ int m_ = pow(m_n_, m_m_);
+ aura::SigmaPlusVerifier d_verifier(g_, h_, m_n_, m_m_);
+ aura::SigmaPlusVerifier D_verifier(g_, h_, t_n_, t_m_);
+
+ //binds the commitments to the y challenge
+ Exponent y;
+ SigmaPrimitives::generate_challenge(commits, y);
+
+ //checks one out of many sigma proof for the blinded subset
+ if(!d_verifier.verify(proof.d_, proof.d_Proof_, true, y)) {
+ LogPrintf("Hierarchic one out of many proof failed due to d_ check failed.");
+ return false;
+ }
+
+ //generates x challenge using the y challenge calculated in the sigma
+ std::vector x;
+ x.resize(m_);
+ SigmaPrimitives::generate_challenge({h_[0] * y}, x[0]);
+ for (int k = 1; k < m_; ++k) {
+ SigmaPrimitives::generate_challenge({h_[0] * x[k - 1]}, x[k]);
+ }
+
+ //creates digests of the subsets
+ std::vector D_;
+ D_.resize(t_);
+ GroupElement D;
+ D = SigmaPrimitives::HelperFunction(proof.d_, x);
+ for (int k = 0; k < t_; ++k) {
+ D_[k] = D + SigmaPrimitives::HelperFunction({commits.begin() + k * m_, commits.begin() + (k + 1) * m_}, x).inverse();
+ }
+
+ //the proof that the digest of our blinded subset is a member of the digests of all subsets
+ if(!D_verifier.verify(D_, proof.D_Proof_, true, x[m_ - 1])) {
+ LogPrintf("Hierarchic one out of many proof failed due to D_ check failed.");
+ return false;
+ }
+ return true;
+ }
+
+ template
+ bool HOOMVerifier::batch_verify(const std::vector& commits,
+ const std::vector& serials,
+ const std::vector>& proofs) const {
+
+ //Pre-hashing the commits for challenge generation
+ Exponent commits_hash;
+ SigmaPrimitives::generate_challenge(commits, commits_hash);
+
+ int t_ = pow(t_n_, t_m_);
+ int m_ = pow(m_n_, m_m_);
+ int batchsize = serials.size();
+
+ std::vector D_;
+ D_.resize(t_);
+ GroupElement D;
+
+ GroupElement left;
+ GroupElement right;
+
+ aura::SigmaPlusVerifier d_verifier(g_, h_, m_n_, m_m_);
+ aura::SigmaPlusVerifier D_verifier(g_, h_, t_n_, t_m_);
+
+ std::vector x;
+ x.resize(m_);
+
+ //where we calculate the powers required for the exponentation
+ std::vector pows;
+ pows.resize(commits.size());
+
+ for(int i = 0; i < batchsize; ++i){
+ //those values are used to store the results of SigmaPlusVerifier's calculate_batch()
+ GroupElement t;
+ std::vector f_i_;
+ GroupElement zero_commit;
+
+ //checks the one out of many proof in the blinded subset
+ Exponent y = commits_hash;
+ if(!d_verifier.verify(proofs[i].d_, proofs[i].d_Proof_, true, y)){
+ LogPrintf("Hierarchic one out of many proof failed due to d_ check failed.");
+ return false;
+ }
+
+ //generates the x challenge and the subset digests
+ SigmaPrimitives::generate_challenge({h_[0] * y}, x[0]);
+ for (int k = 1; k < m_; ++k) {
+ SigmaPrimitives::generate_challenge({h_[0] * x[k - 1]}, x[k]);
+ }
+ D = SigmaPrimitives::HelperFunction(proofs[i].d_, x);
+ for (int k = 0; k < t_; ++k) {
+ D_[k] = D + SigmaPrimitives::HelperFunction({commits.begin() + k * m_, commits.begin() + (k + 1) * m_}, x).inverse();
+ }
+
+ //We use temporary variable to not alter the x[m_ - 1] value
+ Exponent xtemp = x[m_ - 1];
+ if(!D_verifier.calculate_batch(D_, proofs[i].D_Proof_, t, f_i_, zero_commit, xtemp)){
+ LogPrintf("Hierarchic one out of many proof failed due to one of D_ checks failed.");
+ return false;
+ }
+
+ //uses the f_i to add up the powers of commits in the final batch
+ Exponent f_i_sum;
+ for(int k = 0; k < t_; ++k){
+ for(int j = 0; j < m_; ++j) {
+ pows[k * m_ + j] += x[j] * f_i_[k] * serials[i];
+ }
+ //used for the right side of the equation
+ f_i_sum += f_i_[k];
+ }
+
+ left += t * serials[i];
+ right += zero_commit * serials[i] + D.inverse() * f_i_sum * serials[i];
+ }
+
+ secp_primitives::MultiExponent mult(commits, pows);
+ left += mult.get_multiple().inverse();
+
+ if(left != right) {
+ LogPrintf("Hierarchic one out of many proof failed due to final batch check failed.");
+ return false;
+ }
+ return true;
+ }
+
+} // namespace aura
diff --git a/src/libaura/params.cpp b/src/libaura/params.cpp
new file mode 100755
index 0000000000..fc0ec780f6
--- /dev/null
+++ b/src/libaura/params.cpp
@@ -0,0 +1,94 @@
+#include "chainparams.h"
+#include "params.h"
+
+namespace aura {
+
+Params* Params::instance;
+Params* Params::get_default() {
+ if(instance != nullptr)
+ return instance;
+ else {
+ //fixing generator G;
+ GroupElement g;
+
+ if(!(::Params().GetConsensus().IsTestnet())) {
+ unsigned char buff[32] = {0};
+ GroupElement base;
+ base.set_base_g();
+ base.sha256(buff);
+ g.generate(buff);
+ }
+ else
+ g = GroupElement("9216064434961179932092223867844635691966339998754536116709681652691785432045",
+ "33986433546870000256104618635743654523665060392313886665479090285075695067131");
+
+ //fixing n and m; N = n^m = 16,384
+ int n = 4;
+ int m = 7;
+ int t_n = 4;
+ int t_m = 7;
+ int m_n = 4;
+ int m_m = 7;
+ instance = new Params(g, n, m, t_m, t_n, m_m, m_n);
+ return instance;
+ }
+}
+
+Params::Params(const GroupElement& g, int n, int m, int t_n, int t_m, int m_n, int m_m) :
+ g_(g),
+ m_(m),
+ n_(n),
+ t_m_(t_m),
+ t_n_(t_n),
+ m_m_(m_m),
+ m_n_(m_n)
+
+{
+ unsigned char buff0[32] = {0};
+ g.sha256(buff0);
+ GroupElement h0;
+ h0.generate(buff0);
+ h_.reserve(28);
+ h_.emplace_back(h0);
+ for(int i = 1; i < n*m; ++i) {
+ h_.push_back(GroupElement());
+ unsigned char buff[32] = {0};
+ h_[i - 1].sha256(buff);
+ h_[i].generate(buff);
+ }
+}
+
+Params::~Params(){
+ delete instance;
+}
+
+const GroupElement& Params::get_g() const{
+ return g_;
+}
+const GroupElement& Params::get_h0() const{
+ return h_[0];
+}
+
+const std::vector& Params::get_h() const{
+ return h_;
+}
+
+uint64_t Params::get_n() const{
+ return n_;
+}
+uint64_t Params::get_m() const{
+ return m_;
+}
+ uint64_t Params::get_t_n() const{
+ return t_n_;
+ }
+ uint64_t Params::get_t_m() const{
+ return t_m_;
+ }
+ uint64_t Params::get_m_n() const{
+ return m_n_;
+ }
+ uint64_t Params::get_m_m() const{
+ return m_m_;
+ }
+} //namespace aura
diff --git a/src/libaura/params.h b/src/libaura/params.h
new file mode 100755
index 0000000000..37eca7f489
--- /dev/null
+++ b/src/libaura/params.h
@@ -0,0 +1,42 @@
+#ifndef FIRO_AURA_PARAMS_H
+#define FIRO_AURA_PARAMS_H
+#include
+#include
+#include
+
+using namespace secp_primitives;
+
+namespace aura {
+
+class Params {
+public:
+ static Params* get_default();
+ const GroupElement& get_g() const;
+ const GroupElement& get_h0() const;
+ const std::vector& get_h() const;
+ uint64_t get_n() const;
+ uint64_t get_m() const;
+ uint64_t get_t_n() const;
+ uint64_t get_t_m() const;
+ uint64_t get_m_n() const;
+ uint64_t get_m_m() const;
+
+private:
+ Params(const GroupElement& g, int n, int m, int t_n, int t_m, int m_n, int m_m);
+ ~Params();
+
+private:
+ static Params* instance;
+ GroupElement g_;
+ std::vector h_;
+ int m_;
+ int n_;
+ int t_m_;
+ int t_n_;
+ int m_m_;
+ int m_n_;
+};
+
+}//namespace aura
+
+#endif //FIRO_AURA_PARAMS_H
diff --git a/src/libaura/r1_proof.h b/src/libaura/r1_proof.h
new file mode 100755
index 0000000000..642da4fad7
--- /dev/null
+++ b/src/libaura/r1_proof.h
@@ -0,0 +1,78 @@
+#ifndef FIRO_AURA_SIGMA_R1_PROOF_H
+#define FIRO_AURA_SIGMA_R1_PROOF_H
+
+#include
+#include
+#include
+#include "../../serialize.h"
+
+namespace aura {
+
+template
+class R1Proof {
+public:
+ GroupElement A_;
+ GroupElement C_;
+ GroupElement D_;
+ std::vector f_;
+ Exponent ZA_;
+ Exponent ZC_;
+
+public:
+ R1Proof() = default;
+
+public:
+ bool operator==(R1Proof const &other) const {
+ return A_ == other.A_ &&
+ C_ == other.C_ &&
+ D_ == other.D_ &&
+ f_ == other.f_ &&
+ ZA_ == other.ZA_ &&
+ ZC_ == other.ZC_;
+ }
+
+ bool operator!=(R1Proof const &other) const {
+ return !(*this == other);
+ }
+
+public:
+ inline int memoryRequired(int n, int m) const {
+ return A_.memoryRequired() * 3 + ZA_.memoryRequired() * (m*(n - 1) + 2);
+ }
+
+ inline unsigned char* serialize(unsigned char* buffer) const {
+ unsigned char* current = A_.serialize(buffer);
+ current = C_.serialize(current);
+ current = D_.serialize(current);
+ for (std::size_t i = 0; i < f_.size(); ++i)
+ current = f_[i].serialize(current);
+ current = ZA_.serialize(current);
+ return ZC_.serialize(current);
+ }
+ inline unsigned const char* deserialize(unsigned const char* buffer, int n, int m) {
+ unsigned const char* current = A_.deserialize(buffer);
+ current = C_.deserialize(current);
+ current = D_.deserialize(current);
+ int f_size = m * (n - 1);
+ f_.resize(f_size);
+ for(int i = 0; i < f_size; ++i)
+ current = f_[i].deserialize(current);
+ current = ZA_.deserialize(current);
+ return ZC_.deserialize(current);
+ }
+
+ ADD_SERIALIZE_METHODS;
+ template
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ READWRITE(A_);
+ READWRITE(C_);
+ READWRITE(D_);
+ READWRITE(f_);
+ READWRITE(ZA_);
+ READWRITE(ZC_);
+ }
+};
+
+} // namespace aura
+
+#endif // FIRO_AURA_SIGMA_R1_PROOF_H
diff --git a/src/libaura/r1_proof_generator.h b/src/libaura/r1_proof_generator.h
new file mode 100755
index 0000000000..9c2aaac896
--- /dev/null
+++ b/src/libaura/r1_proof_generator.h
@@ -0,0 +1,76 @@
+#ifndef FIRO_AURA_SIGMA_R1_PROOF_GENERATOR_H
+#define FIRO_AURA_SIGMA_R1_PROOF_GENERATOR_H
+
+#include "r1_proof.h"
+#include "aura_primitives.h"
+
+namespace aura {
+
+template
+class R1ProofGenerator{
+
+public:
+ R1ProofGenerator(const GroupElement& g,
+ const std::vector& h_gens,
+ const std::vector& b,
+ const Exponent& r,
+ int n,
+ int m);
+
+ // Returns commitment B.
+ const GroupElement& get_B() const;
+
+ /** \brief Generates r1 proof by randomly selecting the values of vector a.
+ * \param[out] proof_out - R1 proof generated.
+ * \param[in] skip_final_response If set to true, will only generate the initial message of the proof.
+ */
+ void proof(R1Proof& proof_out, bool skip_final_response = false);
+
+ /** \brief Generates R1 proof, which proves that the given matrix b of size n*m contains bits, and for each row exactly 1 bit is set to 1.
+ * \param[out] a_out - List of randomly generated scalars. These values are used in the rest of sigma proof.
+ * \param[out] proof_out - R1 proof generated.
+ * \param[in] skip_final_response If set to true, will only generate the initial message of the proof.
+ */
+ void proof(std::vector& a_out,
+ R1Proof& proof_out,
+ bool skip_final_response = false);
+
+ /** \brief Finishes generation of R1 proof, the part after receiving the challenge x.
+ * \param[in] a - List of randomly generated scalars. These values are used in the rest of sigma proof.
+ * \param[in] challenge_x Value of challenge X.
+ * \param[out] proof_out - R1 proof generated.
+ */
+ void generate_final_response(const std::vector& a,
+ const Exponent& challenge_x,
+ R1Proof& proof_out);
+private:
+
+ Exponent rA_;
+ Exponent rC_;
+ Exponent rD_;
+
+ // Generators for the commitment. Size of h_ must be n*m.
+ const GroupElement& g_;
+ const std::vector& h_;
+
+ // n*m values of a matrix describing index l of the coin being spent.
+ // Each value in this vector is a bit, I.E. 0 or 1.
+ std::vector b_;
+
+ // Randomness of commitment B_Commit.
+ Exponent r;
+
+ // Main commitment B for the [nxm] matrix of b_.
+ GroupElement B_Commit;
+
+ // Size of the matrix for commitment. Number of coins N < n^m.
+ int n_;
+ int m_;
+
+};
+
+} // namespace aura
+
+#include "r1_proof_generator.hpp"
+
+#endif // FIRO_AURA_SIGMA_R1_PROOF_GENERATOR_H
diff --git a/src/libaura/r1_proof_generator.hpp b/src/libaura/r1_proof_generator.hpp
new file mode 100755
index 0000000000..157143423c
--- /dev/null
+++ b/src/libaura/r1_proof_generator.hpp
@@ -0,0 +1,110 @@
+namespace aura {
+
+template
+R1ProofGenerator::R1ProofGenerator(
+ const GroupElement& g,
+ const std::vector& h_gens,
+ const std::vector& b,
+ const Exponent& r,
+ int n ,
+ int m)
+ : g_(g)
+ , h_(h_gens)
+ , b_(b)
+ , r(r)
+ , n_(n)
+ , m_(m)
+{
+ SigmaPrimitives::commit(g_, h_, b_, r, B_Commit);
+}
+
+template
+const GroupElement& R1ProofGenerator::get_B() const {
+ return B_Commit;
+}
+
+template
+void R1ProofGenerator::proof(
+ R1Proof& proof_out, bool skip_final_response) {
+ std::vector a;
+ proof(a, proof_out, skip_final_response);
+}
+
+template
+void R1ProofGenerator::proof(
+ std::vector& a_out,
+ R1Proof& proof_out,
+ bool skip_final_response) {
+ rC_.randomize();
+ rD_.randomize();
+ a_out.resize(n_ * m_);
+ for(int j = 0; j < m_; ++j) {
+ for(int i = 1; i < n_; ++i) {
+ a_out[j * n_ + i].randomize();
+ a_out[j * n_] -= a_out[j * n_ + i];
+ }
+ }
+
+ // proof_out.B_ = B_Commit;
+
+ //compute A
+ GroupElement A;
+ while(!A.isMember() || A.isInfinity()) {
+ rA_.randomize();
+ SigmaPrimitives::commit(g_, h_, a_out, rA_, A);
+ }
+ proof_out.A_ = A;
+
+ //compute C
+ std::vector c;
+ c.resize(n_ * m_);
+ for(int i = 0; i < n_ * m_; ++i) {
+ c[i] = (a_out[i] * (Exponent(uint64_t(1)) - (Exponent(uint64_t(2)) * b_[i])));
+ }
+ GroupElement C;
+ while(!C.isMember() || C.isInfinity()) {
+ rC_.randomize();
+ SigmaPrimitives::commit(g_, h_, c, rC_, C);
+ }
+ proof_out.C_ = C;
+
+ //compute D
+ std::vector d;
+ d.resize(n_ * m_);
+ for(int i = 0; i < n_ * m_; i++) {
+ d[i] = ((a_out[i].square()).negate());
+ }
+ GroupElement D;
+ while(!D.isMember() || D.isInfinity()) {
+ rD_.randomize();
+ SigmaPrimitives::commit(g_, h_, d, rD_, D);
+ }
+ proof_out.D_ = D;
+
+ if (!skip_final_response) {
+ Exponent x;
+ std::vector group_elements = {A, B_Commit, C, D};
+ SigmaPrimitives::generate_challenge(group_elements, x);
+ generate_final_response(a_out, x, proof_out);
+ }
+}
+
+template
+void R1ProofGenerator::generate_final_response(
+ const std::vector& a,
+ const Exponent& challenge_x,
+ R1Proof& proof_out) {
+ //f
+ proof_out.f_.clear();
+ proof_out.f_.reserve(m_ * (n_ - 1));
+ for(int j = 0; j < m_; j++) {
+ for(int i = 1; i < n_; i++)
+ proof_out.f_.emplace_back(b_[(j * n_) + i] * challenge_x + a[(j * n_) + i]);
+ }
+
+ //zA
+ proof_out.ZA_ = r * challenge_x + rA_;
+ proof_out.ZC_ = rC_ * challenge_x + rD_;
+}
+
+} //namespace aura
diff --git a/src/libaura/r1_proof_verifier.h b/src/libaura/r1_proof_verifier.h
new file mode 100755
index 0000000000..071709319d
--- /dev/null
+++ b/src/libaura/r1_proof_verifier.h
@@ -0,0 +1,38 @@
+#ifndef FIRO_AURA_SIGMA_R1_PROOF_VERIFIER_H
+#define FIRO_AURA_SIGMA_R1_PROOF_VERIFIER_H
+
+namespace aura {
+
+template
+class R1ProofVerifier {
+
+public:
+ R1ProofVerifier(const GroupElement& g,
+ const std::vector& h_gens,
+ const GroupElement& B, int n , int m);
+
+ bool verify(const R1Proof& proof,
+ bool skip_final_response_verification = false) const;
+
+ bool verify(const R1Proof& proof,
+ std::vector& f_out,
+ bool skip_final_response_verification = false) const;
+
+ bool verify_final_response(
+ const R1Proof& proof,
+ const Exponent& challenge_x,
+ std::vector& f_out) const;
+
+private:
+ const GroupElement& g_;
+ const std::vector& h_;
+ GroupElement B_Commit;
+ int n_;
+ int m_;
+};
+
+} // namespace aura
+
+#include "r1_proof_verifier.hpp"
+
+#endif // FIRO_AURA_SIGMA_R1_PROOF_VERIFIER_H
diff --git a/src/libaura/r1_proof_verifier.hpp b/src/libaura/r1_proof_verifier.hpp
new file mode 100755
index 0000000000..d59e871fe3
--- /dev/null
+++ b/src/libaura/r1_proof_verifier.hpp
@@ -0,0 +1,105 @@
+namespace aura {
+
+template
+R1ProofVerifier::R1ProofVerifier(
+ const GroupElement& g,
+ const std::vector& h_gens,
+ const GroupElement& B,
+ int n ,
+ int m)
+ : g_(g)
+ , h_(h_gens)
+ , B_Commit(B)
+ , n_(n)
+ , m_(m){
+}
+
+template
+bool R1ProofVerifier::verify(
+ const R1Proof& proof,
+ bool skip_final_response_verification) const {
+ std::vector f;
+ return verify(proof, f, skip_final_response_verification);
+}
+
+template
+bool R1ProofVerifier::verify(
+ const R1Proof& proof,
+ std::vector& f_out,
+ bool skip_final_response_verification) const{
+
+ if(!(proof.A_.isMember() &&
+ B_Commit.isMember() &&
+ proof.C_.isMember() &&
+ proof.D_.isMember()) ||
+ (proof.A_.isInfinity() ||
+ B_Commit.isInfinity() ||
+ proof.C_.isInfinity() ||
+ proof.D_.isInfinity()))
+ return false;
+ const std::vector& f = proof.f_;
+ for (std::size_t i = 0; i < f.size(); i++) {
+ if(!f[i].isMember() || f[i].isZero())
+ return false;
+ }
+
+ if(!(proof.ZA_.isMember() &&
+ proof.ZC_.isMember()) ||
+ (proof.ZA_.isZero() ||
+ proof.ZC_.isZero()))
+ return false;
+
+ if (!skip_final_response_verification) {
+ Exponent x;
+ std::vector group_elements = {proof.A_, B_Commit, proof.C_, proof.D_};
+ SigmaPrimitives::generate_challenge(group_elements, x);
+ return verify_final_response(proof, x, f_out);
+ }
+ return true;
+}
+
+template
+bool R1ProofVerifier::verify_final_response(
+ const R1Proof& proof,
+ const Exponent& challenge_x,
+ std::vector& f_out) const {
+ const std::vector& f = proof.f_;
+
+ for(unsigned int j = 0; j < f.size(); ++j) {
+ if(f[j] == challenge_x)
+ return false;
+ }
+
+ f_out.clear();
+ f_out.reserve(n_ * m_);
+ for(int j = 0; j < m_; ++j) {
+ f_out.push_back(Exponent(uint64_t(0)));
+ Exponent temp;
+ int k = n_ - 1;
+ for(int i = 0; i < k; ++i) {
+ temp += f[j * k + i];
+ f_out.emplace_back(f[j * k + i]);
+ }
+ f_out[j * n_] = challenge_x - temp;
+ }
+
+ GroupElement one;
+ SigmaPrimitives::commit(g_, h_, f_out, proof.ZA_, one);
+ if((B_Commit * challenge_x + proof.A_) != one)
+ return false;
+
+ std::vector f_outprime;
+ f_outprime.reserve(f_out.size());
+ for (std::size_t i = 0; i < f_out.size(); i++) {
+ f_outprime.emplace_back(f_out[i] * (challenge_x - f_out[i]));
+ }
+
+ GroupElement two;
+ SigmaPrimitives::commit(g_, h_, f_outprime, proof.ZC_, two);
+ if ((proof.C_ * challenge_x + proof.D_) != two)
+ return false;
+
+ return true;
+}
+
+} // namespace aura
diff --git a/src/libaura/sigmaplus_proof.h b/src/libaura/sigmaplus_proof.h
new file mode 100755
index 0000000000..f88220ac8d
--- /dev/null
+++ b/src/libaura/sigmaplus_proof.h
@@ -0,0 +1,73 @@
+#ifndef FIRO_AURA_SIGMA_SIGMAPLUS_PROOF_H
+#define FIRO_AURA_SIGMA_SIGMAPLUS_PROOF_H
+
+#include "params.h"
+#include "r1_proof.h"
+
+namespace aura {
+
+template
+class SigmaPlusProof {
+public:
+ int n;
+ int m;
+ GroupElement B_;
+ R1Proof r1Proof_;
+ std::vector Gk_;
+ Exponent z_;
+
+public:
+ SigmaPlusProof(int n, int m): n(n), m(m) {};
+
+public:
+ bool operator==(const SigmaPlusProof& other) const {
+ return n == other.n &&
+ m == other.m &&
+ B_ == other.B_ &&
+ r1Proof_ == other.r1Proof_ &&
+ Gk_ == other.Gk_ &&
+ z_ == other.z_;
+ }
+
+ bool operator!=(const SigmaPlusProof& other) const {
+ return !(*this == other);
+ }
+
+public:
+ inline int memoryRequired() const {
+ return B_.memoryRequired()
+ + r1Proof_.memoryRequired(n, m)
+ + B_.memoryRequired() * m
+ + z_.memoryRequired();
+ }
+
+ inline unsigned char* serialize(unsigned char* buffer) const {
+ unsigned char* current = B_.serialize(buffer);
+ current = r1Proof_.serialize(current);
+ for (std::size_t i = 0; i < Gk_.size(); ++i)
+ current = Gk_[i].serialize(current);
+ return z_.serialize(current);
+ }
+
+ inline unsigned const char* deserialize(unsigned const char* buffer) {
+ unsigned const char* current = B_.deserialize(buffer);
+ current = r1Proof_.deserialize(current, n, m);
+ Gk_.resize(m);
+ for(int i = 0; i < m; ++i)
+ current = Gk_[i].deserialize(current);
+ return z_.deserialize(current);
+ }
+
+ ADD_SERIALIZE_METHODS;
+ template
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ READWRITE(B_);
+ READWRITE(r1Proof_);
+ READWRITE(Gk_);
+ READWRITE(z_);
+ }
+};
+
+} //namespace aura
+
+#endif // FIRO_AURA_SIGMA_SIGMAPLUS_PROOF_H
diff --git a/src/libaura/sigmaplus_prover.h b/src/libaura/sigmaplus_prover.h
new file mode 100755
index 0000000000..54516263f6
--- /dev/null
+++ b/src/libaura/sigmaplus_prover.h
@@ -0,0 +1,35 @@
+#ifndef FIRO_AURA_SIGMA_SIGMAPLUS_PROVER_H
+#define FIRO_AURA_SIGMA_SIGMAPLUS_PROVER_H
+
+#include "r1_proof_generator.h"
+#include "sigmaplus_proof.h"
+
+#include
+
+namespace aura {
+
+template
+class SigmaPlusProver{
+
+public:
+ SigmaPlusProver(const GroupElement& g,
+ const std::vector& h_gens, int n, int m);
+ void proof(const std::vector& commits,
+ std::size_t l,
+ const Exponent& r,
+ bool fPadding,
+ Exponent challenge,
+ SigmaPlusProof& proof_out);
+
+private:
+ GroupElement g_;
+ std::vector h_;
+ int n_;
+ int m_;
+};
+
+} // namespace aura
+
+#include "sigmaplus_prover.hpp"
+
+#endif // FIRO_AURA_SIGMA_SIGMAPLUS_PROVER_H
diff --git a/src/libaura/sigmaplus_prover.hpp b/src/libaura/sigmaplus_prover.hpp
new file mode 100755
index 0000000000..022a60f8f1
--- /dev/null
+++ b/src/libaura/sigmaplus_prover.hpp
@@ -0,0 +1,150 @@
+#include
+namespace aura {
+
+template
+SigmaPlusProver::SigmaPlusProver(
+ const GroupElement& g,
+ const std::vector& h_gens,
+ int n,
+ int m)
+ : g_(g)
+ , h_(h_gens)
+ , n_(n)
+ , m_(m) {
+}
+
+template
+void SigmaPlusProver::proof(
+ const std::vector& commits,
+ std::size_t l,
+ const Exponent& r,
+ bool fPadding,
+ Exponent challenge,
+ SigmaPlusProof& proof_out) {
+ std::size_t setSize = commits.size();
+ assert(setSize > 0);
+
+ Exponent rB;
+ rB.randomize();
+
+ // Create table sigma of nxm bits.
+ std::vector sigma;
+ SigmaPrimitives::convert_to_sigma(l, n_, m_, sigma);
+
+ // Values of Ro_k from Figure 5.
+ std::vector Pk;
+ Pk.resize(m_);
+ for (int k = 0; k < m_; ++k) {
+ Pk[k].randomize();
+ }
+ R1ProofGenerator r1prover(g_, h_, sigma, rB, n_, m_);
+ proof_out.B_ = r1prover.get_B();
+ std::vector a;
+ r1prover.proof(a, proof_out.r1Proof_, true /*Skip generation of final response*/);
+
+ // Compute coefficients of Polynomials P_I(x), for all I from [0..N].
+ std::size_t N = setSize;
+ std::vector > P_i_k;
+ P_i_k.resize(N);
+
+ // last polynomial is special case if fPadding is true
+ for (std::size_t i = 0; i < (fPadding ? N-1 : N); ++i) {
+ std::vector& coefficients = P_i_k[i];
+ std::vector I = SigmaPrimitives::convert_to_nal(i, n_, m_);
+ coefficients.push_back(a[I[0]]);
+ coefficients.push_back(sigma[I[0]]);
+ for (int j = 1; j < m_; ++j) {
+ SigmaPrimitives::new_factor(sigma[j * n_ + I[j]], a[j * n_ + I[j]], coefficients);
+ }
+ }
+
+ if (fPadding) {
+ /*
+ * To optimize calculation of sum of all polynomials indices 's' = setSize-1 through 'n^m-1' we use the
+ * fact that sum of all of elements in each row of 'a' array is zero. Computation is done by going
+ * through n-ary representation of 's' and increasing "digit" at each position to 'n-1' one by one.
+ * During every step digits at higher positions are fixed and digits at lower positions go through all
+ * possible combinations with a total corresponding polynomial sum of 'x^j'.
+ *
+ * The math behind optimization (TeX notation):
+ *
+ * \sum_{i=s+1}^{N-1}p_i(x) =
+ * \sum_{j=0}^{m-1}
+ * \left[
+ * \left( \sum_{i=s_j+1}^{n-1}(\delta_{l_j,i}x+a_{j,i}) \right)
+ * \left( \prod_{k=j}^{m-1}(\delta_{l_k,s_k}x+a_{k,s_k}) \right)
+ * x^j
+ * \right]
+ */
+
+ std::vector I = SigmaPrimitives::convert_to_nal(N-1, n_, m_);
+ std::vector lj = SigmaPrimitives::convert_to_nal(l, n_, m_);
+
+ std::vector p_i_sum;
+ p_i_sum.emplace_back(uint64_t(1));
+ std::vector> partial_p_s;
+
+ // Pre-calculate product parts and calculate p_s(x) at the same time, put the latter into p_i_sum
+ for (int j = m_ - 1; j >= 0; j--) {
+ partial_p_s.push_back(p_i_sum);
+ SigmaPrimitives::new_factor(sigma[j * n_ + I[j]], a[j * n_ + I[j]], p_i_sum);
+ }
+
+ for (int j = 0; j < m_; j++) {
+ // \sum_{i=s_j+1}^{n-1}(\delta_{l_j,i}x+a_{j,i})
+ Exponent a_sum(uint64_t(0));
+ for (int i = I[j] + 1; i < n_; i++)
+ a_sum += a[j * n_ + i];
+ Exponent x_sum(uint64_t(lj[j] >= I[j]+1 ? 1 : 0));
+
+ // Multiply by \prod_{k=j}^{m-1}(\delta_{l_k,s_k}x+a_{k,s_k})
+ std::vector &polynomial = partial_p_s[m_ - j - 1];
+ SigmaPrimitives::new_factor(x_sum, a_sum, polynomial);
+
+ // Multiply by x^j and add to the result
+ for (int k = 0; k < m_ - j; k++)
+ p_i_sum[j + k] += polynomial[k];
+ }
+
+ P_i_k[N-1] = p_i_sum;
+ }
+
+ //computing G_k`s;
+ std::vector Gk;
+ Gk.reserve(m_);
+ for (int k = 0; k < m_; ++k) {
+ std::vector P_i;
+ P_i.reserve(N);
+ for (size_t i = 0; i < N; ++i) {
+ P_i.emplace_back(P_i_k[i][k]);
+ }
+ secp_primitives::MultiExponent mult(commits, P_i);
+ GroupElement c_k = mult.get_multiple();
+ c_k += SigmaPrimitives::commit(g_, Exponent(uint64_t(0)), h_[0], Pk[k]);
+ Gk.emplace_back(c_k);
+ }
+ proof_out.Gk_ = Gk;
+
+ // Compute value of challenge X, then continue R1 proof and sigma final response proof.
+ std::vector group_elements = {h_[0] * challenge,
+ proof_out.r1Proof_.A_, proof_out.B_, proof_out.r1Proof_.C_, proof_out.r1Proof_.D_};
+
+ group_elements.insert(group_elements.end(), Gk.begin(), Gk.end());
+ Exponent x;
+ SigmaPrimitives::generate_challenge(group_elements, x);
+ r1prover.generate_final_response(a, x, proof_out.r1Proof_);
+ challenge = x;
+ //computing z
+ Exponent z;
+ z = r * x.exponent(uint64_t(m_));
+ Exponent sum;
+ Exponent x_k(uint64_t(1));
+ for (int k = 0; k < m_; ++k) {
+ sum += (Pk[k] * x_k);
+ x_k *= x;
+ }
+ z -= sum;
+ proof_out.z_ = z;
+}
+
+} // namespace aura
diff --git a/src/libaura/sigmaplus_verifier.h b/src/libaura/sigmaplus_verifier.h
new file mode 100755
index 0000000000..c140aed139
--- /dev/null
+++ b/src/libaura/sigmaplus_verifier.h
@@ -0,0 +1,63 @@
+#ifndef FIRO_AURA_SIGMA_SIGMAPLUS_VERIFIER_H
+#define FIRO_AURA_SIGMA_SIGMAPLUS_VERIFIER_H
+
+#include "r1_proof_verifier.h"
+#include "util.h"
+
+namespace aura {
+template
+class SigmaPlusVerifier{
+
+public:
+ SigmaPlusVerifier(const GroupElement& g,
+ const std::vector& h_gens,
+ int n, int m_);
+
+ bool verify(const std::vector& commits,
+ const SigmaPlusProof& proof,
+ bool fPadding,
+ Exponent challenge) const;
+
+ bool batch_verify(const std::vector& commits,
+ const std::vector& serials,
+ const std::vector& fPadding,
+ const std::vector& setSizes,
+ const std::vector>& proofs) const;
+
+
+ bool calculate_batch(const std::vector& commits,
+ const SigmaPlusProof& proof,
+ GroupElement& t,
+ std::vector& f_i_,
+ GroupElement& zero_commit,
+ Exponent challenge) const;
+
+ bool membership_checks(const SigmaPlusProof& proof) const;
+ bool compute_fs(const SigmaPlusProof& proof, const Exponent& x, std::vector& f_) const;
+ bool abcd_checks(const SigmaPlusProof& proof, const Exponent& x, const std::vector& f_) const;
+
+ void compute_fis(int j, const std::vector& f, std::vector& f_i_) const;
+ void compute_fis(const Exponent& f_i, int j, const std::vector& f, typename std::vector::iterator& ptr, typename std::vector::iterator end_ptr) const;
+ void compute_batch_fis(
+ const Exponent& f_i,
+ int j,
+ const std::vector& f,
+ const Exponent& y,
+ Exponent& e,
+ typename std::vector::iterator& ptr,
+ typename std::vector::iterator start_ptr,
+ typename std::vector::iterator end_ptr) const;
+
+
+private:
+ GroupElement g_;
+ std::vector