From c0fe29370a259dd3616226a4b6d27dbe8fd7a6e1 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 24 Sep 2015 17:29:22 +0200 Subject: [PATCH 001/177] Make HTTP server shutdown more graceful Shutting down the HTTP server currently breaks off all current requests. This can create a race condition with RPC `stop` command, where the calling process never receives confirmation. This change removes the listening sockets on shutdown so that no new requests can come in, but no longer breaks off requests in progress. Meant to fix bitcoin/#6717. Zcash: cherry-picked from commit 5e0c22135600fe36811da3b78216efc61ba765fb --- src/httpserver.cpp | 27 +++++++++++++++++++++------ src/rpcserver.cpp | 3 ++- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 4215a0f2626..8acce2f0f06 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -155,6 +155,8 @@ static std::vector rpc_allow_subnets; static WorkQueue* workQueue = 0; //! Handlers for (sub)paths std::vector pathHandlers; +//! Bound listening sockets +std::vector boundSockets; /** Check if a network address is allowed to access the HTTP server */ static bool ClientAllowed(const CNetAddr& netaddr) @@ -264,6 +266,13 @@ static void http_request_cb(struct evhttp_request* req, void* arg) } } +/** Callback to reject HTTP requests after shutdown. */ +static void http_reject_request_cb(struct evhttp_request* req, void*) +{ + LogPrint("http", "Rejecting request while shutting down\n"); + evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL); +} + /** Event dispatcher thread */ static void ThreadHTTP(struct event_base* base, struct evhttp* http) { @@ -278,7 +287,6 @@ static void ThreadHTTP(struct event_base* base, struct evhttp* http) static bool HTTPBindAddresses(struct evhttp* http) { int defaultPort = GetArg("-rpcport", BaseParams().RPCPort()); - int nBound = 0; std::vector > endpoints; // Determine what addresses to bind to @@ -304,13 +312,14 @@ static bool HTTPBindAddresses(struct evhttp* http) // Bind addresses for (std::vector >::iterator i = endpoints.begin(); i != endpoints.end(); ++i) { LogPrint("http", "Binding RPC on address %s port %i\n", i->first, i->second); - if (evhttp_bind_socket(http, i->first.empty() ? NULL : i->first.c_str(), i->second) == 0) { - nBound += 1; + evhttp_bound_socket *bind_handle = evhttp_bind_socket_with_handle(http, i->first.empty() ? NULL : i->first.c_str(), i->second); + if (bind_handle) { + boundSockets.push_back(bind_handle); } else { LogPrintf("Binding RPC on address %s port %i failed.\n", i->first, i->second); } } - return nBound > 0; + return !boundSockets.empty(); } /** Simple wrapper to set thread name and run work queue */ @@ -414,8 +423,14 @@ bool StartHTTPServer(boost::thread_group& threadGroup) void InterruptHTTPServer() { LogPrint("http", "Interrupting HTTP server\n"); - if (eventBase) - event_base_loopbreak(eventBase); + if (eventHTTP) { + // Unlisten sockets + BOOST_FOREACH (evhttp_bound_socket *socket, boundSockets) { + evhttp_del_accept_socket(eventHTTP, socket); + } + // Reject requests on current connections + evhttp_set_gencb(eventHTTP, http_reject_request_cb, NULL); + } if (workQueue) workQueue->Interrupt(); } diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index c2c76a1e219..a01366f7488 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -246,7 +246,8 @@ UniValue stop(const UniValue& params, bool fHelp) throw runtime_error( "stop\n" "\nStop Zcash server."); - // Shutdown will take long enough that the response should get back + // Event loop will exit after current HTTP requests have been handled, so + // this reply will get back to the client. StartShutdown(); return "Zcash server stopping"; } From dbf7057f7a61f6971f903c0e7fa9f3133ab22dbe Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 25 Sep 2015 13:49:08 +0200 Subject: [PATCH 002/177] http: Wait for worker threads to exit Add a WaitExit() call to http's WorkQueue to make it delete the work queue only when all worker threads stopped. This fixes a problem that was reproducable by pressing Ctrl-C during AppInit2: ``` /usr/include/boost/thread/pthread/condition_variable_fwd.hpp:81: boost::condition_variable::~condition_variable(): Assertion `!ret' failed. /usr/include/boost/thread/pthread/mutex.hpp:108: boost::mutex::~mutex(): Assertion `!posix::pthread_mutex_destroy(&m)' failed. ``` I was assuming that `threadGroup->join_all();` would always have been called when entering the Shutdown(). However this is not the case in bitcoind's AppInit2-non-zero-exit case "was left out intentionally here". Zcash: cherry-picked from commit de9de2de361ab1355b976f17371d73e36fe3bf56 Fixes #2334 and #2214. --- src/httpserver.cpp | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 8acce2f0f06..6cf09974e0d 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -72,13 +72,35 @@ class WorkQueue std::deque queue; bool running; size_t maxDepth; + int numThreads; + + /** RAII object to keep track of number of running worker threads */ + class ThreadCounter + { + public: + WorkQueue &wq; + ThreadCounter(WorkQueue &w): wq(w) + { + boost::lock_guard lock(wq.cs); + wq.numThreads += 1; + } + ~ThreadCounter() + { + boost::lock_guard lock(wq.cs); + wq.numThreads -= 1; + wq.cond.notify_all(); + } + }; public: WorkQueue(size_t maxDepth) : running(true), - maxDepth(maxDepth) + maxDepth(maxDepth), + numThreads(0) { } - /* Precondition: worker threads have all stopped */ + /*( Precondition: worker threads have all stopped + * (call WaitExit) + */ ~WorkQueue() { while (!queue.empty()) { @@ -100,6 +122,7 @@ class WorkQueue /** Thread function */ void Run() { + ThreadCounter count(*this); while (running) { WorkItem* i = 0; { @@ -122,6 +145,13 @@ class WorkQueue running = false; cond.notify_all(); } + /** Wait for worker threads to exit */ + void WaitExit() + { + boost::unique_lock lock(cs); + while (numThreads > 0) + cond.wait(lock); + } /** Return current depth of queue */ size_t Depth() @@ -438,7 +468,11 @@ void InterruptHTTPServer() void StopHTTPServer() { LogPrint("http", "Stopping HTTP server\n"); - delete workQueue; + if (workQueue) { + LogPrint("http", "Waiting for HTTP worker threads to exit\n"); + workQueue->WaitExit(); + delete workQueue; + } if (eventHTTP) { evhttp_free(eventHTTP); eventHTTP = 0; From 2abe8ef721ea7bdff5d908f5ee3a9bc34d54a1c8 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 25 Sep 2015 15:35:37 +0200 Subject: [PATCH 003/177] http: Force-exit event loop after predefined time This makes sure that the event loop eventually terminates, even if an event (like an open timeout, or a hanging connection) happens to be holding it up. Zcash: cherry-picked from commit ec908d5f7aa9ad7e3487018e06a24cb6449cc58b --- src/httpserver.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 6cf09974e0d..f2da2de1389 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -461,6 +461,13 @@ void InterruptHTTPServer() // Reject requests on current connections evhttp_set_gencb(eventHTTP, http_reject_request_cb, NULL); } + if (eventBase) { + // Force-exit event loop after predefined time + struct timeval tv; + tv.tv_sec = 10; + tv.tv_usec = 0; + event_base_loopexit(eventBase, &tv); + } if (workQueue) workQueue->Interrupt(); } From c7f77e28f0e4e8cb4f5ca6ba3877ab75bb983930 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 11 Nov 2015 17:34:10 +0100 Subject: [PATCH 004/177] http: speed up shutdown This continues/fixes #6719. `event_base_loopbreak` was not doing what I expected it to, at least in libevent 2.0.21. What I expected was that it sets a timeout, given that no other pending events it would exit in N seconds. However, what it does was delay the event loop exit with 10 seconds, even if nothing is pending. Solve it in a different way: give the event loop thread time to exit out of itself, and if it doesn't, send loopbreak. This speeds up the RPC tests a lot, each exit incurred a 10 second overhead, with this change there should be no shutdown overhead in the common case and up to two seconds if the event loop is blocking. As a bonus this breaks dependency on boost::thread_group, as the HTTP server minds its own offspring. Zcash: cherry-picked from commit a264c32e3321ae909ca59cb8ce8bf5d812dbc4e1 --- src/httpserver.cpp | 30 ++++++++++++++++++++---------- src/httpserver.h | 2 +- src/init.cpp | 2 +- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/httpserver.cpp b/src/httpserver.cpp index f2da2de1389..a7ca741cc23 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -438,15 +438,17 @@ bool InitHTTPServer() return true; } -bool StartHTTPServer(boost::thread_group& threadGroup) +boost::thread threadHTTP; + +bool StartHTTPServer() { LogPrint("http", "Starting HTTP server\n"); int rpcThreads = std::max((long)GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L); LogPrintf("HTTP: starting %d worker threads\n", rpcThreads); - threadGroup.create_thread(boost::bind(&ThreadHTTP, eventBase, eventHTTP)); + threadHTTP = boost::thread(boost::bind(&ThreadHTTP, eventBase, eventHTTP)); for (int i = 0; i < rpcThreads; i++) - threadGroup.create_thread(boost::bind(&HTTPWorkQueueRun, workQueue)); + boost::thread(boost::bind(&HTTPWorkQueueRun, workQueue)); return true; } @@ -461,13 +463,6 @@ void InterruptHTTPServer() // Reject requests on current connections evhttp_set_gencb(eventHTTP, http_reject_request_cb, NULL); } - if (eventBase) { - // Force-exit event loop after predefined time - struct timeval tv; - tv.tv_sec = 10; - tv.tv_usec = 0; - event_base_loopexit(eventBase, &tv); - } if (workQueue) workQueue->Interrupt(); } @@ -480,6 +475,20 @@ void StopHTTPServer() workQueue->WaitExit(); delete workQueue; } + if (eventBase) { + LogPrint("http", "Waiting for HTTP event thread to exit\n"); + // Give event loop a few seconds to exit (to send back last RPC responses), then break it + // Before this was solved with event_base_loopexit, but that didn't work as expected in + // at least libevent 2.0.21 and always introduced a delay. In libevent + // master that appears to be solved, so in the future that solution + // could be used again (if desirable). + // (see discussion in https://github.com/bitcoin/bitcoin/pull/6990) + if (!threadHTTP.try_join_for(boost::chrono::milliseconds(2000))) { + LogPrintf("HTTP event loop did not exit within allotted time, sending loopbreak\n"); + event_base_loopbreak(eventBase); + threadHTTP.join(); + } + } if (eventHTTP) { evhttp_free(eventHTTP); eventHTTP = 0; @@ -488,6 +497,7 @@ void StopHTTPServer() event_base_free(eventBase); eventBase = 0; } + LogPrint("http", "Stopped HTTP server\n"); } struct event_base* EventBase() diff --git a/src/httpserver.h b/src/httpserver.h index 347e7c3abb9..93fb5d8d60d 100644 --- a/src/httpserver.h +++ b/src/httpserver.h @@ -28,7 +28,7 @@ bool InitHTTPServer(); * This is separate from InitHTTPServer to give users race-condition-free time * to register their handlers between InitHTTPServer and StartHTTPServer. */ -bool StartHTTPServer(boost::thread_group& threadGroup); +bool StartHTTPServer(); /** Interrupt HTTP server threads */ void InterruptHTTPServer(); /** Stop HTTP server */ diff --git a/src/init.cpp b/src/init.cpp index cb91a1c1dcc..4f1618e28fa 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -712,7 +712,7 @@ bool AppInitServers(boost::thread_group& threadGroup) return false; if (GetBoolArg("-rest", false) && !StartREST()) return false; - if (!StartHTTPServer(threadGroup)) + if (!StartHTTPServer()) return false; return true; } From c98b91b7c5fd9779c67529aa9c7f99609075357f Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 28 Jul 2016 18:21:00 -0400 Subject: [PATCH 005/177] httpserver: explicitly detach worker threads When using std::thread in place of boost::thread, letting the threads destruct results in a std::terminate. According to the docs, the same thing should be be happening in later boost versions: http://www.boost.org/doc/libs/1_55_0/doc/html/thread/thread_management.html#thread.thread_management.thread.destructor I'm unsure why this hasn't blown up already, but explicitly detaching can't hurt. Zcash: cherry-picked from commit d3773ca9aeb0d2f12dc0c5a0726778050c8cb455 This fixes #2554 (zcash-cli stop during getblocktemplate long poll causes 'Assertion `!pthread_mutex_unlock(&m)' failed.') --- src/httpserver.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/httpserver.cpp b/src/httpserver.cpp index a7ca741cc23..e2a6af6ad3e 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -447,8 +447,10 @@ bool StartHTTPServer() LogPrintf("HTTP: starting %d worker threads\n", rpcThreads); threadHTTP = boost::thread(boost::bind(&ThreadHTTP, eventBase, eventHTTP)); - for (int i = 0; i < rpcThreads; i++) - boost::thread(boost::bind(&HTTPWorkQueueRun, workQueue)); + for (int i = 0; i < rpcThreads; i++) { + boost::thread rpc_worker(HTTPWorkQueueRun, workQueue); + rpc_worker.detach(); + } return true; } From 51e448641d6cbcd582afa22cd8475f8c3086dad7 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 2 Aug 2017 11:17:25 +0100 Subject: [PATCH 006/177] Squashed 'src/snark/' content from commit 9ada3f8 git-subtree-dir: src/snark git-subtree-split: 9ada3f84ab484c57b2247c2f41091fd6a0916573 --- .gitignore | 49 + AUTHORS | 19 + LICENSE | 24 + Makefile | 277 +++ README.md | 628 ++++++ doxygen.conf | 1807 +++++++++++++++++ src/algebra/curves/alt_bn128/alt_bn128_g1.cpp | 524 +++++ src/algebra/curves/alt_bn128/alt_bn128_g1.hpp | 95 + src/algebra/curves/alt_bn128/alt_bn128_g2.cpp | 505 +++++ src/algebra/curves/alt_bn128/alt_bn128_g2.hpp | 96 + .../curves/alt_bn128/alt_bn128_init.cpp | 273 +++ .../curves/alt_bn128/alt_bn128_init.hpp | 57 + .../curves/alt_bn128/alt_bn128_pairing.cpp | 547 +++++ .../curves/alt_bn128/alt_bn128_pairing.hpp | 92 + src/algebra/curves/alt_bn128/alt_bn128_pp.cpp | 58 + src/algebra/curves/alt_bn128/alt_bn128_pp.hpp | 50 + src/algebra/curves/curve_utils.hpp | 22 + src/algebra/curves/curve_utils.tcc | 37 + src/algebra/curves/public_params.hpp | 103 + src/algebra/curves/tests/test_bilinearity.cpp | 136 ++ src/algebra/curves/tests/test_groups.cpp | 175 ++ .../domains/basic_radix2_domain.hpp | 45 + .../domains/basic_radix2_domain.tcc | 112 + .../domains/basic_radix2_domain_aux.hpp | 48 + .../domains/basic_radix2_domain_aux.tcc | 242 +++ .../evaluation_domain/evaluation_domain.hpp | 125 ++ .../evaluation_domain/evaluation_domain.tcc | 117 ++ src/algebra/exponentiation/exponentiation.hpp | 31 + src/algebra/exponentiation/exponentiation.tcc | 53 + src/algebra/fields/bigint.hpp | 70 + src/algebra/fields/bigint.tcc | 278 +++ src/algebra/fields/field_utils.hpp | 51 + src/algebra/fields/field_utils.tcc | 183 ++ src/algebra/fields/fp.hpp | 182 ++ src/algebra/fields/fp.tcc | 790 +++++++ src/algebra/fields/fp12_2over3over2.hpp | 116 ++ src/algebra/fields/fp12_2over3over2.tcc | 412 ++++ src/algebra/fields/fp2.hpp | 120 ++ src/algebra/fields/fp2.tcc | 261 +++ src/algebra/fields/fp3.hpp | 122 ++ src/algebra/fields/fp3.tcc | 259 +++ src/algebra/fields/fp6_3over2.hpp | 104 + src/algebra/fields/fp6_3over2.tcc | 216 ++ src/algebra/fields/fp_aux.tcc | 389 ++++ src/algebra/fields/tests/test_bigint.cpp | 107 + src/algebra/fields/tests/test_fields.cpp | 245 +++ .../knowledge_commitment.hpp | 84 + .../knowledge_commitment.tcc | 111 + .../scalar_multiplication/kc_multiexp.hpp | 55 + .../scalar_multiplication/kc_multiexp.tcc | 274 +++ .../scalar_multiplication/multiexp.hpp | 110 + .../scalar_multiplication/multiexp.tcc | 590 ++++++ src/algebra/scalar_multiplication/wnaf.hpp | 39 + src/algebra/scalar_multiplication/wnaf.tcc | 123 ++ src/common/assert_except.hpp | 12 + .../data_structures/accumulation_vector.hpp | 74 + .../data_structures/accumulation_vector.tcc | 84 + src/common/data_structures/merkle_tree.hpp | 71 + src/common/data_structures/merkle_tree.tcc | 246 +++ src/common/data_structures/sparse_vector.hpp | 79 + src/common/data_structures/sparse_vector.tcc | 316 +++ src/common/default_types/ec_pp.hpp | 53 + .../default_types/r1cs_ppzksnark_pp.hpp | 22 + src/common/profiling.cpp | 379 ++++ src/common/profiling.hpp | 51 + src/common/serialization.hpp | 104 + src/common/serialization.tcc | 180 ++ src/common/template_utils.hpp | 26 + src/common/utils.cpp | 102 + src/common/utils.hpp | 57 + src/common/utils.tcc | 23 + src/gadgetlib1/constraint_profiling.cpp | 48 + src/gadgetlib1/constraint_profiling.hpp | 42 + src/gadgetlib1/examples/simple_example.hpp | 23 + src/gadgetlib1/examples/simple_example.tcc | 54 + src/gadgetlib1/gadget.hpp | 27 + src/gadgetlib1/gadget.tcc | 23 + src/gadgetlib1/gadgets/basic_gadgets.hpp | 351 ++++ src/gadgetlib1/gadgets/basic_gadgets.tcc | 705 +++++++ src/gadgetlib1/gadgets/gadget_from_r1cs.hpp | 45 + src/gadgetlib1/gadgets/gadget_from_r1cs.tcc | 123 ++ .../gadgets/hashes/digest_selector_gadget.hpp | 42 + .../gadgets/hashes/digest_selector_gadget.tcc | 62 + src/gadgetlib1/gadgets/hashes/hash_io.hpp | 63 + src/gadgetlib1/gadgets/hashes/hash_io.tcc | 105 + .../gadgets/hashes/sha256/sha256_aux.hpp | 160 ++ .../gadgets/hashes/sha256/sha256_aux.tcc | 297 +++ .../hashes/sha256/sha256_components.hpp | 108 + .../hashes/sha256/sha256_components.tcc | 250 +++ .../gadgets/hashes/sha256/sha256_gadget.hpp | 98 + .../gadgets/hashes/sha256/sha256_gadget.tcc | 230 +++ .../tests/generate_sha256_gadget_tests.py | 55 + .../hashes/sha256/tests/pypy_sha256.py | 263 +++ .../sha256/tests/test_sha256_gadget.cpp | 46 + .../merkle_authentication_path_variable.hpp | 38 + .../merkle_authentication_path_variable.tcc | 76 + .../merkle_tree_check_read_gadget.hpp | 73 + .../merkle_tree_check_read_gadget.tcc | 196 ++ .../merkle_tree_check_update_gadget.hpp | 91 + .../merkle_tree_check_update_gadget.tcc | 265 +++ .../tests/test_merkle_tree_gadgets.cpp | 48 + src/gadgetlib1/pb_variable.hpp | 144 ++ src/gadgetlib1/pb_variable.tcc | 330 +++ src/gadgetlib1/protoboard.hpp | 75 + src/gadgetlib1/protoboard.tcc | 189 ++ src/reductions/r1cs_to_qap/r1cs_to_qap.hpp | 70 + src/reductions/r1cs_to_qap/r1cs_to_qap.tcc | 338 +++ src/relations/arithmetic_programs/qap/qap.hpp | 193 ++ src/relations/arithmetic_programs/qap/qap.tcc | 324 +++ .../qap/tests/test_qap.cpp | 115 ++ .../r1cs/examples/r1cs_examples.hpp | 73 + .../r1cs/examples/r1cs_examples.tcc | 164 ++ .../r1cs/r1cs.hpp | 153 ++ .../r1cs/r1cs.tcc | 310 +++ src/relations/variable.hpp | 213 ++ src/relations/variable.tcc | 512 +++++ .../examples/run_r1cs_ppzksnark.hpp | 35 + .../examples/run_r1cs_ppzksnark.tcc | 114 ++ .../profiling/profile_r1cs_ppzksnark.cpp | 71 + .../r1cs_ppzksnark/r1cs_ppzksnark.hpp | 479 +++++ .../r1cs_ppzksnark/r1cs_ppzksnark.tcc | 762 +++++++ .../r1cs_ppzksnark/r1cs_ppzksnark_params.hpp | 34 + .../tests/test_r1cs_ppzksnark.cpp | 42 + 123 files changed, 22264 insertions(+) create mode 100644 .gitignore create mode 100644 AUTHORS create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 doxygen.conf create mode 100644 src/algebra/curves/alt_bn128/alt_bn128_g1.cpp create mode 100644 src/algebra/curves/alt_bn128/alt_bn128_g1.hpp create mode 100644 src/algebra/curves/alt_bn128/alt_bn128_g2.cpp create mode 100644 src/algebra/curves/alt_bn128/alt_bn128_g2.hpp create mode 100644 src/algebra/curves/alt_bn128/alt_bn128_init.cpp create mode 100644 src/algebra/curves/alt_bn128/alt_bn128_init.hpp create mode 100644 src/algebra/curves/alt_bn128/alt_bn128_pairing.cpp create mode 100644 src/algebra/curves/alt_bn128/alt_bn128_pairing.hpp create mode 100644 src/algebra/curves/alt_bn128/alt_bn128_pp.cpp create mode 100644 src/algebra/curves/alt_bn128/alt_bn128_pp.hpp create mode 100644 src/algebra/curves/curve_utils.hpp create mode 100644 src/algebra/curves/curve_utils.tcc create mode 100644 src/algebra/curves/public_params.hpp create mode 100644 src/algebra/curves/tests/test_bilinearity.cpp create mode 100644 src/algebra/curves/tests/test_groups.cpp create mode 100644 src/algebra/evaluation_domain/domains/basic_radix2_domain.hpp create mode 100644 src/algebra/evaluation_domain/domains/basic_radix2_domain.tcc create mode 100644 src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp create mode 100644 src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc create mode 100644 src/algebra/evaluation_domain/evaluation_domain.hpp create mode 100644 src/algebra/evaluation_domain/evaluation_domain.tcc create mode 100644 src/algebra/exponentiation/exponentiation.hpp create mode 100644 src/algebra/exponentiation/exponentiation.tcc create mode 100644 src/algebra/fields/bigint.hpp create mode 100644 src/algebra/fields/bigint.tcc create mode 100644 src/algebra/fields/field_utils.hpp create mode 100644 src/algebra/fields/field_utils.tcc create mode 100644 src/algebra/fields/fp.hpp create mode 100644 src/algebra/fields/fp.tcc create mode 100644 src/algebra/fields/fp12_2over3over2.hpp create mode 100644 src/algebra/fields/fp12_2over3over2.tcc create mode 100644 src/algebra/fields/fp2.hpp create mode 100644 src/algebra/fields/fp2.tcc create mode 100644 src/algebra/fields/fp3.hpp create mode 100644 src/algebra/fields/fp3.tcc create mode 100644 src/algebra/fields/fp6_3over2.hpp create mode 100644 src/algebra/fields/fp6_3over2.tcc create mode 100644 src/algebra/fields/fp_aux.tcc create mode 100644 src/algebra/fields/tests/test_bigint.cpp create mode 100644 src/algebra/fields/tests/test_fields.cpp create mode 100644 src/algebra/knowledge_commitment/knowledge_commitment.hpp create mode 100644 src/algebra/knowledge_commitment/knowledge_commitment.tcc create mode 100644 src/algebra/scalar_multiplication/kc_multiexp.hpp create mode 100644 src/algebra/scalar_multiplication/kc_multiexp.tcc create mode 100644 src/algebra/scalar_multiplication/multiexp.hpp create mode 100644 src/algebra/scalar_multiplication/multiexp.tcc create mode 100644 src/algebra/scalar_multiplication/wnaf.hpp create mode 100644 src/algebra/scalar_multiplication/wnaf.tcc create mode 100644 src/common/assert_except.hpp create mode 100644 src/common/data_structures/accumulation_vector.hpp create mode 100644 src/common/data_structures/accumulation_vector.tcc create mode 100644 src/common/data_structures/merkle_tree.hpp create mode 100644 src/common/data_structures/merkle_tree.tcc create mode 100644 src/common/data_structures/sparse_vector.hpp create mode 100644 src/common/data_structures/sparse_vector.tcc create mode 100644 src/common/default_types/ec_pp.hpp create mode 100644 src/common/default_types/r1cs_ppzksnark_pp.hpp create mode 100644 src/common/profiling.cpp create mode 100644 src/common/profiling.hpp create mode 100644 src/common/serialization.hpp create mode 100644 src/common/serialization.tcc create mode 100644 src/common/template_utils.hpp create mode 100644 src/common/utils.cpp create mode 100644 src/common/utils.hpp create mode 100644 src/common/utils.tcc create mode 100644 src/gadgetlib1/constraint_profiling.cpp create mode 100644 src/gadgetlib1/constraint_profiling.hpp create mode 100644 src/gadgetlib1/examples/simple_example.hpp create mode 100644 src/gadgetlib1/examples/simple_example.tcc create mode 100644 src/gadgetlib1/gadget.hpp create mode 100644 src/gadgetlib1/gadget.tcc create mode 100644 src/gadgetlib1/gadgets/basic_gadgets.hpp create mode 100644 src/gadgetlib1/gadgets/basic_gadgets.tcc create mode 100644 src/gadgetlib1/gadgets/gadget_from_r1cs.hpp create mode 100644 src/gadgetlib1/gadgets/gadget_from_r1cs.tcc create mode 100644 src/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp create mode 100644 src/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc create mode 100644 src/gadgetlib1/gadgets/hashes/hash_io.hpp create mode 100644 src/gadgetlib1/gadgets/hashes/hash_io.tcc create mode 100644 src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp create mode 100644 src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc create mode 100644 src/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp create mode 100644 src/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc create mode 100644 src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp create mode 100644 src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc create mode 100644 src/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py create mode 100644 src/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py create mode 100644 src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp create mode 100644 src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp create mode 100644 src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc create mode 100644 src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp create mode 100644 src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc create mode 100644 src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp create mode 100644 src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc create mode 100644 src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp create mode 100644 src/gadgetlib1/pb_variable.hpp create mode 100644 src/gadgetlib1/pb_variable.tcc create mode 100644 src/gadgetlib1/protoboard.hpp create mode 100644 src/gadgetlib1/protoboard.tcc create mode 100644 src/reductions/r1cs_to_qap/r1cs_to_qap.hpp create mode 100644 src/reductions/r1cs_to_qap/r1cs_to_qap.tcc create mode 100644 src/relations/arithmetic_programs/qap/qap.hpp create mode 100644 src/relations/arithmetic_programs/qap/qap.tcc create mode 100644 src/relations/arithmetic_programs/qap/tests/test_qap.cpp create mode 100644 src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp create mode 100644 src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc create mode 100644 src/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp create mode 100644 src/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc create mode 100644 src/relations/variable.hpp create mode 100644 src/relations/variable.tcc create mode 100644 src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp create mode 100644 src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc create mode 100644 src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp create mode 100644 src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp create mode 100644 src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc create mode 100644 src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp create mode 100644 src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000000..f6fb450a271 --- /dev/null +++ b/.gitignore @@ -0,0 +1,49 @@ +*.o +*.a +*.so +*.d +depinst/ +depsrc/ +README.html +doxygen/ +src/gadgetlib2/examples/tutorial +src/gadgetlib2/tests/gadgetlib2_test + +src/algebra/curves/tests/test_bilinearity +src/algebra/curves/tests/test_groups +src/algebra/fields/tests/test_fields +src/common/routing_algorithms/profiling/profile_routing_algorithms +src/common/routing_algorithms/tests/test_routing_algorithms +src/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram +src/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget +src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget +src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets +src/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets +src/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget +src/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget +src/reductions/ram_to_r1cs/examples/demo_arithmetization +src/relations/arithmetic_programs/qap/tests/test_qap +src/relations/arithmetic_programs/ssp/tests/test_ssp +src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd +src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd +src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd +src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd +src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark +src/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark +src/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark +src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark +src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark +src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark +src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark +src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark +src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator +src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover +src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier +src/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark +src/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark +src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark +src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark +src/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark +src/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark +src/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark +src/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000000..1b2d7a24703 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,19 @@ +SCIPR Lab: + Eli Ben-Sasson + Alessandro Chiesa + Daniel Genkin + Shaul Kfir + Eran Tromer + Madars Virza + +External contributors: + Michael Backes + Manuel Barbosa + Dario Fiore + Jens Groth + Joshua A. Kroll + Shigeo MITSUNARI + Raphael Reischuk + Tadanori TERUYA + Sean Bowe + Daira Hopwood diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000000..81cea11e135 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +The libsnark library is developed by SCIPR Lab (http://scipr-lab.org) +and contributors. + +Copyright (c) 2012-2014 SCIPR Lab and contributors (see AUTHORS file). + +All files, with the exceptions below, are released under the MIT License: + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 00000000000..13e54da68b5 --- /dev/null +++ b/Makefile @@ -0,0 +1,277 @@ +#******************************************************************************** +# Makefile for the libsnark library. +#******************************************************************************** +#* @author This file is part of libsnark, developed by SCIPR Lab +#* and contributors (see AUTHORS). +#* @copyright MIT license (see LICENSE file) +#*******************************************************************************/ + +# To override these, use "make OPTFLAGS=..." etc. +CURVE = BN128 +OPTFLAGS = -O2 -march=native -mtune=native +FEATUREFLAGS = -DUSE_ASM -DMONTGOMERY_OUTPUT + +# Initialize this using "CXXFLAGS=... make". The makefile appends to that. +CXXFLAGS += -std=c++11 -Wall -Wextra -Wno-unused-parameter -Wno-comment -Wfatal-errors $(OPTFLAGS) $(FEATUREFLAGS) -DCURVE_$(CURVE) + +DEPSRC = depsrc +DEPINST = depinst + +CXXFLAGS += -I$(DEPINST)/include -Isrc +LDFLAGS += -L$(DEPINST)/lib -Wl,-rpath,$(DEPINST)/lib +LDLIBS += -lgmpxx -lgmp -lboost_program_options +# OpenSSL and its dependencies (needed explicitly for static builds): +LDLIBS += -lcrypto -ldl -lz +# List of .a files to include within libsnark.a and libsnark.so: +AR_LIBS = +# List of library files to install: +INSTALL_LIBS = $(LIB_FILE) +# Sentinel file to check existence of this directory (since directories don't work as a Make dependency): +DEPINST_EXISTS = $(DEPINST)/.exists + + +COMPILE_GTEST := +ifneq ($(NO_GTEST),1) + GTESTDIR=/usr/src/gtest +# Compile GTest from sourcecode if we can (e.g., Ubuntu). Otherwise use precompiled one (e.g., Fedora). +# See https://code.google.com/p/googletest/wiki/FAQ#Why_is_it_not_recommended_to_install_a_pre-compiled_copy_of_Goog . + COMPILE_GTEST :=$(shell test -d $(GTESTDIR) && echo -n 1) + GTEST_LDLIBS += -lgtest -lpthread +endif + +ifneq ($(NO_SUPERCOP),1) + SUPERCOP_LDLIBS += -lsupercop + INSTALL_LIBS += depinst/lib/libsupercop.a + # Would have been nicer to roll supercop into libsnark.a ("AR_LIBS += $(DEPINST)/lib/libsupercop.a"), but it doesn't support position-independent code (libsnark issue #20). +endif + +LIB_SRCS = \ + src/algebra/curves/alt_bn128/alt_bn128_g1.cpp \ + src/algebra/curves/alt_bn128/alt_bn128_g2.cpp \ + src/algebra/curves/alt_bn128/alt_bn128_init.cpp \ + src/algebra/curves/alt_bn128/alt_bn128_pairing.cpp \ + src/algebra/curves/alt_bn128/alt_bn128_pp.cpp \ + src/common/profiling.cpp \ + src/common/utils.cpp \ + src/gadgetlib1/constraint_profiling.cpp \ + +ifeq ($(CURVE),BN128) + LIB_SRCS += \ + src/algebra/curves/bn128/bn128_g1.cpp \ + src/algebra/curves/bn128/bn128_g2.cpp \ + src/algebra/curves/bn128/bn128_gt.cpp \ + src/algebra/curves/bn128/bn128_init.cpp \ + src/algebra/curves/bn128/bn128_pairing.cpp \ + src/algebra/curves/bn128/bn128_pp.cpp + + CXXFLAGS += -DBN_SUPPORT_SNARK + AR_LIBS += $(DEPINST)/lib/libzm.a +endif + +# FIXME: most of these are broken due to removed code. +DISABLED_EXECUTABLES = \ + src/algebra/curves/tests/test_bilinearity \ + src/algebra/curves/tests/test_groups \ + src/algebra/fields/tests/test_fields \ + src/common/routing_algorithms/profiling/profile_routing_algorithms \ + src/common/routing_algorithms/tests/test_routing_algorithms \ + src/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram \ + src/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget \ + src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget \ + src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets \ + src/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets \ + src/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget \ + src/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget \ + src/reductions/ram_to_r1cs/examples/demo_arithmetization \ + src/relations/arithmetic_programs/qap/tests/test_qap \ + src/relations/arithmetic_programs/ssp/tests/test_ssp \ + src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd \ + src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd \ + src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd \ + src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd \ + src/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark \ + src/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark \ + src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark \ + src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark \ + src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark \ + src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark \ + src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark \ + src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator \ + src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover \ + src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier \ + src/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark \ + src/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark \ + src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark \ + src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark \ + src/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark \ + src/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark \ + src/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark \ + src/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark + +EXECUTABLES = \ + src/algebra/fields/tests/test_bigint + +EXECUTABLES_WITH_GTEST = \ + src/gadgetlib2/examples/tutorial \ + src/gadgetlib2/tests/gadgetlib2_test + +EXECUTABLES_WITH_SUPERCOP = \ + src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark + +DOCS = README.html + +LIBSNARK_A = libsnark.a + +# For documentation of the following options, see README.md . + +ifeq ($(NO_PROCPS),1) + CXXFLAGS += -DNO_PROCPS +else + LDLIBS += -lprocps +endif + +ifeq ($(LOWMEM),1) + CXXFLAGS += -DLOWMEM +endif + +ifeq ($(PROFILE_OP_COUNTS),1) + STATIC = 1 + CXXFLAGS += -DPROFILE_OP_COUNTS +endif + +ifeq ($(STATIC),1) + CXXFLAGS += -static -DSTATIC +else + CXXFLAGS += -fPIC +endif + +ifeq ($(MULTICORE),1) + CXXFLAGS += -DMULTICORE -fopenmp +endif + +ifeq ($(CPPDEBUG),1) + CXXFLAGS += -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC + DEBUG = 1 +endif + +ifeq ($(DEBUG),1) + CXXFLAGS += -DDEBUG -ggdb3 +endif + +ifeq ($(PERFORMANCE),1) + OPTFLAGS = -O3 -march=native -mtune=native + CXXFLAGS += -DNDEBUG + # Enable link-time optimization: + CXXFLAGS += -flto -fuse-linker-plugin + LDFLAGS += -flto +endif + +LIB_OBJS =$(patsubst %.cpp,%.o,$(LIB_SRCS)) +EXEC_OBJS =$(patsubst %,%.o,$(EXECUTABLES) $(EXECUTABLES_WITH_GTEST) $(EXECUTABLES_WITH_SUPERCOP)) + +all: \ + $(if $(NO_GTEST),,$(EXECUTABLES_WITH_GTEST)) \ + $(if $(NO_SUPERCOP),,$(EXECUTABLES_WITH_SUPERCOP)) \ + $(EXECUTABLES) \ + $(if $(NO_DOCS),,doc) + +doc: $(DOCS) + +$(DEPINST_EXISTS): + # Create placeholder directories for installed dependencies. Some make settings (including the default) require actually running ./prepare-depends.sh to populate this directory. + mkdir -p $(DEPINST)/lib $(DEPINST)/include + touch $@ + +# In order to detect changes to #include dependencies. -MMD below generates a .d file for each .o file. Include the .d file. +-include $(patsubst %.o,%.d, $(LIB_OBJS) $(EXEC_OBJS) ) + +$(LIB_OBJS) $(EXEC_OBJS): %.o: %.cpp + $(CXX) -o $@ $< -c -MMD $(CXXFLAGS) + +LIBGTEST_A = $(DEPINST)/lib/libgtest.a + +$(LIBGTEST_A): $(GTESTDIR)/src/gtest-all.cc $(DEPINST_EXISTS) + $(CXX) -o $(DEPINST)/lib/gtest-all.o -I $(GTESTDIR) -c -isystem $(GTESTDIR)/include $< $(CXXFLAGS) + $(AR) -rv $(LIBGTEST_A) $(DEPINST)/lib/gtest-all.o + +# libsnark.a will contains all of our relevant object files, and we also mash in the .a files of relevant dependencies built by ./prepare-depends.sh +$(LIBSNARK_A): $(LIB_OBJS) $(AR_LIBS) + ( \ + echo "create $(LIBSNARK_A)"; \ + echo "addmod $(LIB_OBJS)"; \ + if [ -n "$(AR_LIBS)" ]; then for AR_LIB in $(AR_LIBS); do echo addlib $$AR_LIB; done; fi; \ + echo "save"; \ + echo "end"; \ + ) | $(AR) -M + $(AR) s $(LIBSNARK_A) + +libsnark.so: $(LIBSNARK_A) $(DEPINST_EXISTS) + $(CXX) -o $@ --shared -Wl,--whole-archive $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) -Wl,--no-whole-archive $(LDLIBS) + +src/gadgetlib2/tests/gadgetlib2_test: \ + src/gadgetlib2/tests/adapters_UTEST.cpp \ + src/gadgetlib2/tests/constraint_UTEST.cpp \ + src/gadgetlib2/tests/gadget_UTEST.cpp \ + src/gadgetlib2/tests/integration_UTEST.cpp \ + src/gadgetlib2/tests/protoboard_UTEST.cpp \ + src/gadgetlib2/tests/variable_UTEST.cpp + +$(EXECUTABLES): %: %.o $(LIBSNARK_A) $(DEPINST_EXISTS) + $(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(LDLIBS) + +$(EXECUTABLES_WITH_GTEST): %: %.o $(LIBSNARK_A) $(if $(COMPILE_GTEST),$(LIBGTEST_A)) $(DEPINST_EXISTS) + $(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(GTEST_LDLIBS) $(LDLIBS) + +$(EXECUTABLES_WITH_SUPERCOP): %: %.o $(LIBSNARK_A) $(DEPINST_EXISTS) + $(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(SUPERCOP_LDLIBS) $(LDLIBS) + + +ifeq ($(STATIC),1) +LIB_FILE = $(LIBSNARK_A) +else +LIB_FILE = libsnark.so +endif + +lib: $(LIB_FILE) + +$(DOCS): %.html: %.md + markdown_py -f $@ $^ -x toc -x extra --noisy +# TODO: Would be nice to enable "-x smartypants" but Ubuntu 12.04 doesn't support that. +# TODO: switch to redcarpet, to produce same output as GitHub's processing of README.md. But what about TOC? + +ifeq ($(PREFIX),) +install: + $(error Please provide PREFIX. E.g. make install PREFIX=/usr) +else +HEADERS_SRC=$(shell find src -name '*.hpp' -o -name '*.tcc') +HEADERS_DEST=$(patsubst src/%,$(PREFIX)/include/libsnark/%,$(HEADERS_SRC)) + +$(HEADERS_DEST): $(PREFIX)/include/libsnark/%: src/% + mkdir -p $(shell dirname $@) + cp $< $@ + +install: $(INSTALL_LIBS) $(HEADERS_DEST) $(DEPINST_EXISTS) + mkdir -p $(PREFIX)/lib + cp -v $(INSTALL_LIBS) $(PREFIX)/lib/ + cp -rv $(DEPINST)/include $(PREFIX) +endif + +doxy: + doxygen doxygen.conf + +# Clean generated files, except locally-compiled dependencies +clean: + $(RM) \ + $(LIB_OBJS) $(EXEC_OBJS) \ + $(EXECUTABLES) $(EXECUTABLES_WITH_GTEST) $(EXECUTABLES_WITH_SUPERCOP) \ + $(DOCS) \ + ${patsubst %.o,%.d,${LIB_OBJS} ${EXEC_OBJS}} \ + libsnark.so $(LIBSNARK_A) \ + $(RM) -fr doxygen/ \ + $(RM) $(LIBGTEST_A) $(DEPINST)/lib/gtest-all.o + +# Clean all, including locally-compiled dependencies +clean-all: clean + $(RM) -fr $(DEPSRC) $(DEPINST) + +.PHONY: all clean clean-all doc doxy lib install diff --git a/README.md b/README.md new file mode 100644 index 00000000000..d5aa3400630 --- /dev/null +++ b/README.md @@ -0,0 +1,628 @@ +libsnark: a C++ library for zkSNARK proofs +================================================================================ + +-------------------------------------------------------------------------------- +Authors +-------------------------------------------------------------------------------- + +The libsnark library is developed by the [SCIPR Lab] project and contributors +and is released under the MIT License (see the [LICENSE] file). + +Copyright (c) 2012-2014 SCIPR Lab and contributors (see [AUTHORS] file). + +-------------------------------------------------------------------------------- +[TOC] + + + +-------------------------------------------------------------------------------- +Overview +-------------------------------------------------------------------------------- + +This library implements __zkSNARK__ schemes, which are a cryptographic method +for proving/verifying, in zero knowledge, the integrity of computations. + +A computation can be expressed as an NP statement, in forms such as the following: + +- "The C program _foo_, when executed, returns exit code 0 if given the input _bar_ and some additional input _qux_." +- "The Boolean circuit _foo_ is satisfiable by some input _qux_." +- "The arithmetic circuit _foo_ accepts the partial assignment _bar_, when extended into some full assignment _qux_." +- "The set of constraints _foo_ is satisfiable by the partial assignment _bar_, when extended into some full assignment _qux_." + +A prover who knows the witness for the NP statement (i.e., a satisfying input/assignment) can produce a short proof attesting to the truth of the NP statement. This proof can be verified by anyone, and offers the following properties. + +- __Zero knowledge:__ + the verifier learns nothing from the proof beside the truth of the statement (i.e., the value _qux_, in the above examples, remains secret). +- __Succinctness:__ + the proof is short and easy to verify. +- __Non-interactivity:__ + the proof is a string (i.e. it does not require back-and-forth interaction between the prover and the verifier). +- __Soundness:__ + the proof is computationally sound (i.e., it is infeasible to fake a proof of a false NP statement). Such a proof system is also called an _argument_. +- __Proof of knowledge:__ + the proof attests not just that the NP statement is true, but also that the + prover knows why (e.g., knows a valid _qux_). + +These properties are summarized by the _zkSNARK_ acronym, which stands for _Zero-Knowledge Succinct Non-interactive ARgument of Knowledge_ (though zkSNARKs are also knows as +_succinct non-interactive computationally-sound zero-knowledge proofs of knowledge_). +For formal definitions and theoretical discussions about these, see +\[BCCT12], \[BCIOP13], and the references therein. + +The libsnark library currently provides a C++ implementation of: + +1. General-purpose proof systems: + 1. A preprocessing zkSNARK for the NP-complete language "R1CS" + (_Rank-1 Constraint Systems_), which is a language that is similar to arithmetic + circuit satisfiability. + 2. A preprocessing SNARK for a language of arithmetic circuits, "BACS" + (_Bilinear Arithmetic Circuit Satisfiability_). This simplifies the writing + of NP statements when the additional flexibility of R1CS is not needed. + Internally, it reduces to R1CS. + 3. A preprocessing SNARK for the language "USCS" + (_Unitary-Square Constraint Systems_). This abstracts and implements the core + contribution of \[DFGK14] + 4. A preprocessing SNARK for a language of Boolean circuits, "TBCS" + (_Two-input Boolean Circuit Satisfiability_). Internally, it reduces to USCS. + This is much more efficient than going through R1CS. + 5. ADSNARK, a preprocessing SNARKs for proving statements on authenticated + data, as described in \[BBFR15]. + 6. Proof-Carrying Data (PCD). This uses recursive composition of SNARKs, as + explained in \[BCCT13] and optimized in \[BCTV14b]. +2. Gadget libraries (gadgetlib1 and gadgetlib2) for constructing R1CS + instances out of modular "gadget" classes. +3. Examples of applications that use the above proof systems to prove + statements about: + 1. Several toy examples. + 2. Execution of TinyRAM machine code, as explained in \[BCTV14a] and + \[BCGTV13]. (Such machine code can be obtained, e.g., by compiling from C.) + This is easily adapted to any other Random Access Machine that satisfies a + simple load-store interface. + 3. A scalable for TinyRAM using Proof-Carrying Data, as explained in \[BCTV14b] + 4. Zero-knowldge cluster MapReduce, as explained in \[CTV15]. + +The zkSNARK construction implemented by libsnark follows, extends, and +optimizes the approach described in \[BCTV14], itself an extension of +\[BCGTV13], following the approach of \[BCIOP13] and \[GGPR13]. An alternative +implementation of the basic approach is the _Pinocchio_ system of \[PGHR13]. +See these references for discussions of efficiency aspects that arise in +practical use of such constructions, as well as security and trust +considerations. + +This scheme is a _preprocessing zkSNARK_ (_ppzkSNARK_): before proofs can be +created and verified, one needs to first decide on a size/circuit/system +representing the NP statements to be proved, and run a _generator_ algorithm to +create corresponding public parameters (a long proving key and a short +verification key). + +Using the library involves the following high-level steps: + +1. Express the statements to be proved as an R1CS (or any of the other + languages above, such as arithmetic circuits, Boolean circuits, or TinyRAM). + This is done by writing C++ code that constructs an R1CS, and linking this code + together with libsnark +2. Use libsnark's generator algorithm to create the public parameters for this + statement (once and for all). +3. Use libsnark's prover algorithm to create proofs of true statements about + the satisfiability of the R1CS. +4. Use libsnark's verifier algorithm to check proofs for alleged statements. + + +-------------------------------------------------------------------------------- +The NP-complete language R1CS +-------------------------------------------------------------------------------- + +The ppzkSNARK supports proving/verifying membership in a specific NP-complete +language: R1CS (*rank-1 constraint systems*). An instance of the language is +specified by a set of equations over a prime field F, and each equation looks like: + < A, (1,X) > * < B , (1,X) > = < C, (1,X) > +where A,B,C are vectors over F, and X is a vector of variables. + +In particular, arithmetic (as well as boolean) circuits are easily reducible to +this language by converting each gate into a rank-1 constraint. See \[BCGTV13] +Appendix E (and "System of Rank 1 Quadratic Equations") for more details about this. + + +-------------------------------------------------------------------------------- +Elliptic curve choices +-------------------------------------------------------------------------------- + +The ppzkSNARK can be instantiated with different parameter choices, depending on +which elliptic curve is used. The libsnark library currently provides three +options: + +* "edwards": + an instantiation based on an Edwards curve, providing 80 bits of security. + +* "bn128": + an instantiation based on a Barreto-Naehrig curve, providing 128 + bits of security. The underlying curve implementation is + \[ate-pairing], which has incorporated our patch that changes the + BN curve to one suitable for SNARK applications. + + * This implementation uses dynamically-generated machine code for the curve + arithmetic. Some modern systems disallow execution of code on the heap, and + will thus block this implementation. + + For example, on Fedora 20 at its default settings, you will get the error + `zmInit ERR:can't protect` when running this code. To solve this, + run `sudo setsebool -P allow_execheap 1` to allow execution, + or use `make CURVE=ALT_BN128` instead. + +* "alt_bn128": + an alternative to "bn128", somewhat slower but avoids dynamic code generation. + +Note that bn128 requires an x86-64 CPU while the other curve choices +should be architecture-independent; see [portability](#portability). + + +-------------------------------------------------------------------------------- +Gadget libraries +-------------------------------------------------------------------------------- + +The libsnark library currently provides two libraries for conveniently constructing +R1CS instances out of reusable "gadgets". Both libraries provide a way to construct +gadgets on other gadgets as well as additional explicit equations. In this way, +complex R1CS instances can be built bottom up. + +### gadgetlib1 + +This is a low-level library which expose all features of the preprocessing +zkSNARK for R1CS. Its design is based on templates (as does the ppzkSNARK code) +to efficiently support working on multiple elliptic curves simultaneously. This +library is used for most of the constraint-building in libsnark, both internal +(reductions and Proof-Carrying Data) and examples applications. + +### gadgetlib2 + +This is an alternative library for constructing systems of polynomial equations +and, in particular, also R1CS instances. It is better documented and easier to +use than gadgetlib1, and its interface does not use templates. However, fewer +useful gadgets are provided. + + +-------------------------------------------------------------------------------- +Security +-------------------------------------------------------------------------------- + +The theoretical security of the underlying mathematical constructions, and the +requisite assumptions, are analyzed in detailed in the aforementioned research +papers. + +** +This code is a research-quality proof of concept, and has not +yet undergone extensive review or testing. It is thus not suitable, +as is, for use in critical or production systems. +** + +Known issues include the following: + +* The ppzkSNARK's generator and prover exhibit data-dependent running times + and memory usage. These form timing and cache-contention side channels, + which may be an issue in some applications. + +* Randomness is retrieved from /dev/urandom, but this should be + changed to a carefully considered (depending on system and threat + model) external, high-quality randomness source when creating + long-term proving/verification keys. + + +-------------------------------------------------------------------------------- +Build instructions +-------------------------------------------------------------------------------- + +The libsnark library relies on the following: + +- C++ build environment +- GMP for certain bit-integer arithmetic +- libprocps for reporting memory usage +- GTest for some of the unit tests + +So far we have tested these only on Linux, though we have been able to make the library work, +with some features disabled (such as memory profiling or GTest tests), on Windows via Cygwin +and on Mac OS X. (If you succeed in achieving more complete ports of the library, please +let us know!) See also the notes on [portability](#portability) below. + +For example, on a fresh install of Ubuntu 14.04, install the following packages: + + $ sudo apt-get install build-essential git libgmp3-dev libprocps3-dev libgtest-dev python-markdown libboost-all-dev libssl-dev + +Or, on Fedora 20: + + $ sudo yum install gcc-c++ make git gmp-devel procps-ng-devel gtest-devel python-markdown + +Run the following, to fetch dependencies from their GitHub repos and compile them. +(Not required if you set `CURVE` to other than the default `BN128` and also set `NO_SUPERCOP=1`.) + + $ ./prepare-depends.sh + +Then, to compile the library, tests, profiling harness and documentation, run: + + $ make + +To create just the HTML documentation, run + + $ make doc + +and then view the resulting `README.html` (which contains the very text you are reading now). + +To create Doxygen documentation summarizing all files, classes and functions, +with some (currently sparse) comments, install the `doxygen` and `graphviz` packages, then run + + $ make doxy + +(this may take a few minutes). Then view the resulting [`doxygen/index.html`](doxygen/index.html). + +### Using libsnark as a library + +To develop an application that uses libsnark, you could add it within the libsnark directory tree and adjust the Makefile, but it is far better to build libsnark as a (shared or static) library. You can then write your code in a separate directory tree, and link it against libsnark. + + +To build just the shared object library `libsnark.so`, run: + + $ make lib + +To build just the static library `libsnark.a`, run: + + $ make lib STATIC=1 + +Note that static compilation requires static versions of all libraries it depends on. +It may help to minize these dependencies by appending +`CURVE=ALT_BN128 NO_PROCPS=1 NO_GTEST=1 NO_SUPERCOP=1`. On Fedora 21, the requisite +library RPM dependencies are then: +`boost-static glibc-static gmp-static libstdc++-static openssl-static zlib-static + boost-devel glibc-devel gmp-devel gmp-devel libstdc++-devel openssl-devel openssl-devel`. + +To build *and install* the libsnark library: + + $ make install PREFIX=/install/path + +This will install `libsnark.so` into `/install/path/lib`; so your application should be linked using `-L/install/path/lib -lsnark`. It also installs the requisite headers into `/install/path/include`; so your application should be compiled using `-I/install/path/include`. + +In addition, unless you use `NO_SUPERCOP=1`, `libsupercop.a` will be installed and should be linked in using `-lsupercop`. + + +### Building on Windows using Cygwin +Install Cygwin using the graphical installer, including the `g++`, `libgmp` +and `git` packages. Then disable the dependencies not easily supported under CygWin, +using: + + $ make NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 + + +### Building on Mac OS X + +On Mac OS X, install GMP from MacPorts (`port install gmp`). Then disable the +dependencies not easily supported under CygWin, using: + + $ make NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 + +MacPorts does not write its libraries into standard system folders, so you +might need to explicitly provide the paths to the header files and libraries by +appending `CXXFLAGS=-I/opt/local/include LDFLAGS=-L/opt/local/lib` to the line +above. Similarly, to pass the paths to ate-pairing you would run +`INC_DIR=-I/opt/local/include LIB_DIR=-L/opt/local/lib ./prepare-depends.sh` +instead of `./prepare-depends.sh` above. + +-------------------------------------------------------------------------------- +Tutorials +-------------------------------------------------------------------------------- + +libsnark includes a tutorial, and some usage examples, for the high-level API. + +* `src/gadgetlib1/examples1` contains a simple example for constructing a + constraint system using gadgetlib1. + +* `src/gadgetlib2/examples` contains a tutorial for using gadgetlib2 to express + NP statements as constraint systems. It introduces basic terminology, design + overview, and recommended programming style. It also shows how to invoke + ppzkSNARKs on such constraint systems. The main file, `tutorial.cpp`, builds + into a standalone executable. + +* `src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp` + constructs a simple constraint system and runs the ppzksnark. See below for how to + run it. + + +-------------------------------------------------------------------------------- +Executing profiling example +-------------------------------------------------------------------------------- + +The command + + $ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 Fr + +exercises the ppzkSNARK (first generator, then prover, then verifier) on an +R1CS instance with 1000 equations and an input consisting of 10 field elements. + +(If you get the error `zmInit ERR:can't protect`, see the discussion +[above](#elliptic-curve-choices).) + +The command + + $ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 bytes + +does the same but now the input consists of 10 bytes. + + +-------------------------------------------------------------------------------- +Build options +-------------------------------------------------------------------------------- + +The following flags change the behavior of the compiled code. + +* `make FEATUREFLAGS='-Dname1 -Dname2 ...'` + + Override the active conditional #define names (you can see the default at the top of the Makefile). + The next bullets list the most important conditionally-#defined features. + For example, `make FEATUREFLAGS='-DBINARY_OUTPUT'` enables binary output and disables the default + assembly optimizations and Montgomery-representation output. + +* define `BINARY_OUTPUT` + + In serialization, output raw binary data (instead of decimal, when not set). + +* `make CURVE=choice` / define `CURVE_choice` (where `choice` is one of: + ALT_BN128, BN128, EDWARDS, MNT4, MNT6) + + Set the default curve to one of the above (see [elliptic curve choices](#elliptic-curve-choices)). + +* `make DEBUG=1` / define `DEBUG` + + Print additional information for debugging purposes. + +* `make LOWMEM=1` / define `LOWMEM` + + Limit the size of multi-exponentiation tables, for low-memory platforms. + +* `make NO_DOCS=1` + + Do not generate HTML documentation, e.g. on platforms where Markdown is not easily available. + +* `make NO_PROCPS=1` + + Do not link against libprocps. This disables memory profiling. + +* `make NO_GTEST=1` + + Do not link against GTest. The tutorial and test suite of gadgetlib2 tutorial won't be compiled. + +* `make NO_SUPERCOP=1` + + Do not link against SUPERCOP for optimized crypto. The ADSNARK executables will not be built. + +* `make MULTICORE=1` + + Enable parallelized execution of the ppzkSNARK generator and prover, using OpenMP. + This will utilize all cores on the CPU for heavyweight parallelizabe operations such as + FFT and multiexponentiation. The default is single-core. + + To override the maximum number of cores used, set the environment variable `OMP_NUM_THREADS` + at runtime (not compile time), e.g., `OMP_NUM_THREADS=8 test_r1cs_sp_ppzkpc`. It defaults + to the autodetected number of cores, but on some devices, dynamic core management confused + OpenMP's autodetection, so setting `OMP_NUM_THREADS` is necessary for full utilization. + +* define `NO_PT_COMPRESSION` + + Do not use point compression. + This gives much faster serialization times, at the expense of ~2x larger + sizes for serialized keys and proofs. + +* define `MONTGOMERY_OUTPUT` (on by default) + + Serialize Fp elements as their Montgomery representations. If this + option is disabled then Fp elements are serialized as their + equivalence classes, which is slower but produces human-readable + output. + +* `make PROFILE_OP_COUNTS=1` / define `PROFILE_OP_COUNTS` + + Collect counts for field and curve operations inside static variables + of the corresponding algebraic objects. This option works for all + curves except bn128. + +* define `USE_ASM` (on by default) + + Use unrolled assembly routines for F[p] arithmetic and faster heap in + multi-exponentiation. (When not set, use GMP's `mpn_*` routines instead.) + +* define `USE_MIXED_ADDITION` + + Convert each element of the proving key and verification key to + affine coordinates. This allows using mixed addition formulas in + multiexponentiation and results in slightly faster prover and + verifier runtime at expense of increased proving time. + +* `make PERFORMANCE=1` + + Enables compiler optimizations such as link-time optimization, and disables debugging aids. + (On some distributions this causes a `plugin needed to handle lto object` link error and `undefined reference`s, which can be remedied by `AR=gcc-ar make ...`.) + +Not all combinations are tested together or supported by every part of the codebase. + + +-------------------------------------------------------------------------------- +Portability +-------------------------------------------------------------------------------- + +libsnark is written in fairly standard C++11. + +However, having been developed on Linux on x86-64 CPUs, libsnark has some limitations +with respect to portability. Specifically: + +1. libsnark's algebraic data structures assume little-endian byte order. + +2. Profiling routines use `clock_gettime` and `readproc` calls, which are Linux-specific. + +3. Random-number generation is done by reading from `/dev/urandom`, which is + specific to Unix-like systems. + +4. libsnark binary serialization routines (see `BINARY_OUTPUT` above) assume + a fixed machine word size (i.e. sizeof(mp_limb_t) for GMP's limb data type). + Objects serialized in binary on a 64-bit system cannot be de-serialized on + a 32-bit system, and vice versa. + (The decimal serialization routines have no such limitation.) + +5. libsnark requires a C++ compiler with good C++11 support. It has been + tested with g++ 4.7, g++ 4.8, and clang 3.4. + +6. On x86-64, we by default use highly optimized assembly implementations for some + operations (see `USE_ASM` above). On other architectures we fall back to a + portable C++ implementation, which is slower. + +Tested configurations include: + +* Debian jessie with g++ 4.7 on x86-64 +* Debian jessie with clang 3.4 on x86-64 +* Fedora 20/21 with g++ 4.8.2/4.9.2 on x86-64 and i686 +* Ubuntu 14.04 LTS with g++ 4.8 on x86-64 +* Ubuntu 14.04 LTS with g++ 4.8 on x86-32, for EDWARDS and ALT_BN128 curve choices +* Debian wheezy with g++ 4.7 on ARM little endian (Debian armel port) inside QEMU, for EDWARDS and ALT_BN128 curve choices +* Windows 7 with g++ 4.8.3 under Cygwin 1.7.30 on x86-64 with NO_PROCPS=1, NO_GTEST=1 and NO_DOCS=1, for EDWARDS and ALT_BN128 curve choices +* Mac OS X 10.9.4 (Mavericks) with Apple LLVM version 5.1 (based on LLVM 3.4svn) on x86-64 with NO_PROCPS=1, NO_GTEST=1 and NO_DOCS=1 + + +-------------------------------------------------------------------------------- +Directory structure +-------------------------------------------------------------------------------- + +The directory structure of the libsnark library is as follows: + +* src/ --- main C++ source code, containing the following modules: + * algebra/ --- fields and elliptic curve groups + * common/ --- miscellaneous utilities + * gadgetlib1/ --- gadgetlib1, a library to construct R1CS instances + * gadgets/ --- basic gadgets for gadgetlib1 + * gadgetlib2/ --- gadgetlib2, a library to construct R1CS instances + * qap/ --- quadratic arithmetic program + * domains/ --- support for fast interpolation/evaluation, by providing + FFTs and Lagrange-coefficient computations for various domains + * relations/ --- interfaces for expressing statement (relations between instances and witnesses) as various NP-complete languages + * constraint_satisfaction_problems/ --- R1CS and USCS languages + * circuit_satisfaction_problems/ --- Boolean and arithmetic circuit satisfiability languages + * ram_computations/ --- RAM computation languages + * zk_proof_systems --- interfaces and implementations of the proof systems + * reductions --- reductions between languages (used internally, but contains many examples of building constraints) + + Some of these module directories have the following subdirectories: + + * ... + * examples/ --- example code and tutorials for this module + * tests/ --- unit tests for this module + + In particular, the top-level API examples are at `src/r1cs_ppzksnark/examples/` and `src/gadgetlib2/examples/`. + +* depsrc/ --- created by `prepare_depends.sh` for retrieved sourcecode and local builds of external code + (currently: \[ate-pairing], and its dependency xbyak). + +* depinst/ --- created by `prepare_depends.sh` and `Makefile` + for local installation of locally-compiled dependencies. + +* doxygen/ --- created by `make doxy` and contains a Doxygen summary of all files, classes etc. in libsnark. + + +-------------------------------------------------------------------------------- +Further considerations +-------------------------------------------------------------------------------- + +### Multiexponentiation window size + +The ppzkSNARK's generator has to solve a fixed-base multi-exponentiation +problem. We use a window-based method in which the optimal window size depends +on the size of the multiexponentiation instance *and* the platform. + +On our benchmarking platform (a 3.40 GHz Intel Core i7-4770 CPU), we have +computed for each curve optimal windows, provided as +"fixed_base_exp_window_table" initialization sequences, for each curve; see +`X_init.cpp` for X=edwards,bn128,alt_bn128. + +Performance on other platforms may not be optimal (but probably not be far off). +Future releases of the libsnark library will include a tool that generates +optimal window sizes. + + +-------------------------------------------------------------------------------- +References +-------------------------------------------------------------------------------- + +\[BBFR15] [ + _ADSNARK: nearly practical and privacy-preserving proofs on authenticated data_ +](https://eprint.iacr.org/2014/617), + Michael Backes, Manuel Barbosa, Dario Fiore, Raphael M. Reischuk, + IEEE Symposium on Security and Privacy (Oakland) 2015 + +\[BCCT12] [ + _From extractable collision resistance to succinct non-Interactive arguments of knowledge, and back again_ +](http://eprint.iacr.org/2011/443), + Nir Bitansky, Ran Canetti, Alessandro Chiesa, Eran Tromer, + Innovations in Computer Science (ITCS) 2012 + +\[BCCT13] [ + _Recursive composition and bootstrapping for SNARKs and proof-carrying data_ +](http://eprint.iacr.org/2012/095) + Nir Bitansky, Ran Canetti, Alessandro Chiesa, Eran Tromer, + Symposium on Theory of Computing (STOC) 13 + +\[BCGTV13] [ + _SNARKs for C: Verifying Program Executions Succinctly and in Zero Knowledge_ +](http://eprint.iacr.org/2013/507), + Eli Ben-Sasson, Alessandro Chiesa, Daniel Genkin, Eran Tromer, Madars Virza, + CRYPTO 2013 + +\[BCIOP13] [ + _Succinct Non-Interactive Arguments via Linear Interactive Proofs_ +](http://eprint.iacr.org/2012/718), + Nir Bitansky, Alessandro Chiesa, Yuval Ishai, Rafail Ostrovsky, Omer Paneth, + Theory of Cryptography Conference 2013 + +\[BCTV14a] [ + _Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture_ +](http://eprint.iacr.org/2013/879), + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + USENIX Security 2014 + +\[BCTV14b] [ + _Scalable succinct non-interactive arguments via cycles of elliptic curves_ +](https://eprint.iacr.org/2014/595), + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + CRYPTO 2014 + +\[CTV15] [ + _Cluster computing in zero knowledge_ +](https://eprint.iacr.org/2015/377), + Alessandro Chiesa, Eran Tromer, Madars Virza, + Eurocrypt 2015 + +\[DFGK14] [ + Square span programs with applications to succinct NIZK arguments +](https://eprint.iacr.org/2014/718), + George Danezis, Cedric Fournet, Jens Groth, Markulf Kohlweiss, + ASIACCS 2014 + +\[GGPR13] [ + _Quadratic span programs and succinct NIZKs without PCPs_ +](http://eprint.iacr.org/2012/215), + Rosario Gennaro, Craig Gentry, Bryan Parno, Mariana Raykova, + EUROCRYPT 2013 + +\[ate-pairing] [ + _High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves_ +](https://github.com/herumi/ate-pairing), + MITSUNARI Shigeo, TERUYA Tadanori + +\[PGHR13] [ + _Pinocchio: Nearly Practical Verifiable Computation_ +](http://eprint.iacr.org/2013/279), + Bryan Parno, Craig Gentry, Jon Howell, Mariana Raykova, + IEEE Symposium on Security and Privacy (Oakland) 2013 + +[SCIPR Lab]: http://www.scipr-lab.org/ (Succinct Computational Integrity and Privacy Research Lab) + +[LICENSE]: LICENSE (LICENSE file in top directory of libsnark distribution) + +[AUTHORS]: AUTHORS (AUTHORS file in top directory of libsnark distribution) diff --git a/doxygen.conf b/doxygen.conf new file mode 100644 index 00000000000..5fbe6168109 --- /dev/null +++ b/doxygen.conf @@ -0,0 +1,1807 @@ +# Doxyfile 1.8.2 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = libsnark + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +STRIP_FROM_PATH = src + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. + +EXTENSION_MAPPING = tcc=C++ + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented classes, +# or namespaces to their corresponding documentation. Such a link can be +# prevented in individual cases by by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES (the +# default) will make doxygen replace the get and set methods by a property in +# the documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = src README.md + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.md *.c *.h *.cpp *.hpp *.tcc *.inc *.cc + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = Debug \ + Release + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = "perl -pe 's/^(libsnark: .*)$/$1 {#mainpage}/ if $.==1; s!//+ *(TODO|FIXME|XXX)!/// \\todo!'" + # The 1st replacement marks README.md as the main page. + # The 2nd replacement identifies additional TODO notations. + # These should be done with FILTER_PATTERNS instead, but it looks like shell escaping is different there. + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = YES + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = doxygen + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 0 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = YES + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = amsfonts + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = NO + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = YES + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/src/algebra/curves/alt_bn128/alt_bn128_g1.cpp b/src/algebra/curves/alt_bn128/alt_bn128_g1.cpp new file mode 100644 index 00000000000..bf7f43d6f57 --- /dev/null +++ b/src/algebra/curves/alt_bn128/alt_bn128_g1.cpp @@ -0,0 +1,524 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long alt_bn128_G1::add_cnt = 0; +long long alt_bn128_G1::dbl_cnt = 0; +#endif + +std::vector alt_bn128_G1::wnaf_window_table; +std::vector alt_bn128_G1::fixed_base_exp_window_table; +alt_bn128_G1 alt_bn128_G1::G1_zero; +alt_bn128_G1 alt_bn128_G1::G1_one; + +alt_bn128_G1::alt_bn128_G1() +{ + this->X = G1_zero.X; + this->Y = G1_zero.Y; + this->Z = G1_zero.Z; +} + +void alt_bn128_G1::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + alt_bn128_G1 copy(*this); + copy.to_affine_coordinates(); + gmp_printf("(%Nd , %Nd)\n", + copy.X.as_bigint().data, alt_bn128_Fq::num_limbs, + copy.Y.as_bigint().data, alt_bn128_Fq::num_limbs); + } +} + +void alt_bn128_G1::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + gmp_printf("(%Nd : %Nd : %Nd)\n", + this->X.as_bigint().data, alt_bn128_Fq::num_limbs, + this->Y.as_bigint().data, alt_bn128_Fq::num_limbs, + this->Z.as_bigint().data, alt_bn128_Fq::num_limbs); + } +} + +void alt_bn128_G1::to_affine_coordinates() +{ + if (this->is_zero()) + { + this->X = alt_bn128_Fq::zero(); + this->Y = alt_bn128_Fq::one(); + this->Z = alt_bn128_Fq::zero(); + } + else + { + alt_bn128_Fq Z_inv = Z.inverse(); + alt_bn128_Fq Z2_inv = Z_inv.squared(); + alt_bn128_Fq Z3_inv = Z2_inv * Z_inv; + this->X = this->X * Z2_inv; + this->Y = this->Y * Z3_inv; + this->Z = alt_bn128_Fq::one(); + } +} + +void alt_bn128_G1::to_special() +{ + this->to_affine_coordinates(); +} + +bool alt_bn128_G1::is_special() const +{ + return (this->is_zero() || this->Z == alt_bn128_Fq::one()); +} + +bool alt_bn128_G1::is_zero() const +{ + return (this->Z.is_zero()); +} + +bool alt_bn128_G1::operator==(const alt_bn128_G1 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + alt_bn128_Fq Z1_squared = (this->Z).squared(); + alt_bn128_Fq Z2_squared = (other.Z).squared(); + + if ((this->X * Z2_squared) != (other.X * Z1_squared)) + { + return false; + } + + alt_bn128_Fq Z1_cubed = (this->Z) * Z1_squared; + alt_bn128_Fq Z2_cubed = (other.Z) * Z2_squared; + + if ((this->Y * Z2_cubed) != (other.Y * Z1_cubed)) + { + return false; + } + + return true; +} + +bool alt_bn128_G1::operator!=(const alt_bn128_G1& other) const +{ + return !(operator==(other)); +} + +alt_bn128_G1 alt_bn128_G1::operator+(const alt_bn128_G1 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // check for doubling case + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + alt_bn128_Fq Z1Z1 = (this->Z).squared(); + alt_bn128_Fq Z2Z2 = (other.Z).squared(); + + alt_bn128_Fq U1 = this->X * Z2Z2; + alt_bn128_Fq U2 = other.X * Z1Z1; + + alt_bn128_Fq Z1_cubed = (this->Z) * Z1Z1; + alt_bn128_Fq Z2_cubed = (other.Z) * Z2Z2; + + alt_bn128_Fq S1 = (this->Y) * Z2_cubed; // S1 = Y1 * Z2 * Z2Z2 + alt_bn128_Fq S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1 + + if (U1 == U2 && S1 == S2) + { + // dbl case; nothing of above can be reused + return this->dbl(); + } + + // rest of add case + alt_bn128_Fq H = U2 - U1; // H = U2-U1 + alt_bn128_Fq S2_minus_S1 = S2-S1; + alt_bn128_Fq I = (H+H).squared(); // I = (2 * H)^2 + alt_bn128_Fq J = H * I; // J = H * I + alt_bn128_Fq r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1) + alt_bn128_Fq V = U1 * I; // V = U1 * I + alt_bn128_Fq X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V + alt_bn128_Fq S1_J = S1 * J; + alt_bn128_Fq Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J + alt_bn128_Fq Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H + + return alt_bn128_G1(X3, Y3, Z3); +} + +alt_bn128_G1 alt_bn128_G1::operator-() const +{ + return alt_bn128_G1(this->X, -(this->Y), this->Z); +} + + +alt_bn128_G1 alt_bn128_G1::operator-(const alt_bn128_G1 &other) const +{ + return (*this) + (-other); +} + +alt_bn128_G1 alt_bn128_G1::add(const alt_bn128_G1 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case + if (this->operator==(other)) + { + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl + + alt_bn128_Fq Z1Z1 = (this->Z).squared(); // Z1Z1 = Z1^2 + alt_bn128_Fq Z2Z2 = (other.Z).squared(); // Z2Z2 = Z2^2 + alt_bn128_Fq U1 = (this->X) * Z2Z2; // U1 = X1 * Z2Z2 + alt_bn128_Fq U2 = (other.X) * Z1Z1; // U2 = X2 * Z1Z1 + alt_bn128_Fq S1 = (this->Y) * (other.Z) * Z2Z2; // S1 = Y1 * Z2 * Z2Z2 + alt_bn128_Fq S2 = (other.Y) * (this->Z) * Z1Z1; // S2 = Y2 * Z1 * Z1Z1 + alt_bn128_Fq H = U2 - U1; // H = U2-U1 + alt_bn128_Fq S2_minus_S1 = S2-S1; + alt_bn128_Fq I = (H+H).squared(); // I = (2 * H)^2 + alt_bn128_Fq J = H * I; // J = H * I + alt_bn128_Fq r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1) + alt_bn128_Fq V = U1 * I; // V = U1 * I + alt_bn128_Fq X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V + alt_bn128_Fq S1_J = S1 * J; + alt_bn128_Fq Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J + alt_bn128_Fq Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H + + return alt_bn128_G1(X3, Y3, Z3); +} + +alt_bn128_G1 alt_bn128_G1::mixed_add(const alt_bn128_G1 &other) const +{ +#ifdef DEBUG + assert(other.is_special()); +#endif + + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // check for doubling case + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + // we know that Z2 = 1 + + const alt_bn128_Fq Z1Z1 = (this->Z).squared(); + + const alt_bn128_Fq &U1 = this->X; + const alt_bn128_Fq U2 = other.X * Z1Z1; + + const alt_bn128_Fq Z1_cubed = (this->Z) * Z1Z1; + + const alt_bn128_Fq &S1 = (this->Y); // S1 = Y1 * Z2 * Z2Z2 + const alt_bn128_Fq S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1 + + if (U1 == U2 && S1 == S2) + { + // dbl case; nothing of above can be reused + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl + alt_bn128_Fq H = U2-(this->X); // H = U2-X1 + alt_bn128_Fq HH = H.squared() ; // HH = H&2 + alt_bn128_Fq I = HH+HH; // I = 4*HH + I = I + I; + alt_bn128_Fq J = H*I; // J = H*I + alt_bn128_Fq r = S2-(this->Y); // r = 2*(S2-Y1) + r = r + r; + alt_bn128_Fq V = (this->X) * I ; // V = X1*I + alt_bn128_Fq X3 = r.squared()-J-V-V; // X3 = r^2-J-2*V + alt_bn128_Fq Y3 = (this->Y)*J; // Y3 = r*(V-X3)-2*Y1*J + Y3 = r*(V-X3) - Y3 - Y3; + alt_bn128_Fq Z3 = ((this->Z)+H).squared() - Z1Z1 - HH; // Z3 = (Z1+H)^2-Z1Z1-HH + + return alt_bn128_G1(X3, Y3, Z3); +} + +alt_bn128_G1 alt_bn128_G1::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + // handle point at infinity + if (this->is_zero()) + { + return (*this); + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l + + alt_bn128_Fq A = (this->X).squared(); // A = X1^2 + alt_bn128_Fq B = (this->Y).squared(); // B = Y1^2 + alt_bn128_Fq C = B.squared(); // C = B^2 + alt_bn128_Fq D = (this->X + B).squared() - A - C; + D = D+D; // D = 2 * ((X1 + B)^2 - A - C) + alt_bn128_Fq E = A + A + A; // E = 3 * A + alt_bn128_Fq F = E.squared(); // F = E^2 + alt_bn128_Fq X3 = F - (D+D); // X3 = F - 2 D + alt_bn128_Fq eightC = C+C; + eightC = eightC + eightC; + eightC = eightC + eightC; + alt_bn128_Fq Y3 = E * (D - X3) - eightC; // Y3 = E * (D - X3) - 8 * C + alt_bn128_Fq Y1Z1 = (this->Y)*(this->Z); + alt_bn128_Fq Z3 = Y1Z1 + Y1Z1; // Z3 = 2 * Y1 * Z1 + + return alt_bn128_G1(X3, Y3, Z3); +} + +bool alt_bn128_G1::is_well_formed() const +{ + if (this->is_zero()) + { + return true; + } + else + { + /* + y^2 = x^3 + b + + We are using Jacobian coordinates, so equation we need to check is actually + + (y/z^3)^2 = (x/z^2)^3 + b + y^2 / z^6 = x^3 / z^6 + b + y^2 = x^3 + b z^6 + */ + alt_bn128_Fq X2 = this->X.squared(); + alt_bn128_Fq Y2 = this->Y.squared(); + alt_bn128_Fq Z2 = this->Z.squared(); + + alt_bn128_Fq X3 = this->X * X2; + alt_bn128_Fq Z3 = this->Z * Z2; + alt_bn128_Fq Z6 = Z3.squared(); + + return (Y2 == X3 + alt_bn128_coeff_b * Z6); + } +} + +alt_bn128_G1 alt_bn128_G1::zero() +{ + return G1_zero; +} + +alt_bn128_G1 alt_bn128_G1::one() +{ + return G1_one; +} + +alt_bn128_G1 alt_bn128_G1::random_element() +{ + return (scalar_field::random_element().as_bigint()) * G1_one; +} + +std::ostream& operator<<(std::ostream &out, const alt_bn128_G1 &g) +{ + alt_bn128_G1 copy(g); + copy.to_affine_coordinates(); + + out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR; +#ifdef NO_PT_COMPRESSION + out << copy.X << OUTPUT_SEPARATOR << copy.Y; +#else + /* storing LSB of Y */ + out << copy.X << OUTPUT_SEPARATOR << (copy.Y.as_bigint().data[0] & 1); +#endif + + return out; +} + +std::istream& operator>>(std::istream &in, alt_bn128_G1 &g) +{ + char is_zero; + alt_bn128_Fq tX, tY; + +#ifdef NO_PT_COMPRESSION + in >> is_zero >> tX >> tY; + is_zero -= '0'; +#else + in.read((char*)&is_zero, 1); // this reads is_zero; + is_zero -= '0'; + consume_OUTPUT_SEPARATOR(in); + + unsigned char Y_lsb; + in >> tX; + consume_OUTPUT_SEPARATOR(in); + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + // y = +/- sqrt(x^3 + b) + if (!is_zero) + { + alt_bn128_Fq tX2 = tX.squared(); + alt_bn128_Fq tY2 = tX2*tX + alt_bn128_coeff_b; + tY = tY2.sqrt(); + + if ((tY.as_bigint().data[0] & 1) != Y_lsb) + { + tY = -tY; + } + } +#endif + // using Jacobian coordinates + if (!is_zero) + { + g.X = tX; + g.Y = tY; + g.Z = alt_bn128_Fq::one(); + } + else + { + g = alt_bn128_G1::zero(); + } + + return in; +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v) +{ + out << v.size() << "\n"; + for (const alt_bn128_G1& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +std::istream& operator>>(std::istream& in, std::vector &v) +{ + v.clear(); + + size_t s; + in >> s; + consume_newline(in); + + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + alt_bn128_G1 g; + in >> g; + consume_OUTPUT_NEWLINE(in); + v.emplace_back(g); + } + + return in; +} + +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.Z); + } + batch_invert(Z_vec); + + const alt_bn128_Fq one = alt_bn128_Fq::one(); + + for (size_t i = 0; i < vec.size(); ++i) + { + alt_bn128_Fq Z2 = Z_vec[i].squared(); + alt_bn128_Fq Z3 = Z_vec[i] * Z2; + + vec[i].X = vec[i].X * Z2; + vec[i].Y = vec[i].Y * Z3; + vec[i].Z = one; + } +} + +} // libsnark diff --git a/src/algebra/curves/alt_bn128/alt_bn128_g1.hpp b/src/algebra/curves/alt_bn128/alt_bn128_g1.hpp new file mode 100644 index 00000000000..da11a2e8c4b --- /dev/null +++ b/src/algebra/curves/alt_bn128/alt_bn128_g1.hpp @@ -0,0 +1,95 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALT_BN128_G1_HPP_ +#define ALT_BN128_G1_HPP_ +#include +#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" +#include "algebra/curves/curve_utils.hpp" + +namespace libsnark { + +class alt_bn128_G1; +std::ostream& operator<<(std::ostream &, const alt_bn128_G1&); +std::istream& operator>>(std::istream &, alt_bn128_G1&); + +class alt_bn128_G1 { +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + static alt_bn128_G1 G1_zero; + static alt_bn128_G1 G1_one; + + typedef alt_bn128_Fq base_field; + typedef alt_bn128_Fr scalar_field; + + alt_bn128_Fq X, Y, Z; + + // using Jacobian coordinates + alt_bn128_G1(); + alt_bn128_G1(const alt_bn128_Fq& X, const alt_bn128_Fq& Y, const alt_bn128_Fq& Z) : X(X), Y(Y), Z(Z) {}; + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const alt_bn128_G1 &other) const; + bool operator!=(const alt_bn128_G1 &other) const; + + alt_bn128_G1 operator+(const alt_bn128_G1 &other) const; + alt_bn128_G1 operator-() const; + alt_bn128_G1 operator-(const alt_bn128_G1 &other) const; + + alt_bn128_G1 add(const alt_bn128_G1 &other) const; + alt_bn128_G1 mixed_add(const alt_bn128_G1 &other) const; + alt_bn128_G1 dbl() const; + + bool is_well_formed() const; + + static alt_bn128_G1 zero(); + static alt_bn128_G1 one(); + static alt_bn128_G1 random_element(); + + static size_t size_in_bits() { return base_field::size_in_bits() + 1; } + static bigint base_field_char() { return base_field::field_char(); } + static bigint order() { return scalar_field::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const alt_bn128_G1 &g); + friend std::istream& operator>>(std::istream &in, alt_bn128_G1 &g); +}; + +template +alt_bn128_G1 operator*(const bigint &lhs, const alt_bn128_G1 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +alt_bn128_G1 operator*(const Fp_model &lhs, const alt_bn128_G1 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v); +std::istream& operator>>(std::istream& in, std::vector &v); + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark +#endif // ALT_BN128_G1_HPP_ diff --git a/src/algebra/curves/alt_bn128/alt_bn128_g2.cpp b/src/algebra/curves/alt_bn128/alt_bn128_g2.cpp new file mode 100644 index 00000000000..c4152e4374d --- /dev/null +++ b/src/algebra/curves/alt_bn128/alt_bn128_g2.cpp @@ -0,0 +1,505 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long alt_bn128_G2::add_cnt = 0; +long long alt_bn128_G2::dbl_cnt = 0; +#endif + +std::vector alt_bn128_G2::wnaf_window_table; +std::vector alt_bn128_G2::fixed_base_exp_window_table; +alt_bn128_G2 alt_bn128_G2::G2_zero; +alt_bn128_G2 alt_bn128_G2::G2_one; + +alt_bn128_G2::alt_bn128_G2() +{ + this->X = G2_zero.X; + this->Y = G2_zero.Y; + this->Z = G2_zero.Z; +} + +alt_bn128_Fq2 alt_bn128_G2::mul_by_b(const alt_bn128_Fq2 &elt) +{ + return alt_bn128_Fq2(alt_bn128_twist_mul_by_b_c0 * elt.c0, alt_bn128_twist_mul_by_b_c1 * elt.c1); +} + +void alt_bn128_G2::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + alt_bn128_G2 copy(*this); + copy.to_affine_coordinates(); + gmp_printf("(%Nd*z + %Nd , %Nd*z + %Nd)\n", + copy.X.c1.as_bigint().data, alt_bn128_Fq::num_limbs, + copy.X.c0.as_bigint().data, alt_bn128_Fq::num_limbs, + copy.Y.c1.as_bigint().data, alt_bn128_Fq::num_limbs, + copy.Y.c0.as_bigint().data, alt_bn128_Fq::num_limbs); + } +} + +void alt_bn128_G2::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + gmp_printf("(%Nd*z + %Nd : %Nd*z + %Nd : %Nd*z + %Nd)\n", + this->X.c1.as_bigint().data, alt_bn128_Fq::num_limbs, + this->X.c0.as_bigint().data, alt_bn128_Fq::num_limbs, + this->Y.c1.as_bigint().data, alt_bn128_Fq::num_limbs, + this->Y.c0.as_bigint().data, alt_bn128_Fq::num_limbs, + this->Z.c1.as_bigint().data, alt_bn128_Fq::num_limbs, + this->Z.c0.as_bigint().data, alt_bn128_Fq::num_limbs); + } +} + +void alt_bn128_G2::to_affine_coordinates() +{ + if (this->is_zero()) + { + this->X = alt_bn128_Fq2::zero(); + this->Y = alt_bn128_Fq2::one(); + this->Z = alt_bn128_Fq2::zero(); + } + else + { + alt_bn128_Fq2 Z_inv = Z.inverse(); + alt_bn128_Fq2 Z2_inv = Z_inv.squared(); + alt_bn128_Fq2 Z3_inv = Z2_inv * Z_inv; + this->X = this->X * Z2_inv; + this->Y = this->Y * Z3_inv; + this->Z = alt_bn128_Fq2::one(); + } +} + +void alt_bn128_G2::to_special() +{ + this->to_affine_coordinates(); +} + +bool alt_bn128_G2::is_special() const +{ + return (this->is_zero() || this->Z == alt_bn128_Fq2::one()); +} + +bool alt_bn128_G2::is_zero() const +{ + return (this->Z.is_zero()); +} + +bool alt_bn128_G2::operator==(const alt_bn128_G2 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + alt_bn128_Fq2 Z1_squared = (this->Z).squared(); + alt_bn128_Fq2 Z2_squared = (other.Z).squared(); + + if ((this->X * Z2_squared) != (other.X * Z1_squared)) + { + return false; + } + + alt_bn128_Fq2 Z1_cubed = (this->Z) * Z1_squared; + alt_bn128_Fq2 Z2_cubed = (other.Z) * Z2_squared; + + if ((this->Y * Z2_cubed) != (other.Y * Z1_cubed)) + { + return false; + } + + return true; +} + +bool alt_bn128_G2::operator!=(const alt_bn128_G2& other) const +{ + return !(operator==(other)); +} + +alt_bn128_G2 alt_bn128_G2::operator+(const alt_bn128_G2 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // check for doubling case + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + alt_bn128_Fq2 Z1Z1 = (this->Z).squared(); + alt_bn128_Fq2 Z2Z2 = (other.Z).squared(); + + alt_bn128_Fq2 U1 = this->X * Z2Z2; + alt_bn128_Fq2 U2 = other.X * Z1Z1; + + alt_bn128_Fq2 Z1_cubed = (this->Z) * Z1Z1; + alt_bn128_Fq2 Z2_cubed = (other.Z) * Z2Z2; + + alt_bn128_Fq2 S1 = (this->Y) * Z2_cubed; // S1 = Y1 * Z2 * Z2Z2 + alt_bn128_Fq2 S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1 + + if (U1 == U2 && S1 == S2) + { + // dbl case; nothing of above can be reused + return this->dbl(); + } + + // rest of add case + alt_bn128_Fq2 H = U2 - U1; // H = U2-U1 + alt_bn128_Fq2 S2_minus_S1 = S2-S1; + alt_bn128_Fq2 I = (H+H).squared(); // I = (2 * H)^2 + alt_bn128_Fq2 J = H * I; // J = H * I + alt_bn128_Fq2 r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1) + alt_bn128_Fq2 V = U1 * I; // V = U1 * I + alt_bn128_Fq2 X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V + alt_bn128_Fq2 S1_J = S1 * J; + alt_bn128_Fq2 Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J + alt_bn128_Fq2 Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H + + return alt_bn128_G2(X3, Y3, Z3); +} + +alt_bn128_G2 alt_bn128_G2::operator-() const +{ + return alt_bn128_G2(this->X, -(this->Y), this->Z); +} + + +alt_bn128_G2 alt_bn128_G2::operator-(const alt_bn128_G2 &other) const +{ + return (*this) + (-other); +} + +alt_bn128_G2 alt_bn128_G2::add(const alt_bn128_G2 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case + if (this->operator==(other)) + { + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 + + alt_bn128_Fq2 Z1Z1 = (this->Z).squared(); // Z1Z1 = Z1^2 + alt_bn128_Fq2 Z2Z2 = (other.Z).squared(); // Z2Z2 = Z2^2 + alt_bn128_Fq2 U1 = (this->X) * Z2Z2; // U1 = X1 * Z2Z2 + alt_bn128_Fq2 U2 = (other.X) * Z1Z1; // U2 = X2 * Z1Z1 + alt_bn128_Fq2 S1 = (this->Y) * (other.Z) * Z2Z2; // S1 = Y1 * Z2 * Z2Z2 + alt_bn128_Fq2 S2 = (other.Y) * (this->Z) * Z1Z1; // S2 = Y2 * Z1 * Z1Z1 + alt_bn128_Fq2 H = U2 - U1; // H = U2-U1 + alt_bn128_Fq2 S2_minus_S1 = S2-S1; + alt_bn128_Fq2 I = (H+H).squared(); // I = (2 * H)^2 + alt_bn128_Fq2 J = H * I; // J = H * I + alt_bn128_Fq2 r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1) + alt_bn128_Fq2 V = U1 * I; // V = U1 * I + alt_bn128_Fq2 X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V + alt_bn128_Fq2 S1_J = S1 * J; + alt_bn128_Fq2 Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J + alt_bn128_Fq2 Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H + + return alt_bn128_G2(X3, Y3, Z3); +} + +alt_bn128_G2 alt_bn128_G2::mixed_add(const alt_bn128_G2 &other) const +{ +#ifdef DEBUG + assert(other.is_special()); +#endif + + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // check for doubling case + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + // we know that Z2 = 1 + + const alt_bn128_Fq2 Z1Z1 = (this->Z).squared(); + + const alt_bn128_Fq2 &U1 = this->X; + const alt_bn128_Fq2 U2 = other.X * Z1Z1; + + const alt_bn128_Fq2 Z1_cubed = (this->Z) * Z1Z1; + + const alt_bn128_Fq2 &S1 = (this->Y); // S1 = Y1 * Z2 * Z2Z2 + const alt_bn128_Fq2 S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1 + + if (U1 == U2 && S1 == S2) + { + // dbl case; nothing of above can be reused + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl + alt_bn128_Fq2 H = U2-(this->X); // H = U2-X1 + alt_bn128_Fq2 HH = H.squared() ; // HH = H&2 + alt_bn128_Fq2 I = HH+HH; // I = 4*HH + I = I + I; + alt_bn128_Fq2 J = H*I; // J = H*I + alt_bn128_Fq2 r = S2-(this->Y); // r = 2*(S2-Y1) + r = r + r; + alt_bn128_Fq2 V = (this->X) * I ; // V = X1*I + alt_bn128_Fq2 X3 = r.squared()-J-V-V; // X3 = r^2-J-2*V + alt_bn128_Fq2 Y3 = (this->Y)*J; // Y3 = r*(V-X3)-2*Y1*J + Y3 = r*(V-X3) - Y3 - Y3; + alt_bn128_Fq2 Z3 = ((this->Z)+H).squared() - Z1Z1 - HH; // Z3 = (Z1+H)^2-Z1Z1-HH + + return alt_bn128_G2(X3, Y3, Z3); +} + +alt_bn128_G2 alt_bn128_G2::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + // handle point at infinity + if (this->is_zero()) + { + return (*this); + } + + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#doubling-dbl-2007-bl + + alt_bn128_Fq2 A = (this->X).squared(); // A = X1^2 + alt_bn128_Fq2 B = (this->Y).squared(); // B = Y1^2 + alt_bn128_Fq2 C = B.squared(); // C = B^2 + alt_bn128_Fq2 D = (this->X + B).squared() - A - C; + D = D+D; // D = 2 * ((X1 + B)^2 - A - C) + alt_bn128_Fq2 E = A + A + A; // E = 3 * A + alt_bn128_Fq2 F = E.squared(); // F = E^2 + alt_bn128_Fq2 X3 = F - (D+D); // X3 = F - 2 D + alt_bn128_Fq2 eightC = C+C; + eightC = eightC + eightC; + eightC = eightC + eightC; + alt_bn128_Fq2 Y3 = E * (D - X3) - eightC; // Y3 = E * (D - X3) - 8 * C + alt_bn128_Fq2 Y1Z1 = (this->Y)*(this->Z); + alt_bn128_Fq2 Z3 = Y1Z1 + Y1Z1; // Z3 = 2 * Y1 * Z1 + + return alt_bn128_G2(X3, Y3, Z3); +} + +alt_bn128_G2 alt_bn128_G2::mul_by_q() const +{ + return alt_bn128_G2(alt_bn128_twist_mul_by_q_X * (this->X).Frobenius_map(1), + alt_bn128_twist_mul_by_q_Y * (this->Y).Frobenius_map(1), + (this->Z).Frobenius_map(1)); +} + +bool alt_bn128_G2::is_well_formed() const +{ + if (this->is_zero()) + { + return true; + } + else + { + /* + y^2 = x^3 + b + + We are using Jacobian coordinates, so equation we need to check is actually + + (y/z^3)^2 = (x/z^2)^3 + b + y^2 / z^6 = x^3 / z^6 + b + y^2 = x^3 + b z^6 + */ + alt_bn128_Fq2 X2 = this->X.squared(); + alt_bn128_Fq2 Y2 = this->Y.squared(); + alt_bn128_Fq2 Z2 = this->Z.squared(); + + alt_bn128_Fq2 X3 = this->X * X2; + alt_bn128_Fq2 Z3 = this->Z * Z2; + alt_bn128_Fq2 Z6 = Z3.squared(); + + return (Y2 == X3 + alt_bn128_twist_coeff_b * Z6); + } +} + +alt_bn128_G2 alt_bn128_G2::zero() +{ + return G2_zero; +} + +alt_bn128_G2 alt_bn128_G2::one() +{ + return G2_one; +} + +alt_bn128_G2 alt_bn128_G2::random_element() +{ + return (alt_bn128_Fr::random_element().as_bigint()) * G2_one; +} + +std::ostream& operator<<(std::ostream &out, const alt_bn128_G2 &g) +{ + alt_bn128_G2 copy(g); + copy.to_affine_coordinates(); + out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR; +#ifdef NO_PT_COMPRESSION + out << copy.X << OUTPUT_SEPARATOR << copy.Y; +#else + /* storing LSB of Y */ + out << copy.X << OUTPUT_SEPARATOR << (copy.Y.c0.as_bigint().data[0] & 1); +#endif + + return out; +} + +std::istream& operator>>(std::istream &in, alt_bn128_G2 &g) +{ + char is_zero; + alt_bn128_Fq2 tX, tY; + +#ifdef NO_PT_COMPRESSION + in >> is_zero >> tX >> tY; + is_zero -= '0'; +#else + in.read((char*)&is_zero, 1); // this reads is_zero; + is_zero -= '0'; + consume_OUTPUT_SEPARATOR(in); + + unsigned char Y_lsb; + in >> tX; + consume_OUTPUT_SEPARATOR(in); + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + // y = +/- sqrt(x^3 + b) + if (!is_zero) + { + alt_bn128_Fq2 tX2 = tX.squared(); + alt_bn128_Fq2 tY2 = tX2 * tX + alt_bn128_twist_coeff_b; + tY = tY2.sqrt(); + + if ((tY.c0.as_bigint().data[0] & 1) != Y_lsb) + { + tY = -tY; + } + } +#endif + // using projective coordinates + if (!is_zero) + { + g.X = tX; + g.Y = tY; + g.Z = alt_bn128_Fq2::one(); + } + else + { + g = alt_bn128_G2::zero(); + } + + return in; +} + +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.Z); + } + batch_invert(Z_vec); + + const alt_bn128_Fq2 one = alt_bn128_Fq2::one(); + + for (size_t i = 0; i < vec.size(); ++i) + { + alt_bn128_Fq2 Z2 = Z_vec[i].squared(); + alt_bn128_Fq2 Z3 = Z_vec[i] * Z2; + + vec[i].X = vec[i].X * Z2; + vec[i].Y = vec[i].Y * Z3; + vec[i].Z = one; + } +} + +} // libsnark diff --git a/src/algebra/curves/alt_bn128/alt_bn128_g2.hpp b/src/algebra/curves/alt_bn128/alt_bn128_g2.hpp new file mode 100644 index 00000000000..a996a2d1a10 --- /dev/null +++ b/src/algebra/curves/alt_bn128/alt_bn128_g2.hpp @@ -0,0 +1,96 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALT_BN128_G2_HPP_ +#define ALT_BN128_G2_HPP_ +#include +#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" +#include "algebra/curves/curve_utils.hpp" + +namespace libsnark { + +class alt_bn128_G2; +std::ostream& operator<<(std::ostream &, const alt_bn128_G2&); +std::istream& operator>>(std::istream &, alt_bn128_G2&); + +class alt_bn128_G2 { +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + static alt_bn128_G2 G2_zero; + static alt_bn128_G2 G2_one; + + typedef alt_bn128_Fq base_field; + typedef alt_bn128_Fq2 twist_field; + typedef alt_bn128_Fr scalar_field; + + alt_bn128_Fq2 X, Y, Z; + + // using Jacobian coordinates + alt_bn128_G2(); + alt_bn128_G2(const alt_bn128_Fq2& X, const alt_bn128_Fq2& Y, const alt_bn128_Fq2& Z) : X(X), Y(Y), Z(Z) {}; + + static alt_bn128_Fq2 mul_by_b(const alt_bn128_Fq2 &elt); + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const alt_bn128_G2 &other) const; + bool operator!=(const alt_bn128_G2 &other) const; + + alt_bn128_G2 operator+(const alt_bn128_G2 &other) const; + alt_bn128_G2 operator-() const; + alt_bn128_G2 operator-(const alt_bn128_G2 &other) const; + + alt_bn128_G2 add(const alt_bn128_G2 &other) const; + alt_bn128_G2 mixed_add(const alt_bn128_G2 &other) const; + alt_bn128_G2 dbl() const; + alt_bn128_G2 mul_by_q() const; + + bool is_well_formed() const; + + static alt_bn128_G2 zero(); + static alt_bn128_G2 one(); + static alt_bn128_G2 random_element(); + + static size_t size_in_bits() { return twist_field::size_in_bits() + 1; } + static bigint base_field_char() { return base_field::field_char(); } + static bigint order() { return scalar_field::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const alt_bn128_G2 &g); + friend std::istream& operator>>(std::istream &in, alt_bn128_G2 &g); +}; + +template +alt_bn128_G2 operator*(const bigint &lhs, const alt_bn128_G2 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +alt_bn128_G2 operator*(const Fp_model &lhs, const alt_bn128_G2 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark +#endif // ALT_BN128_G2_HPP_ diff --git a/src/algebra/curves/alt_bn128/alt_bn128_init.cpp b/src/algebra/curves/alt_bn128/alt_bn128_init.cpp new file mode 100644 index 00000000000..7c23773d674 --- /dev/null +++ b/src/algebra/curves/alt_bn128/alt_bn128_init.cpp @@ -0,0 +1,273 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp" + +namespace libsnark { + +bigint alt_bn128_modulus_r; +bigint alt_bn128_modulus_q; + +alt_bn128_Fq alt_bn128_coeff_b; +alt_bn128_Fq2 alt_bn128_twist; +alt_bn128_Fq2 alt_bn128_twist_coeff_b; +alt_bn128_Fq alt_bn128_twist_mul_by_b_c0; +alt_bn128_Fq alt_bn128_twist_mul_by_b_c1; +alt_bn128_Fq2 alt_bn128_twist_mul_by_q_X; +alt_bn128_Fq2 alt_bn128_twist_mul_by_q_Y; + +bigint alt_bn128_ate_loop_count; +bool alt_bn128_ate_is_loop_count_neg; +bigint<12*alt_bn128_q_limbs> alt_bn128_final_exponent; +bigint alt_bn128_final_exponent_z; +bool alt_bn128_final_exponent_is_z_neg; + +void init_alt_bn128_params() +{ + typedef bigint bigint_r; + typedef bigint bigint_q; + + assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this + + /* parameters for scalar field Fr */ + + alt_bn128_modulus_r = bigint_r("21888242871839275222246405745257275088548364400416034343698204186575808495617"); + assert(alt_bn128_Fr::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + alt_bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); + alt_bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); + alt_bn128_Fr::inv = 0xc2e1f593efffffff; + } + if (sizeof(mp_limb_t) == 4) + { + alt_bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); + alt_bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); + alt_bn128_Fr::inv = 0xefffffff; + } + alt_bn128_Fr::num_bits = 254; + alt_bn128_Fr::euler = bigint_r("10944121435919637611123202872628637544274182200208017171849102093287904247808"); + alt_bn128_Fr::s = 28; + alt_bn128_Fr::t = bigint_r("81540058820840996586704275553141814055101440848469862132140264610111"); + alt_bn128_Fr::t_minus_1_over_2 = bigint_r("40770029410420498293352137776570907027550720424234931066070132305055"); + alt_bn128_Fr::multiplicative_generator = alt_bn128_Fr("5"); + alt_bn128_Fr::root_of_unity = alt_bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); + alt_bn128_Fr::nqr = alt_bn128_Fr("5"); + alt_bn128_Fr::nqr_to_t = alt_bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); + + /* parameters for base field Fq */ + + alt_bn128_modulus_q = bigint_q("21888242871839275222246405745257275088696311157297823662689037894645226208583"); + assert(alt_bn128_Fq::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + alt_bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); + alt_bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); + alt_bn128_Fq::inv = 0x87d20782e4866389; + } + if (sizeof(mp_limb_t) == 4) + { + alt_bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); + alt_bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); + alt_bn128_Fq::inv = 0xe4866389; + } + alt_bn128_Fq::num_bits = 254; + alt_bn128_Fq::euler = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); + alt_bn128_Fq::s = 1; + alt_bn128_Fq::t = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); + alt_bn128_Fq::t_minus_1_over_2 = bigint_q("5472060717959818805561601436314318772174077789324455915672259473661306552145"); + alt_bn128_Fq::multiplicative_generator = alt_bn128_Fq("3"); + alt_bn128_Fq::root_of_unity = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + alt_bn128_Fq::nqr = alt_bn128_Fq("3"); + alt_bn128_Fq::nqr_to_t = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + + /* parameters for twist field Fq2 */ + alt_bn128_Fq2::euler = bigint<2*alt_bn128_q_limbs>("239547588008311421220994022608339370399626158265550411218223901127035046843189118723920525909718935985594116157406550130918127817069793474323196511433944"); + alt_bn128_Fq2::s = 4; + alt_bn128_Fq2::t = bigint<2*alt_bn128_q_limbs>("29943448501038927652624252826042421299953269783193801402277987640879380855398639840490065738714866998199264519675818766364765977133724184290399563929243"); + alt_bn128_Fq2::t_minus_1_over_2 = bigint<2*alt_bn128_q_limbs>("14971724250519463826312126413021210649976634891596900701138993820439690427699319920245032869357433499099632259837909383182382988566862092145199781964621"); + alt_bn128_Fq2::non_residue = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + alt_bn128_Fq2::nqr = alt_bn128_Fq2(alt_bn128_Fq("2"),alt_bn128_Fq("1")); + alt_bn128_Fq2::nqr_to_t = alt_bn128_Fq2(alt_bn128_Fq("5033503716262624267312492558379982687175200734934877598599011485707452665730"),alt_bn128_Fq("314498342015008975724433667930697407966947188435857772134235984660852259084")); + alt_bn128_Fq2::Frobenius_coeffs_c1[0] = alt_bn128_Fq("1"); + alt_bn128_Fq2::Frobenius_coeffs_c1[1] = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + + /* parameters for Fq6 */ + alt_bn128_Fq6::non_residue = alt_bn128_Fq2(alt_bn128_Fq("9"),alt_bn128_Fq("1")); + alt_bn128_Fq6::Frobenius_coeffs_c1[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c1[1] = alt_bn128_Fq2(alt_bn128_Fq("21575463638280843010398324269430826099269044274347216827212613867836435027261"),alt_bn128_Fq("10307601595873709700152284273816112264069230130616436755625194854815875713954")); + alt_bn128_Fq6::Frobenius_coeffs_c1[2] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c1[3] = alt_bn128_Fq2(alt_bn128_Fq("3772000881919853776433695186713858239009073593817195771773381919316419345261"),alt_bn128_Fq("2236595495967245188281701248203181795121068902605861227855261137820944008926")); + alt_bn128_Fq6::Frobenius_coeffs_c1[4] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c1[5] = alt_bn128_Fq2(alt_bn128_Fq("18429021223477853657660792034369865839114504446431234726392080002137598044644"),alt_bn128_Fq("9344045779998320333812420223237981029506012124075525679208581902008406485703")); + alt_bn128_Fq6::Frobenius_coeffs_c2[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c2[1] = alt_bn128_Fq2(alt_bn128_Fq("2581911344467009335267311115468803099551665605076196740867805258568234346338"),alt_bn128_Fq("19937756971775647987995932169929341994314640652964949448313374472400716661030")); + alt_bn128_Fq6::Frobenius_coeffs_c2[2] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c2[3] = alt_bn128_Fq2(alt_bn128_Fq("5324479202449903542726783395506214481928257762400643279780343368557297135718"),alt_bn128_Fq("16208900380737693084919495127334387981393726419856888799917914180988844123039")); + alt_bn128_Fq6::Frobenius_coeffs_c2[4] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c2[5] = alt_bn128_Fq2(alt_bn128_Fq("13981852324922362344252311234282257507216387789820983642040889267519694726527"),alt_bn128_Fq("7629828391165209371577384193250820201684255241773809077146787135900891633097")); + + /* parameters for Fq12 */ + + alt_bn128_Fq12::non_residue = alt_bn128_Fq2(alt_bn128_Fq("9"),alt_bn128_Fq("1")); + alt_bn128_Fq12::Frobenius_coeffs_c1[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[1] = alt_bn128_Fq2(alt_bn128_Fq("8376118865763821496583973867626364092589906065868298776909617916018768340080"),alt_bn128_Fq("16469823323077808223889137241176536799009286646108169935659301613961712198316")); + alt_bn128_Fq12::Frobenius_coeffs_c1[2] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556617"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[3] = alt_bn128_Fq2(alt_bn128_Fq("11697423496358154304825782922584725312912383441159505038794027105778954184319"),alt_bn128_Fq("303847389135065887422783454877609941456349188919719272345083954437860409601")); + alt_bn128_Fq12::Frobenius_coeffs_c1[4] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[5] = alt_bn128_Fq2(alt_bn128_Fq("3321304630594332808241809054958361220322477375291206261884409189760185844239"),alt_bn128_Fq("5722266937896532885780051958958348231143373700109372999374820235121374419868")); + alt_bn128_Fq12::Frobenius_coeffs_c1[6] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[7] = alt_bn128_Fq2(alt_bn128_Fq("13512124006075453725662431877630910996106405091429524885779419978626457868503"),alt_bn128_Fq("5418419548761466998357268504080738289687024511189653727029736280683514010267")); + alt_bn128_Fq12::Frobenius_coeffs_c1[8] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[9] = alt_bn128_Fq2(alt_bn128_Fq("10190819375481120917420622822672549775783927716138318623895010788866272024264"),alt_bn128_Fq("21584395482704209334823622290379665147239961968378104390343953940207365798982")); + alt_bn128_Fq12::Frobenius_coeffs_c1[10] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651967"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[11] = alt_bn128_Fq2(alt_bn128_Fq("18566938241244942414004596690298913868373833782006617400804628704885040364344"),alt_bn128_Fq("16165975933942742336466353786298926857552937457188450663314217659523851788715")); + + /* choice of short Weierstrass curve and its twist */ + + alt_bn128_coeff_b = alt_bn128_Fq("3"); + alt_bn128_twist = alt_bn128_Fq2(alt_bn128_Fq("9"), alt_bn128_Fq("1")); + alt_bn128_twist_coeff_b = alt_bn128_coeff_b * alt_bn128_twist.inverse(); + alt_bn128_twist_mul_by_b_c0 = alt_bn128_coeff_b * alt_bn128_Fq2::non_residue; + alt_bn128_twist_mul_by_b_c1 = alt_bn128_coeff_b * alt_bn128_Fq2::non_residue; + alt_bn128_twist_mul_by_q_X = alt_bn128_Fq2(alt_bn128_Fq("21575463638280843010398324269430826099269044274347216827212613867836435027261"), + alt_bn128_Fq("10307601595873709700152284273816112264069230130616436755625194854815875713954")); + alt_bn128_twist_mul_by_q_Y = alt_bn128_Fq2(alt_bn128_Fq("2821565182194536844548159561693502659359617185244120367078079554186484126554"), + alt_bn128_Fq("3505843767911556378687030309984248845540243509899259641013678093033130930403")); + + /* choice of group G1 */ + alt_bn128_G1::G1_zero = alt_bn128_G1(alt_bn128_Fq::zero(), + alt_bn128_Fq::one(), + alt_bn128_Fq::zero()); + alt_bn128_G1::G1_one = alt_bn128_G1(alt_bn128_Fq("1"), + alt_bn128_Fq("2"), + alt_bn128_Fq::one()); + alt_bn128_G1::wnaf_window_table.push_back(11); + alt_bn128_G1::wnaf_window_table.push_back(24); + alt_bn128_G1::wnaf_window_table.push_back(60); + alt_bn128_G1::wnaf_window_table.push_back(127); + + alt_bn128_G1::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 4.99] + alt_bn128_G1::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [4.99, 10.99] + alt_bn128_G1::fixed_base_exp_window_table.push_back(5); + // window 3 is unbeaten in [10.99, 32.29] + alt_bn128_G1::fixed_base_exp_window_table.push_back(11); + // window 4 is unbeaten in [32.29, 55.23] + alt_bn128_G1::fixed_base_exp_window_table.push_back(32); + // window 5 is unbeaten in [55.23, 162.03] + alt_bn128_G1::fixed_base_exp_window_table.push_back(55); + // window 6 is unbeaten in [162.03, 360.15] + alt_bn128_G1::fixed_base_exp_window_table.push_back(162); + // window 7 is unbeaten in [360.15, 815.44] + alt_bn128_G1::fixed_base_exp_window_table.push_back(360); + // window 8 is unbeaten in [815.44, 2373.07] + alt_bn128_G1::fixed_base_exp_window_table.push_back(815); + // window 9 is unbeaten in [2373.07, 6977.75] + alt_bn128_G1::fixed_base_exp_window_table.push_back(2373); + // window 10 is unbeaten in [6977.75, 7122.23] + alt_bn128_G1::fixed_base_exp_window_table.push_back(6978); + // window 11 is unbeaten in [7122.23, 57818.46] + alt_bn128_G1::fixed_base_exp_window_table.push_back(7122); + // window 12 is never the best + alt_bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 13 is unbeaten in [57818.46, 169679.14] + alt_bn128_G1::fixed_base_exp_window_table.push_back(57818); + // window 14 is never the best + alt_bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 15 is unbeaten in [169679.14, 439758.91] + alt_bn128_G1::fixed_base_exp_window_table.push_back(169679); + // window 16 is unbeaten in [439758.91, 936073.41] + alt_bn128_G1::fixed_base_exp_window_table.push_back(439759); + // window 17 is unbeaten in [936073.41, 4666554.74] + alt_bn128_G1::fixed_base_exp_window_table.push_back(936073); + // window 18 is never the best + alt_bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 19 is unbeaten in [4666554.74, 7580404.42] + alt_bn128_G1::fixed_base_exp_window_table.push_back(4666555); + // window 20 is unbeaten in [7580404.42, 34552892.20] + alt_bn128_G1::fixed_base_exp_window_table.push_back(7580404); + // window 21 is never the best + alt_bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 22 is unbeaten in [34552892.20, inf] + alt_bn128_G1::fixed_base_exp_window_table.push_back(34552892); + + /* choice of group G2 */ + + alt_bn128_G2::G2_zero = alt_bn128_G2(alt_bn128_Fq2::zero(), + alt_bn128_Fq2::one(), + alt_bn128_Fq2::zero()); + + alt_bn128_G2::G2_one = alt_bn128_G2(alt_bn128_Fq2(alt_bn128_Fq("10857046999023057135944570762232829481370756359578518086990519993285655852781"), + alt_bn128_Fq("11559732032986387107991004021392285783925812861821192530917403151452391805634")), + alt_bn128_Fq2(alt_bn128_Fq("8495653923123431417604973247489272438418190587263600148770280649306958101930"), + alt_bn128_Fq("4082367875863433681332203403145435568316851327593401208105741076214120093531")), + alt_bn128_Fq2::one()); + alt_bn128_G2::wnaf_window_table.push_back(5); + alt_bn128_G2::wnaf_window_table.push_back(15); + alt_bn128_G2::wnaf_window_table.push_back(39); + alt_bn128_G2::wnaf_window_table.push_back(109); + + alt_bn128_G2::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 5.10] + alt_bn128_G2::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [5.10, 10.43] + alt_bn128_G2::fixed_base_exp_window_table.push_back(5); + // window 3 is unbeaten in [10.43, 25.28] + alt_bn128_G2::fixed_base_exp_window_table.push_back(10); + // window 4 is unbeaten in [25.28, 59.00] + alt_bn128_G2::fixed_base_exp_window_table.push_back(25); + // window 5 is unbeaten in [59.00, 154.03] + alt_bn128_G2::fixed_base_exp_window_table.push_back(59); + // window 6 is unbeaten in [154.03, 334.25] + alt_bn128_G2::fixed_base_exp_window_table.push_back(154); + // window 7 is unbeaten in [334.25, 742.58] + alt_bn128_G2::fixed_base_exp_window_table.push_back(334); + // window 8 is unbeaten in [742.58, 2034.40] + alt_bn128_G2::fixed_base_exp_window_table.push_back(743); + // window 9 is unbeaten in [2034.40, 4987.56] + alt_bn128_G2::fixed_base_exp_window_table.push_back(2034); + // window 10 is unbeaten in [4987.56, 8888.27] + alt_bn128_G2::fixed_base_exp_window_table.push_back(4988); + // window 11 is unbeaten in [8888.27, 26271.13] + alt_bn128_G2::fixed_base_exp_window_table.push_back(8888); + // window 12 is unbeaten in [26271.13, 39768.20] + alt_bn128_G2::fixed_base_exp_window_table.push_back(26271); + // window 13 is unbeaten in [39768.20, 106275.75] + alt_bn128_G2::fixed_base_exp_window_table.push_back(39768); + // window 14 is unbeaten in [106275.75, 141703.40] + alt_bn128_G2::fixed_base_exp_window_table.push_back(106276); + // window 15 is unbeaten in [141703.40, 462422.97] + alt_bn128_G2::fixed_base_exp_window_table.push_back(141703); + // window 16 is unbeaten in [462422.97, 926871.84] + alt_bn128_G2::fixed_base_exp_window_table.push_back(462423); + // window 17 is unbeaten in [926871.84, 4873049.17] + alt_bn128_G2::fixed_base_exp_window_table.push_back(926872); + // window 18 is never the best + alt_bn128_G2::fixed_base_exp_window_table.push_back(0); + // window 19 is unbeaten in [4873049.17, 5706707.88] + alt_bn128_G2::fixed_base_exp_window_table.push_back(4873049); + // window 20 is unbeaten in [5706707.88, 31673814.95] + alt_bn128_G2::fixed_base_exp_window_table.push_back(5706708); + // window 21 is never the best + alt_bn128_G2::fixed_base_exp_window_table.push_back(0); + // window 22 is unbeaten in [31673814.95, inf] + alt_bn128_G2::fixed_base_exp_window_table.push_back(31673815); + + /* pairing parameters */ + + alt_bn128_ate_loop_count = bigint_q("29793968203157093288"); + alt_bn128_ate_is_loop_count_neg = false; + alt_bn128_final_exponent = bigint<12*alt_bn128_q_limbs>("552484233613224096312617126783173147097382103762957654188882734314196910839907541213974502761540629817009608548654680343627701153829446747810907373256841551006201639677726139946029199968412598804882391702273019083653272047566316584365559776493027495458238373902875937659943504873220554161550525926302303331747463515644711876653177129578303191095900909191624817826566688241804408081892785725967931714097716709526092261278071952560171111444072049229123565057483750161460024353346284167282452756217662335528813519139808291170539072125381230815729071544861602750936964829313608137325426383735122175229541155376346436093930287402089517426973178917569713384748081827255472576937471496195752727188261435633271238710131736096299798168852925540549342330775279877006784354801422249722573783561685179618816480037695005515426162362431072245638324744480"); + alt_bn128_final_exponent_z = bigint_q("4965661367192848881"); + alt_bn128_final_exponent_is_z_neg = false; + +} +} // libsnark diff --git a/src/algebra/curves/alt_bn128/alt_bn128_init.hpp b/src/algebra/curves/alt_bn128/alt_bn128_init.hpp new file mode 100644 index 00000000000..c3bea76738c --- /dev/null +++ b/src/algebra/curves/alt_bn128/alt_bn128_init.hpp @@ -0,0 +1,57 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALT_BN128_INIT_HPP_ +#define ALT_BN128_INIT_HPP_ +#include "algebra/curves/public_params.hpp" +#include "algebra/fields/fp.hpp" +#include "algebra/fields/fp2.hpp" +#include "algebra/fields/fp6_3over2.hpp" +#include "algebra/fields/fp12_2over3over2.hpp" + +namespace libsnark { + +const mp_size_t alt_bn128_r_bitcount = 254; +const mp_size_t alt_bn128_q_bitcount = 254; + +const mp_size_t alt_bn128_r_limbs = (alt_bn128_r_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; +const mp_size_t alt_bn128_q_limbs = (alt_bn128_q_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; + +extern bigint alt_bn128_modulus_r; +extern bigint alt_bn128_modulus_q; + +typedef Fp_model alt_bn128_Fr; +typedef Fp_model alt_bn128_Fq; +typedef Fp2_model alt_bn128_Fq2; +typedef Fp6_3over2_model alt_bn128_Fq6; +typedef Fp12_2over3over2_model alt_bn128_Fq12; +typedef alt_bn128_Fq12 alt_bn128_GT; + +// parameters for Barreto--Naehrig curve E/Fq : y^2 = x^3 + b +extern alt_bn128_Fq alt_bn128_coeff_b; +// parameters for twisted Barreto--Naehrig curve E'/Fq2 : y^2 = x^3 + b/xi +extern alt_bn128_Fq2 alt_bn128_twist; +extern alt_bn128_Fq2 alt_bn128_twist_coeff_b; +extern alt_bn128_Fq alt_bn128_twist_mul_by_b_c0; +extern alt_bn128_Fq alt_bn128_twist_mul_by_b_c1; +extern alt_bn128_Fq2 alt_bn128_twist_mul_by_q_X; +extern alt_bn128_Fq2 alt_bn128_twist_mul_by_q_Y; + +// parameters for pairing +extern bigint alt_bn128_ate_loop_count; +extern bool alt_bn128_ate_is_loop_count_neg; +extern bigint<12*alt_bn128_q_limbs> alt_bn128_final_exponent; +extern bigint alt_bn128_final_exponent_z; +extern bool alt_bn128_final_exponent_is_z_neg; + +void init_alt_bn128_params(); + +class alt_bn128_G1; +class alt_bn128_G2; + +} // libsnark +#endif // ALT_BN128_INIT_HPP_ diff --git a/src/algebra/curves/alt_bn128/alt_bn128_pairing.cpp b/src/algebra/curves/alt_bn128/alt_bn128_pairing.cpp new file mode 100644 index 00000000000..db556c5b287 --- /dev/null +++ b/src/algebra/curves/alt_bn128/alt_bn128_pairing.cpp @@ -0,0 +1,547 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/alt_bn128/alt_bn128_pairing.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp" +#include +#include "common/profiling.hpp" +#include "common/assert_except.hpp" + +namespace libsnark { + +bool alt_bn128_ate_G1_precomp::operator==(const alt_bn128_ate_G1_precomp &other) const +{ + return (this->PX == other.PX && + this->PY == other.PY); +} + +std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_G1_precomp &prec_P) +{ + out << prec_P.PX << OUTPUT_SEPARATOR << prec_P.PY; + + return out; +} + +std::istream& operator>>(std::istream &in, alt_bn128_ate_G1_precomp &prec_P) +{ + in >> prec_P.PX; + consume_OUTPUT_SEPARATOR(in); + in >> prec_P.PY; + + return in; +} + +bool alt_bn128_ate_ell_coeffs::operator==(const alt_bn128_ate_ell_coeffs &other) const +{ + return (this->ell_0 == other.ell_0 && + this->ell_VW == other.ell_VW && + this->ell_VV == other.ell_VV); +} + +std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_ell_coeffs &c) +{ + out << c.ell_0 << OUTPUT_SEPARATOR << c.ell_VW << OUTPUT_SEPARATOR << c.ell_VV; + return out; +} + +std::istream& operator>>(std::istream &in, alt_bn128_ate_ell_coeffs &c) +{ + in >> c.ell_0; + consume_OUTPUT_SEPARATOR(in); + in >> c.ell_VW; + consume_OUTPUT_SEPARATOR(in); + in >> c.ell_VV; + + return in; +} + +bool alt_bn128_ate_G2_precomp::operator==(const alt_bn128_ate_G2_precomp &other) const +{ + return (this->QX == other.QX && + this->QY == other.QY && + this->coeffs == other.coeffs); +} + +std::ostream& operator<<(std::ostream& out, const alt_bn128_ate_G2_precomp &prec_Q) +{ + out << prec_Q.QX << OUTPUT_SEPARATOR << prec_Q.QY << "\n"; + out << prec_Q.coeffs.size() << "\n"; + for (const alt_bn128_ate_ell_coeffs &c : prec_Q.coeffs) + { + out << c << OUTPUT_NEWLINE; + } + return out; +} + +std::istream& operator>>(std::istream& in, alt_bn128_ate_G2_precomp &prec_Q) +{ + in >> prec_Q.QX; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.QY; + consume_newline(in); + + prec_Q.coeffs.clear(); + size_t s; + in >> s; + + consume_newline(in); + + prec_Q.coeffs.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + alt_bn128_ate_ell_coeffs c; + in >> c; + consume_OUTPUT_NEWLINE(in); + prec_Q.coeffs.emplace_back(c); + } + + return in; +} + +/* final exponentiations */ + +alt_bn128_Fq12 alt_bn128_final_exponentiation_first_chunk(const alt_bn128_Fq12 &elt) +{ + enter_block("Call to alt_bn128_final_exponentiation_first_chunk"); + + /* + Computes result = elt^((q^6-1)*(q^2+1)). + Follows, e.g., Beuchat et al page 9, by computing result as follows: + elt^((q^6-1)*(q^2+1)) = (conj(elt) * elt^(-1))^(q^2+1) + More precisely: + A = conj(elt) + B = elt.inverse() + C = A * B + D = C.Frobenius_map(2) + result = D * C + */ + + const alt_bn128_Fq12 A = alt_bn128_Fq12(elt.c0,-elt.c1); + const alt_bn128_Fq12 B = elt.inverse(); + const alt_bn128_Fq12 C = A * B; + const alt_bn128_Fq12 D = C.Frobenius_map(2); + const alt_bn128_Fq12 result = D * C; + + leave_block("Call to alt_bn128_final_exponentiation_first_chunk"); + + return result; +} + +alt_bn128_Fq12 alt_bn128_exp_by_neg_z(const alt_bn128_Fq12 &elt) +{ + enter_block("Call to alt_bn128_exp_by_neg_z"); + + alt_bn128_Fq12 result = elt.cyclotomic_exp(alt_bn128_final_exponent_z); + if (!alt_bn128_final_exponent_is_z_neg) + { + result = result.unitary_inverse(); + } + + leave_block("Call to alt_bn128_exp_by_neg_z"); + + return result; +} + +alt_bn128_Fq12 alt_bn128_final_exponentiation_last_chunk(const alt_bn128_Fq12 &elt) +{ + enter_block("Call to alt_bn128_final_exponentiation_last_chunk"); + + /* + Follows Laura Fuentes-Castaneda et al. "Faster hashing to G2" + by computing: + + result = elt^(q^3 * (12*z^3 + 6z^2 + 4z - 1) + + q^2 * (12*z^3 + 6z^2 + 6z) + + q * (12*z^3 + 6z^2 + 4z) + + 1 * (12*z^3 + 12z^2 + 6z + 1)) + which equals + + result = elt^( 2z * ( 6z^2 + 3z + 1 ) * (q^4 - q^2 + 1)/r ). + + Using the following addition chain: + + A = exp_by_neg_z(elt) // = elt^(-z) + B = A^2 // = elt^(-2*z) + C = B^2 // = elt^(-4*z) + D = C * B // = elt^(-6*z) + E = exp_by_neg_z(D) // = elt^(6*z^2) + F = E^2 // = elt^(12*z^2) + G = epx_by_neg_z(F) // = elt^(-12*z^3) + H = conj(D) // = elt^(6*z) + I = conj(G) // = elt^(12*z^3) + J = I * E // = elt^(12*z^3 + 6*z^2) + K = J * H // = elt^(12*z^3 + 6*z^2 + 6*z) + L = K * B // = elt^(12*z^3 + 6*z^2 + 4*z) + M = K * E // = elt^(12*z^3 + 12*z^2 + 6*z) + N = M * elt // = elt^(12*z^3 + 12*z^2 + 6*z + 1) + O = L.Frobenius_map(1) // = elt^(q*(12*z^3 + 6*z^2 + 4*z)) + P = O * N // = elt^(q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1)) + Q = K.Frobenius_map(2) // = elt^(q^2 * (12*z^3 + 6*z^2 + 6*z)) + R = Q * P // = elt^(q^2 * (12*z^3 + 6*z^2 + 6*z) + q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1)) + S = conj(elt) // = elt^(-1) + T = S * L // = elt^(12*z^3 + 6*z^2 + 4*z - 1) + U = T.Frobenius_map(3) // = elt^(q^3(12*z^3 + 6*z^2 + 4*z - 1)) + V = U * R // = elt^(q^3(12*z^3 + 6*z^2 + 4*z - 1) + q^2 * (12*z^3 + 6*z^2 + 6*z) + q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1)) + result = V + + */ + + const alt_bn128_Fq12 A = alt_bn128_exp_by_neg_z(elt); + const alt_bn128_Fq12 B = A.cyclotomic_squared(); + const alt_bn128_Fq12 C = B.cyclotomic_squared(); + const alt_bn128_Fq12 D = C * B; + const alt_bn128_Fq12 E = alt_bn128_exp_by_neg_z(D); + const alt_bn128_Fq12 F = E.cyclotomic_squared(); + const alt_bn128_Fq12 G = alt_bn128_exp_by_neg_z(F); + const alt_bn128_Fq12 H = D.unitary_inverse(); + const alt_bn128_Fq12 I = G.unitary_inverse(); + const alt_bn128_Fq12 J = I * E; + const alt_bn128_Fq12 K = J * H; + const alt_bn128_Fq12 L = K * B; + const alt_bn128_Fq12 M = K * E; + const alt_bn128_Fq12 N = M * elt; + const alt_bn128_Fq12 O = L.Frobenius_map(1); + const alt_bn128_Fq12 P = O * N; + const alt_bn128_Fq12 Q = K.Frobenius_map(2); + const alt_bn128_Fq12 R = Q * P; + const alt_bn128_Fq12 S = elt.unitary_inverse(); + const alt_bn128_Fq12 T = S * L; + const alt_bn128_Fq12 U = T.Frobenius_map(3); + const alt_bn128_Fq12 V = U * R; + + const alt_bn128_Fq12 result = V; + + leave_block("Call to alt_bn128_final_exponentiation_last_chunk"); + + return result; +} + +alt_bn128_GT alt_bn128_final_exponentiation(const alt_bn128_Fq12 &elt) +{ + enter_block("Call to alt_bn128_final_exponentiation"); + /* OLD naive version: + alt_bn128_GT result = elt^alt_bn128_final_exponent; + */ + alt_bn128_Fq12 A = alt_bn128_final_exponentiation_first_chunk(elt); + alt_bn128_GT result = alt_bn128_final_exponentiation_last_chunk(A); + + leave_block("Call to alt_bn128_final_exponentiation"); + return result; +} + +/* ate pairing */ + +void doubling_step_for_flipped_miller_loop(const alt_bn128_Fq two_inv, + alt_bn128_G2 ¤t, + alt_bn128_ate_ell_coeffs &c) +{ + const alt_bn128_Fq2 X = current.X, Y = current.Y, Z = current.Z; + + const alt_bn128_Fq2 A = two_inv * (X * Y); // A = X1 * Y1 / 2 + const alt_bn128_Fq2 B = Y.squared(); // B = Y1^2 + const alt_bn128_Fq2 C = Z.squared(); // C = Z1^2 + const alt_bn128_Fq2 D = C+C+C; // D = 3 * C + const alt_bn128_Fq2 E = alt_bn128_twist_coeff_b * D; // E = twist_b * D + const alt_bn128_Fq2 F = E+E+E; // F = 3 * E + const alt_bn128_Fq2 G = two_inv * (B+F); // G = (B+F)/2 + const alt_bn128_Fq2 H = (Y+Z).squared() - (B+C); // H = (Y1+Z1)^2-(B+C) + const alt_bn128_Fq2 I = E-B; // I = E-B + const alt_bn128_Fq2 J = X.squared(); // J = X1^2 + const alt_bn128_Fq2 E_squared = E.squared(); // E_squared = E^2 + + current.X = A * (B-F); // X3 = A * (B-F) + current.Y = G.squared() - (E_squared+E_squared+E_squared); // Y3 = G^2 - 3*E^2 + current.Z = B * H; // Z3 = B * H + c.ell_0 = alt_bn128_twist * I; // ell_0 = xi * I + c.ell_VW = -H; // ell_VW = - H (later: * yP) + c.ell_VV = J+J+J; // ell_VV = 3*J (later: * xP) +} + +void mixed_addition_step_for_flipped_miller_loop(const alt_bn128_G2 base, + alt_bn128_G2 ¤t, + alt_bn128_ate_ell_coeffs &c) +{ + const alt_bn128_Fq2 X1 = current.X, Y1 = current.Y, Z1 = current.Z; + const alt_bn128_Fq2 &x2 = base.X, &y2 = base.Y; + + const alt_bn128_Fq2 D = X1 - x2 * Z1; // D = X1 - X2*Z1 + const alt_bn128_Fq2 E = Y1 - y2 * Z1; // E = Y1 - Y2*Z1 + const alt_bn128_Fq2 F = D.squared(); // F = D^2 + const alt_bn128_Fq2 G = E.squared(); // G = E^2 + const alt_bn128_Fq2 H = D*F; // H = D*F + const alt_bn128_Fq2 I = X1 * F; // I = X1 * F + const alt_bn128_Fq2 J = H + Z1*G - (I+I); // J = H + Z1*G - (I+I) + + current.X = D * J; // X3 = D*J + current.Y = E * (I-J)-(H * Y1); // Y3 = E*(I-J)-(H*Y1) + current.Z = Z1 * H; // Z3 = Z1*H + c.ell_0 = alt_bn128_twist * (E * x2 - D * y2); // ell_0 = xi * (E * X2 - D * Y2) + c.ell_VV = - E; // ell_VV = - E (later: * xP) + c.ell_VW = D; // ell_VW = D (later: * yP ) +} + +alt_bn128_ate_G1_precomp alt_bn128_ate_precompute_G1(const alt_bn128_G1& P) +{ + enter_block("Call to alt_bn128_ate_precompute_G1"); + + alt_bn128_G1 Pcopy = P; + Pcopy.to_affine_coordinates(); + + alt_bn128_ate_G1_precomp result; + result.PX = Pcopy.X; + result.PY = Pcopy.Y; + + leave_block("Call to alt_bn128_ate_precompute_G1"); + return result; +} + +alt_bn128_ate_G2_precomp alt_bn128_ate_precompute_G2(const alt_bn128_G2& Q) +{ + enter_block("Call to alt_bn128_ate_precompute_G2"); + + alt_bn128_G2 Qcopy(Q); + Qcopy.to_affine_coordinates(); + + alt_bn128_Fq two_inv = (alt_bn128_Fq("2").inverse()); // could add to global params if needed + + alt_bn128_ate_G2_precomp result; + result.QX = Qcopy.X; + result.QY = Qcopy.Y; + + alt_bn128_G2 R; + R.X = Qcopy.X; + R.Y = Qcopy.Y; + R.Z = alt_bn128_Fq2::one(); + + const bigint &loop_count = alt_bn128_ate_loop_count; + bool found_one = false; + alt_bn128_ate_ell_coeffs c; + + for (long i = loop_count.max_bits(); i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + doubling_step_for_flipped_miller_loop(two_inv, R, c); + result.coeffs.push_back(c); + + if (bit) + { + mixed_addition_step_for_flipped_miller_loop(Qcopy, R, c); + result.coeffs.push_back(c); + } + } + + alt_bn128_G2 Q1 = Qcopy.mul_by_q(); + assert_except(Q1.Z == alt_bn128_Fq2::one()); + alt_bn128_G2 Q2 = Q1.mul_by_q(); + assert_except(Q2.Z == alt_bn128_Fq2::one()); + + if (alt_bn128_ate_is_loop_count_neg) + { + R.Y = - R.Y; + } + Q2.Y = - Q2.Y; + + mixed_addition_step_for_flipped_miller_loop(Q1, R, c); + result.coeffs.push_back(c); + + mixed_addition_step_for_flipped_miller_loop(Q2, R, c); + result.coeffs.push_back(c); + + leave_block("Call to alt_bn128_ate_precompute_G2"); + return result; +} + +alt_bn128_Fq12 alt_bn128_ate_miller_loop(const alt_bn128_ate_G1_precomp &prec_P, + const alt_bn128_ate_G2_precomp &prec_Q) +{ + enter_block("Call to alt_bn128_ate_miller_loop"); + + alt_bn128_Fq12 f = alt_bn128_Fq12::one(); + + bool found_one = false; + size_t idx = 0; + + const bigint &loop_count = alt_bn128_ate_loop_count; + alt_bn128_ate_ell_coeffs c; + + for (long i = loop_count.max_bits(); i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + alt_bn128_param_p (skipping leading zeros) in MSB to LSB + order */ + + c = prec_Q.coeffs[idx++]; + f = f.squared(); + f = f.mul_by_024(c.ell_0, prec_P.PY * c.ell_VW, prec_P.PX * c.ell_VV); + + if (bit) + { + c = prec_Q.coeffs[idx++]; + f = f.mul_by_024(c.ell_0, prec_P.PY * c.ell_VW, prec_P.PX * c.ell_VV); + } + + } + + if (alt_bn128_ate_is_loop_count_neg) + { + f = f.inverse(); + } + + c = prec_Q.coeffs[idx++]; + f = f.mul_by_024(c.ell_0,prec_P.PY * c.ell_VW,prec_P.PX * c.ell_VV); + + c = prec_Q.coeffs[idx++]; + f = f.mul_by_024(c.ell_0,prec_P.PY * c.ell_VW,prec_P.PX * c.ell_VV); + + leave_block("Call to alt_bn128_ate_miller_loop"); + return f; +} + +alt_bn128_Fq12 alt_bn128_ate_double_miller_loop(const alt_bn128_ate_G1_precomp &prec_P1, + const alt_bn128_ate_G2_precomp &prec_Q1, + const alt_bn128_ate_G1_precomp &prec_P2, + const alt_bn128_ate_G2_precomp &prec_Q2) +{ + enter_block("Call to alt_bn128_ate_double_miller_loop"); + + alt_bn128_Fq12 f = alt_bn128_Fq12::one(); + + bool found_one = false; + size_t idx = 0; + + const bigint &loop_count = alt_bn128_ate_loop_count; + for (long i = loop_count.max_bits(); i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + alt_bn128_param_p (skipping leading zeros) in MSB to LSB + order */ + + alt_bn128_ate_ell_coeffs c1 = prec_Q1.coeffs[idx]; + alt_bn128_ate_ell_coeffs c2 = prec_Q2.coeffs[idx]; + ++idx; + + f = f.squared(); + + f = f.mul_by_024(c1.ell_0, prec_P1.PY * c1.ell_VW, prec_P1.PX * c1.ell_VV); + f = f.mul_by_024(c2.ell_0, prec_P2.PY * c2.ell_VW, prec_P2.PX * c2.ell_VV); + + if (bit) + { + alt_bn128_ate_ell_coeffs c1 = prec_Q1.coeffs[idx]; + alt_bn128_ate_ell_coeffs c2 = prec_Q2.coeffs[idx]; + ++idx; + + f = f.mul_by_024(c1.ell_0, prec_P1.PY * c1.ell_VW, prec_P1.PX * c1.ell_VV); + f = f.mul_by_024(c2.ell_0, prec_P2.PY * c2.ell_VW, prec_P2.PX * c2.ell_VV); + } + } + + if (alt_bn128_ate_is_loop_count_neg) + { + f = f.inverse(); + } + + alt_bn128_ate_ell_coeffs c1 = prec_Q1.coeffs[idx]; + alt_bn128_ate_ell_coeffs c2 = prec_Q2.coeffs[idx]; + ++idx; + f = f.mul_by_024(c1.ell_0, prec_P1.PY * c1.ell_VW, prec_P1.PX * c1.ell_VV); + f = f.mul_by_024(c2.ell_0, prec_P2.PY * c2.ell_VW, prec_P2.PX * c2.ell_VV); + + c1 = prec_Q1.coeffs[idx]; + c2 = prec_Q2.coeffs[idx]; + ++idx; + f = f.mul_by_024(c1.ell_0, prec_P1.PY * c1.ell_VW, prec_P1.PX * c1.ell_VV); + f = f.mul_by_024(c2.ell_0, prec_P2.PY * c2.ell_VW, prec_P2.PX * c2.ell_VV); + + leave_block("Call to alt_bn128_ate_double_miller_loop"); + + return f; +} + +alt_bn128_Fq12 alt_bn128_ate_pairing(const alt_bn128_G1& P, const alt_bn128_G2 &Q) +{ + enter_block("Call to alt_bn128_ate_pairing"); + alt_bn128_ate_G1_precomp prec_P = alt_bn128_ate_precompute_G1(P); + alt_bn128_ate_G2_precomp prec_Q = alt_bn128_ate_precompute_G2(Q); + alt_bn128_Fq12 result = alt_bn128_ate_miller_loop(prec_P, prec_Q); + leave_block("Call to alt_bn128_ate_pairing"); + return result; +} + +alt_bn128_GT alt_bn128_ate_reduced_pairing(const alt_bn128_G1 &P, const alt_bn128_G2 &Q) +{ + enter_block("Call to alt_bn128_ate_reduced_pairing"); + const alt_bn128_Fq12 f = alt_bn128_ate_pairing(P, Q); + const alt_bn128_GT result = alt_bn128_final_exponentiation(f); + leave_block("Call to alt_bn128_ate_reduced_pairing"); + return result; +} + +/* choice of pairing */ + +alt_bn128_G1_precomp alt_bn128_precompute_G1(const alt_bn128_G1& P) +{ + return alt_bn128_ate_precompute_G1(P); +} + +alt_bn128_G2_precomp alt_bn128_precompute_G2(const alt_bn128_G2& Q) +{ + return alt_bn128_ate_precompute_G2(Q); +} + +alt_bn128_Fq12 alt_bn128_miller_loop(const alt_bn128_G1_precomp &prec_P, + const alt_bn128_G2_precomp &prec_Q) +{ + return alt_bn128_ate_miller_loop(prec_P, prec_Q); +} + +alt_bn128_Fq12 alt_bn128_double_miller_loop(const alt_bn128_G1_precomp &prec_P1, + const alt_bn128_G2_precomp &prec_Q1, + const alt_bn128_G1_precomp &prec_P2, + const alt_bn128_G2_precomp &prec_Q2) +{ + return alt_bn128_ate_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); +} + +alt_bn128_Fq12 alt_bn128_pairing(const alt_bn128_G1& P, + const alt_bn128_G2 &Q) +{ + return alt_bn128_ate_pairing(P, Q); +} + +alt_bn128_GT alt_bn128_reduced_pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q) +{ + return alt_bn128_ate_reduced_pairing(P, Q); +} +} // libsnark diff --git a/src/algebra/curves/alt_bn128/alt_bn128_pairing.hpp b/src/algebra/curves/alt_bn128/alt_bn128_pairing.hpp new file mode 100644 index 00000000000..15d325485f5 --- /dev/null +++ b/src/algebra/curves/alt_bn128/alt_bn128_pairing.hpp @@ -0,0 +1,92 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALT_BN128_PAIRING_HPP_ +#define ALT_BN128_PAIRING_HPP_ +#include +#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" + +namespace libsnark { + +/* final exponentiation */ + +alt_bn128_GT alt_bn128_final_exponentiation(const alt_bn128_Fq12 &elt); + +/* ate pairing */ + +struct alt_bn128_ate_G1_precomp { + alt_bn128_Fq PX; + alt_bn128_Fq PY; + + bool operator==(const alt_bn128_ate_G1_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_G1_precomp &prec_P); + friend std::istream& operator>>(std::istream &in, alt_bn128_ate_G1_precomp &prec_P); +}; + +struct alt_bn128_ate_ell_coeffs { + alt_bn128_Fq2 ell_0; + alt_bn128_Fq2 ell_VW; + alt_bn128_Fq2 ell_VV; + + bool operator==(const alt_bn128_ate_ell_coeffs &other) const; + friend std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_ell_coeffs &dc); + friend std::istream& operator>>(std::istream &in, alt_bn128_ate_ell_coeffs &dc); +}; + +struct alt_bn128_ate_G2_precomp { + alt_bn128_Fq2 QX; + alt_bn128_Fq2 QY; + std::vector coeffs; + + bool operator==(const alt_bn128_ate_G2_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_G2_precomp &prec_Q); + friend std::istream& operator>>(std::istream &in, alt_bn128_ate_G2_precomp &prec_Q); +}; + +alt_bn128_ate_G1_precomp alt_bn128_ate_precompute_G1(const alt_bn128_G1& P); +alt_bn128_ate_G2_precomp alt_bn128_ate_precompute_G2(const alt_bn128_G2& Q); + +alt_bn128_Fq12 alt_bn128_ate_miller_loop(const alt_bn128_ate_G1_precomp &prec_P, + const alt_bn128_ate_G2_precomp &prec_Q); +alt_bn128_Fq12 alt_bn128_ate_double_miller_loop(const alt_bn128_ate_G1_precomp &prec_P1, + const alt_bn128_ate_G2_precomp &prec_Q1, + const alt_bn128_ate_G1_precomp &prec_P2, + const alt_bn128_ate_G2_precomp &prec_Q2); + +alt_bn128_Fq12 alt_bn128_ate_pairing(const alt_bn128_G1& P, + const alt_bn128_G2 &Q); +alt_bn128_GT alt_bn128_ate_reduced_pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q); + +/* choice of pairing */ + +typedef alt_bn128_ate_G1_precomp alt_bn128_G1_precomp; +typedef alt_bn128_ate_G2_precomp alt_bn128_G2_precomp; + +alt_bn128_G1_precomp alt_bn128_precompute_G1(const alt_bn128_G1& P); + +alt_bn128_G2_precomp alt_bn128_precompute_G2(const alt_bn128_G2& Q); + +alt_bn128_Fq12 alt_bn128_miller_loop(const alt_bn128_G1_precomp &prec_P, + const alt_bn128_G2_precomp &prec_Q); + +alt_bn128_Fq12 alt_bn128_double_miller_loop(const alt_bn128_G1_precomp &prec_P1, + const alt_bn128_G2_precomp &prec_Q1, + const alt_bn128_G1_precomp &prec_P2, + const alt_bn128_G2_precomp &prec_Q2); + +alt_bn128_Fq12 alt_bn128_pairing(const alt_bn128_G1& P, + const alt_bn128_G2 &Q); + +alt_bn128_GT alt_bn128_reduced_pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q); + +alt_bn128_GT alt_bn128_affine_reduced_pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q); + +} // libsnark +#endif // ALT_BN128_PAIRING_HPP_ diff --git a/src/algebra/curves/alt_bn128/alt_bn128_pp.cpp b/src/algebra/curves/alt_bn128/alt_bn128_pp.cpp new file mode 100644 index 00000000000..25ea924d8e1 --- /dev/null +++ b/src/algebra/curves/alt_bn128/alt_bn128_pp.cpp @@ -0,0 +1,58 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" + +namespace libsnark { + +void alt_bn128_pp::init_public_params() +{ + init_alt_bn128_params(); +} + +alt_bn128_GT alt_bn128_pp::final_exponentiation(const alt_bn128_Fq12 &elt) +{ + return alt_bn128_final_exponentiation(elt); +} + +alt_bn128_G1_precomp alt_bn128_pp::precompute_G1(const alt_bn128_G1 &P) +{ + return alt_bn128_precompute_G1(P); +} + +alt_bn128_G2_precomp alt_bn128_pp::precompute_G2(const alt_bn128_G2 &Q) +{ + return alt_bn128_precompute_G2(Q); +} + +alt_bn128_Fq12 alt_bn128_pp::miller_loop(const alt_bn128_G1_precomp &prec_P, + const alt_bn128_G2_precomp &prec_Q) +{ + return alt_bn128_miller_loop(prec_P, prec_Q); +} + +alt_bn128_Fq12 alt_bn128_pp::double_miller_loop(const alt_bn128_G1_precomp &prec_P1, + const alt_bn128_G2_precomp &prec_Q1, + const alt_bn128_G1_precomp &prec_P2, + const alt_bn128_G2_precomp &prec_Q2) +{ + return alt_bn128_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); +} + +alt_bn128_Fq12 alt_bn128_pp::pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q) +{ + return alt_bn128_pairing(P, Q); +} + +alt_bn128_Fq12 alt_bn128_pp::reduced_pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q) +{ + return alt_bn128_reduced_pairing(P, Q); +} + +} // libsnark diff --git a/src/algebra/curves/alt_bn128/alt_bn128_pp.hpp b/src/algebra/curves/alt_bn128/alt_bn128_pp.hpp new file mode 100644 index 00000000000..ec8059dcb1b --- /dev/null +++ b/src/algebra/curves/alt_bn128/alt_bn128_pp.hpp @@ -0,0 +1,50 @@ +/** @file +***************************************************************************** +* @author This file is part of libsnark, developed by SCIPR Lab +* and contributors (see AUTHORS). +* @copyright MIT license (see LICENSE file) +*****************************************************************************/ + +#ifndef ALT_BN128_PP_HPP_ +#define ALT_BN128_PP_HPP_ +#include "algebra/curves/public_params.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_pairing.hpp" + +namespace libsnark { + +class alt_bn128_pp { +public: + typedef alt_bn128_Fr Fp_type; + typedef alt_bn128_G1 G1_type; + typedef alt_bn128_G2 G2_type; + typedef alt_bn128_G1_precomp G1_precomp_type; + typedef alt_bn128_G2_precomp G2_precomp_type; + typedef alt_bn128_Fq Fq_type; + typedef alt_bn128_Fq2 Fqe_type; + typedef alt_bn128_Fq12 Fqk_type; + typedef alt_bn128_GT GT_type; + + static const bool has_affine_pairing = false; + + static void init_public_params(); + static alt_bn128_GT final_exponentiation(const alt_bn128_Fq12 &elt); + static alt_bn128_G1_precomp precompute_G1(const alt_bn128_G1 &P); + static alt_bn128_G2_precomp precompute_G2(const alt_bn128_G2 &Q); + static alt_bn128_Fq12 miller_loop(const alt_bn128_G1_precomp &prec_P, + const alt_bn128_G2_precomp &prec_Q); + static alt_bn128_Fq12 double_miller_loop(const alt_bn128_G1_precomp &prec_P1, + const alt_bn128_G2_precomp &prec_Q1, + const alt_bn128_G1_precomp &prec_P2, + const alt_bn128_G2_precomp &prec_Q2); + static alt_bn128_Fq12 pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q); + static alt_bn128_Fq12 reduced_pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q); +}; + +} // libsnark + +#endif // ALT_BN128_PP_HPP_ diff --git a/src/algebra/curves/curve_utils.hpp b/src/algebra/curves/curve_utils.hpp new file mode 100644 index 00000000000..33a8e1e1784 --- /dev/null +++ b/src/algebra/curves/curve_utils.hpp @@ -0,0 +1,22 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef CURVE_UTILS_HPP_ +#define CURVE_UTILS_HPP_ +#include + +#include "algebra/fields/bigint.hpp" + +namespace libsnark { + +template +GroupT scalar_mul(const GroupT &base, const bigint &scalar); + +} // libsnark +#include "algebra/curves/curve_utils.tcc" + +#endif // CURVE_UTILS_HPP_ diff --git a/src/algebra/curves/curve_utils.tcc b/src/algebra/curves/curve_utils.tcc new file mode 100644 index 00000000000..251d75d8ba1 --- /dev/null +++ b/src/algebra/curves/curve_utils.tcc @@ -0,0 +1,37 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef CURVE_UTILS_TCC_ +#define CURVE_UTILS_TCC_ + +namespace libsnark { + +template +GroupT scalar_mul(const GroupT &base, const bigint &scalar) +{ + GroupT result = GroupT::zero(); + + bool found_one = false; + for (long i = scalar.max_bits() - 1; i >= 0; --i) + { + if (found_one) + { + result = result.dbl(); + } + + if (scalar.test_bit(i)) + { + found_one = true; + result = result + base; + } + } + + return result; +} + +} // libsnark +#endif // CURVE_UTILS_TCC_ diff --git a/src/algebra/curves/public_params.hpp b/src/algebra/curves/public_params.hpp new file mode 100644 index 00000000000..07e047560df --- /dev/null +++ b/src/algebra/curves/public_params.hpp @@ -0,0 +1,103 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PUBLIC_PARAMS_HPP_ +#define PUBLIC_PARAMS_HPP_ +#include + +namespace libsnark { + +/* + for every curve the user should define corresponding + public_params with the following typedefs: + + Fp_type + G1_type + G2_type + G1_precomp_type + G2_precomp_type + affine_ate_G1_precomp_type + affine_ate_G2_precomp_type + Fq_type + Fqe_type + Fqk_type + GT_type + + one should also define the following static methods: + + void init_public_params(); + + GT final_exponentiation(const Fqk &elt); + + G1_precomp precompute_G1(const G1 &P); + G2_precomp precompute_G2(const G2 &Q); + + Fqk miller_loop(const G1_precomp &prec_P, + const G2_precomp &prec_Q); + + affine_ate_G1_precomp affine_ate_precompute_G1(const G1 &P); + affine_ate_G2_precomp affine_ate_precompute_G2(const G2 &Q); + + + Fqk affine_ate_miller_loop(const affine_ate_G1_precomp &prec_P, + const affine_ate_G2_precomp &prec_Q); + Fqk affine_ate_e_over_e_miller_loop(const affine_ate_G1_precomp &prec_P1, + const affine_ate_G2_precomp &prec_Q1, + const affine_ate_G1_precomp &prec_P2, + const affine_ate_G2_precomp &prec_Q2); + Fqk affine_ate_e_times_e_over_e_miller_loop(const affine_ate_G1_precomp &prec_P1, + const affine_ate_G2_precomp &prec_Q1, + const affine_ate_G1_precomp &prec_P2, + const affine_ate_G2_precomp &prec_Q2, + const affine_ate_G1_precomp &prec_P3, + const affine_ate_G2_precomp &prec_Q3); + Fqk double_miller_loop(const G1_precomp &prec_P1, + const G2_precomp &prec_Q1, + const G1_precomp &prec_P2, + const G2_precomp &prec_Q2); + + Fqk pairing(const G1 &P, + const G2 &Q); + GT reduced_pairing(const G1 &P, + const G2 &Q); + GT affine_reduced_pairing(const G1 &P, + const G2 &Q); +*/ + +template +using Fr = typename EC_ppT::Fp_type; +template +using G1 = typename EC_ppT::G1_type; +template +using G2 = typename EC_ppT::G2_type; +template +using G1_precomp = typename EC_ppT::G1_precomp_type; +template +using G2_precomp = typename EC_ppT::G2_precomp_type; +template +using affine_ate_G1_precomp = typename EC_ppT::affine_ate_G1_precomp_type; +template +using affine_ate_G2_precomp = typename EC_ppT::affine_ate_G2_precomp_type; +template +using Fq = typename EC_ppT::Fq_type; +template +using Fqe = typename EC_ppT::Fqe_type; +template +using Fqk = typename EC_ppT::Fqk_type; +template +using GT = typename EC_ppT::GT_type; + +template +using Fr_vector = std::vector >; +template +using G1_vector = std::vector >; +template +using G2_vector = std::vector >; + +} // libsnark + +#endif // PUBLIC_PARAMS_HPP_ diff --git a/src/algebra/curves/tests/test_bilinearity.cpp b/src/algebra/curves/tests/test_bilinearity.cpp new file mode 100644 index 00000000000..295745281a5 --- /dev/null +++ b/src/algebra/curves/tests/test_bilinearity.cpp @@ -0,0 +1,136 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/profiling.hpp" +#include "algebra/curves/edwards/edwards_pp.hpp" +#ifdef CURVE_BN128 +#include "algebra/curves/bn128/bn128_pp.hpp" +#endif +#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" + +using namespace libsnark; + +template +void pairing_test() +{ + GT GT_one = GT::one(); + + printf("Running bilinearity tests:\n"); + G1 P = (Fr::random_element()) * G1::one(); + //G1 P = Fr("2") * G1::one(); + G2 Q = (Fr::random_element()) * G2::one(); + //G2 Q = Fr("3") * G2::one(); + + printf("P:\n"); + P.print(); + P.print_coordinates(); + printf("Q:\n"); + Q.print(); + Q.print_coordinates(); + printf("\n\n"); + + Fr s = Fr::random_element(); + //Fr s = Fr("2"); + G1 sP = s * P; + G2 sQ = s * Q; + + printf("Pairing bilinearity tests (three must match):\n"); + GT ans1 = ppT::reduced_pairing(sP, Q); + GT ans2 = ppT::reduced_pairing(P, sQ); + GT ans3 = ppT::reduced_pairing(P, Q)^s; + ans1.print(); + ans2.print(); + ans3.print(); + assert(ans1 == ans2); + assert(ans2 == ans3); + + assert(ans1 != GT_one); + assert((ans1^Fr::field_char()) == GT_one); + printf("\n\n"); +} + +template +void double_miller_loop_test() +{ + const G1 P1 = (Fr::random_element()) * G1::one(); + const G1 P2 = (Fr::random_element()) * G1::one(); + const G2 Q1 = (Fr::random_element()) * G2::one(); + const G2 Q2 = (Fr::random_element()) * G2::one(); + + const G1_precomp prec_P1 = ppT::precompute_G1(P1); + const G1_precomp prec_P2 = ppT::precompute_G1(P2); + const G2_precomp prec_Q1 = ppT::precompute_G2(Q1); + const G2_precomp prec_Q2 = ppT::precompute_G2(Q2); + + const Fqk ans_1 = ppT::miller_loop(prec_P1, prec_Q1); + const Fqk ans_2 = ppT::miller_loop(prec_P2, prec_Q2); + const Fqk ans_12 = ppT::double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); + assert(ans_1 * ans_2 == ans_12); +} + +template +void affine_pairing_test() +{ + GT GT_one = GT::one(); + + printf("Running bilinearity tests:\n"); + G1 P = (Fr::random_element()) * G1::one(); + G2 Q = (Fr::random_element()) * G2::one(); + + printf("P:\n"); + P.print(); + printf("Q:\n"); + Q.print(); + printf("\n\n"); + + Fr s = Fr::random_element(); + G1 sP = s * P; + G2 sQ = s * Q; + + printf("Pairing bilinearity tests (three must match):\n"); + GT ans1 = ppT::affine_reduced_pairing(sP, Q); + GT ans2 = ppT::affine_reduced_pairing(P, sQ); + GT ans3 = ppT::affine_reduced_pairing(P, Q)^s; + ans1.print(); + ans2.print(); + ans3.print(); + assert(ans1 == ans2); + assert(ans2 == ans3); + + assert(ans1 != GT_one); + assert((ans1^Fr::field_char()) == GT_one); + printf("\n\n"); +} + +int main(void) +{ + start_profiling(); + edwards_pp::init_public_params(); + pairing_test(); + double_miller_loop_test(); + + mnt6_pp::init_public_params(); + pairing_test(); + double_miller_loop_test(); + affine_pairing_test(); + + mnt4_pp::init_public_params(); + pairing_test(); + double_miller_loop_test(); + affine_pairing_test(); + + alt_bn128_pp::init_public_params(); + pairing_test(); + double_miller_loop_test(); + +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + bn128_pp::init_public_params(); + pairing_test(); + double_miller_loop_test(); +#endif +} diff --git a/src/algebra/curves/tests/test_groups.cpp b/src/algebra/curves/tests/test_groups.cpp new file mode 100644 index 00000000000..725e490d7b4 --- /dev/null +++ b/src/algebra/curves/tests/test_groups.cpp @@ -0,0 +1,175 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/profiling.hpp" +#include "algebra/curves/edwards/edwards_pp.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#ifdef CURVE_BN128 +#include "algebra/curves/bn128/bn128_pp.hpp" +#endif +#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" +#include + +using namespace libsnark; + +template +void test_mixed_add() +{ + GroupT base, el, result; + + base = GroupT::zero(); + el = GroupT::zero(); + el.to_special(); + result = base.mixed_add(el); + assert(result == base + el); + + base = GroupT::zero(); + el = GroupT::random_element(); + el.to_special(); + result = base.mixed_add(el); + assert(result == base + el); + + base = GroupT::random_element(); + el = GroupT::zero(); + el.to_special(); + result = base.mixed_add(el); + assert(result == base + el); + + base = GroupT::random_element(); + el = GroupT::random_element(); + el.to_special(); + result = base.mixed_add(el); + assert(result == base + el); + + base = GroupT::random_element(); + el = base; + el.to_special(); + result = base.mixed_add(el); + assert(result == base.dbl()); +} + +template +void test_group() +{ + bigint<1> rand1 = bigint<1>("76749407"); + bigint<1> rand2 = bigint<1>("44410867"); + bigint<1> randsum = bigint<1>("121160274"); + + GroupT zero = GroupT::zero(); + assert(zero == zero); + GroupT one = GroupT::one(); + assert(one == one); + GroupT two = bigint<1>(2l) * GroupT::one(); + assert(two == two); + GroupT five = bigint<1>(5l) * GroupT::one(); + + GroupT three = bigint<1>(3l) * GroupT::one(); + GroupT four = bigint<1>(4l) * GroupT::one(); + + assert(two+five == three+four); + + GroupT a = GroupT::random_element(); + GroupT b = GroupT::random_element(); + + assert(one != zero); + assert(a != zero); + assert(a != one); + + assert(b != zero); + assert(b != one); + + assert(a.dbl() == a + a); + assert(b.dbl() == b + b); + assert(one.add(two) == three); + assert(two.add(one) == three); + assert(a + b == b + a); + assert(a - a == zero); + assert(a - b == a + (-b)); + assert(a - b == (-b) + a); + + // handle special cases + assert(zero + (-a) == -a); + assert(zero - a == -a); + assert(a - zero == a); + assert(a + zero == a); + assert(zero + a == a); + + assert((a + b).dbl() == (a + b) + (b + a)); + assert(bigint<1>("2") * (a + b) == (a + b) + (b + a)); + + assert((rand1 * a) + (rand2 * a) == (randsum * a)); + + assert(GroupT::order() * a == zero); + assert(GroupT::order() * one == zero); + assert((GroupT::order() * a) - a != zero); + assert((GroupT::order() * one) - one != zero); + + test_mixed_add(); +} + +template +void test_mul_by_q() +{ + GroupT a = GroupT::random_element(); + assert((GroupT::base_field_char()*a) == a.mul_by_q()); +} + +template +void test_output() +{ + GroupT g = GroupT::zero(); + + for (size_t i = 0; i < 1000; ++i) + { + std::stringstream ss; + ss << g; + GroupT gg; + ss >> gg; + assert(g == gg); + /* use a random point in next iteration */ + g = GroupT::random_element(); + } +} + +int main(void) +{ + edwards_pp::init_public_params(); + test_group >(); + test_output >(); + test_group >(); + test_output >(); + test_mul_by_q >(); + + mnt4_pp::init_public_params(); + test_group >(); + test_output >(); + test_group >(); + test_output >(); + test_mul_by_q >(); + + mnt6_pp::init_public_params(); + test_group >(); + test_output >(); + test_group >(); + test_output >(); + test_mul_by_q >(); + + alt_bn128_pp::init_public_params(); + test_group >(); + test_output >(); + test_group >(); + test_output >(); + test_mul_by_q >(); + +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + bn128_pp::init_public_params(); + test_group >(); + test_output >(); + test_group >(); + test_output >(); +#endif +} diff --git a/src/algebra/evaluation_domain/domains/basic_radix2_domain.hpp b/src/algebra/evaluation_domain/domains/basic_radix2_domain.hpp new file mode 100644 index 00000000000..3e127a063d1 --- /dev/null +++ b/src/algebra/evaluation_domain/domains/basic_radix2_domain.hpp @@ -0,0 +1,45 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the "basic radix-2" evaluation domain. + + Roughly, the domain has size m = 2^k and consists of the m-th roots of unity. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BASIC_RADIX2_DOMAIN_HPP_ +#define BASIC_RADIX2_DOMAIN_HPP_ + +#include "algebra/evaluation_domain/evaluation_domain.hpp" + +namespace libsnark { + +template +class basic_radix2_domain : public evaluation_domain { +public: + + FieldT omega; + + basic_radix2_domain(const size_t m); + + void FFT(std::vector &a); + void iFFT(std::vector &a); + void cosetFFT(std::vector &a, const FieldT &g); + void icosetFFT(std::vector &a, const FieldT &g); + std::vector lagrange_coeffs(const FieldT &t); + FieldT get_element(const size_t idx); + FieldT compute_Z(const FieldT &t); + void add_poly_Z(const FieldT &coeff, std::vector &H); + void divide_by_Z_on_coset(std::vector &P); + +}; + +} // libsnark + +#include "algebra/evaluation_domain/domains/basic_radix2_domain.tcc" + +#endif // BASIC_RADIX2_DOMAIN_HPP_ diff --git a/src/algebra/evaluation_domain/domains/basic_radix2_domain.tcc b/src/algebra/evaluation_domain/domains/basic_radix2_domain.tcc new file mode 100644 index 00000000000..d315e8319e4 --- /dev/null +++ b/src/algebra/evaluation_domain/domains/basic_radix2_domain.tcc @@ -0,0 +1,112 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the "basic radix-2" evaluation domain. + + See basic_radix2_domain.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BASIC_RADIX2_DOMAIN_TCC_ +#define BASIC_RADIX2_DOMAIN_TCC_ + +#include "algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp" + +namespace libsnark { + +template +basic_radix2_domain::basic_radix2_domain(const size_t m) : evaluation_domain(m) +{ + assert(m > 1); + const size_t logm = log2(m); + assert(logm <= (FieldT::s)); + + omega = get_root_of_unity(m); +} + +template +void basic_radix2_domain::FFT(std::vector &a) +{ + enter_block("Execute FFT"); + assert(a.size() == this->m); + _basic_radix2_FFT(a, omega); + leave_block("Execute FFT"); +} + +template +void basic_radix2_domain::iFFT(std::vector &a) +{ + enter_block("Execute inverse FFT"); + assert(a.size() == this->m); + _basic_radix2_FFT(a, omega.inverse()); + + const FieldT sconst = FieldT(a.size()).inverse(); + for (size_t i = 0; i < a.size(); ++i) + { + a[i] *= sconst; + } + leave_block("Execute inverse FFT"); +} + +template +void basic_radix2_domain::cosetFFT(std::vector &a, const FieldT &g) +{ + enter_block("Execute coset FFT"); + _multiply_by_coset(a, g); + FFT(a); + leave_block("Execute coset FFT"); +} + +template +void basic_radix2_domain::icosetFFT(std::vector &a, const FieldT &g) +{ + enter_block("Execute inverse coset IFFT"); + iFFT(a); + _multiply_by_coset(a, g.inverse()); + leave_block("Execute inverse coset IFFT"); +} + +template +std::vector basic_radix2_domain::lagrange_coeffs(const FieldT &t) +{ + return _basic_radix2_lagrange_coeffs(this->m, t); +} + +template +FieldT basic_radix2_domain::get_element(const size_t idx) +{ + return omega^idx; +} + +template +FieldT basic_radix2_domain::compute_Z(const FieldT &t) +{ + return (t^this->m) - FieldT::one(); +} + +template +void basic_radix2_domain::add_poly_Z(const FieldT &coeff, std::vector &H) +{ + assert(H.size() == this->m+1); + H[this->m] += coeff; + H[0] -= coeff; +} + +template +void basic_radix2_domain::divide_by_Z_on_coset(std::vector &P) +{ + const FieldT coset = FieldT::multiplicative_generator; + const FieldT Z_inverse_at_coset = this->compute_Z(coset).inverse(); + for (size_t i = 0; i < this->m; ++i) + { + P[i] *= Z_inverse_at_coset; + } +} + +} // libsnark + +#endif // BASIC_RADIX2_DOMAIN_TCC_ diff --git a/src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp b/src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp new file mode 100644 index 00000000000..c42ab2f6fe7 --- /dev/null +++ b/src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp @@ -0,0 +1,48 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for auxiliary functions for the "basic radix-2" evaluation domain. + + These functions compute the radix-2 FFT (in single- or multi-thread mode) and, + also compute Lagrange coefficients. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BASIC_RADIX2_DOMAIN_AUX_HPP_ +#define BASIC_RADIX2_DOMAIN_AUX_HPP_ + +namespace libsnark { + +/** + * Compute the radix-2 FFT of the vector a over the set S={omega^{0},...,omega^{m-1}}. + */ +template +void _basic_radix2_FFT(std::vector &a, const FieldT &omega); + +/** + * A multi-thread version of _basic_radix2_FFT. + */ +template +void _parallel_basic_radix2_FFT(std::vector &a, const FieldT &omega); + +/** + * Translate the vector a to a coset defined by g. + */ +template +void _multiply_by_coset(std::vector &a, const FieldT &g); + +/** + * Compute the m Lagrange coefficients, relative to the set S={omega^{0},...,omega^{m-1}}, at the field element t. + */ +template +std::vector _basic_radix2_lagrange_coeffs(const size_t m, const FieldT &t); + +} // libsnark + +#include "algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc" + +#endif // BASIC_RADIX2_DOMAIN_AUX_HPP_ diff --git a/src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc b/src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc new file mode 100644 index 00000000000..138b82dbc10 --- /dev/null +++ b/src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc @@ -0,0 +1,242 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for auxiliary functions for the "basic radix-2" evaluation domain. + + See basic_radix2_domain_aux.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BASIC_RADIX2_DOMAIN_AUX_TCC_ +#define BASIC_RADIX2_DOMAIN_AUX_TCC_ + +#include +#ifdef MULTICORE +#include +#endif +#include "algebra/fields/field_utils.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +#ifdef MULTICORE +#define _basic_radix2_FFT _basic_parallel_radix2_FFT +#else +#define _basic_radix2_FFT _basic_serial_radix2_FFT +#endif + +/* + Below we make use of pseudocode from [CLRS 2n Ed, pp. 864]. + Also, note that it's the caller's responsibility to multiply by 1/N. + */ +template +void _basic_serial_radix2_FFT(std::vector &a, const FieldT &omega) +{ + const size_t n = a.size(), logn = log2(n); + assert(n == (1u << logn)); + + /* swapping in place (from Storer's book) */ + for (size_t k = 0; k < n; ++k) + { + const size_t rk = bitreverse(k, logn); + if (k < rk) + std::swap(a[k], a[rk]); + } + + size_t m = 1; // invariant: m = 2^{s-1} + for (size_t s = 1; s <= logn; ++s) + { + // w_m is 2^s-th root of unity now + const FieldT w_m = omega^(n/(2*m)); + + asm volatile ("/* pre-inner */"); + for (size_t k = 0; k < n; k += 2*m) + { + FieldT w = FieldT::one(); + for (size_t j = 0; j < m; ++j) + { + const FieldT t = w * a[k+j+m]; + a[k+j+m] = a[k+j] - t; + a[k+j] += t; + w *= w_m; + } + } + asm volatile ("/* post-inner */"); + m *= 2; + } +} + +template +void _basic_parallel_radix2_FFT_inner(std::vector &a, const FieldT &omega, const size_t log_cpus) +{ + const size_t num_cpus = 1ul< > tmp(num_cpus); + for (size_t j = 0; j < num_cpus; ++j) + { + tmp[j].resize(1ul<<(log_m-log_cpus), FieldT::zero()); + } + +#ifdef MULTICORE + #pragma omp parallel for +#endif + for (size_t j = 0; j < num_cpus; ++j) + { + const FieldT omega_j = omega^j; + const FieldT omega_step = omega^(j<<(log_m - log_cpus)); + + FieldT elt = FieldT::one(); + for (size_t i = 0; i < 1ul<<(log_m - log_cpus); ++i) + { + for (size_t s = 0; s < num_cpus; ++s) + { + // invariant: elt is omega^(j*idx) + const size_t idx = (i + (s<<(log_m - log_cpus))) % (1u << log_m); + tmp[j][i] += a[idx] * elt; + elt *= omega_step; + } + elt *= omega_j; + } + } + leave_block("Shuffle inputs"); + + enter_block("Execute sub-FFTs"); + const FieldT omega_num_cpus = omega^num_cpus; + +#ifdef MULTICORE + #pragma omp parallel for +#endif + for (size_t j = 0; j < num_cpus; ++j) + { + _basic_serial_radix2_FFT(tmp[j], omega_num_cpus); + } + leave_block("Execute sub-FFTs"); + + enter_block("Re-shuffle outputs"); + +#ifdef MULTICORE + #pragma omp parallel for +#endif + for (size_t i = 0; i < num_cpus; ++i) + { + for (size_t j = 0; j < 1ul<<(log_m - log_cpus); ++j) + { + // now: i = idx >> (log_m - log_cpus) and j = idx % (1u << (log_m - log_cpus)), for idx = ((i<<(log_m-log_cpus))+j) % (1u << log_m) + a[(j< +void _basic_parallel_radix2_FFT(std::vector &a, const FieldT &omega) +{ +#ifdef MULTICORE + const size_t num_cpus = omp_get_max_threads(); +#else + const size_t num_cpus = 1; +#endif + const size_t log_cpus = ((num_cpus & (num_cpus - 1)) == 0 ? log2(num_cpus) : log2(num_cpus) - 1); + +#ifdef DEBUG + print_indent(); printf("* Invoking parallel FFT on 2^%zu CPUs (omp_get_max_threads = %zu)\n", log_cpus, num_cpus); +#endif + + if (log_cpus == 0) + { + _basic_serial_radix2_FFT(a, omega); + } + else + { + _basic_parallel_radix2_FFT_inner(a, omega, log_cpus); + } +} + +template +void _multiply_by_coset(std::vector &a, const FieldT &g) +{ + //enter_block("Multiply by coset"); + FieldT u = g; + for (size_t i = 1; i < a.size(); ++i) + { + a[i] *= u; + u *= g; + } + //leave_block("Multiply by coset"); +} + +template +std::vector _basic_radix2_lagrange_coeffs(const size_t m, const FieldT &t) +{ + if (m == 1) + { + return std::vector(1, FieldT::one()); + } + + assert(m == (1u << log2(m))); + + const FieldT omega = get_root_of_unity(m); + + std::vector u(m, FieldT::zero()); + + /* + If t equals one of the roots of unity in S={omega^{0},...,omega^{m-1}} + then output 1 at the right place, and 0 elsewhere + */ + + if ((t^m) == (FieldT::one())) + { + FieldT omega_i = FieldT::one(); + for (size_t i = 0; i < m; ++i) + { + if (omega_i == t) // i.e., t equals omega^i + { + u[i] = FieldT::one(); + return u; + } + + omega_i *= omega; + } + } + + /* + Otherwise, if t does not equal any of the roots of unity in S, + then compute each L_{i,S}(t) as Z_{S}(t) * v_i / (t-\omega^i) + where: + - Z_{S}(t) = \prod_{j} (t-\omega^j) = (t^m-1), and + - v_{i} = 1 / \prod_{j \neq i} (\omega^i-\omega^j). + Below we use the fact that v_{0} = 1/m and v_{i+1} = \omega * v_{i}. + */ + + const FieldT Z = (t^m)-FieldT::one(); + FieldT l = Z * FieldT(m).inverse(); + FieldT r = FieldT::one(); + for (size_t i = 0; i < m; ++i) + { + u[i] = l * (t - r).inverse(); + l *= omega; + r *= omega; + } + + return u; +} + +} // libsnark + +#endif // BASIC_RADIX2_DOMAIN_AUX_TCC_ diff --git a/src/algebra/evaluation_domain/evaluation_domain.hpp b/src/algebra/evaluation_domain/evaluation_domain.hpp new file mode 100644 index 00000000000..358db979803 --- /dev/null +++ b/src/algebra/evaluation_domain/evaluation_domain.hpp @@ -0,0 +1,125 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for evaluation domains. + + Roughly, given a desired size m for the domain, the constructor selects + a choice of domain S with size ~m that has been selected so to optimize + - computations of Lagrange polynomials, and + - FFT/iFFT computations. + An evaluation domain also provides other other functions, e.g., accessing + individual elements in S or evaluating its vanishing polynomial. + + The descriptions below make use of the definition of a *Lagrange polynomial*, + which we recall. Given a field F, a subset S=(a_i)_i of F, and an index idx + in {0,...,|S-1|}, the idx-th Lagrange polynomial (wrt to subset S) is defined to be + \f[ L_{idx,S}(z) := prod_{k \neq idx} (z - a_k) / prod_{k \neq idx} (a_{idx} - a_k) \f] + Note that, by construction: + \f[ \forall j \neq idx: L_{idx,S}(a_{idx}) = 1 \text{ and } L_{idx,S}(a_j) = 0 \f] + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EVALUATION_DOMAIN_HPP_ +#define EVALUATION_DOMAIN_HPP_ + +#include + +namespace libsnark { + +/** + * An evaluation domain. + */ +template +class evaluation_domain { +public: + + const size_t m; + + /** + * Construct an evaluation domain S of size m, if possible. + * + * (See the function get_evaluation_domain below.) + */ + evaluation_domain(const size_t m) : m(m) {}; + + /** + * Get the idx-th element in S. + */ + virtual FieldT get_element(const size_t idx) = 0; + + /** + * Compute the FFT, over the domain S, of the vector a. + */ + virtual void FFT(std::vector &a) = 0; + + /** + * Compute the inverse FFT, over the domain S, of the vector a. + */ + virtual void iFFT(std::vector &a) = 0; + + /** + * Compute the FFT, over the domain g*S, of the vector a. + */ + virtual void cosetFFT(std::vector &a, const FieldT &g) = 0; + + /** + * Compute the inverse FFT, over the domain g*S, of the vector a. + */ + virtual void icosetFFT(std::vector &a, const FieldT &g) = 0; + + /** + * Evaluate all Lagrange polynomials. + * + * The inputs are: + * - an integer m + * - an element t + * The output is a vector (b_{0},...,b_{m-1}) + * where b_{i} is the evaluation of L_{i,S}(z) at z = t. + */ + virtual std::vector lagrange_coeffs(const FieldT &t) = 0; + + /** + * Evaluate the vanishing polynomial of S at the field element t. + */ + virtual FieldT compute_Z(const FieldT &t) = 0; + + /** + * Add the coefficients of the vanishing polynomial of S to the coefficients of the polynomial H. + */ + virtual void add_poly_Z(const FieldT &coeff, std::vector &H) = 0; + + /** + * Multiply by the evaluation, on a coset of S, of the inverse of the vanishing polynomial of S. + */ + virtual void divide_by_Z_on_coset(std::vector &P) = 0; +}; + +/** + * Return an evaluation domain object in which the domain S has size |S| >= min_size. + * The function chooses from different supported domains, depending on min_size. + */ +template +std::shared_ptr > get_evaluation_domain(const size_t min_size); + +/** + * Naive evaluation of a *single* Lagrange polynomial, used for testing purposes. + * + * The inputs are: + * - an integer m + * - a domain S = (a_{0},...,a_{m-1}) of size m + * - a field element element t + * - an index idx in {0,...,m-1} + * The output is the polynomial L_{idx,S}(z) evaluated at z = t. + */ +template +FieldT lagrange_eval(const size_t m, const std::vector &domain, const FieldT &t, const size_t idx); + +} // libsnark + +#include "algebra/evaluation_domain/evaluation_domain.tcc" + +#endif // EVALUATION_DOMAIN_HPP_ diff --git a/src/algebra/evaluation_domain/evaluation_domain.tcc b/src/algebra/evaluation_domain/evaluation_domain.tcc new file mode 100644 index 00000000000..8e3ea7a625b --- /dev/null +++ b/src/algebra/evaluation_domain/evaluation_domain.tcc @@ -0,0 +1,117 @@ +/** @file + ***************************************************************************** + + Imeplementation of interfaces for evaluation domains. + + See evaluation_domain.hpp . + + We currently implement, and select among, three types of domains: + - "basic radix-2": the domain has size m = 2^k and consists of the m-th roots of unity + - "extended radix-2": the domain has size m = 2^{k+1} and consists of "the m-th roots of unity" union "a coset" + - "step radix-2": the domain has size m = 2^k + 2^r and consists of "the 2^k-th roots of unity" union "a coset of 2^r-th roots of unity" + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EVALUATION_DOMAIN_TCC_ +#define EVALUATION_DOMAIN_TCC_ + +#include +#include "algebra/fields/field_utils.hpp" +#include "algebra/evaluation_domain/domains/basic_radix2_domain.hpp" + +namespace libsnark { + +template +std::shared_ptr > get_evaluation_domain(const size_t min_size) +{ + assert(min_size > 1); + const size_t log_min_size = log2(min_size); + assert(log_min_size <= (FieldT::s+1)); + + std::shared_ptr > result; + if (min_size == (1u << log_min_size)) + { + if (log_min_size == FieldT::s+1) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("* Selected domain: extended_radix2\n"); + } + assert(0); + } + else + { + if (!inhibit_profiling_info) + { + print_indent(); printf("* Selected domain: basic_radix2\n"); + } + result.reset(new basic_radix2_domain(min_size)); + } + } + else + { + const size_t big = 1ul<<(log2(min_size)-1); + const size_t small = min_size - big; + const size_t rounded_small = (1ul<(big + rounded_small)); + } + else + { + if (!inhibit_profiling_info) + { + print_indent(); printf("* Selected domain: extended_radix2\n"); + } + assert(0); + } + } + else + { + if (!inhibit_profiling_info) + { + print_indent(); printf("* Selected domain: step_radix2\n"); + } + assert(0); + } + } + + return result; +} + +template +FieldT lagrange_eval(const size_t m, const std::vector &domain, const FieldT &t, const size_t idx) +{ + assert(m == domain.size()); + assert(idx < m); + + FieldT num = FieldT::one(); + FieldT denom = FieldT::one(); + + for (size_t k = 0; k < m; ++k) + { + if (k == idx) + { + continue; + } + + num *= t - domain[k]; + denom *= domain[idx] - domain[k]; + } + + return num * denom.inverse(); +} + +} // libsnark + +#endif // EVALUATION_DOMAIN_TCC_ diff --git a/src/algebra/exponentiation/exponentiation.hpp b/src/algebra/exponentiation/exponentiation.hpp new file mode 100644 index 00000000000..a8a2c925cbf --- /dev/null +++ b/src/algebra/exponentiation/exponentiation.hpp @@ -0,0 +1,31 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for (square-and-multiply) exponentiation. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EXPONENTIATION_HPP_ +#define EXPONENTIATION_HPP_ + +#include + +#include "algebra/fields/bigint.hpp" + +namespace libsnark { + +template +FieldT power(const FieldT &base, const bigint &exponent); + +template +FieldT power(const FieldT &base, const unsigned long exponent); + +} // libsnark + +#include "algebra/exponentiation/exponentiation.tcc" + +#endif // EXPONENTIATION_HPP_ diff --git a/src/algebra/exponentiation/exponentiation.tcc b/src/algebra/exponentiation/exponentiation.tcc new file mode 100644 index 00000000000..dd557eb1233 --- /dev/null +++ b/src/algebra/exponentiation/exponentiation.tcc @@ -0,0 +1,53 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for (square-and-multiply) exponentiation. + + See exponentiation.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EXPONENTIATION_TCC_ +#define EXPONENTIATION_TCC_ + +#include "common/utils.hpp" + +namespace libsnark { + +template +FieldT power(const FieldT &base, const bigint &exponent) +{ + FieldT result = FieldT::one(); + + bool found_one = false; + + for (long i = exponent.max_bits() - 1; i >= 0; --i) + { + if (found_one) + { + result = result * result; + } + + if (exponent.test_bit(i)) + { + found_one = true; + result = result * base; + } + } + + return result; +} + +template +FieldT power(const FieldT &base, const unsigned long exponent) +{ + return power(base, bigint<1>(exponent)); +} + +} // libsnark + +#endif // EXPONENTIATION_TCC_ diff --git a/src/algebra/fields/bigint.hpp b/src/algebra/fields/bigint.hpp new file mode 100644 index 00000000000..ff00dd5cf4a --- /dev/null +++ b/src/algebra/fields/bigint.hpp @@ -0,0 +1,70 @@ +/** @file + ***************************************************************************** + Declaration of bigint wrapper class around GMP's MPZ long integers. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BIGINT_HPP_ +#define BIGINT_HPP_ +#include +#include +#include +#include "common/serialization.hpp" + +namespace libsnark { + +template class bigint; +template std::ostream& operator<<(std::ostream &, const bigint&); +template std::istream& operator>>(std::istream &, bigint&); + +/** + * Wrapper class around GMP's MPZ long integers. It supports arithmetic operations, + * serialization and randomization. Serialization is fragile, see common/serialization.hpp. + */ + +template +class bigint { +public: + static const mp_size_t N = n; + + mp_limb_t data[n] = {0}; + + bigint() = default; + bigint(const unsigned long x); /// Initalize from a small integer + bigint(const char* s); /// Initialize from a string containing an integer in decimal notation + bigint(const mpz_t r); /// Initialize from MPZ element + + void print() const; + void print_hex() const; + bool operator==(const bigint& other) const; + bool operator!=(const bigint& other) const; + void clear(); + bool is_zero() const; + size_t max_bits() const { return n * GMP_NUMB_BITS; } + size_t num_bits() const; + + unsigned long as_ulong() const; /* return the last limb of the integer */ + void to_mpz(mpz_t r) const; + bool test_bit(const std::size_t bitno) const; + + template inline void operator+=(const bigint& other); + template inline bigint operator*(const bigint& other) const; + template static inline void div_qr(bigint& quotient, bigint& remainder, + const bigint& dividend, const bigint& divisor); + template inline bigint shorten(const bigint& q, const char *msg) const; + + inline void limit(const bigint& q, const char *msg) const; + bool operator>(const bigint& other) const; + + bigint& randomize(); + + friend std::ostream& operator<< (std::ostream &out, const bigint &b); + friend std::istream& operator>> (std::istream &in, bigint &b); +}; + +} // libsnark +#include "algebra/fields/bigint.tcc" +#endif diff --git a/src/algebra/fields/bigint.tcc b/src/algebra/fields/bigint.tcc new file mode 100644 index 00000000000..f81addf4530 --- /dev/null +++ b/src/algebra/fields/bigint.tcc @@ -0,0 +1,278 @@ +/** @file + ***************************************************************************** + Implementation of bigint wrapper class around GMP's MPZ long integers. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BIGINT_TCC_ +#define BIGINT_TCC_ +#include +#include +#include +#include "sodium.h" + +namespace libsnark { + +template +bigint::bigint(const unsigned long x) /// Initalize from a small integer +{ + static_assert(ULONG_MAX <= GMP_NUMB_MAX, "unsigned long does not fit in a GMP limb"); + this->data[0] = x; +} + +template +bigint::bigint(const char* s) /// Initialize from a string containing an integer in decimal notation +{ + size_t l = strlen(s); + unsigned char* s_copy = new unsigned char[l]; + + for (size_t i = 0; i < l; ++i) + { + assert(s[i] >= '0' && s[i] <= '9'); + s_copy[i] = s[i] - '0'; + } + + mp_size_t limbs_written = mpn_set_str(this->data, s_copy, l, 10); + assert(limbs_written <= n); + + delete[] s_copy; +} + +template +bigint::bigint(const mpz_t r) /// Initialize from MPZ element +{ + mpz_t k; + mpz_init_set(k, r); + + for (size_t i = 0; i < n; ++i) + { + data[i] = mpz_get_ui(k); + mpz_fdiv_q_2exp(k, k, GMP_NUMB_BITS); + } + + assert(mpz_sgn(k) == 0); + mpz_clear(k); +} + +template +void bigint::print() const +{ + gmp_printf("%Nd\n", this->data, n); +} + +template +void bigint::print_hex() const +{ + gmp_printf("%Nx\n", this->data, n); +} + +template +bool bigint::operator==(const bigint& other) const +{ + return (mpn_cmp(this->data, other.data, n) == 0); +} + +template +bool bigint::operator!=(const bigint& other) const +{ + return !(operator==(other)); +} + +template +void bigint::clear() +{ + mpn_zero(this->data, n); +} + +template +bool bigint::is_zero() const +{ + for (mp_size_t i = 0; i < n; ++i) + { + if (this->data[i]) + { + return false; + } + } + + return true; +} + +template +size_t bigint::num_bits() const +{ +/* + for (long i = max_bits(); i >= 0; --i) + { + if (this->test_bit(i)) + { + return i+1; + } + } + + return 0; +*/ + for (long i = n-1; i >= 0; --i) + { + mp_limb_t x = this->data[i]; + if (x == 0) + { + continue; + } + else + { + return ((i+1) * GMP_NUMB_BITS) - __builtin_clzl(x); + } + } + return 0; +} + +template +unsigned long bigint::as_ulong() const +{ + return this->data[0]; +} + +template +void bigint::to_mpz(mpz_t r) const +{ + mpz_set_ui(r, 0); + + for (int i = n-1; i >= 0; --i) + { + mpz_mul_2exp(r, r, GMP_NUMB_BITS); + mpz_add_ui(r, r, this->data[i]); + } +} + +template +bool bigint::test_bit(const std::size_t bitno) const +{ + if (bitno >= n * GMP_NUMB_BITS) + { + return false; + } + else + { + const std::size_t part = bitno/GMP_NUMB_BITS; + const std::size_t bit = bitno - (GMP_NUMB_BITS*part); + const mp_limb_t one = 1; + return (this->data[part] & (one< template +inline void bigint::operator+=(const bigint& other) +{ + static_assert(n >= m, "first arg must not be smaller than second arg for bigint in-place add"); + mpn_add(data, data, n, other.data, m); +} + +template template +inline bigint bigint::operator*(const bigint& other) const +{ + static_assert(n >= m, "first arg must not be smaller than second arg for bigint mul"); + bigint res; + mpn_mul(res.data, data, n, other.data, m); + return res; +} + +template template +inline void bigint::div_qr(bigint& quotient, bigint& remainder, + const bigint& dividend, const bigint& divisor) +{ + static_assert(n >= d, "dividend must not be smaller than divisor for bigint::div_qr"); + assert(divisor.data[d-1] != 0); + mpn_tdiv_qr(quotient.data, remainder.data, 0, dividend.data, n, divisor.data, d); +} + +// Return a copy shortened to m limbs provided it is less than limit, throwing std::domain_error if not in range. +template template +inline bigint bigint::shorten(const bigint& q, const char *msg) const +{ + static_assert(m <= n, "number of limbs must not increase for bigint::shorten"); + for (mp_size_t i = m; i < n; i++) { // high-order limbs + if (data[i] != 0) { + throw std::domain_error(msg); + } + } + bigint res; + mpn_copyi(res.data, data, n); + res.limit(q, msg); + return res; +} + +template +inline void bigint::limit(const bigint& q, const char *msg) const +{ + if (!(q > *this)) { + throw std::domain_error(msg); + } +} + +template +inline bool bigint::operator>(const bigint& other) const +{ + return mpn_cmp(this->data, other.data, n) > 0; +} + +template +bigint& bigint::randomize() +{ + assert(GMP_NUMB_BITS == sizeof(mp_limb_t) * 8); + + randombytes_buf(this->data, sizeof(mp_limb_t) * n); + + return (*this); +} + + +template +std::ostream& operator<<(std::ostream &out, const bigint &b) +{ +#ifdef BINARY_OUTPUT + out.write((char*)b.data, sizeof(b.data[0]) * n); +#else + mpz_t t; + mpz_init(t); + b.to_mpz(t); + + out << t; + + mpz_clear(t); +#endif + return out; +} + +template +std::istream& operator>>(std::istream &in, bigint &b) +{ +#ifdef BINARY_OUTPUT + in.read((char*)b.data, sizeof(b.data[0]) * n); +#else + std::string s; + in >> s; + + size_t l = s.size(); + unsigned char* s_copy = new unsigned char[l]; + + for (size_t i = 0; i < l; ++i) + { + assert(s[i] >= '0' && s[i] <= '9'); + s_copy[i] = s[i] - '0'; + } + + mp_size_t limbs_written = mpn_set_str(b.data, s_copy, l, 10); + assert(limbs_written <= n); + + delete[] s_copy; +#endif + return in; +} + +} // libsnark +#endif // BIGINT_TCC_ diff --git a/src/algebra/fields/field_utils.hpp b/src/algebra/fields/field_utils.hpp new file mode 100644 index 00000000000..a07ecfe284e --- /dev/null +++ b/src/algebra/fields/field_utils.hpp @@ -0,0 +1,51 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FIELD_UTILS_HPP_ +#define FIELD_UTILS_HPP_ +#include + +#include "common/utils.hpp" +#include "algebra/fields/bigint.hpp" + +namespace libsnark { + +// returns root of unity of order n (for n a power of 2), if one exists +template +FieldT get_root_of_unity(const size_t n); + +template +std::vector pack_int_vector_into_field_element_vector(const std::vector &v, const size_t w); + +template +std::vector pack_bit_vector_into_field_element_vector(const bit_vector &v, const size_t chunk_bits); + +template +std::vector pack_bit_vector_into_field_element_vector(const bit_vector &v); + +template +std::vector convert_bit_vector_to_field_element_vector(const bit_vector &v); + +template +bit_vector convert_field_element_vector_to_bit_vector(const std::vector &v); + +template +bit_vector convert_field_element_to_bit_vector(const FieldT &el); + +template +bit_vector convert_field_element_to_bit_vector(const FieldT &el, const size_t bitcount); + +template +FieldT convert_bit_vector_to_field_element(const bit_vector &v); + +template +void batch_invert(std::vector &vec); + +} // libsnark +#include "algebra/fields/field_utils.tcc" + +#endif // FIELD_UTILS_HPP_ diff --git a/src/algebra/fields/field_utils.tcc b/src/algebra/fields/field_utils.tcc new file mode 100644 index 00000000000..13197b226f5 --- /dev/null +++ b/src/algebra/fields/field_utils.tcc @@ -0,0 +1,183 @@ +/** @file + ***************************************************************************** + Implementation of misc. math and serialization utility functions + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FIELD_UTILS_TCC_ +#define FIELD_UTILS_TCC_ + +#include "common/utils.hpp" + +namespace libsnark { + +template +FieldT coset_shift() +{ + return FieldT::multiplicative_generator.squared(); +} + +template +FieldT get_root_of_unity(const size_t n) +{ + const size_t logn = log2(n); + assert(n == (1u << logn)); + assert(logn <= FieldT::s); + + FieldT omega = FieldT::root_of_unity; + for (size_t i = FieldT::s; i > logn; --i) + { + omega *= omega; + } + + return omega; +} + +template +std::vector pack_int_vector_into_field_element_vector(const std::vector &v, const size_t w) +{ + const size_t chunk_bits = FieldT::capacity(); + const size_t repacked_size = div_ceil(v.size() * w, chunk_bits); + std::vector result(repacked_size); + + for (size_t i = 0; i < repacked_size; ++i) + { + bigint b; + for (size_t j = 0; j < chunk_bits; ++j) + { + const size_t word_index = (i * chunk_bits + j) / w; + const size_t pos_in_word = (i * chunk_bits + j) % w; + const size_t word_or_0 = (word_index < v.size() ? v[word_index] : 0); + const size_t bit = (word_or_0 >> pos_in_word) & 1; + + b.data[j / GMP_NUMB_BITS] |= bit << (j % GMP_NUMB_BITS); + } + result[i] = FieldT(b); + } + + return result; +} + +template +std::vector pack_bit_vector_into_field_element_vector(const bit_vector &v, const size_t chunk_bits) +{ + assert(chunk_bits <= FieldT::capacity()); + + const size_t repacked_size = div_ceil(v.size(), chunk_bits); + std::vector result(repacked_size); + + for (size_t i = 0; i < repacked_size; ++i) + { + bigint b; + for (size_t j = 0; j < chunk_bits; ++j) + { + b.data[j / GMP_NUMB_BITS] |= ((i * chunk_bits + j) < v.size() && v[i * chunk_bits + j] ? 1ll : 0ll) << (j % GMP_NUMB_BITS); + } + result[i] = FieldT(b); + } + + return result; +} + +template +std::vector pack_bit_vector_into_field_element_vector(const bit_vector &v) +{ + return pack_bit_vector_into_field_element_vector(v, FieldT::capacity()); +} + +template +std::vector convert_bit_vector_to_field_element_vector(const bit_vector &v) +{ + std::vector result; + result.reserve(v.size()); + + for (const bool b : v) + { + result.emplace_back(b ? FieldT::one() : FieldT::zero()); + } + + return result; +} + +template +bit_vector convert_field_element_vector_to_bit_vector(const std::vector &v) +{ + bit_vector result; + + for (const FieldT &el : v) + { + const bit_vector el_bits = convert_field_element_to_bit_vector(el); + result.insert(result.end(), el_bits.begin(), el_bits.end()); + } + + return result; +} + +template +bit_vector convert_field_element_to_bit_vector(const FieldT &el) +{ + bit_vector result; + + bigint b = el.as_bigint(); + for (size_t i = 0; i < FieldT::size_in_bits(); ++i) + { + result.push_back(b.test_bit(i)); + } + + return result; +} + +template +bit_vector convert_field_element_to_bit_vector(const FieldT &el, const size_t bitcount) +{ + bit_vector result = convert_field_element_to_bit_vector(el); + result.resize(bitcount); + + return result; +} + +template +FieldT convert_bit_vector_to_field_element(const bit_vector &v) +{ + assert(v.size() <= FieldT::size_in_bits()); + + FieldT res = FieldT::zero(); + FieldT c = FieldT::one(); + for (bool b : v) + { + res += b ? c : FieldT::zero(); + c += c; + } + return res; +} + +template +void batch_invert(std::vector &vec) +{ + std::vector prod; + prod.reserve(vec.size()); + + FieldT acc = FieldT::one(); + + for (auto el : vec) + { + assert(!el.is_zero()); + prod.emplace_back(acc); + acc = acc * el; + } + + FieldT acc_inverse = acc.inverse(); + + for (long i = vec.size()-1; i >= 0; --i) + { + const FieldT old_el = vec[i]; + vec[i] = acc_inverse * prod[i]; + acc_inverse = acc_inverse * old_el; + } +} + +} // libsnark +#endif // FIELD_UTILS_TCC_ diff --git a/src/algebra/fields/fp.hpp b/src/algebra/fields/fp.hpp new file mode 100644 index 00000000000..a4986833c30 --- /dev/null +++ b/src/algebra/fields/fp.hpp @@ -0,0 +1,182 @@ +/** @file + ***************************************************************************** + Declaration of arithmetic in the finite field F[p], for prime p of fixed length. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP_HPP_ +#define FP_HPP_ + +#include "algebra/fields/bigint.hpp" +#include "algebra/exponentiation/exponentiation.hpp" + +namespace libsnark { + +template& modulus> +class Fp_model; + +template& modulus> +std::ostream& operator<<(std::ostream &, const Fp_model&); + +template& modulus> +std::istream& operator>>(std::istream &, Fp_model &); + +/** + * Arithmetic in the finite field F[p], for prime p of fixed length. + * + * This class implements Fp-arithmetic, for a large prime p, using a fixed number + * of words. It is optimized for tight memory consumption, so the modulus p is + * passed as a template parameter, to avoid per-element overheads. + * + * The implementation is mostly a wrapper around GMP's MPN (constant-size integers). + * But for the integer sizes of interest for libsnark (3 to 5 limbs of 64 bits each), + * we implement performance-critical routines, like addition and multiplication, + * using hand-optimzied assembly code. +*/ +template& modulus> +class Fp_model { +public: + bigint mont_repr; +public: + static const mp_size_t num_limbs = n; + static const constexpr bigint& mod = modulus; +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long sub_cnt; + static long long mul_cnt; + static long long sqr_cnt; + static long long inv_cnt; +#endif + static size_t num_bits; + static bigint euler; // (modulus-1)/2 + static size_t s; // modulus = 2^s * t + 1 + static bigint t; // with t odd + static bigint t_minus_1_over_2; // (t-1)/2 + static Fp_model nqr; // a quadratic nonresidue + static Fp_model nqr_to_t; // nqr^t + static Fp_model multiplicative_generator; // generator of Fp^* + static Fp_model root_of_unity; // generator^((modulus-1)/2^s) + static mp_limb_t inv; // modulus^(-1) mod W, where W = 2^(word size) + static bigint Rsquared; // R^2, where R = W^k, where k = ?? + static bigint Rcubed; // R^3 + + static bool modulus_is_valid() { return modulus.data[n-1] != 0; } // mpn inverse assumes that highest limb is non-zero + + Fp_model() {}; + Fp_model(const bigint &b); + Fp_model(const long x, const bool is_unsigned=false); + + void set_ulong(const unsigned long x); + + void mul_reduce(const bigint &other); + + void clear(); + + /* Return the standard (not Montgomery) representation of the + Field element's requivalence class. I.e. Fp(2).as_bigint() + would return bigint(2) */ + bigint as_bigint() const; + /* Return the last limb of the standard representation of the + field element. E.g. on 64-bit architectures Fp(123).as_ulong() + and Fp(2^64+123).as_ulong() would both return 123. */ + unsigned long as_ulong() const; + + bool operator==(const Fp_model& other) const; + bool operator!=(const Fp_model& other) const; + bool is_zero() const; + + void print() const; + + Fp_model& operator+=(const Fp_model& other); + Fp_model& operator-=(const Fp_model& other); + Fp_model& operator*=(const Fp_model& other); + Fp_model& operator^=(const unsigned long pow); + + template + Fp_model& operator^=(const bigint &pow); + + Fp_model operator+(const Fp_model& other) const; + Fp_model operator-(const Fp_model& other) const; + Fp_model operator*(const Fp_model& other) const; + Fp_model operator-() const; + Fp_model squared() const; + Fp_model& invert(); + Fp_model inverse() const; + Fp_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate) + + Fp_model operator^(const unsigned long pow) const; + template + Fp_model operator^(const bigint &pow) const; + + static size_t size_in_bits() { return num_bits; } + static size_t capacity() { return num_bits - 1; } + static bigint field_char() { return modulus; } + + static Fp_model zero(); + static Fp_model one(); + static Fp_model random_element(); + + friend std::ostream& operator<< (std::ostream &out, const Fp_model &p); + friend std::istream& operator>> (std::istream &in, Fp_model &p); +}; + +#ifdef PROFILE_OP_COUNTS +template& modulus> +long long Fp_model::add_cnt = 0; + +template& modulus> +long long Fp_model::sub_cnt = 0; + +template& modulus> +long long Fp_model::mul_cnt = 0; + +template& modulus> +long long Fp_model::sqr_cnt = 0; + +template& modulus> +long long Fp_model::inv_cnt = 0; +#endif + +template& modulus> +size_t Fp_model::num_bits; + +template& modulus> +bigint Fp_model::euler; + +template& modulus> +size_t Fp_model::s; + +template& modulus> +bigint Fp_model::t; + +template& modulus> +bigint Fp_model::t_minus_1_over_2; + +template& modulus> +Fp_model Fp_model::nqr; + +template& modulus> +Fp_model Fp_model::nqr_to_t; + +template& modulus> +Fp_model Fp_model::multiplicative_generator; + +template& modulus> +Fp_model Fp_model::root_of_unity; + +template& modulus> +mp_limb_t Fp_model::inv; + +template& modulus> +bigint Fp_model::Rsquared; + +template& modulus> +bigint Fp_model::Rcubed; + +} // libsnark +#include "algebra/fields/fp.tcc" + +#endif // FP_HPP_ diff --git a/src/algebra/fields/fp.tcc b/src/algebra/fields/fp.tcc new file mode 100644 index 00000000000..566e99324a8 --- /dev/null +++ b/src/algebra/fields/fp.tcc @@ -0,0 +1,790 @@ +/** @file + ***************************************************************************** + Implementation of arithmetic in the finite field F[p], for prime p of fixed length. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP_TCC_ +#define FP_TCC_ +#include +#include +#include + +#include "algebra/fields/fp_aux.tcc" +#include "algebra/fields/field_utils.hpp" +#include "common/assert_except.hpp" + +namespace libsnark { + +template& modulus> +void Fp_model::mul_reduce(const bigint &other) +{ + /* stupid pre-processor tricks; beware */ +#if defined(__x86_64__) && defined(USE_ASM) + if (n == 3) + { // Use asm-optimized Comba multiplication and reduction + mp_limb_t res[2*n]; + mp_limb_t c0, c1, c2; + COMBA_3_BY_3_MUL(c0, c1, c2, res, this->mont_repr.data, other.data); + + mp_limb_t k; + mp_limb_t tmp1, tmp2, tmp3; + REDUCE_6_LIMB_PRODUCT(k, tmp1, tmp2, tmp3, inv, res, modulus.data); + + /* subtract t > mod */ + __asm__ + ("/* check for overflow */ \n\t" + MONT_CMP(16) + MONT_CMP(8) + MONT_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + MONT_FIRSTSUB + MONT_NEXTSUB(8) + MONT_NEXTSUB(16) + "done%=: \n\t" + : + : [tmp] "r" (res+n), [M] "r" (modulus.data) + : "cc", "memory", "%rax"); + mpn_copyi(this->mont_repr.data, res+n, n); + } + else if (n == 4) + { // use asm-optimized "CIOS method" + + mp_limb_t tmp[n+1]; + mp_limb_t T0=0, T1=1, cy=2, u=3; // TODO: fix this + + __asm__ (MONT_PRECOMPUTE + MONT_FIRSTITER(1) + MONT_FIRSTITER(2) + MONT_FIRSTITER(3) + MONT_FINALIZE(3) + MONT_ITERFIRST(1) + MONT_ITERITER(1, 1) + MONT_ITERITER(1, 2) + MONT_ITERITER(1, 3) + MONT_FINALIZE(3) + MONT_ITERFIRST(2) + MONT_ITERITER(2, 1) + MONT_ITERITER(2, 2) + MONT_ITERITER(2, 3) + MONT_FINALIZE(3) + MONT_ITERFIRST(3) + MONT_ITERITER(3, 1) + MONT_ITERITER(3, 2) + MONT_ITERITER(3, 3) + MONT_FINALIZE(3) + "/* check for overflow */ \n\t" + MONT_CMP(24) + MONT_CMP(16) + MONT_CMP(8) + MONT_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + MONT_FIRSTSUB + MONT_NEXTSUB(8) + MONT_NEXTSUB(16) + MONT_NEXTSUB(24) + "done%=: \n\t" + : + : [tmp] "r" (tmp), [A] "r" (this->mont_repr.data), [B] "r" (other.data), [inv] "r" (inv), [M] "r" (modulus.data), + [T0] "r" (T0), [T1] "r" (T1), [cy] "r" (cy), [u] "r" (u) + : "cc", "memory", "%rax", "%rdx" + ); + mpn_copyi(this->mont_repr.data, tmp, n); + } + else if (n == 5) + { // use asm-optimized "CIOS method" + + mp_limb_t tmp[n+1]; + mp_limb_t T0=0, T1=1, cy=2, u=3; // TODO: fix this + + __asm__ (MONT_PRECOMPUTE + MONT_FIRSTITER(1) + MONT_FIRSTITER(2) + MONT_FIRSTITER(3) + MONT_FIRSTITER(4) + MONT_FINALIZE(4) + MONT_ITERFIRST(1) + MONT_ITERITER(1, 1) + MONT_ITERITER(1, 2) + MONT_ITERITER(1, 3) + MONT_ITERITER(1, 4) + MONT_FINALIZE(4) + MONT_ITERFIRST(2) + MONT_ITERITER(2, 1) + MONT_ITERITER(2, 2) + MONT_ITERITER(2, 3) + MONT_ITERITER(2, 4) + MONT_FINALIZE(4) + MONT_ITERFIRST(3) + MONT_ITERITER(3, 1) + MONT_ITERITER(3, 2) + MONT_ITERITER(3, 3) + MONT_ITERITER(3, 4) + MONT_FINALIZE(4) + MONT_ITERFIRST(4) + MONT_ITERITER(4, 1) + MONT_ITERITER(4, 2) + MONT_ITERITER(4, 3) + MONT_ITERITER(4, 4) + MONT_FINALIZE(4) + "/* check for overflow */ \n\t" + MONT_CMP(32) + MONT_CMP(24) + MONT_CMP(16) + MONT_CMP(8) + MONT_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + MONT_FIRSTSUB + MONT_NEXTSUB(8) + MONT_NEXTSUB(16) + MONT_NEXTSUB(24) + MONT_NEXTSUB(32) + "done%=: \n\t" + : + : [tmp] "r" (tmp), [A] "r" (this->mont_repr.data), [B] "r" (other.data), [inv] "r" (inv), [M] "r" (modulus.data), + [T0] "r" (T0), [T1] "r" (T1), [cy] "r" (cy), [u] "r" (u) + : "cc", "memory", "%rax", "%rdx" + ); + mpn_copyi(this->mont_repr.data, tmp, n); + } + else +#endif + { + mp_limb_t res[2*n]; + mpn_mul_n(res, this->mont_repr.data, other.data, n); + + /* + The Montgomery reduction here is based on Algorithm 14.32 in + Handbook of Applied Cryptography + . + */ + for (size_t i = 0; i < n; ++i) + { + mp_limb_t k = inv * res[i]; + /* calculate res = res + k * mod * b^i */ + mp_limb_t carryout = mpn_addmul_1(res+i, modulus.data, n, k); + carryout = mpn_add_1(res+n+i, res+n+i, n-i, carryout); + assert(carryout == 0); + } + + if (mpn_cmp(res+n, modulus.data, n) >= 0) + { + const mp_limb_t borrow = mpn_sub(res+n, res+n, n, modulus.data, n); + assert(borrow == 0); + } + + mpn_copyi(this->mont_repr.data, res+n, n); + } +} + +template& modulus> +Fp_model::Fp_model(const bigint &b) +{ + mpn_copyi(this->mont_repr.data, Rsquared.data, n); + mul_reduce(b); +} + +template& modulus> +Fp_model::Fp_model(const long x, const bool is_unsigned) +{ + if (is_unsigned || x >= 0) + { + this->mont_repr.data[0] = x; + } + else + { + const mp_limb_t borrow = mpn_sub_1(this->mont_repr.data, modulus.data, n, -x); + assert(borrow == 0); + } + + mul_reduce(Rsquared); +} + +template& modulus> +void Fp_model::set_ulong(const unsigned long x) +{ + this->mont_repr.clear(); + this->mont_repr.data[0] = x; + mul_reduce(Rsquared); +} + +template& modulus> +void Fp_model::clear() +{ + this->mont_repr.clear(); +} + +template& modulus> +bigint Fp_model::as_bigint() const +{ + bigint one; + one.clear(); + one.data[0] = 1; + + Fp_model res(*this); + res.mul_reduce(one); + + return (res.mont_repr); +} + +template& modulus> +unsigned long Fp_model::as_ulong() const +{ + return this->as_bigint().as_ulong(); +} + +template& modulus> +bool Fp_model::operator==(const Fp_model& other) const +{ + return (this->mont_repr == other.mont_repr); +} + +template& modulus> +bool Fp_model::operator!=(const Fp_model& other) const +{ + return (this->mont_repr != other.mont_repr); +} + +template& modulus> +bool Fp_model::is_zero() const +{ + return (this->mont_repr.is_zero()); // zero maps to zero +} + +template& modulus> +void Fp_model::print() const +{ + Fp_model tmp; + tmp.mont_repr.data[0] = 1; + tmp.mul_reduce(this->mont_repr); + + tmp.mont_repr.print(); +} + +template& modulus> +Fp_model Fp_model::zero() +{ + Fp_model res; + res.mont_repr.clear(); + return res; +} + +template& modulus> +Fp_model Fp_model::one() +{ + Fp_model res; + res.mont_repr.data[0] = 1; + res.mul_reduce(Rsquared); + return res; +} + +template& modulus> +Fp_model& Fp_model::operator+=(const Fp_model& other) +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif +#if defined(__x86_64__) && defined(USE_ASM) + if (n == 3) + { + __asm__ + ("/* perform bignum addition */ \n\t" + ADD_FIRSTADD + ADD_NEXTADD(8) + ADD_NEXTADD(16) + "/* if overflow: subtract */ \n\t" + "/* (tricky point: if A and B are in the range we do not need to do anything special for the possible carry flag) */ \n\t" + "jc subtract%= \n\t" + + "/* check for overflow */ \n\t" + ADD_CMP(16) + ADD_CMP(8) + ADD_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + ADD_FIRSTSUB + ADD_NEXTSUB(8) + ADD_NEXTSUB(16) + "done%=: \n\t" + : + : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) + : "cc", "memory", "%rax"); + } + else if (n == 4) + { + __asm__ + ("/* perform bignum addition */ \n\t" + ADD_FIRSTADD + ADD_NEXTADD(8) + ADD_NEXTADD(16) + ADD_NEXTADD(24) + "/* if overflow: subtract */ \n\t" + "/* (tricky point: if A and B are in the range we do not need to do anything special for the possible carry flag) */ \n\t" + "jc subtract%= \n\t" + + "/* check for overflow */ \n\t" + ADD_CMP(24) + ADD_CMP(16) + ADD_CMP(8) + ADD_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + ADD_FIRSTSUB + ADD_NEXTSUB(8) + ADD_NEXTSUB(16) + ADD_NEXTSUB(24) + "done%=: \n\t" + : + : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) + : "cc", "memory", "%rax"); + } + else if (n == 5) + { + __asm__ + ("/* perform bignum addition */ \n\t" + ADD_FIRSTADD + ADD_NEXTADD(8) + ADD_NEXTADD(16) + ADD_NEXTADD(24) + ADD_NEXTADD(32) + "/* if overflow: subtract */ \n\t" + "/* (tricky point: if A and B are in the range we do not need to do anything special for the possible carry flag) */ \n\t" + "jc subtract%= \n\t" + + "/* check for overflow */ \n\t" + ADD_CMP(32) + ADD_CMP(24) + ADD_CMP(16) + ADD_CMP(8) + ADD_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + ADD_FIRSTSUB + ADD_NEXTSUB(8) + ADD_NEXTSUB(16) + ADD_NEXTSUB(24) + ADD_NEXTSUB(32) + "done%=: \n\t" + : + : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) + : "cc", "memory", "%rax"); + } + else +#endif + { + mp_limb_t scratch[n+1]; + const mp_limb_t carry = mpn_add_n(scratch, this->mont_repr.data, other.mont_repr.data, n); + scratch[n] = carry; + + if (carry || mpn_cmp(scratch, modulus.data, n) >= 0) + { + const mp_limb_t borrow = mpn_sub(scratch, scratch, n+1, modulus.data, n); + assert(borrow == 0); + } + + mpn_copyi(this->mont_repr.data, scratch, n); + } + + return *this; +} + +template& modulus> +Fp_model& Fp_model::operator-=(const Fp_model& other) +{ +#ifdef PROFILE_OP_COUNTS + this->sub_cnt++; +#endif +#if defined(__x86_64__) && defined(USE_ASM) + if (n == 3) + { + __asm__ + (SUB_FIRSTSUB + SUB_NEXTSUB(8) + SUB_NEXTSUB(16) + + "jnc done%=\n\t" + + SUB_FIRSTADD + SUB_NEXTADD(8) + SUB_NEXTADD(16) + + "done%=:\n\t" + : + : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) + : "cc", "memory", "%rax"); + } + else if (n == 4) + { + __asm__ + (SUB_FIRSTSUB + SUB_NEXTSUB(8) + SUB_NEXTSUB(16) + SUB_NEXTSUB(24) + + "jnc done%=\n\t" + + SUB_FIRSTADD + SUB_NEXTADD(8) + SUB_NEXTADD(16) + SUB_NEXTADD(24) + + "done%=:\n\t" + : + : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) + : "cc", "memory", "%rax"); + } + else if (n == 5) + { + __asm__ + (SUB_FIRSTSUB + SUB_NEXTSUB(8) + SUB_NEXTSUB(16) + SUB_NEXTSUB(24) + SUB_NEXTSUB(32) + + "jnc done%=\n\t" + + SUB_FIRSTADD + SUB_NEXTADD(8) + SUB_NEXTADD(16) + SUB_NEXTADD(24) + SUB_NEXTADD(32) + + "done%=:\n\t" + : + : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) + : "cc", "memory", "%rax"); + } + else +#endif + { + mp_limb_t scratch[n+1]; + if (mpn_cmp(this->mont_repr.data, other.mont_repr.data, n) < 0) + { + const mp_limb_t carry = mpn_add_n(scratch, this->mont_repr.data, modulus.data, n); + scratch[n] = carry; + } + else + { + mpn_copyi(scratch, this->mont_repr.data, n); + scratch[n] = 0; + } + + const mp_limb_t borrow = mpn_sub(scratch, scratch, n+1, other.mont_repr.data, n); + assert(borrow == 0); + + mpn_copyi(this->mont_repr.data, scratch, n); + } + return *this; +} + +template& modulus> +Fp_model& Fp_model::operator*=(const Fp_model& other) +{ +#ifdef PROFILE_OP_COUNTS + this->mul_cnt++; +#endif + + mul_reduce(other.mont_repr); + return *this; +} + +template& modulus> +Fp_model& Fp_model::operator^=(const unsigned long pow) +{ + (*this) = power >(*this, pow); + return (*this); +} + +template& modulus> +template +Fp_model& Fp_model::operator^=(const bigint &pow) +{ + (*this) = power, m>(*this, pow); + return (*this); +} + +template& modulus> +Fp_model Fp_model::operator+(const Fp_model& other) const +{ + Fp_model r(*this); + return (r += other); +} + +template& modulus> +Fp_model Fp_model::operator-(const Fp_model& other) const +{ + Fp_model r(*this); + return (r -= other); +} + +template& modulus> +Fp_model Fp_model::operator*(const Fp_model& other) const +{ + Fp_model r(*this); + return (r *= other); +} + +template& modulus> +Fp_model Fp_model::operator^(const unsigned long pow) const +{ + Fp_model r(*this); + return (r ^= pow); +} + +template& modulus> +template +Fp_model Fp_model::operator^(const bigint &pow) const +{ + Fp_model r(*this); + return (r ^= pow); +} + +template& modulus> +Fp_model Fp_model::operator-() const +{ +#ifdef PROFILE_OP_COUNTS + this->sub_cnt++; +#endif + + if (this->is_zero()) + { + return (*this); + } + else + { + Fp_model r; + mpn_sub_n(r.mont_repr.data, modulus.data, this->mont_repr.data, n); + return r; + } +} + +template& modulus> +Fp_model Fp_model::squared() const +{ +#ifdef PROFILE_OP_COUNTS + this->sqr_cnt++; + this->mul_cnt--; // zero out the upcoming mul +#endif + /* stupid pre-processor tricks; beware */ +#if defined(__x86_64__) && defined(USE_ASM) + if (n == 3) + { // use asm-optimized Comba squaring + mp_limb_t res[2*n]; + mp_limb_t c0, c1, c2; + COMBA_3_BY_3_SQR(c0, c1, c2, res, this->mont_repr.data); + + mp_limb_t k; + mp_limb_t tmp1, tmp2, tmp3; + REDUCE_6_LIMB_PRODUCT(k, tmp1, tmp2, tmp3, inv, res, modulus.data); + + /* subtract t > mod */ + __asm__ volatile + ("/* check for overflow */ \n\t" + MONT_CMP(16) + MONT_CMP(8) + MONT_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + MONT_FIRSTSUB + MONT_NEXTSUB(8) + MONT_NEXTSUB(16) + "done%=: \n\t" + : + : [tmp] "r" (res+n), [M] "r" (modulus.data) + : "cc", "memory", "%rax"); + + Fp_model r; + mpn_copyi(r.mont_repr.data, res+n, n); + return r; + } + else +#endif + { + Fp_model r(*this); + return (r *= r); + } +} + +template& modulus> +Fp_model& Fp_model::invert() +{ +#ifdef PROFILE_OP_COUNTS + this->inv_cnt++; +#endif + + assert(!this->is_zero()); + + bigint g; /* gp should have room for vn = n limbs */ + + mp_limb_t s[n+1]; /* sp should have room for vn+1 limbs */ + mp_size_t sn; + + bigint v = modulus; // both source operands are destroyed by mpn_gcdext + + /* computes gcd(u, v) = g = u*s + v*t, so s*u will be 1 (mod v) */ + const mp_size_t gn = mpn_gcdext(g.data, s, &sn, this->mont_repr.data, n, v.data, n); + assert(gn == 1 && g.data[0] == 1); /* inverse exists */ + + mp_limb_t q; /* division result fits into q, as sn <= n+1 */ + /* sn < 0 indicates negative sn; will fix up later */ + + if (std::abs(sn) >= n) + { + /* if sn could require modulus reduction, do it here */ + mpn_tdiv_qr(&q, this->mont_repr.data, 0, s, std::abs(sn), modulus.data, n); + } + else + { + /* otherwise just copy it over */ + mpn_zero(this->mont_repr.data, n); + mpn_copyi(this->mont_repr.data, s, std::abs(sn)); + } + + /* fix up the negative sn */ + if (sn < 0) + { + const mp_limb_t borrow = mpn_sub_n(this->mont_repr.data, modulus.data, this->mont_repr.data, n); + assert(borrow == 0); + } + + mul_reduce(Rcubed); + return *this; +} + +template& modulus> +Fp_model Fp_model::inverse() const +{ + Fp_model r(*this); + return (r.invert()); +} + +template& modulus> +Fp_model Fp_model::random_element() /// returns random element of Fp_model +{ + /* note that as Montgomery representation is a bijection then + selecting a random element of {xR} is the same as selecting a + random element of {x} */ + Fp_model r; + do + { + r.mont_repr.randomize(); + + /* clear all bits higher than MSB of modulus */ + size_t bitno = GMP_NUMB_BITS * n - 1; + while (modulus.test_bit(bitno) == false) + { + const std::size_t part = bitno/GMP_NUMB_BITS; + const std::size_t bit = bitno - (GMP_NUMB_BITS*part); + + r.mont_repr.data[part] &= ~(1ul<= modulus -- repeat (rejection sampling) */ + while (mpn_cmp(r.mont_repr.data, modulus.data, n) >= 0); + + return r; +} + +template& modulus> +Fp_model Fp_model::sqrt() const +{ + if (is_zero()) { + return *this; + } + + Fp_model one = Fp_model::one(); + + size_t v = Fp_model::s; + Fp_model z = Fp_model::nqr_to_t; + Fp_model w = (*this)^Fp_model::t_minus_1_over_2; + Fp_model x = (*this) * w; + Fp_model b = x * w; // b = (*this)^t + + + // check if square with euler's criterion + Fp_model check = b; + for (size_t i = 0; i < v-1; ++i) + { + check = check.squared(); + } + if (check != one) + { + assert_except(0); + } + + + // compute square root with Tonelli--Shanks + // (does not terminate if not a square!) + + while (b != one) + { + size_t m = 0; + Fp_model b2m = b; + while (b2m != one) + { + /* invariant: b2m = b^(2^m) after entering this loop */ + b2m = b2m.squared(); + m += 1; + } + + int j = v-m-1; + w = z; + while (j > 0) + { + w = w.squared(); + --j; + } // w = z^2^(v-m-1) + + z = w.squared(); + b = b * z; + x = x * w; + v = m; + } + + return x; +} + +template& modulus> +std::ostream& operator<<(std::ostream &out, const Fp_model &p) +{ +#ifndef MONTGOMERY_OUTPUT + Fp_model tmp; + tmp.mont_repr.data[0] = 1; + tmp.mul_reduce(p.mont_repr); + out << tmp.mont_repr; +#else + out << p.mont_repr; +#endif + return out; +} + +template& modulus> +std::istream& operator>>(std::istream &in, Fp_model &p) +{ +#ifndef MONTGOMERY_OUTPUT + in >> p.mont_repr; + p.mul_reduce(Fp_model::Rsquared); +#else + in >> p.mont_repr; +#endif + return in; +} + +} // libsnark +#endif // FP_TCC_ diff --git a/src/algebra/fields/fp12_2over3over2.hpp b/src/algebra/fields/fp12_2over3over2.hpp new file mode 100644 index 00000000000..1de9d88b45c --- /dev/null +++ b/src/algebra/fields/fp12_2over3over2.hpp @@ -0,0 +1,116 @@ +/** @file + ***************************************************************************** + Declaration of arithmetic in the finite field F[((p^2)^3)^2]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP12_2OVER3OVER2_HPP_ +#define FP12_2OVER3OVER2_HPP_ +#include "algebra/fields/fp.hpp" +#include "algebra/fields/fp2.hpp" +#include "algebra/fields/fp6_3over2.hpp" +#include + +namespace libsnark { + +template& modulus> +class Fp12_2over3over2_model; + +template& modulus> +std::ostream& operator<<(std::ostream &, const Fp12_2over3over2_model &); + +template& modulus> +std::istream& operator>>(std::istream &, Fp12_2over3over2_model &); + +/** + * Arithmetic in the finite field F[((p^2)^3)^2]. + * + * Let p := modulus. This interface provides arithmetic for the extension field + * Fp12 = Fp6[W]/(W^2-V) where Fp6 = Fp2[V]/(V^3-non_residue) and non_residue is in Fp2 + * + * ASSUMPTION: p = 1 (mod 6) + */ +template& modulus> +class Fp12_2over3over2_model { +public: + typedef Fp_model my_Fp; + typedef Fp2_model my_Fp2; + typedef Fp6_3over2_model my_Fp6; + + static Fp2_model non_residue; + static Fp2_model Frobenius_coeffs_c1[12]; // non_residue^((modulus^i-1)/6) for i=0,...,11 + + my_Fp6 c0, c1; + Fp12_2over3over2_model() {}; + Fp12_2over3over2_model(const my_Fp6& c0, const my_Fp6& c1) : c0(c0), c1(c1) {}; + + void clear() { c0.clear(); c1.clear(); } + void print() const { printf("c0/c1:\n"); c0.print(); c1.print(); } + + static Fp12_2over3over2_model zero(); + static Fp12_2over3over2_model one(); + static Fp12_2over3over2_model random_element(); + + bool is_zero() const { return c0.is_zero() && c1.is_zero(); } + bool operator==(const Fp12_2over3over2_model &other) const; + bool operator!=(const Fp12_2over3over2_model &other) const; + + Fp12_2over3over2_model operator+(const Fp12_2over3over2_model &other) const; + Fp12_2over3over2_model operator-(const Fp12_2over3over2_model &other) const; + Fp12_2over3over2_model operator*(const Fp12_2over3over2_model &other) const; + Fp12_2over3over2_model operator-() const; + Fp12_2over3over2_model squared() const; // default is squared_complex + Fp12_2over3over2_model squared_karatsuba() const; + Fp12_2over3over2_model squared_complex() const; + Fp12_2over3over2_model inverse() const; + Fp12_2over3over2_model Frobenius_map(unsigned long power) const; + Fp12_2over3over2_model unitary_inverse() const; + Fp12_2over3over2_model cyclotomic_squared() const; + + Fp12_2over3over2_model mul_by_024(const my_Fp2 &ell_0, const my_Fp2 &ell_VW, const my_Fp2 &ell_VV) const; + + static my_Fp6 mul_by_non_residue(const my_Fp6 &elt); + + template + Fp12_2over3over2_model cyclotomic_exp(const bigint &exponent) const; + + static bigint base_field_char() { return modulus; } + static size_t extension_degree() { return 12; } + + friend std::ostream& operator<< (std::ostream &out, const Fp12_2over3over2_model &el); + friend std::istream& operator>> (std::istream &in, Fp12_2over3over2_model &el); +}; + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v); + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v); + +template& modulus> +Fp12_2over3over2_model operator*(const Fp_model &lhs, const Fp12_2over3over2_model &rhs); + +template& modulus> +Fp12_2over3over2_model operator*(const Fp2_model &lhs, const Fp12_2over3over2_model &rhs); + +template& modulus> +Fp12_2over3over2_model operator*(const Fp6_3over2_model &lhs, const Fp12_2over3over2_model &rhs); + +template& modulus, mp_size_t m> +Fp12_2over3over2_model operator^(const Fp12_2over3over2_model &self, const bigint &exponent); + +template& modulus, mp_size_t m, const bigint& exp_modulus> +Fp12_2over3over2_model operator^(const Fp12_2over3over2_model &self, const Fp_model &exponent); + +template& modulus> +Fp2_model Fp12_2over3over2_model::non_residue; + +template& modulus> +Fp2_model Fp12_2over3over2_model::Frobenius_coeffs_c1[12]; + +} // libsnark +#include "algebra/fields/fp12_2over3over2.tcc" +#endif // FP12_2OVER3OVER2_HPP_ diff --git a/src/algebra/fields/fp12_2over3over2.tcc b/src/algebra/fields/fp12_2over3over2.tcc new file mode 100644 index 00000000000..2fbc0b649ad --- /dev/null +++ b/src/algebra/fields/fp12_2over3over2.tcc @@ -0,0 +1,412 @@ +/** @file + ***************************************************************************** + Implementation of arithmetic in the finite field F[((p^2)^3)^2]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP12_2OVER3OVER2_TCC_ +#define FP12_2OVER3OVER2_TCC_ + +namespace libsnark { + +template& modulus> +Fp6_3over2_model Fp12_2over3over2_model::mul_by_non_residue(const Fp6_3over2_model &elt) +{ + return Fp6_3over2_model(non_residue * elt.c2, elt.c0, elt.c1); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::zero() +{ + return Fp12_2over3over2_model(my_Fp6::zero(), my_Fp6::zero()); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::one() +{ + return Fp12_2over3over2_model(my_Fp6::one(), my_Fp6::zero()); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::random_element() +{ + Fp12_2over3over2_model r; + r.c0 = my_Fp6::random_element(); + r.c1 = my_Fp6::random_element(); + + return r; +} + +template& modulus> +bool Fp12_2over3over2_model::operator==(const Fp12_2over3over2_model &other) const +{ + return (this->c0 == other.c0 && this->c1 == other.c1); +} + +template& modulus> +bool Fp12_2over3over2_model::operator!=(const Fp12_2over3over2_model &other) const +{ + return !(operator==(other)); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::operator+(const Fp12_2over3over2_model &other) const +{ + return Fp12_2over3over2_model(this->c0 + other.c0, + this->c1 + other.c1); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::operator-(const Fp12_2over3over2_model &other) const +{ + return Fp12_2over3over2_model(this->c0 - other.c0, + this->c1 - other.c1); +} + +template& modulus> +Fp12_2over3over2_model operator*(const Fp_model &lhs, const Fp12_2over3over2_model &rhs) +{ + return Fp12_2over3over2_model(lhs*rhs.c0, + lhs*rhs.c1); +} + +template& modulus> +Fp12_2over3over2_model operator*(const Fp2_model &lhs, const Fp12_2over3over2_model &rhs) +{ + return Fp12_2over3over2_model(lhs*rhs.c0, + lhs*rhs.c1); +} + +template& modulus> +Fp12_2over3over2_model operator*(const Fp6_3over2_model &lhs, const Fp12_2over3over2_model &rhs) +{ + return Fp12_2over3over2_model(lhs*rhs.c0, + lhs*rhs.c1); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::operator*(const Fp12_2over3over2_model &other) const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ + + const my_Fp6 &A = other.c0, &B = other.c1, + &a = this->c0, &b = this->c1; + const my_Fp6 aA = a * A; + const my_Fp6 bB = b * B; + + return Fp12_2over3over2_model(aA + Fp12_2over3over2_model::mul_by_non_residue(bB), + (a + b)*(A+B) - aA - bB); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::operator-() const +{ + return Fp12_2over3over2_model(-this->c0, + -this->c1); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::squared() const +{ + return squared_complex(); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::squared_karatsuba() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba squaring) */ + + const my_Fp6 &a = this->c0, &b = this->c1; + const my_Fp6 asq = a.squared(); + const my_Fp6 bsq = b.squared(); + + return Fp12_2over3over2_model(asq + Fp12_2over3over2_model::mul_by_non_residue(bsq), + (a + b).squared() - asq - bsq); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::squared_complex() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Complex squaring) */ + + const my_Fp6 &a = this->c0, &b = this->c1; + const my_Fp6 ab = a * b; + + return Fp12_2over3over2_model((a + b) * (a + Fp12_2over3over2_model::mul_by_non_residue(b)) - ab - Fp12_2over3over2_model::mul_by_non_residue(ab), + ab + ab); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::inverse() const +{ + /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 8 */ + + const my_Fp6 &a = this->c0, &b = this->c1; + const my_Fp6 t0 = a.squared(); + const my_Fp6 t1 = b.squared(); + const my_Fp6 t2 = t0 - Fp12_2over3over2_model::mul_by_non_residue(t1); + const my_Fp6 t3 = t2.inverse(); + const my_Fp6 c0 = a * t3; + const my_Fp6 c1 = - (b * t3); + + return Fp12_2over3over2_model(c0, c1); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::Frobenius_map(unsigned long power) const +{ + return Fp12_2over3over2_model(c0.Frobenius_map(power), + Frobenius_coeffs_c1[power % 12] * c1.Frobenius_map(power)); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::unitary_inverse() const +{ + return Fp12_2over3over2_model(this->c0, + -this->c1); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::cyclotomic_squared() const +{ + /* OLD: naive implementation + return (*this).squared(); + */ + my_Fp2 z0 = this->c0.c0; + my_Fp2 z4 = this->c0.c1; + my_Fp2 z3 = this->c0.c2; + my_Fp2 z2 = this->c1.c0; + my_Fp2 z1 = this->c1.c1; + my_Fp2 z5 = this->c1.c2; + + my_Fp2 t0, t1, t2, t3, t4, t5, tmp; + + // t0 + t1*y = (z0 + z1*y)^2 = a^2 + tmp = z0 * z1; + t0 = (z0 + z1) * (z0 + my_Fp6::non_residue * z1) - tmp - my_Fp6::non_residue * tmp; + t1 = tmp + tmp; + // t2 + t3*y = (z2 + z3*y)^2 = b^2 + tmp = z2 * z3; + t2 = (z2 + z3) * (z2 + my_Fp6::non_residue * z3) - tmp - my_Fp6::non_residue * tmp; + t3 = tmp + tmp; + // t4 + t5*y = (z4 + z5*y)^2 = c^2 + tmp = z4 * z5; + t4 = (z4 + z5) * (z4 + my_Fp6::non_residue * z5) - tmp - my_Fp6::non_residue * tmp; + t5 = tmp + tmp; + + // for A + + // z0 = 3 * t0 - 2 * z0 + z0 = t0 - z0; + z0 = z0 + z0; + z0 = z0 + t0; + // z1 = 3 * t1 + 2 * z1 + z1 = t1 + z1; + z1 = z1 + z1; + z1 = z1 + t1; + + // for B + + // z2 = 3 * (xi * t5) + 2 * z2 + tmp = my_Fp6::non_residue * t5; + z2 = tmp + z2; + z2 = z2 + z2; + z2 = z2 + tmp; + + // z3 = 3 * t4 - 2 * z3 + z3 = t4 - z3; + z3 = z3 + z3; + z3 = z3 + t4; + + // for C + + // z4 = 3 * t2 - 2 * z4 + z4 = t2 - z4; + z4 = z4 + z4; + z4 = z4 + t2; + + // z5 = 3 * t3 + 2 * z5 + z5 = t3 + z5; + z5 = z5 + z5; + z5 = z5 + t3; + + return Fp12_2over3over2_model(my_Fp6(z0,z4,z3),my_Fp6(z2,z1,z5)); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::mul_by_024(const Fp2_model &ell_0, + const Fp2_model &ell_VW, + const Fp2_model &ell_VV) const +{ + /* OLD: naive implementation + Fp12_2over3over2_model a(my_Fp6(ell_0, my_Fp2::zero(), ell_VV), + my_Fp6(my_Fp2::zero(), ell_VW, my_Fp2::zero())); + + return (*this) * a; + */ + my_Fp2 z0 = this->c0.c0; + my_Fp2 z1 = this->c0.c1; + my_Fp2 z2 = this->c0.c2; + my_Fp2 z3 = this->c1.c0; + my_Fp2 z4 = this->c1.c1; + my_Fp2 z5 = this->c1.c2; + + my_Fp2 x0 = ell_0; + my_Fp2 x2 = ell_VV; + my_Fp2 x4 = ell_VW; + + my_Fp2 t0, t1, t2, s0, T3, T4, D0, D2, D4, S1; + + D0 = z0 * x0; + D2 = z2 * x2; + D4 = z4 * x4; + t2 = z0 + z4; + t1 = z0 + z2; + s0 = z1 + z3 + z5; + + // For z.a_.a_ = z0. + S1 = z1 * x2; + T3 = S1 + D4; + T4 = my_Fp6::non_residue * T3 + D0; + z0 = T4; + + // For z.a_.b_ = z1 + T3 = z5 * x4; + S1 = S1 + T3; + T3 = T3 + D2; + T4 = my_Fp6::non_residue * T3; + T3 = z1 * x0; + S1 = S1 + T3; + T4 = T4 + T3; + z1 = T4; + + // For z.a_.c_ = z2 + t0 = x0 + x2; + T3 = t1 * t0 - D0 - D2; + T4 = z3 * x4; + S1 = S1 + T4; + T3 = T3 + T4; + + // For z.b_.a_ = z3 (z3 needs z2) + t0 = z2 + z4; + z2 = T3; + t1 = x2 + x4; + T3 = t0 * t1 - D2 - D4; + T4 = my_Fp6::non_residue * T3; + T3 = z3 * x0; + S1 = S1 + T3; + T4 = T4 + T3; + z3 = T4; + + // For z.b_.b_ = z4 + T3 = z5 * x2; + S1 = S1 + T3; + T4 = my_Fp6::non_residue * T3; + t0 = x0 + x4; + T3 = t2 * t0 - D0 - D4; + T4 = T4 + T3; + z4 = T4; + + // For z.b_.c_ = z5. + t0 = x0 + x2 + x4; + T3 = s0 * t0 - S1; + z5 = T3; + + return Fp12_2over3over2_model(my_Fp6(z0,z1,z2),my_Fp6(z3,z4,z5)); + +} + +template& modulus, mp_size_t m> +Fp12_2over3over2_model operator^(const Fp12_2over3over2_model &self, const bigint &exponent) +{ + return power >(self, exponent); +} + +template& modulus, mp_size_t m, const bigint& exp_modulus> +Fp12_2over3over2_model operator^(const Fp12_2over3over2_model &self, const Fp_model &exponent) +{ + return self^(exponent.as_bigint()); +} + + +template& modulus> +template +Fp12_2over3over2_model Fp12_2over3over2_model::cyclotomic_exp(const bigint &exponent) const +{ + Fp12_2over3over2_model res = Fp12_2over3over2_model::one(); + + bool found_one = false; + for (long i = m-1; i >= 0; --i) + { + for (long j = GMP_NUMB_BITS - 1; j >= 0; --j) + { + if (found_one) + { + res = res.cyclotomic_squared(); + } + + if (exponent.data[i] & (1ul<& modulus> +std::ostream& operator<<(std::ostream &out, const Fp12_2over3over2_model &el) +{ + out << el.c0 << OUTPUT_SEPARATOR << el.c1; + return out; +} + +template& modulus> +std::istream& operator>>(std::istream &in, Fp12_2over3over2_model &el) +{ + in >> el.c0 >> el.c1; + return in; +} + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v) +{ + out << v.size() << "\n"; + for (const Fp12_2over3over2_model& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v) +{ + v.clear(); + + size_t s; + in >> s; + + char b; + in.read(&b, 1); + + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + Fp12_2over3over2_model el; + in >> el; + v.emplace_back(el); + } + + return in; +} + +} // libsnark +#endif // FP12_2OVER3OVER2_TCC_ diff --git a/src/algebra/fields/fp2.hpp b/src/algebra/fields/fp2.hpp new file mode 100644 index 00000000000..f07726918cd --- /dev/null +++ b/src/algebra/fields/fp2.hpp @@ -0,0 +1,120 @@ +/** @file + ***************************************************************************** + Implementation of arithmetic in the finite field F[p^2]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP2_HPP_ +#define FP2_HPP_ +#include "algebra/fields/fp.hpp" +#include + +namespace libsnark { + +template& modulus> +class Fp2_model; + +template& modulus> +std::ostream& operator<<(std::ostream &, const Fp2_model &); + +template& modulus> +std::istream& operator>>(std::istream &, Fp2_model &); + +/** + * Arithmetic in the field F[p^3]. + * + * Let p := modulus. This interface provides arithmetic for the extension field + * Fp2 = Fp[U]/(U^2-non_residue), where non_residue is in Fp. + * + * ASSUMPTION: p = 1 (mod 6) + */ +template& modulus> +class Fp2_model { +public: + typedef Fp_model my_Fp; + + static bigint<2*n> euler; // (modulus^2-1)/2 + static size_t s; // modulus^2 = 2^s * t + 1 + static bigint<2*n> t; // with t odd + static bigint<2*n> t_minus_1_over_2; // (t-1)/2 + static my_Fp non_residue; // X^4-non_residue irreducible over Fp; used for constructing Fp2 = Fp[X] / (X^2 - non_residue) + static Fp2_model nqr; // a quadratic nonresidue in Fp2 + static Fp2_model nqr_to_t; // nqr^t + static my_Fp Frobenius_coeffs_c1[2]; // non_residue^((modulus^i-1)/2) for i=0,1 + + my_Fp c0, c1; + Fp2_model() {}; + Fp2_model(const my_Fp& c0, const my_Fp& c1) : c0(c0), c1(c1) {}; + + void clear() { c0.clear(); c1.clear(); } + void print() const { printf("c0/c1:\n"); c0.print(); c1.print(); } + + static Fp2_model zero(); + static Fp2_model one(); + static Fp2_model random_element(); + + bool is_zero() const { return c0.is_zero() && c1.is_zero(); } + bool operator==(const Fp2_model &other) const; + bool operator!=(const Fp2_model &other) const; + + Fp2_model operator+(const Fp2_model &other) const; + Fp2_model operator-(const Fp2_model &other) const; + Fp2_model operator*(const Fp2_model &other) const; + Fp2_model operator-() const; + Fp2_model squared() const; // default is squared_complex + Fp2_model inverse() const; + Fp2_model Frobenius_map(unsigned long power) const; + Fp2_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate) + Fp2_model squared_karatsuba() const; + Fp2_model squared_complex() const; + + template + Fp2_model operator^(const bigint &other) const; + + static size_t size_in_bits() { return 2*my_Fp::size_in_bits(); } + static bigint base_field_char() { return modulus; } + + friend std::ostream& operator<< (std::ostream &out, const Fp2_model &el); + friend std::istream& operator>> (std::istream &in, Fp2_model &el); +}; + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v); + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v); + +template& modulus> +Fp2_model operator*(const Fp_model &lhs, const Fp2_model &rhs); + +template& modulus> +bigint<2*n> Fp2_model::euler; + +template& modulus> +size_t Fp2_model::s; + +template& modulus> +bigint<2*n> Fp2_model::t; + +template& modulus> +bigint<2*n> Fp2_model::t_minus_1_over_2; + +template& modulus> +Fp_model Fp2_model::non_residue; + +template& modulus> +Fp2_model Fp2_model::nqr; + +template& modulus> +Fp2_model Fp2_model::nqr_to_t; + +template& modulus> +Fp_model Fp2_model::Frobenius_coeffs_c1[2]; + +} // libsnark +#include "algebra/fields/fp2.tcc" + +#endif // FP2_HPP_ diff --git a/src/algebra/fields/fp2.tcc b/src/algebra/fields/fp2.tcc new file mode 100644 index 00000000000..1632a04c79e --- /dev/null +++ b/src/algebra/fields/fp2.tcc @@ -0,0 +1,261 @@ +/** @file + ***************************************************************************** + Implementation of arithmetic in the finite field F[p^2]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP2_TCC_ +#define FP2_TCC_ + +#include "algebra/fields/field_utils.hpp" + +namespace libsnark { + +template& modulus> +Fp2_model Fp2_model::zero() +{ + return Fp2_model(my_Fp::zero(), my_Fp::zero()); +} + +template& modulus> +Fp2_model Fp2_model::one() +{ + return Fp2_model(my_Fp::one(), my_Fp::zero()); +} + +template& modulus> +Fp2_model Fp2_model::random_element() +{ + Fp2_model r; + r.c0 = my_Fp::random_element(); + r.c1 = my_Fp::random_element(); + + return r; +} + +template& modulus> +bool Fp2_model::operator==(const Fp2_model &other) const +{ + return (this->c0 == other.c0 && this->c1 == other.c1); +} + +template& modulus> +bool Fp2_model::operator!=(const Fp2_model &other) const +{ + return !(operator==(other)); +} + +template& modulus> +Fp2_model Fp2_model::operator+(const Fp2_model &other) const +{ + return Fp2_model(this->c0 + other.c0, + this->c1 + other.c1); +} + +template& modulus> +Fp2_model Fp2_model::operator-(const Fp2_model &other) const +{ + return Fp2_model(this->c0 - other.c0, + this->c1 - other.c1); +} + +template& modulus> +Fp2_model operator*(const Fp_model &lhs, const Fp2_model &rhs) +{ + return Fp2_model(lhs*rhs.c0, + lhs*rhs.c1); +} + +template& modulus> +Fp2_model Fp2_model::operator*(const Fp2_model &other) const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ + const my_Fp + &A = other.c0, &B = other.c1, + &a = this->c0, &b = this->c1; + const my_Fp aA = a * A; + const my_Fp bB = b * B; + + return Fp2_model(aA + non_residue * bB, + (a + b)*(A+B) - aA - bB); +} + +template& modulus> +Fp2_model Fp2_model::operator-() const +{ + return Fp2_model(-this->c0, + -this->c1); +} + +template& modulus> +Fp2_model Fp2_model::squared() const +{ + return squared_complex(); +} + +template& modulus> +Fp2_model Fp2_model::squared_karatsuba() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba squaring) */ + const my_Fp &a = this->c0, &b = this->c1; + const my_Fp asq = a.squared(); + const my_Fp bsq = b.squared(); + + return Fp2_model(asq + non_residue * bsq, + (a + b).squared() - asq - bsq); +} + +template& modulus> +Fp2_model Fp2_model::squared_complex() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Complex squaring) */ + const my_Fp &a = this->c0, &b = this->c1; + const my_Fp ab = a * b; + + return Fp2_model((a + b) * (a + non_residue * b) - ab - non_residue * ab, + ab + ab); +} + +template& modulus> +Fp2_model Fp2_model::inverse() const +{ + const my_Fp &a = this->c0, &b = this->c1; + + /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 8 */ + const my_Fp t0 = a.squared(); + const my_Fp t1 = b.squared(); + const my_Fp t2 = t0 - non_residue * t1; + const my_Fp t3 = t2.inverse(); + const my_Fp c0 = a * t3; + const my_Fp c1 = - (b * t3); + + return Fp2_model(c0, c1); +} + +template& modulus> +Fp2_model Fp2_model::Frobenius_map(unsigned long power) const +{ + return Fp2_model(c0, + Frobenius_coeffs_c1[power % 2] * c1); +} + +template& modulus> +Fp2_model Fp2_model::sqrt() const +{ + if (is_zero()) { + return *this; + } + + Fp2_model one = Fp2_model::one(); + + size_t v = Fp2_model::s; + Fp2_model z = Fp2_model::nqr_to_t; + Fp2_model w = (*this)^Fp2_model::t_minus_1_over_2; + Fp2_model x = (*this) * w; + Fp2_model b = x * w; // b = (*this)^t + + + // check if square with euler's criterion + Fp2_model check = b; + for (size_t i = 0; i < v-1; ++i) + { + check = check.squared(); + } + if (check != one) + { + assert_except(0); + } + + + // compute square root with Tonelli--Shanks + // (does not terminate if not a square!) + + while (b != one) + { + size_t m = 0; + Fp2_model b2m = b; + while (b2m != one) + { + /* invariant: b2m = b^(2^m) after entering this loop */ + b2m = b2m.squared(); + m += 1; + } + + int j = v-m-1; + w = z; + while (j > 0) + { + w = w.squared(); + --j; + } // w = z^2^(v-m-1) + + z = w.squared(); + b = b * z; + x = x * w; + v = m; + } + + return x; +} + +template& modulus> +template +Fp2_model Fp2_model::operator^(const bigint &pow) const +{ + return power, m>(*this, pow); +} + +template& modulus> +std::ostream& operator<<(std::ostream &out, const Fp2_model &el) +{ + out << el.c0 << OUTPUT_SEPARATOR << el.c1; + return out; +} + +template& modulus> +std::istream& operator>>(std::istream &in, Fp2_model &el) +{ + in >> el.c0 >> el.c1; + return in; +} + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v) +{ + out << v.size() << "\n"; + for (const Fp2_model& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v) +{ + v.clear(); + + size_t s; + in >> s; + + char b; + in.read(&b, 1); + + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + Fp2_model el; + in >> el; + v.emplace_back(el); + } + + return in; +} + +} // libsnark +#endif // FP2_TCC_ diff --git a/src/algebra/fields/fp3.hpp b/src/algebra/fields/fp3.hpp new file mode 100644 index 00000000000..53b178a276d --- /dev/null +++ b/src/algebra/fields/fp3.hpp @@ -0,0 +1,122 @@ +/** @file + ***************************************************************************** + Declaration of arithmetic in the finite field F[p^3]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP3_HPP_ +#define FP3_HPP_ +#include "algebra/fields/fp.hpp" +#include + +namespace libsnark { + +template& modulus> +class Fp3_model; + +template& modulus> +std::ostream& operator<<(std::ostream &, const Fp3_model &); + +template& modulus> +std::istream& operator>>(std::istream &, Fp3_model &); + +/** + * Arithmetic in the field F[p^3]. + * + * Let p := modulus. This interface provides arithmetic for the extension field + * Fp3 = Fp[U]/(U^3-non_residue), where non_residue is in Fp. + * + * ASSUMPTION: p = 1 (mod 6) + */ +template& modulus> +class Fp3_model { +public: + typedef Fp_model my_Fp; + + static bigint<3*n> euler; // (modulus^3-1)/2 + static size_t s; // modulus^3 = 2^s * t + 1 + static bigint<3*n> t; // with t odd + static bigint<3*n> t_minus_1_over_2; // (t-1)/2 + static my_Fp non_residue; // X^6-non_residue irreducible over Fp; used for constructing Fp3 = Fp[X] / (X^3 - non_residue) + static Fp3_model nqr; // a quadratic nonresidue in Fp3 + static Fp3_model nqr_to_t; // nqr^t + static my_Fp Frobenius_coeffs_c1[3]; // non_residue^((modulus^i-1)/3) for i=0,1,2 + static my_Fp Frobenius_coeffs_c2[3]; // non_residue^((2*modulus^i-2)/3) for i=0,1,2 + + my_Fp c0, c1, c2; + Fp3_model() {}; + Fp3_model(const my_Fp& c0, const my_Fp& c1, const my_Fp& c2) : c0(c0), c1(c1), c2(c2) {}; + + void clear() { c0.clear(); c1.clear(); c2.clear(); } + void print() const { printf("c0/c1/c2:\n"); c0.print(); c1.print(); c2.print(); } + + static Fp3_model zero(); + static Fp3_model one(); + static Fp3_model random_element(); + + bool is_zero() const { return c0.is_zero() && c1.is_zero() && c2.is_zero(); } + bool operator==(const Fp3_model &other) const; + bool operator!=(const Fp3_model &other) const; + + Fp3_model operator+(const Fp3_model &other) const; + Fp3_model operator-(const Fp3_model &other) const; + Fp3_model operator*(const Fp3_model &other) const; + Fp3_model operator-() const; + Fp3_model squared() const; + Fp3_model inverse() const; + Fp3_model Frobenius_map(unsigned long power) const; + Fp3_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate) + + template + Fp3_model operator^(const bigint &other) const; + + static size_t size_in_bits() { return 3*my_Fp::size_in_bits(); } + static bigint base_field_char() { return modulus; } + + friend std::ostream& operator<< (std::ostream &out, const Fp3_model &el); + friend std::istream& operator>> (std::istream &in, Fp3_model &el); +}; + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v); + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v); + +template& modulus> +Fp3_model operator*(const Fp_model &lhs, const Fp3_model &rhs); + +template& modulus> +bigint<3*n> Fp3_model::euler; + +template& modulus> +size_t Fp3_model::s; + +template& modulus> +bigint<3*n> Fp3_model::t; + +template& modulus> +bigint<3*n> Fp3_model::t_minus_1_over_2; + +template& modulus> +Fp_model Fp3_model::non_residue; + +template& modulus> +Fp3_model Fp3_model::nqr; + +template& modulus> +Fp3_model Fp3_model::nqr_to_t; + +template& modulus> +Fp_model Fp3_model::Frobenius_coeffs_c1[3]; + +template& modulus> +Fp_model Fp3_model::Frobenius_coeffs_c2[3]; + +} // libsnark +#include "algebra/fields/fp3.tcc" + +#endif // FP3_HPP_ diff --git a/src/algebra/fields/fp3.tcc b/src/algebra/fields/fp3.tcc new file mode 100644 index 00000000000..590a2a98729 --- /dev/null +++ b/src/algebra/fields/fp3.tcc @@ -0,0 +1,259 @@ +/** @file + ***************************************************************************** + Implementation of arithmetic in the finite field F[p^3]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP3_TCC_ +#define FP3_TCC_ + +#include "algebra/fields/field_utils.hpp" + +namespace libsnark { + +template& modulus> +Fp3_model Fp3_model::zero() +{ + return Fp3_model(my_Fp::zero(), my_Fp::zero(), my_Fp::zero()); +} + +template& modulus> +Fp3_model Fp3_model::one() +{ + return Fp3_model(my_Fp::one(), my_Fp::zero(), my_Fp::zero()); +} + +template& modulus> +Fp3_model Fp3_model::random_element() +{ + Fp3_model r; + r.c0 = my_Fp::random_element(); + r.c1 = my_Fp::random_element(); + r.c2 = my_Fp::random_element(); + + return r; +} + +template& modulus> +bool Fp3_model::operator==(const Fp3_model &other) const +{ + return (this->c0 == other.c0 && this->c1 == other.c1 && this->c2 == other.c2); +} + +template& modulus> +bool Fp3_model::operator!=(const Fp3_model &other) const +{ + return !(operator==(other)); +} + +template& modulus> +Fp3_model Fp3_model::operator+(const Fp3_model &other) const +{ + return Fp3_model(this->c0 + other.c0, + this->c1 + other.c1, + this->c2 + other.c2); +} + +template& modulus> +Fp3_model Fp3_model::operator-(const Fp3_model &other) const +{ + return Fp3_model(this->c0 - other.c0, + this->c1 - other.c1, + this->c2 - other.c2); +} + +template& modulus> +Fp3_model operator*(const Fp_model &lhs, const Fp3_model &rhs) +{ + return Fp3_model(lhs*rhs.c0, + lhs*rhs.c1, + lhs*rhs.c2); +} + +template& modulus> +Fp3_model Fp3_model::operator*(const Fp3_model &other) const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (Karatsuba) */ + const my_Fp + &A = other.c0, &B = other.c1, &C = other.c2, + &a = this->c0, &b = this->c1, &c = this->c2; + const my_Fp aA = a*A; + const my_Fp bB = b*B; + const my_Fp cC = c*C; + + return Fp3_model(aA + non_residue*((b+c)*(B+C)-bB-cC), + (a+b)*(A+B)-aA-bB+non_residue*cC, + (a+c)*(A+C)-aA+bB-cC); +} + +template& modulus> +Fp3_model Fp3_model::operator-() const +{ + return Fp3_model(-this->c0, + -this->c1, + -this->c2); +} + +template& modulus> +Fp3_model Fp3_model::squared() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (CH-SQR2) */ + const my_Fp + &a = this->c0, &b = this->c1, &c = this->c2; + const my_Fp s0 = a.squared(); + const my_Fp ab = a*b; + const my_Fp s1 = ab + ab; + const my_Fp s2 = (a - b + c).squared(); + const my_Fp bc = b*c; + const my_Fp s3 = bc + bc; + const my_Fp s4 = c.squared(); + + return Fp3_model(s0 + non_residue * s3, + s1 + non_residue * s4, + s1 + s2 + s3 - s0 - s4); +} + +template& modulus> +Fp3_model Fp3_model::inverse() const +{ + const my_Fp + &a = this->c0, &b = this->c1, &c = this->c2; + + /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 17 */ + const my_Fp t0 = a.squared(); + const my_Fp t1 = b.squared(); + const my_Fp t2 = c.squared(); + const my_Fp t3 = a*b; + const my_Fp t4 = a*c; + const my_Fp t5 = b*c; + const my_Fp c0 = t0 - non_residue * t5; + const my_Fp c1 = non_residue * t2 - t3; + const my_Fp c2 = t1 - t4; // typo in paper referenced above. should be "-" as per Scott, but is "*" + const my_Fp t6 = (a * c0 + non_residue * (c * c1 + b * c2)).inverse(); + return Fp3_model(t6 * c0, t6 * c1, t6 * c2); +} + +template& modulus> +Fp3_model Fp3_model::Frobenius_map(unsigned long power) const +{ + return Fp3_model(c0, + Frobenius_coeffs_c1[power % 3] * c1, + Frobenius_coeffs_c2[power % 3] * c2); +} + +template& modulus> +Fp3_model Fp3_model::sqrt() const +{ + Fp3_model one = Fp3_model::one(); + + size_t v = Fp3_model::s; + Fp3_model z = Fp3_model::nqr_to_t; + Fp3_model w = (*this)^Fp3_model::t_minus_1_over_2; + Fp3_model x = (*this) * w; + Fp3_model b = x * w; // b = (*this)^t + +#if DEBUG + // check if square with euler's criterion + Fp3_model check = b; + for (size_t i = 0; i < v-1; ++i) + { + check = check.squared(); + } + if (check != one) + { + assert(0); + } +#endif + + // compute square root with Tonelli--Shanks + // (does not terminate if not a square!) + + while (b != one) + { + size_t m = 0; + Fp3_model b2m = b; + while (b2m != one) + { + /* invariant: b2m = b^(2^m) after entering this loop */ + b2m = b2m.squared(); + m += 1; + } + + int j = v-m-1; + w = z; + while (j > 0) + { + w = w.squared(); + --j; + } // w = z^2^(v-m-1) + + z = w.squared(); + b = b * z; + x = x * w; + v = m; + } + + return x; +} + +template& modulus> +template +Fp3_model Fp3_model::operator^(const bigint &pow) const +{ + return power >(*this, pow); +} + +template& modulus> +std::ostream& operator<<(std::ostream &out, const Fp3_model &el) +{ + out << el.c0 << OUTPUT_SEPARATOR << el.c1 << OUTPUT_SEPARATOR << el.c2; + return out; +} + +template& modulus> +std::istream& operator>>(std::istream &in, Fp3_model &el) +{ + in >> el.c0 >> el.c1 >> el.c2; + return in; +} + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v) +{ + out << v.size() << "\n"; + for (const Fp3_model& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v) +{ + v.clear(); + + size_t s; + in >> s; + + char b; + in.read(&b, 1); + + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + Fp3_model el; + in >> el; + v.emplace_back(el); + } + + return in; +} + +} // libsnark +#endif // FP3_TCC_ diff --git a/src/algebra/fields/fp6_3over2.hpp b/src/algebra/fields/fp6_3over2.hpp new file mode 100644 index 00000000000..335d61c5341 --- /dev/null +++ b/src/algebra/fields/fp6_3over2.hpp @@ -0,0 +1,104 @@ +/** @file + ***************************************************************************** + Declaration of arithmetic in the finite field F[(p^2)^3] + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP6_3OVER2_HPP_ +#define FP6_3OVER2_HPP_ +#include "algebra/fields/fp.hpp" +#include "algebra/fields/fp2.hpp" +#include + +namespace libsnark { + +template& modulus> +class Fp6_3over2_model; + +template& modulus> +std::ostream& operator<<(std::ostream &, const Fp6_3over2_model &); + +template& modulus> +std::istream& operator>>(std::istream &, Fp6_3over2_model &); + +/** + * Arithmetic in the finite field F[(p^2)^3]. + * + * Let p := modulus. This interface provides arithmetic for the extension field + * Fp6 = Fp2[V]/(V^3-non_residue) where non_residue is in Fp. + * + * ASSUMPTION: p = 1 (mod 6) + */ +template& modulus> +class Fp6_3over2_model { +public: + typedef Fp_model my_Fp; + typedef Fp2_model my_Fp2; + + static my_Fp2 non_residue; + static my_Fp2 Frobenius_coeffs_c1[6]; // non_residue^((modulus^i-1)/3) for i=0,1,2,3,4,5 + static my_Fp2 Frobenius_coeffs_c2[6]; // non_residue^((2*modulus^i-2)/3) for i=0,1,2,3,4,5 + + my_Fp2 c0, c1, c2; + Fp6_3over2_model() {}; + Fp6_3over2_model(const my_Fp2& c0, const my_Fp2& c1, const my_Fp2& c2) : c0(c0), c1(c1), c2(c2) {}; + + void clear() { c0.clear(); c1.clear(); c2.clear(); } + void print() const { printf("c0/c1/c2:\n"); c0.print(); c1.print(); c2.print(); } + + static Fp6_3over2_model zero(); + static Fp6_3over2_model one(); + static Fp6_3over2_model random_element(); + + bool is_zero() const { return c0.is_zero() && c1.is_zero() && c2.is_zero(); } + bool operator==(const Fp6_3over2_model &other) const; + bool operator!=(const Fp6_3over2_model &other) const; + + Fp6_3over2_model operator+(const Fp6_3over2_model &other) const; + Fp6_3over2_model operator-(const Fp6_3over2_model &other) const; + Fp6_3over2_model operator*(const Fp6_3over2_model &other) const; + Fp6_3over2_model operator-() const; + Fp6_3over2_model squared() const; + Fp6_3over2_model inverse() const; + Fp6_3over2_model Frobenius_map(unsigned long power) const; + + static my_Fp2 mul_by_non_residue(const my_Fp2 &elt); + + template + Fp6_3over2_model operator^(const bigint &other) const; + + static bigint base_field_char() { return modulus; } + static size_t extension_degree() { return 6; } + + friend std::ostream& operator<< (std::ostream &out, const Fp6_3over2_model &el); + friend std::istream& operator>> (std::istream &in, Fp6_3over2_model &el); +}; + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v); + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v); + +template& modulus> +Fp6_3over2_model operator*(const Fp_model &lhs, const Fp6_3over2_model &rhs); + +template& modulus> +Fp6_3over2_model operator*(const Fp2_model &lhs, const Fp6_3over2_model &rhs); + +template& modulus> +Fp2_model Fp6_3over2_model::non_residue; + +template& modulus> +Fp2_model Fp6_3over2_model::Frobenius_coeffs_c1[6]; + +template& modulus> +Fp2_model Fp6_3over2_model::Frobenius_coeffs_c2[6]; + +} // libsnark +#include "algebra/fields/fp6_3over2.tcc" + +#endif // FP6_3OVER2_HPP_ diff --git a/src/algebra/fields/fp6_3over2.tcc b/src/algebra/fields/fp6_3over2.tcc new file mode 100644 index 00000000000..f4fffde04a7 --- /dev/null +++ b/src/algebra/fields/fp6_3over2.tcc @@ -0,0 +1,216 @@ +/** @file + ***************************************************************************** + Implementation of arithmetic in the finite field F[(p^2)^3]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP6_3OVER2_TCC_ +#define FP6_3OVER2_TCC_ +#include "algebra/fields/field_utils.hpp" + +namespace libsnark { + +template& modulus> +Fp2_model Fp6_3over2_model::mul_by_non_residue(const Fp2_model &elt) +{ + return Fp2_model(non_residue * elt); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::zero() +{ + return Fp6_3over2_model(my_Fp2::zero(), my_Fp2::zero(), my_Fp2::zero()); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::one() +{ + return Fp6_3over2_model(my_Fp2::one(), my_Fp2::zero(), my_Fp2::zero()); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::random_element() +{ + Fp6_3over2_model r; + r.c0 = my_Fp2::random_element(); + r.c1 = my_Fp2::random_element(); + r.c2 = my_Fp2::random_element(); + + return r; +} + +template& modulus> +bool Fp6_3over2_model::operator==(const Fp6_3over2_model &other) const +{ + return (this->c0 == other.c0 && this->c1 == other.c1 && this->c2 == other.c2); +} + +template& modulus> +bool Fp6_3over2_model::operator!=(const Fp6_3over2_model &other) const +{ + return !(operator==(other)); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::operator+(const Fp6_3over2_model &other) const +{ + return Fp6_3over2_model(this->c0 + other.c0, + this->c1 + other.c1, + this->c2 + other.c2); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::operator-(const Fp6_3over2_model &other) const +{ + return Fp6_3over2_model(this->c0 - other.c0, + this->c1 - other.c1, + this->c2 - other.c2); +} + +template& modulus> +Fp6_3over2_model operator*(const Fp_model &lhs, const Fp6_3over2_model &rhs) +{ + return Fp6_3over2_model(lhs*rhs.c0, + lhs*rhs.c1, + lhs*rhs.c2); +} + +template& modulus> +Fp6_3over2_model operator*(const Fp2_model &lhs, const Fp6_3over2_model &rhs) +{ + return Fp6_3over2_model(lhs*rhs.c0, + lhs*rhs.c1, + lhs*rhs.c2); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::operator*(const Fp6_3over2_model &other) const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (Karatsuba) */ + + const my_Fp2 &A = other.c0, &B = other.c1, &C = other.c2, + &a = this->c0, &b = this->c1, &c = this->c2; + const my_Fp2 aA = a*A; + const my_Fp2 bB = b*B; + const my_Fp2 cC = c*C; + + return Fp6_3over2_model(aA + Fp6_3over2_model::mul_by_non_residue((b+c)*(B+C)-bB-cC), + (a+b)*(A+B)-aA-bB+Fp6_3over2_model::mul_by_non_residue(cC), + (a+c)*(A+C)-aA+bB-cC); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::operator-() const +{ + return Fp6_3over2_model(-this->c0, + -this->c1, + -this->c2); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::squared() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (CH-SQR2) */ + + const my_Fp2 &a = this->c0, &b = this->c1, &c = this->c2; + const my_Fp2 s0 = a.squared(); + const my_Fp2 ab = a*b; + const my_Fp2 s1 = ab + ab; + const my_Fp2 s2 = (a - b + c).squared(); + const my_Fp2 bc = b*c; + const my_Fp2 s3 = bc + bc; + const my_Fp2 s4 = c.squared(); + + return Fp6_3over2_model(s0 + Fp6_3over2_model::mul_by_non_residue(s3), + s1 + Fp6_3over2_model::mul_by_non_residue(s4), + s1 + s2 + s3 - s0 - s4); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::inverse() const +{ + /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 17 */ + + const my_Fp2 &a = this->c0, &b = this->c1, &c = this->c2; + const my_Fp2 t0 = a.squared(); + const my_Fp2 t1 = b.squared(); + const my_Fp2 t2 = c.squared(); + const my_Fp2 t3 = a*b; + const my_Fp2 t4 = a*c; + const my_Fp2 t5 = b*c; + const my_Fp2 c0 = t0 - Fp6_3over2_model::mul_by_non_residue(t5); + const my_Fp2 c1 = Fp6_3over2_model::mul_by_non_residue(t2) - t3; + const my_Fp2 c2 = t1 - t4; // typo in paper referenced above. should be "-" as per Scott, but is "*" + const my_Fp2 t6 = (a * c0 + Fp6_3over2_model::mul_by_non_residue((c * c1 + b * c2))).inverse(); + return Fp6_3over2_model(t6 * c0, t6 * c1, t6 * c2); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::Frobenius_map(unsigned long power) const +{ + return Fp6_3over2_model(c0.Frobenius_map(power), + Frobenius_coeffs_c1[power % 6] * c1.Frobenius_map(power), + Frobenius_coeffs_c2[power % 6] * c2.Frobenius_map(power)); +} + +template& modulus> +template +Fp6_3over2_model Fp6_3over2_model::operator^(const bigint &pow) const +{ + return power, m>(*this, pow); +} + +template& modulus> +std::ostream& operator<<(std::ostream &out, const Fp6_3over2_model &el) +{ + out << el.c0 << OUTPUT_SEPARATOR << el.c1 << OUTPUT_SEPARATOR << el.c2; + return out; +} + +template& modulus> +std::istream& operator>>(std::istream &in, Fp6_3over2_model &el) +{ + in >> el.c0 >> el.c1 >> el.c2; + return in; +} + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v) +{ + out << v.size() << "\n"; + for (const Fp6_3over2_model& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v) +{ + v.clear(); + + size_t s; + in >> s; + + char b; + in.read(&b, 1); + + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + Fp6_3over2_model el; + in >> el; + v.emplace_back(el); + } + + return in; +} + +} // libsnark +#endif // FP6_3_OVER_2_TCC_ diff --git a/src/algebra/fields/fp_aux.tcc b/src/algebra/fields/fp_aux.tcc new file mode 100644 index 00000000000..7f8a3eadff6 --- /dev/null +++ b/src/algebra/fields/fp_aux.tcc @@ -0,0 +1,389 @@ +/** @file + ***************************************************************************** + Assembly code snippets for F[p] finite field arithmetic, used by fp.tcc . + Specific to x86-64, and used only if USE_ASM is defined. + On other architectures or without USE_ASM, fp.tcc uses a portable + C++ implementation instead. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP_AUX_TCC_ +#define FP_AUX_TCC_ + +namespace libsnark { + +#define STR_HELPER(x) #x +#define STR(x) STR_HELPER(x) + +/* addq is faster than adcq, even if preceded by clc */ +#define ADD_FIRSTADD \ + "movq (%[B]), %%rax \n\t" \ + "addq %%rax, (%[A]) \n\t" + +#define ADD_NEXTADD(ofs) \ + "movq " STR(ofs) "(%[B]), %%rax \n\t" \ + "adcq %%rax, " STR(ofs) "(%[A]) \n\t" + +#define ADD_CMP(ofs) \ + "movq " STR(ofs) "(%[mod]), %%rax \n\t" \ + "cmpq %%rax, " STR(ofs) "(%[A]) \n\t" \ + "jb done%= \n\t" \ + "ja subtract%= \n\t" + +#define ADD_FIRSTSUB \ + "movq (%[mod]), %%rax \n\t" \ + "subq %%rax, (%[A]) \n\t" + +#define ADD_FIRSTSUB \ + "movq (%[mod]), %%rax \n\t" \ + "subq %%rax, (%[A]) \n\t" + +#define ADD_NEXTSUB(ofs) \ + "movq " STR(ofs) "(%[mod]), %%rax \n\t" \ + "sbbq %%rax, " STR(ofs) "(%[A]) \n\t" + +#define SUB_FIRSTSUB \ + "movq (%[B]), %%rax\n\t" \ + "subq %%rax, (%[A])\n\t" + +#define SUB_NEXTSUB(ofs) \ + "movq " STR(ofs) "(%[B]), %%rax\n\t" \ + "sbbq %%rax, " STR(ofs) "(%[A])\n\t" + +#define SUB_FIRSTADD \ + "movq (%[mod]), %%rax\n\t" \ + "addq %%rax, (%[A])\n\t" + +#define SUB_NEXTADD(ofs) \ + "movq " STR(ofs) "(%[mod]), %%rax\n\t" \ + "adcq %%rax, " STR(ofs) "(%[A])\n\t" + +#define MONT_CMP(ofs) \ + "movq " STR(ofs) "(%[M]), %%rax \n\t" \ + "cmpq %%rax, " STR(ofs) "(%[tmp]) \n\t" \ + "jb done%= \n\t" \ + "ja subtract%= \n\t" + +#define MONT_FIRSTSUB \ + "movq (%[M]), %%rax \n\t" \ + "subq %%rax, (%[tmp]) \n\t" + +#define MONT_NEXTSUB(ofs) \ + "movq " STR(ofs) "(%[M]), %%rax \n\t" \ + "sbbq %%rax, " STR(ofs) "(%[tmp]) \n\t" + +/* + The x86-64 Montgomery multiplication here is similar + to Algorithm 2 (CIOS method) in http://eprint.iacr.org/2012/140.pdf + and the PowerPC pseudocode of gmp-ecm library (c) Paul Zimmermann and Alexander Kruppa + (see comments on top of powerpc64/mulredc.m4). +*/ + +#define MONT_PRECOMPUTE \ + "xorq %[cy], %[cy] \n\t" \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq 0(%[B]) \n\t" \ + "movq %%rax, %[T0] \n\t" \ + "movq %%rdx, %[T1] # T1:T0 <- A[0] * B[0] \n\t" \ + "mulq %[inv] \n\t" \ + "movq %%rax, %[u] # u <- T0 * inv \n\t" \ + "mulq 0(%[M]) \n\t" \ + "addq %[T0], %%rax \n\t" \ + "adcq %%rdx, %[T1] \n\t" \ + "adcq $0, %[cy] # cy:T1 <- (M[0]*u + T1 * b + T0) / b\n\t" + +#define MONT_FIRSTITER(j) \ + "xorq %[T0], %[T0] \n\t" \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq " STR((j*8)) "(%[B]) \n\t" \ + "addq %[T1], %%rax \n\t" \ + "movq %%rax, " STR(((j-1)*8)) "(%[tmp]) \n\t" \ + "adcq $0, %%rdx \n\t" \ + "movq %%rdx, %[T1] # now T1:tmp[j-1] <-- X[0] * Y[j] + T1\n\t" \ + "movq " STR((j*8)) "(%[M]), %%rax \n\t" \ + "mulq %[u] \n\t" \ + "addq %%rax, " STR(((j-1)*8)) "(%[tmp]) \n\t" \ + "adcq %[cy], %%rdx \n\t" \ + "adcq $0, %[T0] \n\t" \ + "xorq %[cy], %[cy] \n\t" \ + "addq %%rdx, %[T1] \n\t" \ + "adcq %[T0], %[cy] # cy:T1:tmp[j-1] <---- (X[0] * Y[j] + T1) + (M[j] * u + cy * b) \n\t" + +#define MONT_ITERFIRST(i) \ + "xorq %[cy], %[cy] \n\t" \ + "movq " STR((i*8)) "(%[A]), %%rax \n\t" \ + "mulq 0(%[B]) \n\t" \ + "addq 0(%[tmp]), %%rax \n\t" \ + "adcq 8(%[tmp]), %%rdx \n\t" \ + "adcq $0, %[cy] \n\t" \ + "movq %%rax, %[T0] \n\t" \ + "movq %%rdx, %[T1] # cy:T1:T0 <- A[i] * B[0] + tmp[1] * b + tmp[0]\n\t" \ + "mulq %[inv] \n\t" \ + "movq %%rax, %[u] # u <- T0 * inv\n\t" \ + "mulq 0(%[M]) \n\t" \ + "addq %[T0], %%rax \n\t" \ + "adcq %%rdx, %[T1] \n\t" \ + "adcq $0, %[cy] # cy:T1 <- (M[0]*u + cy * b * b + T1 * b + T0) / b\n\t" + +#define MONT_ITERITER(i, j) \ + "xorq %[T0], %[T0] \n\t" \ + "movq " STR((i*8)) "(%[A]), %%rax \n\t" \ + "mulq " STR((j*8)) "(%[B]) \n\t" \ + "addq %[T1], %%rax \n\t" \ + "movq %%rax, " STR(((j-1)*8)) "(%[tmp]) \n\t" \ + "adcq $0, %%rdx \n\t" \ + "movq %%rdx, %[T1] # now T1:tmp[j-1] <-- X[i] * Y[j] + T1 \n\t" \ + "movq " STR((j*8)) "(%[M]), %%rax \n\t" \ + "mulq %[u] \n\t" \ + "addq %%rax, " STR(((j-1)*8)) "(%[tmp]) \n\t" \ + "adcq %[cy], %%rdx \n\t" \ + "adcq $0, %[T0] \n\t" \ + "xorq %[cy], %[cy] \n\t" \ + "addq %%rdx, %[T1] \n\t" \ + "adcq %[T0], %[cy] # cy:T1:tmp[j-1] <-- (X[i] * Y[j] + T1) + M[j] * u + cy * b \n\t" \ + "addq " STR(((j+1)*8)) "(%[tmp]), %[T1] \n\t" \ + "adcq $0, %[cy] # cy:T1:tmp[j-1] <-- (X[i] * Y[j] + T1) + M[j] * u + (tmp[j+1] + cy) * b \n\t" + +#define MONT_FINALIZE(j) \ + "movq %[T1], " STR((j*8)) "(%[tmp]) \n\t" \ + "movq %[cy], " STR(((j+1)*8)) "(%[tmp]) \n\t" + +/* + Comba multiplication and squaring routines are based on the + public-domain tomsfastmath library by Tom St Denis + + + + Compared to the above, we save 5-20% of cycles by using careful register + renaming to implement Comba forward operation. + */ + +#define COMBA_3_BY_3_MUL(c0_, c1_, c2_, res_, A_, B_) \ + asm volatile ( \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq 0(%[B]) \n\t" \ + "movq %%rax, 0(%[res]) \n\t" \ + "movq %%rdx, %[c0] \n\t" \ + \ + "xorq %[c1], %[c1] \n\t" \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq 8(%[B]) \n\t" \ + "addq %%rax, %[c0] \n\t" \ + "adcq %%rdx, %[c1] \n\t" \ + \ + "xorq %[c2], %[c2] \n\t" \ + "movq 8(%[A]), %%rax \n\t" \ + "mulq 0(%[B]) \n\t" \ + "addq %%rax, %[c0] \n\t" \ + "movq %[c0], 8(%[res]) \n\t" \ + "adcq %%rdx, %[c1] \n\t" \ + "adcq $0, %[c2] \n\t" \ + \ + "// register renaming (c1, c2, c0)\n\t" \ + "xorq %[c0], %[c0] \n\t" \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq 16(%[B]) \n\t" \ + "addq %%rax, %[c1] \n\t" \ + "adcq %%rdx, %[c2] \n\t" \ + "adcq $0, %[c0] \n\t" \ + \ + "movq 8(%[A]), %%rax \n\t" \ + "mulq 8(%[B]) \n\t" \ + "addq %%rax, %[c1] \n\t" \ + "adcq %%rdx, %[c2] \n\t" \ + "adcq $0, %[c0] \n\t" \ + \ + "movq 16(%[A]), %%rax \n\t" \ + "mulq 0(%[B]) \n\t" \ + "addq %%rax, %[c1] \n\t" \ + "movq %[c1], 16(%[res]) \n\t" \ + "adcq %%rdx, %[c2] \n\t" \ + "adcq $0, %[c0] \n\t" \ + \ + "// register renaming (c2, c0, c1)\n\t" \ + "xorq %[c1], %[c1] \n\t" \ + "movq 8(%[A]), %%rax \n\t" \ + "mulq 16(%[B]) \n\t" \ + "addq %%rax, %[c2] \n\t" \ + "adcq %%rdx, %[c0] \n\t" \ + "adcq $0, %[c1] \n\t" \ + \ + "movq 16(%[A]), %%rax \n\t" \ + "mulq 8(%[B]) \n\t" \ + "addq %%rax, %[c2] \n\t" \ + "movq %[c2], 24(%[res]) \n\t" \ + "adcq %%rdx, %[c0] \n\t" \ + "adcq $0, %[c1] \n\t" \ + \ + "// register renaming (c0, c1, c2)\n\t" \ + "xorq %[c2], %[c2] \n\t" \ + "movq 16(%[A]), %%rax \n\t" \ + "mulq 16(%[B]) \n\t" \ + "addq %%rax, %[c0] \n\t" \ + "movq %[c0], 32(%[res]) \n\t" \ + "adcq %%rdx, %[c1] \n\t" \ + "movq %[c1], 40(%[res]) \n\t" \ + : [c0] "=&r" (c0_), [c1] "=&r" (c1_), [c2] "=&r" (c2_) \ + : [res] "r" (res_), [A] "r" (A_), [B] "r" (B_) \ + : "%rax", "%rdx", "cc", "memory") + +#define COMBA_3_BY_3_SQR(c0_, c1_, c2_, res_, A_) \ + asm volatile ( \ + "xorq %[c1], %[c1] \n\t" \ + "xorq %[c2], %[c2] \n\t" \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq %%rax \n\t" \ + "movq %%rax, 0(%[res]) \n\t" \ + "movq %%rdx, %[c0] \n\t" \ + \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq 8(%[A]) \n\t" \ + "addq %%rax, %[c0] \n\t" \ + "adcq %%rdx, %[c1] \n\t" \ + "addq %%rax, %[c0] \n\t" \ + "movq %[c0], 8(%[res]) \n\t" \ + "adcq %%rdx, %[c1] \n\t" \ + "adcq $0, %[c2] \n\t" \ + \ + "// register renaming (c1, c2, c0)\n\t" \ + "movq 0(%[A]), %%rax \n\t" \ + "xorq %[c0], %[c0] \n\t" \ + "mulq 16(%[A]) \n\t" \ + "addq %%rax, %[c1] \n\t" \ + "adcq %%rdx, %[c2] \n\t" \ + "adcq $0, %[c0] \n\t" \ + "addq %%rax, %[c1] \n\t" \ + "adcq %%rdx, %[c2] \n\t" \ + "adcq $0, %[c0] \n\t" \ + \ + "movq 8(%[A]), %%rax \n\t" \ + "mulq %%rax \n\t" \ + "addq %%rax, %[c1] \n\t" \ + "movq %[c1], 16(%[res]) \n\t" \ + "adcq %%rdx, %[c2] \n\t" \ + "adcq $0, %[c0] \n\t" \ + \ + "// register renaming (c2, c0, c1)\n\t" \ + "movq 8(%[A]), %%rax \n\t" \ + "xorq %[c1], %[c1] \n\t" \ + "mulq 16(%[A]) \n\t" \ + "addq %%rax, %[c2] \n\t" \ + "adcq %%rdx, %[c0] \n\t" \ + "adcq $0, %[c1] \n\t" \ + "addq %%rax, %[c2] \n\t" \ + "movq %[c2], 24(%[res]) \n\t" \ + "adcq %%rdx, %[c0] \n\t" \ + "adcq $0, %[c1] \n\t" \ + \ + "// register renaming (c0, c1, c2)\n\t" \ + "movq 16(%[A]), %%rax \n\t" \ + "mulq %%rax \n\t" \ + "addq %%rax, %[c0] \n\t" \ + "movq %[c0], 32(%[res]) \n\t" \ + "adcq %%rdx, %[c1] \n\t" \ + "movq %[c1], 40(%[res]) \n\t" \ + \ + : [c0] "=&r" (c0_), [c1] "=&r" (c1_), [c2] "=&r" (c2_) \ + : [res] "r" (res_), [A] "r" (A_) \ + : "%rax", "%rdx", "cc", "memory") + +/* + The Montgomery reduction here is based on Algorithm 14.32 in + Handbook of Applied Cryptography + . + */ +#define REDUCE_6_LIMB_PRODUCT(k_, tmp1_, tmp2_, tmp3_, inv_, res_, mod_) \ + __asm__ volatile \ + ("///////////////////////////////////\n\t" \ + "movq 0(%[res]), %%rax \n\t" \ + "mulq %[modprime] \n\t" \ + "movq %%rax, %[k] \n\t" \ + \ + "movq (%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "movq %%rax, %[tmp1] \n\t" \ + "movq %%rdx, %[tmp2] \n\t" \ + \ + "xorq %[tmp3], %[tmp3] \n\t" \ + "movq 8(%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "addq %[tmp1], 0(%[res]) \n\t" \ + "adcq %%rax, %[tmp2] \n\t" \ + "adcq %%rdx, %[tmp3] \n\t" \ + \ + "xorq %[tmp1], %[tmp1] \n\t" \ + "movq 16(%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "addq %[tmp2], 8(%[res]) \n\t" \ + "adcq %%rax, %[tmp3] \n\t" \ + "adcq %%rdx, %[tmp1] \n\t" \ + \ + "addq %[tmp3], 16(%[res]) \n\t" \ + "adcq %[tmp1], 24(%[res]) \n\t" \ + "adcq $0, 32(%[res]) \n\t" \ + "adcq $0, 40(%[res]) \n\t" \ + \ + "///////////////////////////////////\n\t" \ + "movq 8(%[res]), %%rax \n\t" \ + "mulq %[modprime] \n\t" \ + "movq %%rax, %[k] \n\t" \ + \ + "movq (%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "movq %%rax, %[tmp1] \n\t" \ + "movq %%rdx, %[tmp2] \n\t" \ + \ + "xorq %[tmp3], %[tmp3] \n\t" \ + "movq 8(%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "addq %[tmp1], 8(%[res]) \n\t" \ + "adcq %%rax, %[tmp2] \n\t" \ + "adcq %%rdx, %[tmp3] \n\t" \ + \ + "xorq %[tmp1], %[tmp1] \n\t" \ + "movq 16(%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "addq %[tmp2], 16(%[res]) \n\t" \ + "adcq %%rax, %[tmp3] \n\t" \ + "adcq %%rdx, %[tmp1] \n\t" \ + \ + "addq %[tmp3], 24(%[res]) \n\t" \ + "adcq %[tmp1], 32(%[res]) \n\t" \ + "adcq $0, 40(%[res]) \n\t" \ + \ + "///////////////////////////////////\n\t" \ + "movq 16(%[res]), %%rax \n\t" \ + "mulq %[modprime] \n\t" \ + "movq %%rax, %[k] \n\t" \ + \ + "movq (%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "movq %%rax, %[tmp1] \n\t" \ + "movq %%rdx, %[tmp2] \n\t" \ + \ + "xorq %[tmp3], %[tmp3] \n\t" \ + "movq 8(%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "addq %[tmp1], 16(%[res]) \n\t" \ + "adcq %%rax, %[tmp2] \n\t" \ + "adcq %%rdx, %[tmp3] \n\t" \ + \ + "xorq %[tmp1], %[tmp1] \n\t" \ + "movq 16(%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "addq %[tmp2], 24(%[res]) \n\t" \ + "adcq %%rax, %[tmp3] \n\t" \ + "adcq %%rdx, %[tmp1] \n\t" \ + \ + "addq %[tmp3], 32(%[res]) \n\t" \ + "adcq %[tmp1], 40(%[res]) \n\t" \ + : [k] "=&r" (k_), [tmp1] "=&r" (tmp1_), [tmp2] "=&r" (tmp2_), [tmp3] "=&r" (tmp3_) \ + : [modprime] "r" (inv_), [res] "r" (res_), [mod] "r" (mod_) \ + : "%rax", "%rdx", "cc", "memory") + +} // libsnark +#endif // FP_AUX_TCC_ diff --git a/src/algebra/fields/tests/test_bigint.cpp b/src/algebra/fields/tests/test_bigint.cpp new file mode 100644 index 00000000000..b66aae0a3e4 --- /dev/null +++ b/src/algebra/fields/tests/test_bigint.cpp @@ -0,0 +1,107 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/fields/bigint.hpp" + +using namespace libsnark; + +void test_bigint() +{ + static_assert(ULONG_MAX == 0xFFFFFFFFFFFFFFFFul, "unsigned long not 64-bit"); + static_assert(GMP_NUMB_BITS == 64, "GMP limb not 64-bit"); + + const char *b1_decimal = "76749407"; + const char *b2_decimal = "435020359732196472065729437602"; + const char *b3_decimal = "33387554642372758038536799358397002014"; + const char *b2_binary = "0000000000000000000000000000010101111101101000000110100001011010" + "1101101010001001000001101000101000100110011001110001111110100010"; + + bigint<1> b0 = bigint<1>(0ul); + bigint<1> b1 = bigint<1>(b1_decimal); + bigint<2> b2 = bigint<2>(b2_decimal); + + assert(b0.as_ulong() == 0ul); + assert(b0.is_zero()); + assert(b1.as_ulong() == 76749407ul); + assert(!(b1.is_zero())); + assert(b2.as_ulong() == 15747124762497195938ul); + assert(!(b2.is_zero())); + assert(b0 != b1); + assert(!(b0 == b1)); + + assert(b2.max_bits() == 128); + assert(b2.num_bits() == 99); + for (size_t i = 0; i < 128; i++) { + assert(b2.test_bit(i) == (b2_binary[127-i] == '1')); + } + + bigint<3> b3 = b2 * b1; + + assert(b3 == bigint<3>(b3_decimal)); + assert(!(b3.is_zero())); + + bigint<3> b3a { b3 }; + assert(b3a == bigint<3>(b3_decimal)); + assert(b3a == b3); + assert(!(b3a.is_zero())); + + mpz_t m3; + mpz_init(m3); + b3.to_mpz(m3); + bigint<3> b3b { m3 }; + assert(b3b == b3); + + bigint<2> quotient; + bigint<2> remainder; + bigint<3>::div_qr(quotient, remainder, b3, b2); + assert(quotient.num_bits() < GMP_NUMB_BITS); + assert(quotient.as_ulong() == b1.as_ulong()); + bigint<1> b1inc = bigint<1>("76749408"); + bigint<1> b1a = quotient.shorten(b1inc, "test"); + assert(b1a == b1); + assert(remainder.is_zero()); + remainder.limit(b2, "test"); + + try { + (void)(quotient.shorten(b1, "test")); + assert(false); + } catch (std::domain_error) {} + try { + remainder.limit(remainder, "test"); + assert(false); + } catch (std::domain_error) {} + + bigint<1> br = bigint<1>("42"); + b3 += br; + assert(b3 != b3a); + assert(b3 > b3a); + assert(!(b3a > b3)); + + bigint<3>::div_qr(quotient, remainder, b3, b2); + assert(quotient.num_bits() < GMP_NUMB_BITS); + assert(quotient.as_ulong() == b1.as_ulong()); + assert(remainder.num_bits() < GMP_NUMB_BITS); + assert(remainder.as_ulong() == 42); + + b3a.clear(); + assert(b3a.is_zero()); + assert(b3a.num_bits() == 0); + assert(!(b3.is_zero())); + + bigint<4> bx = bigint<4>().randomize(); + bigint<4> by = bigint<4>().randomize(); + assert(!(bx == by)); + + // TODO: test serialization +} + +int main(void) +{ + test_bigint(); + return 0; +} + diff --git a/src/algebra/fields/tests/test_fields.cpp b/src/algebra/fields/tests/test_fields.cpp new file mode 100644 index 00000000000..a05f601e690 --- /dev/null +++ b/src/algebra/fields/tests/test_fields.cpp @@ -0,0 +1,245 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/profiling.hpp" +#include "algebra/curves/edwards/edwards_pp.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#ifdef CURVE_BN128 +#include "algebra/curves/bn128/bn128_pp.hpp" +#endif +#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" +#include "algebra/fields/fp6_3over2.hpp" +#include "algebra/fields/fp12_2over3over2.hpp" + +using namespace libsnark; + +template +void test_field() +{ + bigint<1> rand1 = bigint<1>("76749407"); + bigint<1> rand2 = bigint<1>("44410867"); + bigint<1> randsum = bigint<1>("121160274"); + + FieldT zero = FieldT::zero(); + FieldT one = FieldT::one(); + FieldT a = FieldT::random_element(); + FieldT a_ser; + a_ser = reserialize(a); + assert(a_ser == a); + + FieldT b = FieldT::random_element(); + FieldT c = FieldT::random_element(); + FieldT d = FieldT::random_element(); + + assert(a != zero); + assert(a != one); + + assert(a * a == a.squared()); + assert((a + b).squared() == a.squared() + a*b + b*a + b.squared()); + assert((a + b)*(c + d) == a*c + a*d + b*c + b*d); + assert(a - b == a + (-b)); + assert(a - b == (-b) + a); + + assert((a ^ rand1) * (a ^ rand2) == (a^randsum)); + + assert(a * a.inverse() == one); + assert((a + b) * c.inverse() == a * c.inverse() + (b.inverse() * c).inverse()); + +} + +template +void test_sqrt() +{ + for (size_t i = 0; i < 100; ++i) + { + FieldT a = FieldT::random_element(); + FieldT asq = a.squared(); + assert(asq.sqrt() == a || asq.sqrt() == -a); + } +} + +template +void test_two_squarings() +{ + FieldT a = FieldT::random_element(); + assert(a.squared() == a * a); + assert(a.squared() == a.squared_complex()); + assert(a.squared() == a.squared_karatsuba()); +} + +template +void test_Frobenius() +{ + FieldT a = FieldT::random_element(); + assert(a.Frobenius_map(0) == a); + FieldT a_q = a ^ FieldT::base_field_char(); + for (size_t power = 1; power < 10; ++power) + { + const FieldT a_qi = a.Frobenius_map(power); + assert(a_qi == a_q); + + a_q = a_q ^ FieldT::base_field_char(); + } +} + +template +void test_unitary_inverse() +{ + assert(FieldT::extension_degree() % 2 == 0); + FieldT a = FieldT::random_element(); + FieldT aqcubed_minus1 = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); + assert(aqcubed_minus1.inverse() == aqcubed_minus1.unitary_inverse()); +} + +template +void test_cyclotomic_squaring(); + +template<> +void test_cyclotomic_squaring >() +{ + typedef Fqk FieldT; + assert(FieldT::extension_degree() % 2 == 0); + FieldT a = FieldT::random_element(); + FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); + // beta = a^((q^(k/2)-1)*(q+1)) + FieldT beta = a_unitary.Frobenius_map(1) * a_unitary; + assert(beta.cyclotomic_squared() == beta.squared()); +} + +template<> +void test_cyclotomic_squaring >() +{ + typedef Fqk FieldT; + assert(FieldT::extension_degree() % 2 == 0); + FieldT a = FieldT::random_element(); + FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); + // beta = a^(q^(k/2)-1) + FieldT beta = a_unitary; + assert(beta.cyclotomic_squared() == beta.squared()); +} + +template<> +void test_cyclotomic_squaring >() +{ + typedef Fqk FieldT; + assert(FieldT::extension_degree() % 2 == 0); + FieldT a = FieldT::random_element(); + FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); + // beta = a^((q^(k/2)-1)*(q+1)) + FieldT beta = a_unitary.Frobenius_map(1) * a_unitary; + assert(beta.cyclotomic_squared() == beta.squared()); +} + +template +void test_all_fields() +{ + test_field >(); + test_field >(); + test_field >(); + test_field >(); + + test_sqrt >(); + test_sqrt >(); + test_sqrt >(); + + test_Frobenius >(); + test_Frobenius >(); + + test_unitary_inverse >(); +} + +template +void test_Fp4_tom_cook() +{ + typedef typename Fp4T::my_Fp FieldT; + for (size_t i = 0; i < 100; ++i) + { + const Fp4T a = Fp4T::random_element(); + const Fp4T b = Fp4T::random_element(); + const Fp4T correct_res = a * b; + + Fp4T res; + + const FieldT + &a0 = a.c0.c0, + &a1 = a.c1.c0, + &a2 = a.c0.c1, + &a3 = a.c1.c1; + + const FieldT + &b0 = b.c0.c0, + &b1 = b.c1.c0, + &b2 = b.c0.c1, + &b3 = b.c1.c1; + + FieldT + &c0 = res.c0.c0, + &c1 = res.c1.c0, + &c2 = res.c0.c1, + &c3 = res.c1.c1; + + const FieldT v0 = a0 * b0; + const FieldT v1 = (a0 + a1 + a2 + a3) * (b0 + b1 + b2 + b3); + const FieldT v2 = (a0 - a1 + a2 - a3) * (b0 - b1 + b2 - b3); + const FieldT v3 = (a0 + FieldT(2)*a1 + FieldT(4)*a2 + FieldT(8)*a3) * (b0 + FieldT(2)*b1 + FieldT(4)*b2 + FieldT(8)*b3); + const FieldT v4 = (a0 - FieldT(2)*a1 + FieldT(4)*a2 - FieldT(8)*a3) * (b0 - FieldT(2)*b1 + FieldT(4)*b2 - FieldT(8)*b3); + const FieldT v5 = (a0 + FieldT(3)*a1 + FieldT(9)*a2 + FieldT(27)*a3) * (b0 + FieldT(3)*b1 + FieldT(9)*b2 + FieldT(27)*b3); + const FieldT v6 = a3 * b3; + + const FieldT beta = Fp4T::non_residue; + + c0 = v0 + beta*(FieldT(4).inverse()*v0 - FieldT(6).inverse()*(v1 + v2) + FieldT(24).inverse() * (v3 + v4) - FieldT(5) * v6); + c1 = - FieldT(3).inverse()*v0 + v1 - FieldT(2).inverse()*v2 - FieldT(4).inverse()*v3 + FieldT(20).inverse() * v4 + FieldT(30).inverse() * v5 - FieldT(12) * v6 + beta * ( - FieldT(12).inverse() * (v0 - v1) + FieldT(24).inverse()*(v2 - v3) - FieldT(120).inverse() * (v4 - v5) - FieldT(3) * v6); + c2 = - (FieldT(5)*(FieldT(4).inverse()))* v0 + (FieldT(2)*(FieldT(3).inverse()))*(v1 + v2) - FieldT(24).inverse()*(v3 + v4) + FieldT(4)*v6 + beta*v6; + c3 = FieldT(12).inverse() * (FieldT(5)*v0 - FieldT(7)*v1) - FieldT(24).inverse()*(v2 - FieldT(7)*v3 + v4 + v5) + FieldT(15)*v6; + + assert(res == correct_res); + + // {v0, v3, v4, v5} + const FieldT u = (FieldT::one() - beta).inverse(); + assert(v0 == u * c0 + beta * u * c2 - beta * u * FieldT(2).inverse() * v1 - beta * u * FieldT(2).inverse() * v2 + beta * v6); + assert(v3 == - FieldT(15) * u * c0 - FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 - FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v1 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v2 + - FieldT(3) * (-FieldT(16) + beta) * v6); + assert(v4 == - FieldT(15) * u * c0 + FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 + FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v2 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v1 + - FieldT(3) * (-FieldT(16) + beta) * v6); + assert(v5 == - FieldT(80) * u * c0 - FieldT(240) * u * c1 - FieldT(8) * (FieldT(9) + beta) * u * c2 - FieldT(24) * (FieldT(9) + beta) * u * c3 - FieldT(2) * (-FieldT(81) + beta) * u * v1 + (-FieldT(81) + beta) * u * v2 + - FieldT(8) * (-FieldT(81) + beta) * v6); + + // c0 + beta c2 - (beta v1)/2 - (beta v2)/ 2 - (-1 + beta) beta v6, + // -15 c0 - 30 c1 - 3 (4 + beta) c2 - 6 (4 + beta) c3 + (24 - (3 beta)/2) v1 + (-8 + beta/2) v2 + 3 (-16 + beta) (-1 + beta) v6, + // -15 c0 + 30 c1 - 3 (4 + beta) c2 + 6 (4 + beta) c3 + (-8 + beta/2) v1 + (24 - (3 beta)/2) v2 + 3 (-16 + beta) (-1 + beta) v6, + // -80 c0 - 240 c1 - 8 (9 + beta) c2 - 24 (9 + beta) c3 - 2 (-81 + beta) v1 + (-81 + beta) v2 + 8 (-81 + beta) (-1 + beta) v6 + } +} + +int main(void) +{ + edwards_pp::init_public_params(); + test_all_fields(); + test_cyclotomic_squaring >(); + + mnt4_pp::init_public_params(); + test_all_fields(); + test_Fp4_tom_cook(); + test_two_squarings >(); + test_cyclotomic_squaring >(); + + mnt6_pp::init_public_params(); + test_all_fields(); + test_cyclotomic_squaring >(); + + alt_bn128_pp::init_public_params(); + test_field(); + test_Frobenius(); + test_all_fields(); + +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + bn128_pp::init_public_params(); + test_field >(); + test_field >(); +#endif +} diff --git a/src/algebra/knowledge_commitment/knowledge_commitment.hpp b/src/algebra/knowledge_commitment/knowledge_commitment.hpp new file mode 100644 index 00000000000..90242313455 --- /dev/null +++ b/src/algebra/knowledge_commitment/knowledge_commitment.hpp @@ -0,0 +1,84 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for: + - a knowledge commitment, and + - a knowledge commitment vector. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef KNOWLEDGE_COMMITMENT_HPP_ +#define KNOWLEDGE_COMMITMENT_HPP_ + +#include "algebra/fields/fp.hpp" +#include "common/data_structures/sparse_vector.hpp" + +namespace libsnark { + +/********************** Knowledge commitment *********************************/ + +/** + * A knowledge commitment is a pair (g,h) where g is in T1 and h in T2, + * and T1 and T2 are groups (written additively). + * + * Such pairs form a group by defining: + * - "zero" = (0,0) + * - "one" = (1,1) + * - a * (g,h) + b * (g',h') := ( a * g + b * g', a * h + b * h'). + */ +template +struct knowledge_commitment { + + T1 g; + T2 h; + + knowledge_commitment() = default; + knowledge_commitment(const knowledge_commitment &other) = default; + knowledge_commitment(knowledge_commitment &&other) = default; + knowledge_commitment(const T1 &g, const T2 &h); + + knowledge_commitment& operator=(const knowledge_commitment &other) = default; + knowledge_commitment& operator=(knowledge_commitment &&other) = default; + knowledge_commitment operator+(const knowledge_commitment &other) const; + + bool is_zero() const; + bool operator==(const knowledge_commitment &other) const; + bool operator!=(const knowledge_commitment &other) const; + + static knowledge_commitment zero(); + static knowledge_commitment one(); + + void print() const; + + static size_t size_in_bits(); +}; + +template +knowledge_commitment operator*(const bigint &lhs, const knowledge_commitment &rhs); + +template &modulus_p> +knowledge_commitment operator*(const Fp_model &lhs, const knowledge_commitment &rhs); + +template +std::ostream& operator<<(std::ostream& out, const knowledge_commitment &kc); + +template +std::istream& operator>>(std::istream& in, knowledge_commitment &kc); + +/******************** Knowledge commitment vector ****************************/ + +/** + * A knowledge commitment vector is a sparse vector of knowledge commitments. + */ +template +using knowledge_commitment_vector = sparse_vector >; + +} // libsnark + +#include "algebra/knowledge_commitment/knowledge_commitment.tcc" + +#endif // KNOWLEDGE_COMMITMENT_HPP_ diff --git a/src/algebra/knowledge_commitment/knowledge_commitment.tcc b/src/algebra/knowledge_commitment/knowledge_commitment.tcc new file mode 100644 index 00000000000..15b2926c8ad --- /dev/null +++ b/src/algebra/knowledge_commitment/knowledge_commitment.tcc @@ -0,0 +1,111 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for: + - a knowledge commitment, and + - a knowledge commitment vector. + + See knowledge_commitment.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef KNOWLEDGE_COMMITMENT_TCC_ +#define KNOWLEDGE_COMMITMENT_TCC_ + +namespace libsnark { + +template +knowledge_commitment::knowledge_commitment(const T1 &g, const T2 &h) : + g(g), h(h) +{ +} + +template +knowledge_commitment knowledge_commitment::zero() +{ + return knowledge_commitment(T1::zero(), T2::zero()); +} + +template +knowledge_commitment knowledge_commitment::one() +{ + return knowledge_commitment(T1::one(), T2::one()); +} + +template +knowledge_commitment knowledge_commitment::operator+(const knowledge_commitment &other) const +{ + return knowledge_commitment(this->g + other.g, + this->h + other.h); +} + +template +bool knowledge_commitment::is_zero() const +{ + return (g.is_zero() && h.is_zero()); +} + +template +bool knowledge_commitment::operator==(const knowledge_commitment &other) const +{ + return (this->g == other.g && + this->h == other.h); +} + +template +bool knowledge_commitment::operator!=(const knowledge_commitment &other) const +{ + return !((*this) == other); +} + +template +knowledge_commitment operator*(const bigint &lhs, const knowledge_commitment &rhs) +{ + return knowledge_commitment(lhs * rhs.g, + lhs * rhs.h); +} + +template &modulus_p> +knowledge_commitment operator*(const Fp_model &lhs, const knowledge_commitment &rhs) +{ + return (lhs.as_bigint()) * rhs; +} + +template +void knowledge_commitment::print() const +{ + printf("knowledge_commitment.g:\n"); + g.print(); + printf("knowledge_commitment.h:\n"); + h.print(); +} + +template +size_t knowledge_commitment::size_in_bits() +{ + return T1::size_in_bits() + T2::size_in_bits(); +} + +template +std::ostream& operator<<(std::ostream& out, const knowledge_commitment &kc) +{ + out << kc.g << OUTPUT_SEPARATOR << kc.h; + return out; +} + +template +std::istream& operator>>(std::istream& in, knowledge_commitment &kc) +{ + in >> kc.g; + consume_OUTPUT_SEPARATOR(in); + in >> kc.h; + return in; +} + +} // libsnark + +#endif // KNOWLEDGE_COMMITMENT_TCC_ diff --git a/src/algebra/scalar_multiplication/kc_multiexp.hpp b/src/algebra/scalar_multiplication/kc_multiexp.hpp new file mode 100644 index 00000000000..4e8b55667fa --- /dev/null +++ b/src/algebra/scalar_multiplication/kc_multiexp.hpp @@ -0,0 +1,55 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef KC_MULTIEXP_HPP_ +#define KC_MULTIEXP_HPP_ + +/* + Split out from multiexp to prevent cyclical + dependencies. I.e. previously multiexp dependend on + knowledge_commitment, which dependend on sparse_vector, which + dependend on multiexp (to do accumulate). + + Will probably go away in more general exp refactoring. +*/ + +#include "algebra/knowledge_commitment/knowledge_commitment.hpp" + +namespace libsnark { + +template +knowledge_commitment opt_window_wnaf_exp(const knowledge_commitment &base, + const bigint &scalar, const size_t scalar_bits); + +template +knowledge_commitment kc_multi_exp_with_mixed_addition(const knowledge_commitment_vector &vec, + const size_t min_idx, + const size_t max_idx, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end, + const size_t chunks, + const bool use_multiexp=false); + +template +void kc_batch_to_special(std::vector > &vec); + +template +knowledge_commitment_vector kc_batch_exp(const size_t scalar_size, + const size_t T1_window, + const size_t T2_window, + const window_table &T1_table, + const window_table &T2_table, + const FieldT &T1_coeff, + const FieldT &T2_coeff, + const std::vector &v, + const size_t suggested_num_chunks); + +} // libsnark + +#include "algebra/scalar_multiplication/kc_multiexp.tcc" + +#endif // KC_MULTIEXP_HPP_ diff --git a/src/algebra/scalar_multiplication/kc_multiexp.tcc b/src/algebra/scalar_multiplication/kc_multiexp.tcc new file mode 100644 index 00000000000..e9c08d4bcea --- /dev/null +++ b/src/algebra/scalar_multiplication/kc_multiexp.tcc @@ -0,0 +1,274 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef KC_MULTIEXP_TCC_ +#define KC_MULTIEXP_TCC_ + +namespace libsnark { + +template +knowledge_commitment opt_window_wnaf_exp(const knowledge_commitment &base, + const bigint &scalar, const size_t scalar_bits) +{ + return knowledge_commitment(opt_window_wnaf_exp(base.g, scalar, scalar_bits), + opt_window_wnaf_exp(base.h, scalar, scalar_bits)); +} + +template +knowledge_commitment kc_multi_exp_with_mixed_addition(const knowledge_commitment_vector &vec, + const size_t min_idx, + const size_t max_idx, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end, + const size_t chunks, + const bool use_multiexp) +{ + enter_block("Process scalar vector"); + auto index_it = std::lower_bound(vec.indices.begin(), vec.indices.end(), min_idx); + const size_t offset = index_it - vec.indices.begin(); + + auto value_it = vec.values.begin() + offset; + + const FieldT zero = FieldT::zero(); + const FieldT one = FieldT::one(); + + std::vector p; + std::vector > g; + + knowledge_commitment acc = knowledge_commitment::zero(); + + size_t num_skip = 0; + size_t num_add = 0; + size_t num_other = 0; + + const size_t scalar_length = std::distance(scalar_start, scalar_end); + + while (index_it != vec.indices.end() && *index_it < max_idx) + { + const size_t scalar_position = (*index_it) - min_idx; + assert(scalar_position < scalar_length); + + const FieldT scalar = *(scalar_start + scalar_position); + + if (scalar == zero) + { + // do nothing + ++num_skip; + } + else if (scalar == one) + { +#ifdef USE_MIXED_ADDITION + acc.g = acc.g.mixed_add(value_it->g); + acc.h = acc.h.mixed_add(value_it->h); +#else + acc.g = acc.g + value_it->g; + acc.h = acc.h + value_it->h; +#endif + ++num_add; + } + else + { + p.emplace_back(scalar); + g.emplace_back(*value_it); + ++num_other; + } + + ++index_it; + ++value_it; + } + + //print_indent(); printf("* Elements of w skipped: %zu (%0.2f%%)\n", num_skip, 100.*num_skip/(num_skip+num_add+num_other)); + //print_indent(); printf("* Elements of w processed with special addition: %zu (%0.2f%%)\n", num_add, 100.*num_add/(num_skip+num_add+num_other)); + //print_indent(); printf("* Elements of w remaining: %zu (%0.2f%%)\n", num_other, 100.*num_other/(num_skip+num_add+num_other)); + leave_block("Process scalar vector"); + + return acc + multi_exp, FieldT>(g.begin(), g.end(), p.begin(), p.end(), chunks, use_multiexp); +} + +template +void kc_batch_to_special(std::vector > &vec) +{ + enter_block("Batch-convert knowledge-commitments to special form"); + + std::vector g_vec; + g_vec.reserve(vec.size()); + + for (size_t i = 0; i < vec.size(); ++i) + { + if (!vec[i].g.is_zero()) + { + g_vec.emplace_back(vec[i].g); + } + } + + batch_to_special_all_non_zeros(g_vec); + auto g_it = g_vec.begin(); + T1 T1_zero_special = T1::zero(); + T1_zero_special.to_special(); + + for (size_t i = 0; i < vec.size(); ++i) + { + if (!vec[i].g.is_zero()) + { + vec[i].g = *g_it; + ++g_it; + } + else + { + vec[i].g = T1_zero_special; + } + } + + g_vec.clear(); + + std::vector h_vec; + h_vec.reserve(vec.size()); + + for (size_t i = 0; i < vec.size(); ++i) + { + if (!vec[i].h.is_zero()) + { + h_vec.emplace_back(vec[i].h); + } + } + + batch_to_special_all_non_zeros(h_vec); + auto h_it = h_vec.begin(); + T2 T2_zero_special = T2::zero(); + T2_zero_special.to_special(); + + for (size_t i = 0; i < vec.size(); ++i) + { + if (!vec[i].h.is_zero()) + { + vec[i].h = *h_it; + ++h_it; + } + else + { + vec[i].h = T2_zero_special; + } + } + + g_vec.clear(); + + leave_block("Batch-convert knowledge-commitments to special form"); +} + +template +knowledge_commitment_vector kc_batch_exp_internal(const size_t scalar_size, + const size_t T1_window, + const size_t T2_window, + const window_table &T1_table, + const window_table &T2_table, + const FieldT &T1_coeff, + const FieldT &T2_coeff, + const std::vector &v, + const size_t start_pos, + const size_t end_pos, + const size_t expected_size) +{ + knowledge_commitment_vector res; + + res.values.reserve(expected_size); + res.indices.reserve(expected_size); + + for (size_t pos = start_pos; pos != end_pos; ++pos) + { + if (!v[pos].is_zero()) + { + res.values.emplace_back(knowledge_commitment(windowed_exp(scalar_size, T1_window, T1_table, T1_coeff * v[pos]), + windowed_exp(scalar_size, T2_window, T2_table, T2_coeff * v[pos]))); + res.indices.emplace_back(pos); + } + } + + return res; +} + +template +knowledge_commitment_vector kc_batch_exp(const size_t scalar_size, + const size_t T1_window, + const size_t T2_window, + const window_table &T1_table, + const window_table &T2_table, + const FieldT &T1_coeff, + const FieldT &T2_coeff, + const std::vector &v, + const size_t suggested_num_chunks) +{ + knowledge_commitment_vector res; + res.domain_size_ = v.size(); + + size_t nonzero = 0; + for (size_t i = 0; i < v.size(); ++i) + { + nonzero += (v[i].is_zero() ? 0 : 1); + } + + const size_t num_chunks = std::max((size_t)1, std::min(nonzero, suggested_num_chunks)); + + if (!inhibit_profiling_info) + { + print_indent(); printf("Non-zero coordinate count: %zu/%zu (%0.2f%%)\n", nonzero, v.size(), 100.*nonzero/v.size()); + } + + std::vector > tmp(num_chunks); + std::vector chunk_pos(num_chunks+1); + + const size_t chunk_size = nonzero / num_chunks; + const size_t last_chunk = nonzero - chunk_size * (num_chunks - 1); + + chunk_pos[0] = 0; + + size_t cnt = 0; + size_t chunkno = 1; + + for (size_t i = 0; i < v.size(); ++i) + { + cnt += (v[i].is_zero() ? 0 : 1); + if (cnt == chunk_size && chunkno < num_chunks) + { + chunk_pos[chunkno] = i; + cnt = 0; + ++chunkno; + } + } + + chunk_pos[num_chunks] = v.size(); + +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < num_chunks; ++i) + { + tmp[i] = kc_batch_exp_internal(scalar_size, T1_window, T2_window, T1_table, T2_table, T1_coeff, T2_coeff, v, + chunk_pos[i], chunk_pos[i+1], i == num_chunks - 1 ? last_chunk : chunk_size); +#ifdef USE_MIXED_ADDITION + kc_batch_to_special(tmp[i].values); +#endif + } + + if (num_chunks == 1) + { + tmp[0].domain_size_ = v.size(); + return tmp[0]; + } + else + { + for (size_t i = 0; i < num_chunks; ++i) + { + res.values.insert(res.values.end(), tmp[i].values.begin(), tmp[i].values.end()); + res.indices.insert(res.indices.end(), tmp[i].indices.begin(), tmp[i].indices.end()); + } + return res; + } +} + +} // libsnark + +#endif // KC_MULTIEXP_TCC_ diff --git a/src/algebra/scalar_multiplication/multiexp.hpp b/src/algebra/scalar_multiplication/multiexp.hpp new file mode 100644 index 00000000000..eaf72d61f88 --- /dev/null +++ b/src/algebra/scalar_multiplication/multiexp.hpp @@ -0,0 +1,110 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for multi-exponentiation routines. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MULTIEXP_HPP_ +#define MULTIEXP_HPP_ + +namespace libsnark { + +/** + * Naive multi-exponentiation individually multiplies each base by the + * corresponding scalar and adds up the results. + */ +template +T naive_exp(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end); + +template +T naive_plain_exp(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end); + +/** + * Naive multi-exponentiation uses a variant of the Bos-Coster algorithm [1], + * and implementation suggestions from [2]. + * + * [1] = Bos and Coster, "Addition chain heuristics", CRYPTO '89 + * [2] = Bernstein, Duif, Lange, Schwabe, and Yang, "High-speed high-security signatures", CHES '11 + */ +template +T multi_exp(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end, + const size_t chunks, + const bool use_multiexp=false); + + +/** + * A variant of multi_exp that takes advantage of the method mixed_add (instead of the operator '+'). + */ +template +T multi_exp_with_mixed_addition(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end, + const size_t chunks, + const bool use_multiexp); + +/** + * A window table stores window sizes for different instance sizes for fixed-base multi-scalar multiplications. + */ +template +using window_table = std::vector >; + +/** + * Compute window size for the given number of scalars. + */ +template +size_t get_exp_window_size(const size_t num_scalars); + +/** + * Compute table of window sizes. + */ +template +window_table get_window_table(const size_t scalar_size, + const size_t window, + const T &g); + +template +T windowed_exp(const size_t scalar_size, + const size_t window, + const window_table &powers_of_g, + const FieldT &pow); + +template +std::vector batch_exp(const size_t scalar_size, + const size_t window, + const window_table &table, + const std::vector &v); + +template +std::vector batch_exp_with_coeff(const size_t scalar_size, + const size_t window, + const window_table &table, + const FieldT &coeff, + const std::vector &v); + +// defined in every curve +template +void batch_to_special_all_non_zeros(std::vector &vec); + +template +void batch_to_special(std::vector &vec); + +} // libsnark + +#include "algebra/scalar_multiplication/multiexp.tcc" + +#endif // MULTIEXP_HPP_ diff --git a/src/algebra/scalar_multiplication/multiexp.tcc b/src/algebra/scalar_multiplication/multiexp.tcc new file mode 100644 index 00000000000..a6b14c4dfa4 --- /dev/null +++ b/src/algebra/scalar_multiplication/multiexp.tcc @@ -0,0 +1,590 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for multi-exponentiation routines. + + See multiexp.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MULTIEXP_TCC_ +#define MULTIEXP_TCC_ + +#include "algebra/fields/fp_aux.tcc" + +#include +#include +#include + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/scalar_multiplication/wnaf.hpp" + +namespace libsnark { + +template +class ordered_exponent { +// to use std::push_heap and friends later +public: + size_t idx; + bigint r; + + ordered_exponent(const size_t idx, const bigint &r) : idx(idx), r(r) {}; + + bool operator<(const ordered_exponent &other) const + { +#if defined(__x86_64__) && defined(USE_ASM) + if (n == 3) + { + long res; + __asm__ + ("// check for overflow \n\t" + "mov $0, %[res] \n\t" + ADD_CMP(16) + ADD_CMP(8) + ADD_CMP(0) + "jmp done%= \n\t" + "subtract%=: \n\t" + "mov $1, %[res] \n\t" + "done%=: \n\t" + : [res] "=&r" (res) + : [A] "r" (other.r.data), [mod] "r" (this->r.data) + : "cc", "%rax"); + return res; + } + else if (n == 4) + { + long res; + __asm__ + ("// check for overflow \n\t" + "mov $0, %[res] \n\t" + ADD_CMP(24) + ADD_CMP(16) + ADD_CMP(8) + ADD_CMP(0) + "jmp done%= \n\t" + "subtract%=: \n\t" + "mov $1, %[res] \n\t" + "done%=: \n\t" + : [res] "=&r" (res) + : [A] "r" (other.r.data), [mod] "r" (this->r.data) + : "cc", "%rax"); + return res; + } + else if (n == 5) + { + long res; + __asm__ + ("// check for overflow \n\t" + "mov $0, %[res] \n\t" + ADD_CMP(32) + ADD_CMP(24) + ADD_CMP(16) + ADD_CMP(8) + ADD_CMP(0) + "jmp done%= \n\t" + "subtract%=: \n\t" + "mov $1, %[res] \n\t" + "done%=: \n\t" + : [res] "=&r" (res) + : [A] "r" (other.r.data), [mod] "r" (this->r.data) + : "cc", "%rax"); + return res; + } + else +#endif + { + return (mpn_cmp(this->r.data, other.r.data, n) < 0); + } + } +}; + +template +T naive_exp(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end) +{ + T result(T::zero()); + + typename std::vector::const_iterator vec_it; + typename std::vector::const_iterator scalar_it; + + for (vec_it = vec_start, scalar_it = scalar_start; vec_it != vec_end; ++vec_it, ++scalar_it) + { + bigint scalar_bigint = scalar_it->as_bigint(); + result = result + opt_window_wnaf_exp(*vec_it, scalar_bigint, scalar_bigint.num_bits()); + } + assert(scalar_it == scalar_end); + + return result; +} + +template +T naive_plain_exp(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end) +{ + T result(T::zero()); + + typename std::vector::const_iterator vec_it; + typename std::vector::const_iterator scalar_it; + + for (vec_it = vec_start, scalar_it = scalar_start; vec_it != vec_end; ++vec_it, ++scalar_it) + { + result = result + (*scalar_it) * (*vec_it); + } + assert(scalar_it == scalar_end); + + return result; +} + +/* + The multi-exponentiation algorithm below is a variant of the Bos-Coster algorithm + [Bos and Coster, "Addition chain heuristics", CRYPTO '89]. + The implementation uses suggestions from + [Bernstein, Duif, Lange, Schwabe, and Yang, "High-speed high-security signatures", CHES '11]. +*/ +template +T multi_exp_inner(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end) +{ + const mp_size_t n = std::remove_reference::type::num_limbs; + + if (vec_start == vec_end) + { + return T::zero(); + } + + if (vec_start + 1 == vec_end) + { + return (*scalar_start)*(*vec_start); + } + + std::vector > opt_q; + const size_t vec_len = scalar_end - scalar_start; + const size_t odd_vec_len = (vec_len % 2 == 1 ? vec_len : vec_len + 1); + opt_q.reserve(odd_vec_len); + std::vector g; + g.reserve(odd_vec_len); + + typename std::vector::const_iterator vec_it; + typename std::vector::const_iterator scalar_it; + size_t i; + for (i=0, vec_it = vec_start, scalar_it = scalar_start; vec_it != vec_end; ++vec_it, ++scalar_it, ++i) + { + g.emplace_back(*vec_it); + + opt_q.emplace_back(ordered_exponent(i, scalar_it->as_bigint())); + } + std::make_heap(opt_q.begin(),opt_q.end()); + assert(scalar_it == scalar_end); + + if (vec_len != odd_vec_len) + { + g.emplace_back(T::zero()); + opt_q.emplace_back(ordered_exponent(odd_vec_len - 1, bigint(0ul))); + } + assert(g.size() % 2 == 1); + assert(opt_q.size() == g.size()); + + T opt_result = T::zero(); + + while (true) + { + ordered_exponent &a = opt_q[0]; + ordered_exponent &b = (opt_q[1] < opt_q[2] ? opt_q[2] : opt_q[1]); + + const size_t abits = a.r.num_bits(); + + if (b.r.is_zero()) + { + // opt_result = opt_result + (a.r * g[a.idx]); + opt_result = opt_result + opt_window_wnaf_exp(g[a.idx], a.r, abits); + break; + } + + const size_t bbits = b.r.num_bits(); + const size_t limit = (abits-bbits >= 20 ? 20 : abits-bbits); + + if (bbits < 1ul< (x-y) A + y (B+A) + mpn_sub_n(a.r.data, a.r.data, b.r.data, n); + g[b.idx] = g[b.idx] + g[a.idx]; + } + + // regardless of whether a was cleared or subtracted from we push it down, then take back up + + /* heapify A down */ + size_t a_pos = 0; + while (2*a_pos + 2< odd_vec_len) + { + // this is a max-heap so to maintain a heap property we swap with the largest of the two + if (opt_q[2*a_pos+1] < opt_q[2*a_pos+2]) + { + std::swap(opt_q[a_pos], opt_q[2*a_pos+2]); + a_pos = 2*a_pos+2; + } + else + { + std::swap(opt_q[a_pos], opt_q[2*a_pos+1]); + a_pos = 2*a_pos+1; + } + } + + /* now heapify A up appropriate amount of times */ + while (a_pos > 0 && opt_q[(a_pos-1)/2] < opt_q[a_pos]) + { + std::swap(opt_q[a_pos], opt_q[(a_pos-1)/2]); + a_pos = (a_pos-1) / 2; + } + } + + return opt_result; +} + +template +T multi_exp(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end, + const size_t chunks, + const bool use_multiexp) +{ + const size_t total = vec_end - vec_start; + if (total < chunks) + { + return naive_exp(vec_start, vec_end, scalar_start, scalar_end); + } + + const size_t one = total/chunks; + + std::vector partial(chunks, T::zero()); + + if (use_multiexp) + { +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < chunks; ++i) + { + partial[i] = multi_exp_inner(vec_start + i*one, + (i == chunks-1 ? vec_end : vec_start + (i+1)*one), + scalar_start + i*one, + (i == chunks-1 ? scalar_end : scalar_start + (i+1)*one)); + } + } + else + { +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < chunks; ++i) + { + partial[i] = naive_exp(vec_start + i*one, + (i == chunks-1 ? vec_end : vec_start + (i+1)*one), + scalar_start + i*one, + (i == chunks-1 ? scalar_end : scalar_start + (i+1)*one)); + } + } + + T final = T::zero(); + + for (size_t i = 0; i < chunks; ++i) + { + final = final + partial[i]; + } + + return final; +} + +template +T multi_exp_with_mixed_addition(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end, + const size_t chunks, + const bool use_multiexp) +{ + assert(std::distance(vec_start, vec_end) == std::distance(scalar_start, scalar_end)); + enter_block("Process scalar vector"); + auto value_it = vec_start; + auto scalar_it = scalar_start; + + const FieldT zero = FieldT::zero(); + const FieldT one = FieldT::one(); + std::vector p; + std::vector g; + + T acc = T::zero(); + + size_t num_skip = 0; + size_t num_add = 0; + size_t num_other = 0; + + for (; scalar_it != scalar_end; ++scalar_it, ++value_it) + { + if (*scalar_it == zero) + { + // do nothing + ++num_skip; + } + else if (*scalar_it == one) + { +#ifdef USE_MIXED_ADDITION + acc = acc.mixed_add(*value_it); +#else + acc = acc + (*value_it); +#endif + ++num_add; + } + else + { + p.emplace_back(*scalar_it); + g.emplace_back(*value_it); + ++num_other; + } + } + //print_indent(); printf("* Elements of w skipped: %zu (%0.2f%%)\n", num_skip, 100.*num_skip/(num_skip+num_add+num_other)); + //print_indent(); printf("* Elements of w processed with special addition: %zu (%0.2f%%)\n", num_add, 100.*num_add/(num_skip+num_add+num_other)); + //print_indent(); printf("* Elements of w remaining: %zu (%0.2f%%)\n", num_other, 100.*num_other/(num_skip+num_add+num_other)); + + leave_block("Process scalar vector"); + + return acc + multi_exp(g.begin(), g.end(), p.begin(), p.end(), chunks, use_multiexp); +} + +template +size_t get_exp_window_size(const size_t num_scalars) +{ + if (T::fixed_base_exp_window_table.empty()) + { +#ifdef LOWMEM + return 14; +#else + return 17; +#endif + } + size_t window = 1; + for (long i = T::fixed_base_exp_window_table.size()-1; i >= 0; --i) + { +#ifdef DEBUG + if (!inhibit_profiling_info) + { + printf("%ld %zu %zu\n", i, num_scalars, T::fixed_base_exp_window_table[i]); + } +#endif + if (T::fixed_base_exp_window_table[i] != 0 && num_scalars >= T::fixed_base_exp_window_table[i]) + { + window = i+1; + break; + } + } + + if (!inhibit_profiling_info) + { + print_indent(); printf("Choosing window size %zu for %zu elements\n", window, num_scalars); + } + +#ifdef LOWMEM + window = std::min((size_t)14, window); +#endif + return window; +} + +template +window_table get_window_table(const size_t scalar_size, + const size_t window, + const T &g) +{ + const size_t in_window = 1ul< powers_of_g(outerc, std::vector(in_window, T::zero())); + + T gouter = g; + + for (size_t outer = 0; outer < outerc; ++outer) + { + T ginner = T::zero(); + size_t cur_in_window = outer == outerc-1 ? last_in_window : in_window; + for (size_t inner = 0; inner < cur_in_window; ++inner) + { + powers_of_g[outer][inner] = ginner; + ginner = ginner + gouter; + } + + for (size_t i = 0; i < window; ++i) + { + gouter = gouter + gouter; + } + } + + return powers_of_g; +} + +template +T windowed_exp(const size_t scalar_size, + const size_t window, + const window_table &powers_of_g, + const FieldT &pow) +{ + const size_t outerc = (scalar_size+window-1)/window; + const bigint pow_val = pow.as_bigint(); + + /* exp */ + T res = powers_of_g[0][0]; + + for (size_t outer = 0; outer < outerc; ++outer) + { + size_t inner = 0; + for (size_t i = 0; i < window; ++i) + { + if (pow_val.test_bit(outer*window + i)) + { + inner |= 1u << i; + } + } + + res = res + powers_of_g[outer][inner]; + } + + return res; +} + +template +std::vector batch_exp(const size_t scalar_size, + const size_t window, + const window_table &table, + const std::vector &v) +{ + if (!inhibit_profiling_info) + { + print_indent(); + } + std::vector res(v.size(), table[0][0]); + +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < v.size(); ++i) + { + res[i] = windowed_exp(scalar_size, window, table, v[i]); + + if (!inhibit_profiling_info && (i % 10000 == 0)) + { + printf("."); + fflush(stdout); + } + } + + if (!inhibit_profiling_info) + { + printf(" DONE!\n"); + } + + return res; +} + +template +std::vector batch_exp_with_coeff(const size_t scalar_size, + const size_t window, + const window_table &table, + const FieldT &coeff, + const std::vector &v) +{ + if (!inhibit_profiling_info) + { + print_indent(); + } + std::vector res(v.size(), table[0][0]); + +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < v.size(); ++i) + { + res[i] = windowed_exp(scalar_size, window, table, coeff * v[i]); + + if (!inhibit_profiling_info && (i % 10000 == 0)) + { + printf("."); + fflush(stdout); + } + } + + if (!inhibit_profiling_info) + { + printf(" DONE!\n"); + } + + return res; +} + +template +void batch_to_special(std::vector &vec) +{ + enter_block("Batch-convert elements to special form"); + + std::vector non_zero_vec; + for (size_t i = 0; i < vec.size(); ++i) + { + if (!vec[i].is_zero()) + { + non_zero_vec.emplace_back(vec[i]); + } + } + + batch_to_special_all_non_zeros(non_zero_vec); + auto it = non_zero_vec.begin(); + T zero_special = T::zero(); + zero_special.to_special(); + + for (size_t i = 0; i < vec.size(); ++i) + { + if (!vec[i].is_zero()) + { + vec[i] = *it; + ++it; + } + else + { + vec[i] = zero_special; + } + } + leave_block("Batch-convert elements to special form"); +} + +} // libsnark + +#endif // MULTIEXP_TCC_ diff --git a/src/algebra/scalar_multiplication/wnaf.hpp b/src/algebra/scalar_multiplication/wnaf.hpp new file mode 100644 index 00000000000..a7ecd598e37 --- /dev/null +++ b/src/algebra/scalar_multiplication/wnaf.hpp @@ -0,0 +1,39 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for wNAF ("width-w Non-Adjacent Form") exponentiation routines. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WNAF_HPP_ +#define WNAF_HPP_ + +namespace libsnark { + +/** + * Find the wNAF representation of the given scalar relative to the given window size. + */ +template +std::vector find_wnaf(const size_t window_size, const bigint &scalar); + +/** + * In additive notation, use wNAF exponentiation (with the given window size) to compute scalar * base. + */ +template +T fixed_window_wnaf_exp(const size_t window_size, const T &base, const bigint &scalar); + +/** + * In additive notation, use wNAF exponentiation (with the window size determined by T) to compute scalar * base. + */ +template +T opt_window_wnaf_exp(const T &base, const bigint &scalar, const size_t scalar_bits); + +} // libsnark + +#include "algebra/scalar_multiplication/wnaf.tcc" + +#endif // WNAF_HPP_ diff --git a/src/algebra/scalar_multiplication/wnaf.tcc b/src/algebra/scalar_multiplication/wnaf.tcc new file mode 100644 index 00000000000..a5e47e8e2e4 --- /dev/null +++ b/src/algebra/scalar_multiplication/wnaf.tcc @@ -0,0 +1,123 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for wNAF ("weighted Non-Adjacent Form") exponentiation routines. + + See wnaf.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WNAF_TCC_ +#define WNAF_TCC_ + +namespace libsnark { + +template +std::vector find_wnaf(const size_t window_size, const bigint &scalar) +{ + const size_t length = scalar.max_bits(); // upper bound + std::vector res(length+1); + bigint c = scalar; + long j = 0; + while (!c.is_zero()) + { + long u; + if ((c.data[0] & 1) == 1) + { + u = c.data[0] % (1u << (window_size+1)); + if (u > (1 << window_size)) + { + u = u - (1 << (window_size+1)); + } + + if (u > 0) + { + mpn_sub_1(c.data, c.data, n, u); + } + else + { + mpn_add_1(c.data, c.data, n, -u); + } + } + else + { + u = 0; + } + res[j] = u; + ++j; + + mpn_rshift(c.data, c.data, n, 1); // c = c/2 + } + + return res; +} + +template +T fixed_window_wnaf_exp(const size_t window_size, const T &base, const bigint &scalar) +{ + std::vector naf = find_wnaf(window_size, scalar); + std::vector table(1ul<<(window_size-1)); + T tmp = base; + T dbl = base.dbl(); + for (size_t i = 0; i < 1ul<<(window_size-1); ++i) + { + table[i] = tmp; + tmp = tmp + dbl; + } + + T res = T::zero(); + bool found_nonzero = false; + for (long i = naf.size()-1; i >= 0; --i) + { + if (found_nonzero) + { + res = res.dbl(); + } + + if (naf[i] != 0) + { + found_nonzero = true; + if (naf[i] > 0) + { + res = res + table[naf[i]/2]; + } + else + { + res = res - table[(-naf[i])/2]; + } + } + } + + return res; +} + +template +T opt_window_wnaf_exp(const T &base, const bigint &scalar, const size_t scalar_bits) +{ + size_t best = 0; + for (long i = T::wnaf_window_table.size() - 1; i >= 0; --i) + { + if (scalar_bits >= T::wnaf_window_table[i]) + { + best = i+1; + break; + } + } + + if (best > 0) + { + return fixed_window_wnaf_exp(best, base, scalar); + } + else + { + return scalar * base; + } +} + +} // libsnark + +#endif // WNAF_TCC_ diff --git a/src/common/assert_except.hpp b/src/common/assert_except.hpp new file mode 100644 index 00000000000..7819230445d --- /dev/null +++ b/src/common/assert_except.hpp @@ -0,0 +1,12 @@ +#ifndef ASSERT_except_H +#define ASSERT_except_H + +#include + +inline void assert_except(bool condition) { + if (!condition) { + throw std::runtime_error("Assertion failed."); + } +} + +#endif diff --git a/src/common/data_structures/accumulation_vector.hpp b/src/common/data_structures/accumulation_vector.hpp new file mode 100644 index 00000000000..37e0c9841c9 --- /dev/null +++ b/src/common/data_structures/accumulation_vector.hpp @@ -0,0 +1,74 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for an accumulation vector. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ACCUMULATION_VECTOR_HPP_ +#define ACCUMULATION_VECTOR_HPP_ + +#include "common/data_structures/sparse_vector.hpp" + +namespace libsnark { + +template +class accumulation_vector; + +template +std::ostream& operator<<(std::ostream &out, const accumulation_vector &v); + +template +std::istream& operator>>(std::istream &in, accumulation_vector &v); + +/** + * An accumulation vector comprises an accumulation value and a sparse vector. + * The method "accumulate_chunk" allows one to accumlate portions of the sparse + * vector into the accumualation value. + */ +template +class accumulation_vector { +public: + T first; + sparse_vector rest; + + accumulation_vector() = default; + accumulation_vector(const accumulation_vector &other) = default; + accumulation_vector(accumulation_vector &&other) = default; + accumulation_vector(T &&first, sparse_vector &&rest) : first(std::move(first)), rest(std::move(rest)) {}; + accumulation_vector(T &&first, std::vector &&v) : first(std::move(first)), rest(std::move(v)) {} + accumulation_vector(std::vector &&v) : first(T::zero()), rest(std::move(v)) {}; + + accumulation_vector& operator=(const accumulation_vector &other) = default; + accumulation_vector& operator=(accumulation_vector &&other) = default; + + bool operator==(const accumulation_vector &other) const; + + bool is_fully_accumulated() const; + + size_t domain_size() const; + size_t size() const; + size_t size_in_bits() const; + + template + accumulation_vector accumulate_chunk(const typename std::vector::const_iterator &it_begin, + const typename std::vector::const_iterator &it_end, + const size_t offset) const; + +}; + +template +std::ostream& operator<<(std::ostream &out, const accumulation_vector &v); + +template +std::istream& operator>>(std::istream &in, accumulation_vector &v); + +} // libsnark + +#include "common/data_structures/accumulation_vector.tcc" + +#endif // ACCUMULATION_VECTOR_HPP_ diff --git a/src/common/data_structures/accumulation_vector.tcc b/src/common/data_structures/accumulation_vector.tcc new file mode 100644 index 00000000000..9e524aba723 --- /dev/null +++ b/src/common/data_structures/accumulation_vector.tcc @@ -0,0 +1,84 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for an accumulation vector. + + See accumulation_vector.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ACCUMULATION_VECTOR_TCC_ +#define ACCUMULATION_VECTOR_TCC_ + +namespace libsnark { + +template +bool accumulation_vector::operator==(const accumulation_vector &other) const +{ + return (this->first == other.first && this->rest == other.rest); +} + +template +bool accumulation_vector::is_fully_accumulated() const +{ + return rest.empty(); +} + +template +size_t accumulation_vector::domain_size() const +{ + return rest.domain_size(); +} + +template +size_t accumulation_vector::size() const +{ + return rest.domain_size(); +} + +template +size_t accumulation_vector::size_in_bits() const +{ + const size_t first_size_in_bits = T::size_in_bits(); + const size_t rest_size_in_bits = rest.size_in_bits(); + return first_size_in_bits + rest_size_in_bits; +} + +template +template +accumulation_vector accumulation_vector::accumulate_chunk(const typename std::vector::const_iterator &it_begin, + const typename std::vector::const_iterator &it_end, + const size_t offset) const +{ + std::pair > acc_result = rest.template accumulate(it_begin, it_end, offset); + T new_first = first + acc_result.first; + return accumulation_vector(std::move(new_first), std::move(acc_result.second)); +} + +template +std::ostream& operator<<(std::ostream& out, const accumulation_vector &v) +{ + out << v.first << OUTPUT_NEWLINE; + out << v.rest << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream& in, accumulation_vector &v) +{ + in >> v.first; + consume_OUTPUT_NEWLINE(in); + in >> v.rest; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +} // libsnark + +#endif // ACCUMULATION_VECTOR_TCC_ diff --git a/src/common/data_structures/merkle_tree.hpp b/src/common/data_structures/merkle_tree.hpp new file mode 100644 index 00000000000..6f0c851ba96 --- /dev/null +++ b/src/common/data_structures/merkle_tree.hpp @@ -0,0 +1,71 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a Merkle tree. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_TREE_HPP_ +#define MERKLE_TREE_HPP_ + +#include +#include +#include "common/utils.hpp" + +namespace libsnark { + +/** + * A Merkle tree is maintained as two maps: + * - a map from addresses to values, and + * - a map from addresses to hashes. + * + * The second map maintains the intermediate hashes of a Merkle tree + * built atop the values currently stored in the tree (the + * implementation admits a very efficient support for sparse + * trees). Besides offering methods to load and store values, the + * class offers methods to retrieve the root of the Merkle tree and to + * obtain the authentication paths for (the value at) a given address. + */ + +typedef bit_vector merkle_authentication_node; +typedef std::vector merkle_authentication_path; + +template +class merkle_tree { +private: + + typedef typename HashT::hash_value_type hash_value_type; + typedef typename HashT::merkle_authentication_path_type merkle_authentication_path_type; + +public: + + std::vector hash_defaults; + std::map values; + std::map hashes; + + size_t depth; + size_t value_size; + size_t digest_size; + + merkle_tree(const size_t depth, const size_t value_size); + merkle_tree(const size_t depth, const size_t value_size, const std::vector &contents_as_vector); + merkle_tree(const size_t depth, const size_t value_size, const std::map &contents); + + bit_vector get_value(const size_t address) const; + void set_value(const size_t address, const bit_vector &value); + + hash_value_type get_root() const; + merkle_authentication_path_type get_path(const size_t address) const; + + void dump() const; +}; + +} // libsnark + +#include "common/data_structures/merkle_tree.tcc" + +#endif // MERKLE_TREE_HPP_ diff --git a/src/common/data_structures/merkle_tree.tcc b/src/common/data_structures/merkle_tree.tcc new file mode 100644 index 00000000000..281700b3317 --- /dev/null +++ b/src/common/data_structures/merkle_tree.tcc @@ -0,0 +1,246 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for Merkle tree. + + See merkle_tree.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_TREE_TCC +#define MERKLE_TREE_TCC + +#include + +#include "common/profiling.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +template +typename HashT::hash_value_type two_to_one_CRH(const typename HashT::hash_value_type &l, + const typename HashT::hash_value_type &r) +{ + typename HashT::hash_value_type new_input; + new_input.insert(new_input.end(), l.begin(), l.end()); + new_input.insert(new_input.end(), r.begin(), r.end()); + + const size_t digest_size = HashT::get_digest_len(); + assert(l.size() == digest_size); + assert(r.size() == digest_size); + + return HashT::get_hash(new_input); +} + +template +merkle_tree::merkle_tree(const size_t depth, const size_t value_size) : + depth(depth), value_size(value_size) +{ + assert(depth < sizeof(size_t) * 8); + + digest_size = HashT::get_digest_len(); + assert(value_size <= digest_size); + + hash_value_type last(digest_size); + hash_defaults.reserve(depth+1); + hash_defaults.emplace_back(last); + for (size_t i = 0; i < depth; ++i) + { + last = two_to_one_CRH(last, last); + hash_defaults.emplace_back(last); + } + + std::reverse(hash_defaults.begin(), hash_defaults.end()); +} + +template +merkle_tree::merkle_tree(const size_t depth, + const size_t value_size, + const std::vector &contents_as_vector) : + merkle_tree(depth, value_size) +{ + assert(log2(contents_as_vector.size()) <= depth); + for (size_t address = 0; address < contents_as_vector.size(); ++address) + { + const size_t idx = address + (1ul< 0; --layer) + { + for (size_t idx = idx_begin; idx < idx_end; idx += 2) + { + hash_value_type l = hashes[idx]; // this is sound, because idx_begin is always a left child + hash_value_type r = (idx + 1 < idx_end ? hashes[idx+1] : hash_defaults[layer]); + + hash_value_type h = two_to_one_CRH(l, r); + hashes[(idx-1)/2] = h; + } + + idx_begin = (idx_begin-1)/2; + idx_end = (idx_end-1)/2; + } +} + +template +merkle_tree::merkle_tree(const size_t depth, + const size_t value_size, + const std::map &contents) : + merkle_tree(depth, value_size) +{ + + if (!contents.empty()) + { + assert(contents.rbegin()->first < 1ul<first; + const bit_vector value = it->second; + const size_t idx = address + (1ul< 0; --layer) + { + auto next_last_it = hashes.begin(); + + for (auto it = hashes.begin(); it != last_it; ++it) + { + const size_t idx = it->first; + const hash_value_type hash = it->second; + + if (idx % 2 == 0) + { + // this is the right child of its parent and by invariant we are missing the left child + hashes[(idx-1)/2] = two_to_one_CRH(hash_defaults[layer], hash); + } + else + { + if (std::next(it) == last_it || std::next(it)->first != idx + 1) + { + // this is the left child of its parent and is missing its right child + hashes[(idx-1)/2] = two_to_one_CRH(hash, hash_defaults[layer]); + } + else + { + // typical case: this is the left child of the parent and adjecent to it there is a right child + hashes[(idx-1)/2] = two_to_one_CRH(hash, std::next(it)->second); + ++it; + } + } + } + + last_it = next_last_it; + } + } +} + +template +bit_vector merkle_tree::get_value(const size_t address) const +{ + assert(log2(address) <= depth); + + auto it = values.find(address); + bit_vector padded_result = (it == values.end() ? bit_vector(digest_size) : it->second); + padded_result.resize(value_size); + + return padded_result; +} + +template +void merkle_tree::set_value(const size_t address, + const bit_vector &value) +{ + assert(log2(address) <= depth); + size_t idx = address + (1ul<=0; --layer) + { + idx = (idx-1)/2; + + auto it = hashes.find(2*idx+1); + hash_value_type l = (it == hashes.end() ? hash_defaults[layer+1] : it->second); + + it = hashes.find(2*idx+2); + hash_value_type r = (it == hashes.end() ? hash_defaults[layer+1] : it->second); + + hash_value_type h = two_to_one_CRH(l, r); + hashes[idx] = h; + } +} + +template +typename HashT::hash_value_type merkle_tree::get_root() const +{ + auto it = hashes.find(0); + return (it == hashes.end() ? hash_defaults[0] : it->second); +} + +template +typename HashT::merkle_authentication_path_type merkle_tree::get_path(const size_t address) const +{ + typename HashT::merkle_authentication_path_type result(depth); + assert(log2(address) <= depth); + size_t idx = address + (1ul< 0; --layer) + { + size_t sibling_idx = ((idx + 1) ^ 1) - 1; + auto it = hashes.find(sibling_idx); + if (layer == depth) + { + auto it2 = values.find(sibling_idx - ((1ul<second); + result[layer-1].resize(digest_size); + } + else + { + result[layer-1] = (it == hashes.end() ? hash_defaults[layer] : it->second); + } + + idx = (idx-1)/2; + } + + return result; +} + +template +void merkle_tree::dump() const +{ + for (size_t i = 0; i < 1ul< ", i); + const bit_vector value = (it == values.end() ? bit_vector(value_size) : it->second); + for (bool b : value) + { + printf("%d", b ? 1 : 0); + } + printf("\n"); + } + printf("\n"); +} + +} // libsnark + +#endif // MERKLE_TREE_TCC diff --git a/src/common/data_structures/sparse_vector.hpp b/src/common/data_structures/sparse_vector.hpp new file mode 100644 index 00000000000..8b134f42e39 --- /dev/null +++ b/src/common/data_structures/sparse_vector.hpp @@ -0,0 +1,79 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a sparse vector. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SPARSE_VECTOR_HPP_ +#define SPARSE_VECTOR_HPP_ + +#include + +namespace libsnark { + +template +struct sparse_vector; + +template +std::ostream& operator<<(std::ostream &out, const sparse_vector &v); + +template +std::istream& operator>>(std::istream &in, sparse_vector &v); + +/** + * A sparse vector is a list of indices along with corresponding values. + * The indices are selected from the set {0,1,...,domain_size-1}. + */ +template +struct sparse_vector { + + std::vector indices; + std::vector values; + size_t domain_size_ = 0; + + sparse_vector() = default; + sparse_vector(const sparse_vector &other) = default; + sparse_vector(sparse_vector &&other) = default; + sparse_vector(std::vector &&v); /* constructor from std::vector */ + + sparse_vector& operator=(const sparse_vector &other) = default; + sparse_vector& operator=(sparse_vector &&other) = default; + + T operator[](const size_t idx) const; + + bool operator==(const sparse_vector &other) const; + bool operator==(const std::vector &other) const; + + bool is_valid() const; + bool empty() const; + + size_t domain_size() const; // return domain_size_ + size_t size() const; // return the number of indices (representing the number of non-zero entries) + size_t size_in_bits() const; // return the number bits needed to store the sparse vector + + /* return a pair consisting of the accumulated value and the sparse vector of non-accumuated values */ + template + std::pair > accumulate(const typename std::vector::const_iterator &it_begin, + const typename std::vector::const_iterator &it_end, + const size_t offset) const; + + friend std::ostream& operator<< (std::ostream &out, const sparse_vector &v); + friend std::istream& operator>> (std::istream &in, sparse_vector &v); +}; + +template +std::ostream& operator<<(std::ostream& out, const sparse_vector &v); + +template +std::istream& operator>>(std::istream& in, sparse_vector &v); + +} // libsnark + +#include "common/data_structures/sparse_vector.tcc" + +#endif // SPARSE_VECTOR_HPP_ diff --git a/src/common/data_structures/sparse_vector.tcc b/src/common/data_structures/sparse_vector.tcc new file mode 100644 index 00000000000..cfc5d755990 --- /dev/null +++ b/src/common/data_structures/sparse_vector.tcc @@ -0,0 +1,316 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a sparse vector. + + See sparse_vector.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SPARSE_VECTOR_TCC_ +#define SPARSE_VECTOR_TCC_ + +#include "algebra/scalar_multiplication/multiexp.hpp" + +#include + +namespace libsnark { + +template +sparse_vector::sparse_vector(std::vector &&v) : + values(std::move(v)), domain_size_(values.size()) +{ + indices.resize(domain_size_); + std::iota(indices.begin(), indices.end(), 0); +} + +template +T sparse_vector::operator[](const size_t idx) const +{ + auto it = std::lower_bound(indices.begin(), indices.end(), idx); + return (it != indices.end() && *it == idx) ? values[it - indices.begin()] : T(); +} + +template +bool sparse_vector::operator==(const sparse_vector &other) const +{ + if (this->domain_size_ != other.domain_size_) + { + return false; + } + + size_t this_pos = 0, other_pos = 0; + while (this_pos < this->indices.size() && other_pos < other.indices.size()) + { + if (this->indices[this_pos] == other.indices[other_pos]) + { + if (this->values[this_pos] != other.values[other_pos]) + { + return false; + } + ++this_pos; + ++other_pos; + } + else if (this->indices[this_pos] < other.indices[other_pos]) + { + if (!this->values[this_pos].is_zero()) + { + return false; + } + ++this_pos; + } + else + { + if (!other.values[other_pos].is_zero()) + { + return false; + } + ++other_pos; + } + } + + /* at least one of the vectors has been exhausted, so other must be empty */ + while (this_pos < this->indices.size()) + { + if (!this->values[this_pos].is_zero()) + { + return false; + } + ++this_pos; + } + + while (other_pos < other.indices.size()) + { + if (!other.values[other_pos].is_zero()) + { + return false; + } + ++other_pos; + } + + return true; +} + +template +bool sparse_vector::operator==(const std::vector &other) const +{ + if (this->domain_size_ < other.size()) + { + return false; + } + + size_t j = 0; + for (size_t i = 0; i < other.size(); ++i) + { + if (this->indices[j] == i) + { + if (this->values[j] != other[j]) + { + return false; + } + ++j; + } + else + { + if (!other[j].is_zero()) + { + return false; + } + } + } + + return true; +} + +template +bool sparse_vector::is_valid() const +{ + if (values.size() == indices.size() && values.size() <= domain_size_) + { + return false; + } + + for (size_t i = 0; i + 1 < indices.size(); ++i) + { + if (indices[i] >= indices[i+1]) + { + return false; + } + } + + if (!indices.empty() && indices[indices.size()-1] >= domain_size_) + { + return false; + } + + return true; +} + +template +bool sparse_vector::empty() const +{ + return indices.empty(); +} + +template +size_t sparse_vector::domain_size() const +{ + return domain_size_; +} + +template +size_t sparse_vector::size() const +{ + return indices.size(); +} + +template +size_t sparse_vector::size_in_bits() const +{ + return indices.size() * (sizeof(size_t) * 8 + T::size_in_bits()); +} + +template +template +std::pair > sparse_vector::accumulate(const typename std::vector::const_iterator &it_begin, + const typename std::vector::const_iterator &it_end, + const size_t offset) const +{ + // TODO: does not really belong here. + const size_t chunks = 1; + const bool use_multiexp = true; + + T accumulated_value = T::zero(); + sparse_vector resulting_vector; + resulting_vector.domain_size_ = domain_size_; + + const size_t range_len = it_end - it_begin; + bool in_block = false; + size_t first_pos = -1, last_pos = -1; // g++ -flto emits unitialized warning, even though in_block guards for such cases. + + for (size_t i = 0; i < indices.size(); ++i) + { + const bool matching_pos = (offset <= indices[i] && indices[i] < offset + range_len); + // printf("i = %zu, pos[i] = %zu, offset = %zu, w_size = %zu\n", i, indices[i], offset, w_size); + bool copy_over; + + if (in_block) + { + if (matching_pos && last_pos == i-1) + { + // block can be extended, do it + last_pos = i; + copy_over = false; + } + else + { + // block has ended here + in_block = false; + copy_over = true; + +#ifdef DEBUG + print_indent(); printf("doing multiexp for w_%zu ... w_%zu\n", indices[first_pos], indices[last_pos]); +#endif + accumulated_value = accumulated_value + multi_exp(values.begin() + first_pos, + values.begin() + last_pos + 1, + it_begin + (indices[first_pos] - offset), + it_begin + (indices[last_pos] - offset) + 1, + chunks, use_multiexp); + } + } + else + { + if (matching_pos) + { + // block can be started + first_pos = i; + last_pos = i; + in_block = true; + copy_over = false; + } + else + { + copy_over = true; + } + } + + if (copy_over) + { + resulting_vector.indices.emplace_back(indices[i]); + resulting_vector.values.emplace_back(values[i]); + } + } + + if (in_block) + { +#ifdef DEBUG + print_indent(); printf("doing multiexp for w_%zu ... w_%zu\n", indices[first_pos], indices[last_pos]); +#endif + accumulated_value = accumulated_value + multi_exp(values.begin() + first_pos, + values.begin() + last_pos + 1, + it_begin + (indices[first_pos] - offset), + it_begin + (indices[last_pos] - offset) + 1, + chunks, use_multiexp); + } + + return std::make_pair(accumulated_value, resulting_vector); +} + +template +std::ostream& operator<<(std::ostream& out, const sparse_vector &v) +{ + out << v.domain_size_ << "\n"; + out << v.indices.size() << "\n"; + for (const size_t& i : v.indices) + { + out << i << "\n"; + } + + out << v.values.size() << "\n"; + for (const T& t : v.values) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +template +std::istream& operator>>(std::istream& in, sparse_vector &v) +{ + in >> v.domain_size_; + consume_newline(in); + + size_t s; + in >> s; + consume_newline(in); + v.indices.resize(s); + for (size_t i = 0; i < s; ++i) + { + in >> v.indices[i]; + consume_newline(in); + } + + v.values.clear(); + in >> s; + consume_newline(in); + v.values.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + T t; + in >> t; + consume_OUTPUT_NEWLINE(in); + v.values.emplace_back(t); + } + + return in; +} + +} // libsnark + +#endif // SPARSE_VECTOR_TCC_ diff --git a/src/common/default_types/ec_pp.hpp b/src/common/default_types/ec_pp.hpp new file mode 100644 index 00000000000..b08c2da8816 --- /dev/null +++ b/src/common/default_types/ec_pp.hpp @@ -0,0 +1,53 @@ +/** @file + ***************************************************************************** + + This file defines default_ec_pp based on the CURVE=... make flag, which selects + which elliptic curve is used to implement group arithmetic and pairings. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EC_PP_HPP_ +#define EC_PP_HPP_ + +/************************ Pick the elliptic curve ****************************/ + +#ifdef CURVE_ALT_BN128 +#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" +namespace libsnark { +typedef alt_bn128_pp default_ec_pp; +} // libsnark +#endif + +#ifdef CURVE_BN128 +#include "algebra/curves/bn128/bn128_pp.hpp" +namespace libsnark { +typedef bn128_pp default_ec_pp; +} // libsnark +#endif + +#ifdef CURVE_EDWARDS +#include "algebra/curves/edwards/edwards_pp.hpp" +namespace libsnark { +typedef edwards_pp default_ec_pp; +} // libsnark +#endif + +#ifdef CURVE_MNT4 +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +namespace libsnark { +typedef mnt4_pp default_ec_pp; +} // libsnark +#endif + +#ifdef CURVE_MNT6 +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +namespace libsnark { +typedef mnt6_pp default_ec_pp; +} // libsnark +#endif + +#endif // EC_PP_HPP_ diff --git a/src/common/default_types/r1cs_ppzksnark_pp.hpp b/src/common/default_types/r1cs_ppzksnark_pp.hpp new file mode 100644 index 00000000000..c819b4a85e9 --- /dev/null +++ b/src/common/default_types/r1cs_ppzksnark_pp.hpp @@ -0,0 +1,22 @@ +/** @file + ***************************************************************************** + + This file defines default_r1cs_ppzksnark_pp based on the elliptic curve + choice selected in ec_pp.hpp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKSNARK_PP_HPP_ +#define R1CS_PPZKSNARK_PP_HPP_ + +#include "common/default_types/ec_pp.hpp" + +namespace libsnark { +typedef default_ec_pp default_r1cs_ppzksnark_pp; +} // libsnark + +#endif // R1CS_PPZKSNARK_PP_HPP_ diff --git a/src/common/profiling.cpp b/src/common/profiling.cpp new file mode 100644 index 00000000000..d227203a0fa --- /dev/null +++ b/src/common/profiling.cpp @@ -0,0 +1,379 @@ +/** @file + ***************************************************************************** + + Implementation of functions for profiling code blocks. + + See profiling.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/profiling.hpp" +#include +#include +#include +#include +#include +#include +#include +#include "common/default_types/ec_pp.hpp" +#include "common/utils.hpp" + +#ifndef NO_PROCPS +#include +#endif + +namespace libsnark { + +long long get_nsec_time() +{ + auto timepoint = std::chrono::high_resolution_clock::now(); + return std::chrono::duration_cast(timepoint.time_since_epoch()).count(); +} + +/* Return total CPU time consumsed by all threads of the process, in nanoseconds. */ +long long get_nsec_cpu_time() +{ + ::timespec ts; + if ( ::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) ) + throw ::std::runtime_error("clock_gettime(CLOCK_PROCESS_CPUTIME_ID) failed"); + // If we expected this to work, don't silently ignore failures, because that would hide the problem and incur an unnecessarily system-call overhead. So if we ever observe this exception, we should probably add a suitable #ifdef . + //TODO: clock_gettime(CLOCK_PROCESS_CPUTIME_ID) is not supported by native Windows. What about Cygwin? Should we #ifdef on CLOCK_PROCESS_CPUTIME_ID or on __linux__? + return ts.tv_sec * 1000000000ll + ts.tv_nsec; +} + +long long start_time, last_time; +long long start_cpu_time, last_cpu_time; + +void start_profiling() +{ + printf("Reset time counters for profiling\n"); + + last_time = start_time = get_nsec_time(); + last_cpu_time = start_cpu_time = get_nsec_cpu_time(); +} + +std::map invocation_counts; +std::map enter_times; +std::map last_times; +std::map cumulative_times; +//TODO: Instead of analogous maps for time and cpu_time, use a single struct-valued map +std::map enter_cpu_times; +std::map last_cpu_times; +std::map, long long> op_counts; +std::map, long long> cumulative_op_counts; // ((msg, data_point), value) + // TODO: Convert op_counts and cumulative_op_counts from pair to structs +size_t indentation = 0; + +std::vector block_names; + +std::list > op_data_points = { +#ifdef PROFILE_OP_COUNTS + std::make_pair("Fradd", &Fr::add_cnt), + std::make_pair("Frsub", &Fr::sub_cnt), + std::make_pair("Frmul", &Fr::mul_cnt), + std::make_pair("Frinv", &Fr::inv_cnt), + std::make_pair("Fqadd", &Fq::add_cnt), + std::make_pair("Fqsub", &Fq::sub_cnt), + std::make_pair("Fqmul", &Fq::mul_cnt), + std::make_pair("Fqinv", &Fq::inv_cnt), + std::make_pair("G1add", &G1::add_cnt), + std::make_pair("G1dbl", &G1::dbl_cnt), + std::make_pair("G2add", &G2::add_cnt), + std::make_pair("G2dbl", &G2::dbl_cnt) +#endif +}; + +bool inhibit_profiling_info = false; +bool inhibit_profiling_counters = false; + +void clear_profiling_counters() +{ + invocation_counts.clear(); + last_times.clear(); + last_cpu_times.clear(); + cumulative_times.clear(); +} + +void print_cumulative_time_entry(const std::string &key, const long long factor) +{ + const double total_ms = (cumulative_times.at(key) * 1e-6); + const size_t cnt = invocation_counts.at(key); + const double avg_ms = total_ms / cnt; + printf(" %-45s: %12.5fms = %lld * %0.5fms (%zu invocations, %0.5fms = %lld * %0.5fms per invocation)\n", key.c_str(), total_ms, factor, total_ms/factor, cnt, avg_ms, factor, avg_ms/factor); +} + +void print_cumulative_times(const long long factor) +{ + printf("Dumping times:\n"); + for (auto& kv : cumulative_times) + { + print_cumulative_time_entry(kv.first, factor); + } +} + +void print_cumulative_op_counts(const bool only_fq) +{ +#ifdef PROFILE_OP_COUNTS + printf("Dumping operation counts:\n"); + for (auto& msg : invocation_counts) + { + printf(" %-45s: ", msg.first.c_str()); + bool first = true; + for (auto& data_point : op_data_points) + { + if (only_fq && data_point.first.compare(0, 2, "Fq") != 0) + { + continue; + } + + if (!first) + { + printf(", "); + } + printf("%-5s = %7.0f (%3zu)", + data_point.first.c_str(), + 1. * cumulative_op_counts[std::make_pair(msg.first, data_point.first)] / msg.second, + msg.second); + first = false; + } + printf("\n"); + } +#else + UNUSED(only_fq); +#endif +} + +void print_op_profiling(const std::string &msg) +{ +#ifdef PROFILE_OP_COUNTS + printf("\n"); + print_indent(); + + printf("(opcounts) = ("); + bool first = true; + for (std::pair p : op_data_points) + { + if (!first) + { + printf(", "); + } + + printf("%s=%lld", p.first.c_str(), *(p.second)-op_counts[std::make_pair(msg, p.first)]); + first = false; + } + printf(")"); +#else + UNUSED(msg); +#endif +} + +static void print_times_from_last_and_start(long long now, long long last, + long long cpu_now, long long cpu_last) +{ + long long time_from_start = now - start_time; + long long time_from_last = now - last; + + long long cpu_time_from_start = cpu_now - start_cpu_time; + long long cpu_time_from_last = cpu_now - cpu_last; + + if (time_from_last != 0) { + double parallelism_from_last = 1.0 * cpu_time_from_last / time_from_last; + printf("[%0.4fs x%0.2f]", time_from_last * 1e-9, parallelism_from_last); + } else { + printf("[ ]"); + } + if (time_from_start != 0) { + double parallelism_from_start = 1.0 * cpu_time_from_start / time_from_start; + printf("\t(%0.4fs x%0.2f from start)", time_from_start * 1e-9, parallelism_from_start); + } +} + +void print_time(const char* msg) +{ + if (inhibit_profiling_info) + { + return; + } + + long long now = get_nsec_time(); + long long cpu_now = get_nsec_cpu_time(); + + printf("%-35s\t", msg); + print_times_from_last_and_start(now, last_time, cpu_now, last_cpu_time); +#ifdef PROFILE_OP_COUNTS + print_op_profiling(msg); +#endif + printf("\n"); + + fflush(stdout); + last_time = now; + last_cpu_time = cpu_now; +} + +void print_header(const char *msg) +{ + printf("\n================================================================================\n"); + printf("%s\n", msg); + printf("================================================================================\n\n"); +} + +void print_indent() +{ + for (size_t i = 0; i < indentation; ++i) + { + printf(" "); + } +} + +void op_profiling_enter(const std::string &msg) +{ + for (std::pair p : op_data_points) + { + op_counts[std::make_pair(msg, p.first)] = *(p.second); + } +} + +void enter_block(const std::string &msg, const bool indent) +{ + if (inhibit_profiling_counters) + { + return; + } + + block_names.emplace_back(msg); + long long t = get_nsec_time(); + enter_times[msg] = t; + long long cpu_t = get_nsec_cpu_time(); + enter_cpu_times[msg] = cpu_t; + + if (inhibit_profiling_info) + { + return; + } + +#ifdef MULTICORE +#pragma omp critical +#endif + { + op_profiling_enter(msg); + + print_indent(); + printf("(enter) %-35s\t", msg.c_str()); + print_times_from_last_and_start(t, t, cpu_t, cpu_t); + printf("\n"); + fflush(stdout); + + if (indent) + { + ++indentation; + } + } +} + +void leave_block(const std::string &msg, const bool indent) +{ + if (inhibit_profiling_counters) + { + return; + } + +#ifndef MULTICORE + assert(*(--block_names.end()) == msg); +#endif + block_names.pop_back(); + + ++invocation_counts[msg]; + + long long t = get_nsec_time(); + last_times[msg] = (t - enter_times[msg]); + cumulative_times[msg] += (t - enter_times[msg]); + + long long cpu_t = get_nsec_cpu_time(); + last_cpu_times[msg] = (cpu_t - enter_cpu_times[msg]); + +#ifdef PROFILE_OP_COUNTS + for (std::pair p : op_data_points) + { + cumulative_op_counts[std::make_pair(msg, p.first)] += *(p.second)-op_counts[std::make_pair(msg, p.first)]; + } +#endif + + if (inhibit_profiling_info) + { + return; + } + +#ifdef MULTICORE +#pragma omp critical +#endif + { + if (indent) + { + --indentation; + } + + print_indent(); + printf("(leave) %-35s\t", msg.c_str()); + print_times_from_last_and_start(t, enter_times[msg], cpu_t, enter_cpu_times[msg]); + print_op_profiling(msg); + printf("\n"); + fflush(stdout); + } +} + +void print_mem(const std::string &s) +{ +#ifndef NO_PROCPS + struct proc_t usage; + look_up_our_self(&usage); + if (s.empty()) + { + printf("* Peak vsize (physical memory+swap) in mebibytes: %lu\n", usage.vsize >> 20); + } + else + { + printf("* Peak vsize (physical memory+swap) in mebibytes (%s): %lu\n", s.c_str(), usage.vsize >> 20); + } +#else + printf("* Memory profiling not supported in NO_PROCPS mode\n"); +#endif +} + +void print_compilation_info() +{ +#ifdef __GNUC__ + printf("g++ version: %s\n", __VERSION__); + //printf("Compiled on %s %s\n", __DATE__, __TIME__); +#endif +#ifdef STATIC + printf("STATIC: yes\n"); +#else + printf("STATIC: no\n"); +#endif +#ifdef MULTICORE + printf("MULTICORE: yes\n"); +#else + printf("MULTICORE: no\n"); +#endif +#ifdef DEBUG + printf("DEBUG: yes\n"); +#else + printf("DEBUG: no\n"); +#endif +#ifdef PROFILE_OP_COUNTS + printf("PROFILE_OP_COUNTS: yes\n"); +#else + printf("PROFILE_OP_COUNTS: no\n"); +#endif +#ifdef _GLIBCXX_DEBUG + printf("_GLIBCXX_DEBUG: yes\n"); +#else + printf("_GLIBCXX_DEBUG: no\n"); +#endif +} + +} // libsnark diff --git a/src/common/profiling.hpp b/src/common/profiling.hpp new file mode 100644 index 00000000000..9619117f4b7 --- /dev/null +++ b/src/common/profiling.hpp @@ -0,0 +1,51 @@ +/** @file + ***************************************************************************** + + Declaration of functions for profiling code blocks. + + Reports time, operation counts, memory usage, and others. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PROFILING_HPP_ +#define PROFILING_HPP_ + +#include +#include +#include +#include + +namespace libsnark { + +void start_profiling(); +long long get_nsec_time(); +void print_time(const char* msg); +void print_header(const char* msg); + +void print_indent(); + +extern bool inhibit_profiling_info; +extern bool inhibit_profiling_counters; +extern std::map invocation_counts; +extern std::map last_times; +extern std::map cumulative_times; + +void clear_profiling_counters(); + +void print_cumulative_time_entry(const std::string &key, const long long factor=1); +void print_cumulative_times(const long long factor=1); +void print_cumulative_op_counts(const bool only_fq=false); + +void enter_block(const std::string &msg, const bool indent=true); +void leave_block(const std::string &msg, const bool indent=true); + +void print_mem(const std::string &s = ""); +void print_compilation_info(); + +} // libsnark + +#endif // PROFILING_HPP_ diff --git a/src/common/serialization.hpp b/src/common/serialization.hpp new file mode 100644 index 00000000000..c931c65b25d --- /dev/null +++ b/src/common/serialization.hpp @@ -0,0 +1,104 @@ +/** @file + ***************************************************************************** + + Declaration of serialization routines and constants. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SERIALIZATION_HPP_ +#define SERIALIZATION_HPP_ + +#include +#include +#include +#include +#include + +namespace libsnark { + +/* + * @todo + * The serialization is fragile. Shoud be rewritten using a standard, portable-format + * library like boost::serialize. + * + * However, for now the following conventions are used within the code. + * + * All algebraic objects support either binary or decimal output using + * the standard C++ stream operators (operator<<, operator>>). + * + * The binary mode is activated by defining a BINARY_OUTPUT + * preprocessor macro (e.g. g++ -DBINARY_OUTPUT ...). + * + * Binary output assumes that the stream is to be binary read at its + * current position so any white space should be consumed beforehand. + * + * Consecutive algebraic objects are separated by OUTPUT_NEWLINE and + * within themselves (e.g. X and Y coordinates for field elements) with + * OUTPUT_SEPARATOR (as defined below). + * + * Therefore to dump two integers, two Fp elements and another integer + * one would: + * + * out << 3 << "\n"; + * out << 4 << "\n"; + * out << FieldT(56) << OUTPUT_NEWLINE; + * out << FieldT(78) << OUTPUT_NEWLINE; + * out << 9 << "\n"; + * + * Then reading back it its reader's responsibility (!) to consume "\n" + * after 4, but Fp::operator<< will correctly consume OUTPUT_NEWLINE. + * + * The reader should also consume "\n" after 9, so that another field + * element can be properly chained. This is especially important for + * binary output. + * + * The binary serialization of algebraic objects is currently *not* + * portable between machines of different word sizes. + */ + +#ifdef BINARY_OUTPUT +#define OUTPUT_NEWLINE "" +#define OUTPUT_SEPARATOR "" +#else +#define OUTPUT_NEWLINE "\n" +#define OUTPUT_SEPARATOR " " +#endif + +inline void consume_newline(std::istream &in); +inline void consume_OUTPUT_NEWLINE(std::istream &in); +inline void consume_OUTPUT_SEPARATOR(std::istream &in); + +inline void output_bool(std::ostream &out, const bool b); + +inline void output_bool_vector(std::ostream &out, const std::vector &v); + +template +T reserialize(const T &obj); + +template +std::ostream& operator<<(std::ostream& out, const std::vector &v); + +template +std::istream& operator>>(std::ostream& out, std::vector &v); + +template +std::ostream& operator<<(std::ostream& out, const std::map &m); + +template +std::istream& operator>>(std::istream& in, std::map &m); + +template +std::ostream& operator<<(std::ostream& out, const std::set &s); + +template +std::istream& operator>>(std::istream& in, std::set &s); + +} // libsnark + +#include "common/serialization.tcc" + +#endif // SERIALIZATION_HPP_ diff --git a/src/common/serialization.tcc b/src/common/serialization.tcc new file mode 100644 index 00000000000..398f978500d --- /dev/null +++ b/src/common/serialization.tcc @@ -0,0 +1,180 @@ +/** @file + ***************************************************************************** + + Implementation of serialization routines. + + See serialization.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SERIALIZATION_TCC_ +#define SERIALIZATION_TCC_ + +#include +#include +#include "common/utils.hpp" + +namespace libsnark { + +inline void consume_newline(std::istream &in) +{ + char c; + in.read(&c, 1); +} + +inline void consume_OUTPUT_NEWLINE(std::istream &in) +{ +#ifdef BINARY_OUTPUT + // nothing to consume + UNUSED(in); +#else + char c; + in.read(&c, 1); +#endif +} + +inline void consume_OUTPUT_SEPARATOR(std::istream &in) +{ +#ifdef BINARY_OUTPUT + // nothing to consume + UNUSED(in); +#else + char c; + in.read(&c, 1); +#endif +} + +inline void output_bool(std::ostream &out, const bool b) +{ + out << (b ? 1 : 0) << "\n"; +} + +inline void output_bool_vector(std::ostream &out, const std::vector &v) +{ + out << v.size() << "\n"; + for (const bool b : v) + { + output_bool(out, b); + } +} + +template +T reserialize(const T &obj) +{ + std::stringstream ss; + ss << obj; + T tmp; + ss >> tmp; + assert(obj == tmp); + return tmp; +} + +template +std::ostream& operator<<(std::ostream& out, const std::vector &v) +{ + static_assert(!std::is_same::value, "this does not work for std::vector"); + out << v.size() << "\n"; + for (const T& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +template +std::istream& operator>>(std::istream& in, std::vector &v) +{ + static_assert(!std::is_same::value, "this does not work for std::vector"); + size_t size; + in >> size; + consume_newline(in); + + v.resize(0); + for (size_t i = 0; i < size; ++i) + { + T elt; + in >> elt; + consume_OUTPUT_NEWLINE(in); + v.push_back(elt); + } + + return in; +} + +template +std::ostream& operator<<(std::ostream& out, const std::map &m) +{ + out << m.size() << "\n"; + + for (auto &it : m) + { + out << it.first << "\n"; + out << it.second << "\n"; + } + + return out; +} + +template +std::istream& operator>>(std::istream& in, std::map &m) +{ + m.clear(); + size_t size; + in >> size; + consume_newline(in); + + for (size_t i = 0; i < size; ++i) + { + T1 k; + T2 v; + in >> k; + consume_newline(in); + in >> v; + consume_newline(in); + m[k] = v; + } + + return in; +} + +template +std::ostream& operator<<(std::ostream& out, const std::set &s) +{ + out << s.size() << "\n"; + + for (auto &el : s) + { + out << el << "\n"; + } + + return out; +} + + +template +std::istream& operator>>(std::istream& in, std::set &s) +{ + s.clear(); + size_t size; + in >> size; + consume_newline(in); + + for (size_t i = 0; i < size; ++i) + { + T el; + in >> el; + consume_newline(in); + s.insert(el); + } + + return in; +} + +} + +#endif // SERIALIZATION_TCC_ diff --git a/src/common/template_utils.hpp b/src/common/template_utils.hpp new file mode 100644 index 00000000000..8dbfd261dd6 --- /dev/null +++ b/src/common/template_utils.hpp @@ -0,0 +1,26 @@ +/** @file + ***************************************************************************** + + Declaration of functions for supporting the use of templates. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TEMPLATE_UTILS_HPP_ +#define TEMPLATE_UTILS_HPP_ + +namespace libsnark { + +/* A commonly used SFINAE helper type */ +template +struct void_type +{ + typedef void type; +}; + +} // libsnark + +#endif // TEMPLATE_UTILS_HPP_ diff --git a/src/common/utils.cpp b/src/common/utils.cpp new file mode 100644 index 00000000000..dd114fdf0d5 --- /dev/null +++ b/src/common/utils.cpp @@ -0,0 +1,102 @@ +/** @file + ***************************************************************************** + Implementation of misc math and serialization utility functions + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include +#include +#include "common/utils.hpp" + +namespace libsnark { + +size_t log2(size_t n) +/* returns ceil(log2(n)), so 1ul< 1) + { + n >>= 1; + r++; + } + + return r; +} + +size_t bitreverse(size_t n, const size_t l) +{ + size_t r = 0; + for (size_t k = 0; k < l; ++k) + { + r = (r << 1) | (n & 1); + n >>= 1; + } + return r; +} + +bit_vector int_list_to_bits(const std::initializer_list &l, const size_t wordsize) +{ + bit_vector res(wordsize*l.size()); + for (size_t i = 0; i < l.size(); ++i) + { + for (size_t j = 0; j < wordsize; ++j) + { + res[i*wordsize + j] = (*(l.begin()+i) & (1ul<<(wordsize-1-j))); + } + } + return res; +} + +long long div_ceil(long long x, long long y) +{ + return (x + (y-1)) / y; +} + +bool is_little_endian() +{ + uint64_t a = 0x12345678; + unsigned char *c = (unsigned char*)(&a); + return (*c = 0x78); +} + +std::string FORMAT(const std::string &prefix, const char* format, ...) +{ + const static size_t MAX_FMT = 256; + char buf[MAX_FMT]; + va_list args; + va_start(args, format); + vsnprintf(buf, MAX_FMT, format, args); + va_end(args); + + return prefix + std::string(buf); +} + +void serialize_bit_vector(std::ostream &out, const bit_vector &v) +{ + out << v.size() << "\n"; + for (size_t i = 0; i < v.size(); ++i) + { + out << v[i] << "\n"; + } +} + +void deserialize_bit_vector(std::istream &in, bit_vector &v) +{ + size_t size; + in >> size; + v.resize(size); + for (size_t i = 0; i < size; ++i) + { + bool b; + in >> b; + v[i] = b; + } +} +} // libsnark diff --git a/src/common/utils.hpp b/src/common/utils.hpp new file mode 100644 index 00000000000..d7d9e894739 --- /dev/null +++ b/src/common/utils.hpp @@ -0,0 +1,57 @@ +/** @file + ***************************************************************************** + Declaration of misc math and serialization utility functions + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef UTILS_HPP_ +#define UTILS_HPP_ + +#include +#include +#include +#include +#include + +namespace libsnark { + +typedef std::vector bit_vector; + +/// returns ceil(log2(n)), so 1ul< &l, const size_t wordsize); +long long div_ceil(long long x, long long y); + +bool is_little_endian(); + +std::string FORMAT(const std::string &prefix, const char* format, ...); + +/* A variadic template to suppress unused argument warnings */ +template +void UNUSED(Types&&...) {} + +#ifdef DEBUG +#define FMT FORMAT +#else +#define FMT(...) (UNUSED(__VA_ARGS__), "") +#endif + +void serialize_bit_vector(std::ostream &out, const bit_vector &v); +void deserialize_bit_vector(std::istream &in, bit_vector &v); + +template +size_t size_in_bits(const std::vector &v); + +#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) + +} // libsnark + +#include "common/utils.tcc" /* note that utils has a templatized part (utils.tcc) and non-templatized part (utils.cpp) */ +#endif // UTILS_HPP_ diff --git a/src/common/utils.tcc b/src/common/utils.tcc new file mode 100644 index 00000000000..f97178f8cc5 --- /dev/null +++ b/src/common/utils.tcc @@ -0,0 +1,23 @@ +/** @file + ***************************************************************************** + Implementation of templatized utility functions + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef UTILS_TCC_ +#define UTILS_TCC_ + +namespace libsnark { + +template +size_t size_in_bits(const std::vector &v) +{ + return v.size() * T::size_in_bits(); +} + +} // libsnark + +#endif // UTILS_TCC_ diff --git a/src/gadgetlib1/constraint_profiling.cpp b/src/gadgetlib1/constraint_profiling.cpp new file mode 100644 index 00000000000..bc17e63bc35 --- /dev/null +++ b/src/gadgetlib1/constraint_profiling.cpp @@ -0,0 +1,48 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for profiling constraints. + + See constraint_profiling.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "gadgetlib1/constraint_profiling.hpp" +#include "common/profiling.hpp" + +namespace libsnark { + +size_t constraint_profiling_indent = 0; +std::vector constraint_profiling_table; + +size_t PRINT_CONSTRAINT_PROFILING() +{ + size_t accounted = 0; + print_indent(); + printf("Constraint profiling:\n"); + for (constraint_profiling_entry &ent : constraint_profiling_table) + { + if (ent.indent == 0) + { + accounted += ent.count; + } + + print_indent(); + for (size_t i = 0; i < ent.indent; ++i) + { + printf(" "); + } + printf("* Number of constraints in [%s]: %zu\n", ent.annotation.c_str(), ent.count); + } + + constraint_profiling_table.clear(); + constraint_profiling_indent = 0; + + return accounted; +} + +} diff --git a/src/gadgetlib1/constraint_profiling.hpp b/src/gadgetlib1/constraint_profiling.hpp new file mode 100644 index 00000000000..df8a55de197 --- /dev/null +++ b/src/gadgetlib1/constraint_profiling.hpp @@ -0,0 +1,42 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for profiling constraints. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef CONSTRAINT_PROFILING_HPP_ +#define CONSTRAINT_PROFILING_HPP_ + +#include +#include +#include +#include + +namespace libsnark { + +extern size_t constraint_profiling_indent; + +struct constraint_profiling_entry { + size_t indent; + std::string annotation; + size_t count; +}; + +extern std::vector constraint_profiling_table; + +#define PROFILE_CONSTRAINTS(pb, annotation) \ + for (size_t _num_constraints_before = pb.num_constraints(), _iter = (++constraint_profiling_indent, 0), _cp_pos = constraint_profiling_table.size(); \ + _iter == 0; \ + constraint_profiling_table.insert(constraint_profiling_table.begin() + _cp_pos, constraint_profiling_entry{--constraint_profiling_indent, annotation, pb.num_constraints() - _num_constraints_before}), \ + _iter = 1) + +size_t PRINT_CONSTRAINT_PROFILING(); // returns # of top level constraints + +} // libsnark + +#endif // CONSTRAINT_PROFILING_HPP_ diff --git a/src/gadgetlib1/examples/simple_example.hpp b/src/gadgetlib1/examples/simple_example.hpp new file mode 100644 index 00000000000..faa3a960525 --- /dev/null +++ b/src/gadgetlib1/examples/simple_example.hpp @@ -0,0 +1,23 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SIMPLE_EXAMPLE_HPP_ +#define SIMPLE_EXAMPLE_HPP_ + +#include "examples/r1cs_examples.hpp" + +namespace libsnark { + +template +r1cs_example gen_r1cs_example_from_protoboard(const size_t num_constraints, + const size_t num_inputs); + +} // libsnark + +#include "gadgetlib1/examples/simple_example.tcc" + +#endif // SIMPLE_EXAMPLE_HPP_ diff --git a/src/gadgetlib1/examples/simple_example.tcc b/src/gadgetlib1/examples/simple_example.tcc new file mode 100644 index 00000000000..9d500b5c752 --- /dev/null +++ b/src/gadgetlib1/examples/simple_example.tcc @@ -0,0 +1,54 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SIMPLE_EXAMPLE_TCC_ +#define SIMPLE_EXAMPLE_TCC_ + +#include +#include "gadgetlib1/gadgets/basic_gadgets.hpp" + +namespace libsnark { + +/* NOTE: all examples here actually generate one constraint less to account for soundness constraint in QAP */ + +template +r1cs_example gen_r1cs_example_from_protoboard(const size_t num_constraints, + const size_t num_inputs) +{ + const size_t new_num_constraints = num_constraints - 1; + + /* construct dummy example: inner products of two vectors */ + protoboard pb; + pb_variable_array A; + pb_variable_array B; + pb_variable res; + + // the variables on the protoboard are (ONE (constant 1 term), res, A[0], ..., A[num_constraints-1], B[0], ..., B[num_constraints-1]) + res.allocate(pb, "res"); + A.allocate(pb, new_num_constraints, "A"); + B.allocate(pb, new_num_constraints, "B"); + + inner_product_gadget compute_inner_product(pb, A, B, res, "compute_inner_product"); + compute_inner_product.generate_r1cs_constraints(); + + /* fill in random example */ + for (size_t i = 0; i < new_num_constraints; ++i) + { + pb.val(A[i]) = FieldT::random_element(); + pb.val(B[i]) = FieldT::random_element(); + } + + compute_inner_product.generate_r1cs_witness(); + + pb.constraint_system.num_inputs = num_inputs; + const r1cs_variable_assignment va = pb.values; + const r1cs_variable_assignment input(va.begin(), va.begin() + num_inputs); + return r1cs_example(pb.constraint_system, input, va, num_inputs); +} + +} // libsnark +#endif // R1CS_EXAMPLES_TCC_ diff --git a/src/gadgetlib1/gadget.hpp b/src/gadgetlib1/gadget.hpp new file mode 100644 index 00000000000..dbeaa9d4b49 --- /dev/null +++ b/src/gadgetlib1/gadget.hpp @@ -0,0 +1,27 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef GADGET_HPP_ +#define GADGET_HPP_ + +#include "gadgetlib1/protoboard.hpp" + +namespace libsnark { + +template +class gadget { +protected: + protoboard &pb; + const std::string annotation_prefix; +public: + gadget(protoboard &pb, const std::string &annotation_prefix=""); +}; + +} // libsnark +#include "gadgetlib1/gadget.tcc" + +#endif // GADGET_HPP_ diff --git a/src/gadgetlib1/gadget.tcc b/src/gadgetlib1/gadget.tcc new file mode 100644 index 00000000000..120229bbea8 --- /dev/null +++ b/src/gadgetlib1/gadget.tcc @@ -0,0 +1,23 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef GADGET_TCC_ +#define GADGET_TCC_ + +namespace libsnark { + +template +gadget::gadget(protoboard &pb, const std::string &annotation_prefix) : + pb(pb), annotation_prefix(annotation_prefix) +{ +#ifdef DEBUG + assert(annotation_prefix != ""); +#endif +} + +} // libsnark +#endif // GADGET_TCC_ diff --git a/src/gadgetlib1/gadgets/basic_gadgets.hpp b/src/gadgetlib1/gadgets/basic_gadgets.hpp new file mode 100644 index 00000000000..08e596bee73 --- /dev/null +++ b/src/gadgetlib1/gadgets/basic_gadgets.hpp @@ -0,0 +1,351 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BASIC_GADGETS_HPP_ +#define BASIC_GADGETS_HPP_ + +#include +#include + +#include "gadgetlib1/gadget.hpp" + +namespace libsnark { + +/* forces lc to take value 0 or 1 by adding constraint lc * (1-lc) = 0 */ +template +void generate_boolean_r1cs_constraint(protoboard &pb, const pb_linear_combination &lc, const std::string &annotation_prefix=""); + +template +void generate_r1cs_equals_const_constraint(protoboard &pb, const pb_linear_combination &lc, const FieldT& c, const std::string &annotation_prefix=""); + +template +class packing_gadget : public gadget { +private: + /* no internal variables */ +public: + const pb_linear_combination_array bits; + const pb_linear_combination packed; + + packing_gadget(protoboard &pb, + const pb_linear_combination_array &bits, + const pb_linear_combination &packed, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), bits(bits), packed(packed) {} + + void generate_r1cs_constraints(const bool enforce_bitness); + /* adds constraint result = \sum bits[i] * 2^i */ + + void generate_r1cs_witness_from_packed(); + void generate_r1cs_witness_from_bits(); +}; + +template +class multipacking_gadget : public gadget { +private: + std::vector > packers; +public: + const pb_linear_combination_array bits; + const pb_linear_combination_array packed_vars; + + const size_t chunk_size; + const size_t num_chunks; + // const size_t last_chunk_size; + + multipacking_gadget(protoboard &pb, + const pb_linear_combination_array &bits, + const pb_linear_combination_array &packed_vars, + const size_t chunk_size, + const std::string &annotation_prefix=""); + void generate_r1cs_constraints(const bool enforce_bitness); + void generate_r1cs_witness_from_packed(); + void generate_r1cs_witness_from_bits(); +}; + +template +class field_vector_copy_gadget : public gadget { +public: + const pb_variable_array source; + const pb_variable_array target; + const pb_linear_combination do_copy; + + field_vector_copy_gadget(protoboard &pb, + const pb_variable_array &source, + const pb_variable_array &target, + const pb_linear_combination &do_copy, + const std::string &annotation_prefix=""); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +class bit_vector_copy_gadget : public gadget { +public: + const pb_variable_array source_bits; + const pb_variable_array target_bits; + const pb_linear_combination do_copy; + + pb_variable_array packed_source; + pb_variable_array packed_target; + + std::shared_ptr > pack_source; + std::shared_ptr > pack_target; + std::shared_ptr > copier; + + const size_t chunk_size; + const size_t num_chunks; + + bit_vector_copy_gadget(protoboard &pb, + const pb_variable_array &source_bits, + const pb_variable_array &target_bits, + const pb_linear_combination &do_copy, + const size_t chunk_size, + const std::string &annotation_prefix=""); + void generate_r1cs_constraints(const bool enforce_source_bitness, const bool enforce_target_bitness); + void generate_r1cs_witness(); +}; + +template +class dual_variable_gadget : public gadget { +private: + std::shared_ptr > consistency_check; +public: + pb_variable packed; + pb_variable_array bits; + + dual_variable_gadget(protoboard &pb, + const size_t width, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix) + { + packed.allocate(pb, FMT(this->annotation_prefix, " packed")); + bits.allocate(pb, width, FMT(this->annotation_prefix, " bits")); + consistency_check.reset(new packing_gadget(pb, + bits, + packed, + FMT(this->annotation_prefix, " consistency_check"))); + } + + dual_variable_gadget(protoboard &pb, + const pb_variable_array &bits, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), bits(bits) + { + packed.allocate(pb, FMT(this->annotation_prefix, " packed")); + consistency_check.reset(new packing_gadget(pb, + bits, + packed, + FMT(this->annotation_prefix, " consistency_check"))); + } + + dual_variable_gadget(protoboard &pb, + const pb_variable &packed, + const size_t width, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), packed(packed) + { + bits.allocate(pb, width, FMT(this->annotation_prefix, " bits")); + consistency_check.reset(new packing_gadget(pb, + bits, + packed, + FMT(this->annotation_prefix, " consistency_check"))); + } + + void generate_r1cs_constraints(const bool enforce_bitness); + void generate_r1cs_witness_from_packed(); + void generate_r1cs_witness_from_bits(); +}; + +/* + the gadgets below are Fp specific: + I * X = R + (1-R) * X = 0 + + if X = 0 then R = 0 + if X != 0 then R = 1 and I = X^{-1} +*/ + +template +class disjunction_gadget : public gadget { +private: + pb_variable inv; +public: + const pb_variable_array inputs; + const pb_variable output; + + disjunction_gadget(protoboard& pb, + const pb_variable_array &inputs, + const pb_variable &output, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), inputs(inputs), output(output) + { + assert(inputs.size() >= 1); + inv.allocate(pb, FMT(this->annotation_prefix, " inv")); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_disjunction_gadget(const size_t n); + +template +class conjunction_gadget : public gadget { +private: + pb_variable inv; +public: + const pb_variable_array inputs; + const pb_variable output; + + conjunction_gadget(protoboard& pb, + const pb_variable_array &inputs, + const pb_variable &output, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), inputs(inputs), output(output) + { + assert(inputs.size() >= 1); + inv.allocate(pb, FMT(this->annotation_prefix, " inv")); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_conjunction_gadget(const size_t n); + +template +class comparison_gadget : public gadget { +private: + pb_variable_array alpha; + pb_variable alpha_packed; + std::shared_ptr > pack_alpha; + + std::shared_ptr > all_zeros_test; + pb_variable not_all_zeros; +public: + const size_t n; + const pb_linear_combination A; + const pb_linear_combination B; + const pb_variable less; + const pb_variable less_or_eq; + + comparison_gadget(protoboard& pb, + const size_t n, + const pb_linear_combination &A, + const pb_linear_combination &B, + const pb_variable &less, + const pb_variable &less_or_eq, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), n(n), A(A), B(B), less(less), less_or_eq(less_or_eq) + { + alpha.allocate(pb, n, FMT(this->annotation_prefix, " alpha")); + alpha.emplace_back(less_or_eq); // alpha[n] is less_or_eq + + alpha_packed.allocate(pb, FMT(this->annotation_prefix, " alpha_packed")); + not_all_zeros.allocate(pb, FMT(this->annotation_prefix, " not_all_zeros")); + + pack_alpha.reset(new packing_gadget(pb, alpha, alpha_packed, + FMT(this->annotation_prefix, " pack_alpha"))); + + all_zeros_test.reset(new disjunction_gadget(pb, + pb_variable_array(alpha.begin(), alpha.begin() + n), + not_all_zeros, + FMT(this->annotation_prefix, " all_zeros_test"))); + }; + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_comparison_gadget(const size_t n); + +template +class inner_product_gadget : public gadget { +private: + /* S_i = \sum_{k=0}^{i+1} A[i] * B[i] */ + pb_variable_array S; +public: + const pb_linear_combination_array A; + const pb_linear_combination_array B; + const pb_variable result; + + inner_product_gadget(protoboard& pb, + const pb_linear_combination_array &A, + const pb_linear_combination_array &B, + const pb_variable &result, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), A(A), B(B), result(result) + { + assert(A.size() >= 1); + assert(A.size() == B.size()); + + S.allocate(pb, A.size()-1, FMT(this->annotation_prefix, " S")); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_inner_product_gadget(const size_t n); + +template +class loose_multiplexing_gadget : public gadget { +/* + this implements loose multiplexer: + index not in bounds -> success_flag = 0 + index in bounds && success_flag = 1 -> result is correct + however if index is in bounds we can also set success_flag to 0 (and then result will be forced to be 0) +*/ +public: + pb_variable_array alpha; +private: + std::shared_ptr > compute_result; +public: + const pb_linear_combination_array arr; + const pb_variable index; + const pb_variable result; + const pb_variable success_flag; + + loose_multiplexing_gadget(protoboard& pb, + const pb_linear_combination_array &arr, + const pb_variable &index, + const pb_variable &result, + const pb_variable &success_flag, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), arr(arr), index(index), result(result), success_flag(success_flag) + { + alpha.allocate(pb, arr.size(), FMT(this->annotation_prefix, " alpha")); + compute_result.reset(new inner_product_gadget(pb, alpha, arr, result, FMT(this->annotation_prefix, " compute_result"))); + }; + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_loose_multiplexing_gadget(const size_t n); + +template +void create_linear_combination_constraints(protoboard &pb, + const std::vector &base, + const std::vector > &v, + const VarT &target, + const std::string &annotation_prefix); + +template +void create_linear_combination_witness(protoboard &pb, + const std::vector &base, + const std::vector > &v, + const VarT &target); + +} // libsnark +#include "gadgetlib1/gadgets/basic_gadgets.tcc" + +#endif // BASIC_GADGETS_HPP_ diff --git a/src/gadgetlib1/gadgets/basic_gadgets.tcc b/src/gadgetlib1/gadgets/basic_gadgets.tcc new file mode 100644 index 00000000000..213b1906f29 --- /dev/null +++ b/src/gadgetlib1/gadgets/basic_gadgets.tcc @@ -0,0 +1,705 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BASIC_GADGETS_TCC_ +#define BASIC_GADGETS_TCC_ + +#include "common/profiling.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +template +void generate_boolean_r1cs_constraint(protoboard &pb, const pb_linear_combination &lc, const std::string &annotation_prefix) +/* forces lc to take value 0 or 1 by adding constraint lc * (1-lc) = 0 */ +{ + pb.add_r1cs_constraint(r1cs_constraint(lc, 1-lc, 0), + FMT(annotation_prefix, " boolean_r1cs_constraint")); +} + +template +void generate_r1cs_equals_const_constraint(protoboard &pb, const pb_linear_combination &lc, const FieldT& c, const std::string &annotation_prefix) +{ + pb.add_r1cs_constraint(r1cs_constraint(1, lc, c), + FMT(annotation_prefix, " constness_constraint")); +} + +template +void packing_gadget::generate_r1cs_constraints(const bool enforce_bitness) +/* adds constraint result = \sum bits[i] * 2^i */ +{ + this->pb.add_r1cs_constraint(r1cs_constraint(1, pb_packing_sum(bits), packed), FMT(this->annotation_prefix, " packing_constraint")); + + if (enforce_bitness) + { + for (size_t i = 0; i < bits.size(); ++i) + { + generate_boolean_r1cs_constraint(this->pb, bits[i], FMT(this->annotation_prefix, " bitness_%zu", i)); + } + } +} + +template +void packing_gadget::generate_r1cs_witness_from_packed() +{ + packed.evaluate(this->pb); + assert(this->pb.lc_val(packed).as_bigint().num_bits() <= bits.size()); + bits.fill_with_bits_of_field_element(this->pb, this->pb.lc_val(packed)); +} + +template +void packing_gadget::generate_r1cs_witness_from_bits() +{ + bits.evaluate(this->pb); + this->pb.lc_val(packed) = bits.get_field_element_from_bits(this->pb); +} + +template +multipacking_gadget::multipacking_gadget(protoboard &pb, + const pb_linear_combination_array &bits, + const pb_linear_combination_array &packed_vars, + const size_t chunk_size, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), bits(bits), packed_vars(packed_vars), + chunk_size(chunk_size), + num_chunks(div_ceil(bits.size(), chunk_size)) + // last_chunk_size(bits.size() - (num_chunks-1) * chunk_size) +{ + assert(packed_vars.size() == num_chunks); + for (size_t i = 0; i < num_chunks; ++i) + { + packers.emplace_back(packing_gadget(this->pb, pb_linear_combination_array(bits.begin() + i * chunk_size, + bits.begin() + std::min((i+1) * chunk_size, bits.size())), + packed_vars[i], FMT(this->annotation_prefix, " packers_%zu", i))); + } +} + +template +void multipacking_gadget::generate_r1cs_constraints(const bool enforce_bitness) +{ + for (size_t i = 0; i < num_chunks; ++i) + { + packers[i].generate_r1cs_constraints(enforce_bitness); + } +} + +template +void multipacking_gadget::generate_r1cs_witness_from_packed() +{ + for (size_t i = 0; i < num_chunks; ++i) + { + packers[i].generate_r1cs_witness_from_packed(); + } +} + +template +void multipacking_gadget::generate_r1cs_witness_from_bits() +{ + for (size_t i = 0; i < num_chunks; ++i) + { + packers[i].generate_r1cs_witness_from_bits(); + } +} + +template +size_t multipacking_num_chunks(const size_t num_bits) +{ + return div_ceil(num_bits, FieldT::capacity()); +} + +template +field_vector_copy_gadget::field_vector_copy_gadget(protoboard &pb, + const pb_variable_array &source, + const pb_variable_array &target, + const pb_linear_combination &do_copy, + const std::string &annotation_prefix) : +gadget(pb, annotation_prefix), source(source), target(target), do_copy(do_copy) +{ + assert(source.size() == target.size()); +} + +template +void field_vector_copy_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < source.size(); ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(do_copy, source[i] - target[i], 0), + FMT(this->annotation_prefix, " copying_check_%zu", i)); + } +} + +template +void field_vector_copy_gadget::generate_r1cs_witness() +{ + do_copy.evaluate(this->pb); + assert(this->pb.lc_val(do_copy) == FieldT::one() || this->pb.lc_val(do_copy) == FieldT::zero()); + if (this->pb.lc_val(do_copy) != FieldT::zero()) + { + for (size_t i = 0; i < source.size(); ++i) + { + this->pb.val(target[i]) = this->pb.val(source[i]); + } + } +} + +template +bit_vector_copy_gadget::bit_vector_copy_gadget(protoboard &pb, + const pb_variable_array &source_bits, + const pb_variable_array &target_bits, + const pb_linear_combination &do_copy, + const size_t chunk_size, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), source_bits(source_bits), target_bits(target_bits), do_copy(do_copy), + chunk_size(chunk_size), num_chunks(div_ceil(source_bits.size(), chunk_size)) +{ + assert(source_bits.size() == target_bits.size()); + + packed_source.allocate(pb, num_chunks, FMT(annotation_prefix, " packed_source")); + pack_source.reset(new multipacking_gadget(pb, source_bits, packed_source, chunk_size, FMT(annotation_prefix, " pack_source"))); + + packed_target.allocate(pb, num_chunks, FMT(annotation_prefix, " packed_target")); + pack_target.reset(new multipacking_gadget(pb, target_bits, packed_target, chunk_size, FMT(annotation_prefix, " pack_target"))); + + copier.reset(new field_vector_copy_gadget(pb, packed_source, packed_target, do_copy, FMT(annotation_prefix, " copier"))); +} + +template +void bit_vector_copy_gadget::generate_r1cs_constraints(const bool enforce_source_bitness, const bool enforce_target_bitness) +{ + pack_source->generate_r1cs_constraints(enforce_source_bitness); + pack_target->generate_r1cs_constraints(enforce_target_bitness); + + copier->generate_r1cs_constraints(); +} + +template +void bit_vector_copy_gadget::generate_r1cs_witness() +{ + do_copy.evaluate(this->pb); + assert(this->pb.lc_val(do_copy) == FieldT::zero() || this->pb.lc_val(do_copy) == FieldT::one()); + if (this->pb.lc_val(do_copy) == FieldT::one()) + { + for (size_t i = 0; i < source_bits.size(); ++i) + { + this->pb.val(target_bits[i]) = this->pb.val(source_bits[i]); + } + } + + pack_source->generate_r1cs_witness_from_bits(); + pack_target->generate_r1cs_witness_from_bits(); +} + +template +void dual_variable_gadget::generate_r1cs_constraints(const bool enforce_bitness) +{ + consistency_check->generate_r1cs_constraints(enforce_bitness); +} + +template +void dual_variable_gadget::generate_r1cs_witness_from_packed() +{ + consistency_check->generate_r1cs_witness_from_packed(); +} + +template +void dual_variable_gadget::generate_r1cs_witness_from_bits() +{ + consistency_check->generate_r1cs_witness_from_bits(); +} + +template +void disjunction_gadget::generate_r1cs_constraints() +{ + /* inv * sum = output */ + linear_combination a1, b1, c1; + a1.add_term(inv); + for (size_t i = 0; i < inputs.size(); ++i) + { + b1.add_term(inputs[i]); + } + c1.add_term(output); + + this->pb.add_r1cs_constraint(r1cs_constraint(a1, b1, c1), FMT(this->annotation_prefix, " inv*sum=output")); + + /* (1-output) * sum = 0 */ + linear_combination a2, b2, c2; + a2.add_term(ONE); + a2.add_term(output, -1); + for (size_t i = 0; i < inputs.size(); ++i) + { + b2.add_term(inputs[i]); + } + c2.add_term(ONE, 0); + + this->pb.add_r1cs_constraint(r1cs_constraint(a2, b2, c2), FMT(this->annotation_prefix, " (1-output)*sum=0")); +} + +template +void disjunction_gadget::generate_r1cs_witness() +{ + FieldT sum = FieldT::zero(); + + for (size_t i = 0; i < inputs.size(); ++i) + { + sum += this->pb.val(inputs[i]); + } + + if (sum.is_zero()) + { + this->pb.val(inv) = FieldT::zero(); + this->pb.val(output) = FieldT::zero(); + } + else + { + this->pb.val(inv) = sum.inverse(); + this->pb.val(output) = FieldT::one(); + } +} + +template +void test_disjunction_gadget(const size_t n) +{ + printf("testing disjunction_gadget on all %zu bit strings\n", n); + + protoboard pb; + pb_variable_array inputs; + inputs.allocate(pb, n, "inputs"); + + pb_variable output; + output.allocate(pb, "output"); + + disjunction_gadget d(pb, inputs, output, "d"); + d.generate_r1cs_constraints(); + + for (size_t w = 0; w < 1ul< +void conjunction_gadget::generate_r1cs_constraints() +{ + /* inv * (n-sum) = 1-output */ + linear_combination a1, b1, c1; + a1.add_term(inv); + b1.add_term(ONE, inputs.size()); + for (size_t i = 0; i < inputs.size(); ++i) + { + b1.add_term(inputs[i], -1); + } + c1.add_term(ONE); + c1.add_term(output, -1); + + this->pb.add_r1cs_constraint(r1cs_constraint(a1, b1, c1), FMT(this->annotation_prefix, " inv*(n-sum)=(1-output)")); + + /* output * (n-sum) = 0 */ + linear_combination a2, b2, c2; + a2.add_term(output); + b2.add_term(ONE, inputs.size()); + for (size_t i = 0; i < inputs.size(); ++i) + { + b2.add_term(inputs[i], -1); + } + c2.add_term(ONE, 0); + + this->pb.add_r1cs_constraint(r1cs_constraint(a2, b2, c2), FMT(this->annotation_prefix, " output*(n-sum)=0")); +} + +template +void conjunction_gadget::generate_r1cs_witness() +{ + FieldT sum = FieldT(inputs.size()); + + for (size_t i = 0; i < inputs.size(); ++i) + { + sum -= this->pb.val(inputs[i]); + } + + if (sum.is_zero()) + { + this->pb.val(inv) = FieldT::zero(); + this->pb.val(output) = FieldT::one(); + } + else + { + this->pb.val(inv) = sum.inverse(); + this->pb.val(output) = FieldT::zero(); + } +} + +template +void test_conjunction_gadget(const size_t n) +{ + printf("testing conjunction_gadget on all %zu bit strings\n", n); + + protoboard pb; + pb_variable_array inputs; + inputs.allocate(pb, n, "inputs"); + + pb_variable output; + output.allocate(pb, "output"); + + conjunction_gadget c(pb, inputs, output, "c"); + c.generate_r1cs_constraints(); + + for (size_t w = 0; w < 1ul< +void comparison_gadget::generate_r1cs_constraints() +{ + /* + packed(alpha) = 2^n + B - A + + not_all_zeros = \bigvee_{i=0}^{n-1} alpha_i + + if B - A > 0, then 2^n + B - A > 2^n, + so alpha_n = 1 and not_all_zeros = 1 + if B - A = 0, then 2^n + B - A = 2^n, + so alpha_n = 1 and not_all_zeros = 0 + if B - A < 0, then 2^n + B - A \in {0, 1, \ldots, 2^n-1}, + so alpha_n = 0 + + therefore alpha_n = less_or_eq and alpha_n * not_all_zeros = less + */ + + /* not_all_zeros to be Boolean, alpha_i are Boolean by packing gadget */ + generate_boolean_r1cs_constraint(this->pb, not_all_zeros, + FMT(this->annotation_prefix, " not_all_zeros")); + + /* constraints for packed(alpha) = 2^n + B - A */ + pack_alpha->generate_r1cs_constraints(true); + this->pb.add_r1cs_constraint(r1cs_constraint(1, (FieldT(2)^n) + B - A, alpha_packed), FMT(this->annotation_prefix, " main_constraint")); + + /* compute result */ + all_zeros_test->generate_r1cs_constraints(); + this->pb.add_r1cs_constraint(r1cs_constraint(less_or_eq, not_all_zeros, less), + FMT(this->annotation_prefix, " less")); +} + +template +void comparison_gadget::generate_r1cs_witness() +{ + A.evaluate(this->pb); + B.evaluate(this->pb); + + /* unpack 2^n + B - A into alpha_packed */ + this->pb.val(alpha_packed) = (FieldT(2)^n) + this->pb.lc_val(B) - this->pb.lc_val(A); + pack_alpha->generate_r1cs_witness_from_packed(); + + /* compute result */ + all_zeros_test->generate_r1cs_witness(); + this->pb.val(less) = this->pb.val(less_or_eq) * this->pb.val(not_all_zeros); +} + +template +void test_comparison_gadget(const size_t n) +{ + printf("testing comparison_gadget on all %zu bit inputs\n", n); + + protoboard pb; + + pb_variable A, B, less, less_or_eq; + A.allocate(pb, "A"); + B.allocate(pb, "B"); + less.allocate(pb, "less"); + less_or_eq.allocate(pb, "less_or_eq"); + + comparison_gadget cmp(pb, n, A, B, less, less_or_eq, "cmp"); + cmp.generate_r1cs_constraints(); + + for (size_t a = 0; a < 1ul< +void inner_product_gadget::generate_r1cs_constraints() +{ + /* + S_i = \sum_{k=0}^{i+1} A[i] * B[i] + S[0] = A[0] * B[0] + S[i+1] - S[i] = A[i] * B[i] + */ + for (size_t i = 0; i < A.size(); ++i) + { + this->pb.add_r1cs_constraint( + r1cs_constraint(A[i], B[i], + (i == A.size()-1 ? result : S[i]) + (i == 0 ? 0 * ONE : -S[i-1])), + FMT(this->annotation_prefix, " S_%zu", i)); + } +} + +template +void inner_product_gadget::generate_r1cs_witness() +{ + FieldT total = FieldT::zero(); + for (size_t i = 0; i < A.size(); ++i) + { + A[i].evaluate(this->pb); + B[i].evaluate(this->pb); + + total += this->pb.lc_val(A[i]) * this->pb.lc_val(B[i]); + this->pb.val(i == A.size()-1 ? result : S[i]) = total; + } +} + +template +void test_inner_product_gadget(const size_t n) +{ + printf("testing inner_product_gadget on all %zu bit strings\n", n); + + protoboard pb; + pb_variable_array A; + A.allocate(pb, n, "A"); + pb_variable_array B; + B.allocate(pb, n, "B"); + + pb_variable result; + result.allocate(pb, "result"); + + inner_product_gadget g(pb, A, B, result, "g"); + g.generate_r1cs_constraints(); + + for (size_t i = 0; i < 1ul< +void loose_multiplexing_gadget::generate_r1cs_constraints() +{ + /* \alpha_i (index - i) = 0 */ + for (size_t i = 0; i < arr.size(); ++i) + { + this->pb.add_r1cs_constraint( + r1cs_constraint(alpha[i], index - i, 0), + FMT(this->annotation_prefix, " alpha_%zu", i)); + } + + /* 1 * (\sum \alpha_i) = success_flag */ + linear_combination a, b, c; + a.add_term(ONE); + for (size_t i = 0; i < arr.size(); ++i) + { + b.add_term(alpha[i]); + } + c.add_term(success_flag); + this->pb.add_r1cs_constraint(r1cs_constraint(a, b, c), FMT(this->annotation_prefix, " main_constraint")); + + /* now success_flag is constrained to either 0 (if index is out of + range) or \alpha_i. constrain it and \alpha_i to zero */ + generate_boolean_r1cs_constraint(this->pb, success_flag, FMT(this->annotation_prefix, " success_flag")); + + /* compute result */ + compute_result->generate_r1cs_constraints(); +} + +template +void loose_multiplexing_gadget::generate_r1cs_witness() +{ + /* assumes that idx can be fit in ulong; true for our purposes for now */ + const bigint valint = this->pb.val(index).as_bigint(); + unsigned long idx = valint.as_ulong(); + const bigint arrsize(arr.size()); + + if (idx >= arr.size() || mpn_cmp(valint.data, arrsize.data, FieldT::num_limbs) >= 0) + { + for (size_t i = 0; i < arr.size(); ++i) + { + this->pb.val(alpha[i]) = FieldT::zero(); + } + + this->pb.val(success_flag) = FieldT::zero(); + } + else + { + for (size_t i = 0; i < arr.size(); ++i) + { + this->pb.val(alpha[i]) = (i == idx ? FieldT::one() : FieldT::zero()); + } + + this->pb.val(success_flag) = FieldT::one(); + } + + compute_result->generate_r1cs_witness(); +} + +template +void test_loose_multiplexing_gadget(const size_t n) +{ + printf("testing loose_multiplexing_gadget on 2**%zu pb_variable array inputs\n", n); + protoboard pb; + + pb_variable_array arr; + arr.allocate(pb, 1ul< index, result, success_flag; + index.allocate(pb, "index"); + result.allocate(pb, "result"); + success_flag.allocate(pb, "success_flag"); + + loose_multiplexing_gadget g(pb, arr, index, result, success_flag, "g"); + g.generate_r1cs_constraints(); + + for (size_t i = 0; i < 1ul< +void create_linear_combination_constraints(protoboard &pb, + const std::vector &base, + const std::vector > &v, + const VarT &target, + const std::string &annotation_prefix) +{ + for (size_t i = 0; i < base.size(); ++i) + { + linear_combination a, b, c; + + a.add_term(ONE); + b.add_term(ONE, base[i]); + + for (auto &p : v) + { + b.add_term(p.first.all_vars[i], p.second); + } + + c.add_term(target.all_vars[i]); + + pb.add_r1cs_constraint(r1cs_constraint(a, b, c), FMT(annotation_prefix, " linear_combination_%zu", i)); + } +} + +template +void create_linear_combination_witness(protoboard &pb, + const std::vector &base, + const std::vector > &v, + const VarT &target) +{ + for (size_t i = 0; i < base.size(); ++i) + { + pb.val(target.all_vars[i]) = base[i]; + + for (auto &p : v) + { + pb.val(target.all_vars[i]) += p.second * pb.val(p.first.all_vars[i]); + } + } +} + +} // libsnark +#endif // BASIC_GADGETS_TCC_ diff --git a/src/gadgetlib1/gadgets/gadget_from_r1cs.hpp b/src/gadgetlib1/gadgets/gadget_from_r1cs.hpp new file mode 100644 index 00000000000..e4b8a2acf54 --- /dev/null +++ b/src/gadgetlib1/gadgets/gadget_from_r1cs.hpp @@ -0,0 +1,45 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a gadget that can be created from an R1CS constraint system. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef GADGET_FROM_R1CS_HPP_ +#define GADGET_FROM_R1CS_HPP_ + +#include + +#include "gadgetlib1/gadget.hpp" + +namespace libsnark { + +template +class gadget_from_r1cs : public gadget { + +private: + const std::vector > vars; + const r1cs_constraint_system cs; + std::map cs_to_vars; + +public: + + gadget_from_r1cs(protoboard &pb, + const std::vector > &vars, + const r1cs_constraint_system &cs, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/gadget_from_r1cs.tcc" + +#endif // GADGET_FROM_R1CS_HPP_ diff --git a/src/gadgetlib1/gadgets/gadget_from_r1cs.tcc b/src/gadgetlib1/gadgets/gadget_from_r1cs.tcc new file mode 100644 index 00000000000..bc59b4587e5 --- /dev/null +++ b/src/gadgetlib1/gadgets/gadget_from_r1cs.tcc @@ -0,0 +1,123 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a gadget that can be created from an R1CS constraint system. + + See gadget_from_r1cs.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef GADGET_FROM_R1CS_TCC_ +#define GADGET_FROM_R1CS_TCC_ + +namespace libsnark { + +template +gadget_from_r1cs::gadget_from_r1cs(protoboard &pb, + const std::vector > &vars, + const r1cs_constraint_system &cs, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + vars(vars), + cs(cs) +{ + cs_to_vars[0] = 0; /* constant term maps to constant term */ + + size_t cs_var_idx = 1; + for (auto va : vars) + { +#ifdef DEBUG + printf("gadget_from_r1cs: translating a block of variables with length %zu\n", va.size()); +#endif + for (auto v : va) + { + cs_to_vars[cs_var_idx] = v.index; + +#ifdef DEBUG + if (v.index != 0) + { + // handle annotations, except for re-annotating constant term + const std::map::const_iterator it = cs.variable_annotations.find(cs_var_idx); + + std::string annotation = FMT(annotation_prefix, " variable_%zu", cs_var_idx); + if (it != cs.variable_annotations.end()) + { + annotation = annotation_prefix + " " + it->second; + } + + pb.augment_variable_annotation(v, annotation); + } +#endif + ++cs_var_idx; + } + } + +#ifdef DEBUG + printf("gadget_from_r1cs: sum of all block lengths: %zu\n", cs_var_idx-1); + printf("gadget_from_r1cs: cs.num_variables(): %zu\n", cs.num_variables()); +#endif + + assert(cs_var_idx - 1 == cs.num_variables()); +} + +template +void gadget_from_r1cs::generate_r1cs_constraints() +{ + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + const r1cs_constraint &constr = cs.constraints[i]; + r1cs_constraint translated_constr; + + for (const linear_term &t: constr.a.terms) + { + translated_constr.a.terms.emplace_back(linear_term(pb_variable(cs_to_vars[t.index]), t.coeff)); + } + + for (const linear_term &t: constr.b.terms) + { + translated_constr.b.terms.emplace_back(linear_term(pb_variable(cs_to_vars[t.index]), t.coeff)); + } + + for (const linear_term &t: constr.c.terms) + { + translated_constr.c.terms.emplace_back(linear_term(pb_variable(cs_to_vars[t.index]), t.coeff)); + } + + std::string annotation = FMT(this->annotation_prefix, " constraint_%zu", i); + +#ifdef DEBUG + auto it = cs.constraint_annotations.find(i); + if (it != cs.constraint_annotations.end()) + { + annotation = this->annotation_prefix + " " + it->second; + } +#endif + this->pb.add_r1cs_constraint(translated_constr, annotation); + } +} + +template +void gadget_from_r1cs::generate_r1cs_witness(const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input) +{ + assert(cs.num_inputs() == primary_input.size()); + assert(cs.num_variables() == primary_input.size() + auxiliary_input.size()); + + for (size_t i = 0; i < primary_input.size(); ++i) + { + this->pb.val(pb_variable(cs_to_vars[i+1])) = primary_input[i]; + } + + for (size_t i = 0; i < auxiliary_input.size(); ++i) + { + this->pb.val(pb_variable(cs_to_vars[primary_input.size()+i+1])) = auxiliary_input[i]; + } +} + +} // libsnark + +#endif // GADGET_FROM_R1CS_TCC_ diff --git a/src/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp b/src/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp new file mode 100644 index 00000000000..a7598b9be71 --- /dev/null +++ b/src/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp @@ -0,0 +1,42 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef DIGEST_SELECTOR_GADGET_HPP_ +#define DIGEST_SELECTOR_GADGET_HPP_ + +#include + +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" + +namespace libsnark { + +template +class digest_selector_gadget : public gadget { +public: + size_t digest_size; + digest_variable input; + pb_linear_combination is_right; + digest_variable left; + digest_variable right; + + digest_selector_gadget(protoboard &pb, + const size_t digest_size, + const digest_variable &input, + const pb_linear_combination &is_right, + const digest_variable &left, + const digest_variable &right, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc" + +#endif // DIGEST_SELECTOR_GADGET_HPP_ diff --git a/src/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc b/src/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc new file mode 100644 index 00000000000..422ee170a6c --- /dev/null +++ b/src/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc @@ -0,0 +1,62 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef DIGEST_SELECTOR_GADGET_TCC_ +#define DIGEST_SELECTOR_GADGET_TCC_ + +namespace libsnark { + +template +digest_selector_gadget::digest_selector_gadget(protoboard &pb, + const size_t digest_size, + const digest_variable &input, + const pb_linear_combination &is_right, + const digest_variable &left, + const digest_variable &right, + const std::string &annotation_prefix) : +gadget(pb, annotation_prefix), digest_size(digest_size), input(input), is_right(is_right), left(left), right(right) +{ +} + +template +void digest_selector_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < digest_size; ++i) + { + /* + input = is_right * right + (1-is_right) * left + input - left = is_right(right - left) + */ + this->pb.add_r1cs_constraint(r1cs_constraint(is_right, right.bits[i] - left.bits[i], input.bits[i] - left.bits[i]), + FMT(this->annotation_prefix, " propagate_%zu", i)); + } +} + +template +void digest_selector_gadget::generate_r1cs_witness() +{ + is_right.evaluate(this->pb); + + assert(this->pb.lc_val(is_right) == FieldT::one() || this->pb.lc_val(is_right) == FieldT::zero()); + if (this->pb.lc_val(is_right) == FieldT::one()) + { + for (size_t i = 0; i < digest_size; ++i) + { + this->pb.val(right.bits[i]) = this->pb.val(input.bits[i]); + } + } + else + { + for (size_t i = 0; i < digest_size; ++i) + { + this->pb.val(left.bits[i]) = this->pb.val(input.bits[i]); + } + } +} + +} // libsnark + +#endif // DIGEST_SELECTOR_GADGET_TCC_ diff --git a/src/gadgetlib1/gadgets/hashes/hash_io.hpp b/src/gadgetlib1/gadgets/hashes/hash_io.hpp new file mode 100644 index 00000000000..80ca19c61ed --- /dev/null +++ b/src/gadgetlib1/gadgets/hashes/hash_io.hpp @@ -0,0 +1,63 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef HASH_IO_HPP_ +#define HASH_IO_HPP_ +#include +#include +#include "gadgetlib1/gadgets/basic_gadgets.hpp" + +namespace libsnark { + +template +class digest_variable : public gadget { +public: + size_t digest_size; + pb_variable_array bits; + + digest_variable(protoboard &pb, + const size_t digest_size, + const std::string &annotation_prefix); + + digest_variable(protoboard &pb, + const size_t digest_size, + const pb_variable_array &partial_bits, + const pb_variable &padding, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(const bit_vector& contents); + bit_vector get_digest() const; +}; + +template +class block_variable : public gadget { +public: + size_t block_size; + pb_variable_array bits; + + block_variable(protoboard &pb, + const size_t block_size, + const std::string &annotation_prefix); + + block_variable(protoboard &pb, + const std::vector > &parts, + const std::string &annotation_prefix); + + block_variable(protoboard &pb, + const digest_variable &left, + const digest_variable &right, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(const bit_vector& contents); + bit_vector get_block() const; +}; + +} // libsnark +#include "gadgetlib1/gadgets/hashes/hash_io.tcc" + +#endif // HASH_IO_HPP_ diff --git a/src/gadgetlib1/gadgets/hashes/hash_io.tcc b/src/gadgetlib1/gadgets/hashes/hash_io.tcc new file mode 100644 index 00000000000..b122d8f98e0 --- /dev/null +++ b/src/gadgetlib1/gadgets/hashes/hash_io.tcc @@ -0,0 +1,105 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef HASH_IO_TCC_ +#define HASH_IO_TCC_ + +namespace libsnark { + +template +digest_variable::digest_variable(protoboard &pb, + const size_t digest_size, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), digest_size(digest_size) +{ + bits.allocate(pb, digest_size, FMT(this->annotation_prefix, " bits")); +} + +template +digest_variable::digest_variable(protoboard &pb, + const size_t digest_size, + const pb_variable_array &partial_bits, + const pb_variable &padding, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), digest_size(digest_size) +{ + assert(bits.size() <= digest_size); + bits = partial_bits; + while (bits.size() != digest_size) + { + bits.emplace_back(padding); + } +} + +template +void digest_variable::generate_r1cs_constraints() +{ + for (size_t i = 0; i < digest_size; ++i) + { + generate_boolean_r1cs_constraint(this->pb, bits[i], FMT(this->annotation_prefix, " bits_%zu", i)); + } +} + +template +void digest_variable::generate_r1cs_witness(const bit_vector& contents) +{ + bits.fill_with_bits(this->pb, contents); +} + +template +bit_vector digest_variable::get_digest() const +{ + return bits.get_bits(this->pb); +} + +template +block_variable::block_variable(protoboard &pb, + const size_t block_size, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), block_size(block_size) +{ + bits.allocate(pb, block_size, FMT(this->annotation_prefix, " bits")); +} + +template +block_variable::block_variable(protoboard &pb, + const std::vector > &parts, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + for (auto &part : parts) + { + bits.insert(bits.end(), part.begin(), part.end()); + } +} + +template +block_variable::block_variable(protoboard &pb, + const digest_variable &left, + const digest_variable &right, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + assert(left.bits.size() == right.bits.size()); + block_size = 2 * left.bits.size(); + bits.insert(bits.end(), left.bits.begin(), left.bits.end()); + bits.insert(bits.end(), right.bits.begin(), right.bits.end()); +} + +template +void block_variable::generate_r1cs_witness(const bit_vector& contents) +{ + bits.fill_with_bits(this->pb, contents); +} + +template +bit_vector block_variable::get_block() const +{ + return bits.get_bits(this->pb); +} + +} // libsnark +#endif // HASH_IO_TCC_ diff --git a/src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp b/src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp new file mode 100644 index 00000000000..e0c7a7e0b57 --- /dev/null +++ b/src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp @@ -0,0 +1,160 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for auxiliary gadgets for the SHA256 gadget. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SHA256_AUX_HPP_ +#define SHA256_AUX_HPP_ + +#include "gadgetlib1/gadgets/basic_gadgets.hpp" + +namespace libsnark { + +template +class lastbits_gadget : public gadget { +public: + pb_variable X; + size_t X_bits; + pb_variable result; + pb_linear_combination_array result_bits; + + pb_linear_combination_array full_bits; + std::shared_ptr > unpack_bits; + std::shared_ptr > pack_result; + + lastbits_gadget(protoboard &pb, + const pb_variable &X, + const size_t X_bits, + const pb_variable &result, + const pb_linear_combination_array &result_bits, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +class XOR3_gadget : public gadget { +private: + pb_variable tmp; +public: + pb_linear_combination A; + pb_linear_combination B; + pb_linear_combination C; + bool assume_C_is_zero; + pb_linear_combination out; + + XOR3_gadget(protoboard &pb, + const pb_linear_combination &A, + const pb_linear_combination &B, + const pb_linear_combination &C, + const bool assume_C_is_zero, + const pb_linear_combination &out, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +class small_sigma_gadget : public gadget { +private: + pb_variable_array W; + pb_variable result; +public: + pb_variable_array result_bits; + std::vector > > compute_bits; + std::shared_ptr > pack_result; + + small_sigma_gadget(protoboard &pb, + const pb_variable_array &W, + const pb_variable &result, + const size_t rot1, + const size_t rot2, + const size_t shift, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +class big_sigma_gadget : public gadget { +private: + pb_linear_combination_array W; + pb_variable result; +public: + pb_variable_array result_bits; + std::vector > > compute_bits; + std::shared_ptr > pack_result; + + big_sigma_gadget(protoboard &pb, + const pb_linear_combination_array &W, + const pb_variable &result, + const size_t rot1, + const size_t rot2, + const size_t rot3, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +class choice_gadget : public gadget { +private: + pb_variable_array result_bits; +public: + pb_linear_combination_array X; + pb_linear_combination_array Y; + pb_linear_combination_array Z; + pb_variable result; + std::shared_ptr > pack_result; + + choice_gadget(protoboard &pb, + const pb_linear_combination_array &X, + const pb_linear_combination_array &Y, + const pb_linear_combination_array &Z, + const pb_variable &result, const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +class majority_gadget : public gadget { +private: + pb_variable_array result_bits; + std::shared_ptr > pack_result; +public: + pb_linear_combination_array X; + pb_linear_combination_array Y; + pb_linear_combination_array Z; + pb_variable result; + + majority_gadget(protoboard &pb, + const pb_linear_combination_array &X, + const pb_linear_combination_array &Y, + const pb_linear_combination_array &Z, + const pb_variable &result, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc" + +#endif // SHA256_AUX_HPP_ diff --git a/src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc b/src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc new file mode 100644 index 00000000000..8ab67be5fb4 --- /dev/null +++ b/src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc @@ -0,0 +1,297 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for auxiliary gadgets for the SHA256 gadget. + + See sha256_aux.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SHA256_AUX_TCC_ +#define SHA256_AUX_TCC_ + +namespace libsnark { + +template +lastbits_gadget::lastbits_gadget(protoboard &pb, + const pb_variable &X, + const size_t X_bits, + const pb_variable &result, + const pb_linear_combination_array &result_bits, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + X(X), + X_bits(X_bits), + result(result), + result_bits(result_bits) +{ + full_bits = result_bits; + for (size_t i = result_bits.size(); i < X_bits; ++i) + { + pb_variable full_bits_overflow; + full_bits_overflow.allocate(pb, FMT(this->annotation_prefix, " full_bits_%zu", i)); + full_bits.emplace_back(full_bits_overflow); + } + + unpack_bits.reset(new packing_gadget(pb, full_bits, X, FMT(this->annotation_prefix, " unpack_bits"))); + pack_result.reset(new packing_gadget(pb, result_bits, result, FMT(this->annotation_prefix, " pack_result"))); +} + +template +void lastbits_gadget::generate_r1cs_constraints() +{ + unpack_bits->generate_r1cs_constraints(true); + pack_result->generate_r1cs_constraints(false); +} + +template +void lastbits_gadget::generate_r1cs_witness() +{ + unpack_bits->generate_r1cs_witness_from_packed(); + pack_result->generate_r1cs_witness_from_bits(); +} + +template +XOR3_gadget::XOR3_gadget(protoboard &pb, + const pb_linear_combination &A, + const pb_linear_combination &B, + const pb_linear_combination &C, + const bool assume_C_is_zero, + const pb_linear_combination &out, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + A(A), + B(B), + C(C), + assume_C_is_zero(assume_C_is_zero), + out(out) +{ + if (!assume_C_is_zero) + { + tmp.allocate(pb, FMT(this->annotation_prefix, " tmp")); + } +} + +template +void XOR3_gadget::generate_r1cs_constraints() +{ + /* + tmp = A + B - 2AB i.e. tmp = A xor B + out = tmp + C - 2tmp C i.e. out = tmp xor C + */ + if (assume_C_is_zero) + { + this->pb.add_r1cs_constraint(r1cs_constraint(2*A, B, A + B - out), FMT(this->annotation_prefix, " implicit_tmp_equals_out")); + } + else + { + this->pb.add_r1cs_constraint(r1cs_constraint(2*A, B, A + B - tmp), FMT(this->annotation_prefix, " tmp")); + this->pb.add_r1cs_constraint(r1cs_constraint(2 * tmp, C, tmp + C - out), FMT(this->annotation_prefix, " out")); + } +} + +template +void XOR3_gadget::generate_r1cs_witness() +{ + if (assume_C_is_zero) + { + this->pb.lc_val(out) = this->pb.lc_val(A) + this->pb.lc_val(B) - FieldT(2) * this->pb.lc_val(A) * this->pb.lc_val(B); + } + else + { + this->pb.val(tmp) = this->pb.lc_val(A) + this->pb.lc_val(B) - FieldT(2) * this->pb.lc_val(A) * this->pb.lc_val(B); + this->pb.lc_val(out) = this->pb.val(tmp) + this->pb.lc_val(C) - FieldT(2) * this->pb.val(tmp) * this->pb.lc_val(C); + } +} + +#define SHA256_GADGET_ROTR(A, i, k) A[((i)+(k)) % 32] + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +small_sigma_gadget::small_sigma_gadget(protoboard &pb, + const pb_variable_array &W, + const pb_variable &result, + const size_t rot1, + const size_t rot2, + const size_t shift, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + W(W), + result(result) +{ + result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits")); + compute_bits.resize(32); + for (size_t i = 0; i < 32; ++i) + { + compute_bits[i].reset(new XOR3_gadget(pb, SHA256_GADGET_ROTR(W, i, rot1), SHA256_GADGET_ROTR(W, i, rot2), + (i + shift < 32 ? W[i+shift] : ONE), + (i + shift >= 32), result_bits[i], + FMT(this->annotation_prefix, " compute_bits_%zu", i))); + } + pack_result.reset(new packing_gadget(pb, result_bits, result, FMT(this->annotation_prefix, " pack_result"))); +} + +template +void small_sigma_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < 32; ++i) + { + compute_bits[i]->generate_r1cs_constraints(); + } + + pack_result->generate_r1cs_constraints(false); +} + +template +void small_sigma_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < 32; ++i) + { + compute_bits[i]->generate_r1cs_witness(); + } + + pack_result->generate_r1cs_witness_from_bits(); +} + +template +big_sigma_gadget::big_sigma_gadget(protoboard &pb, + const pb_linear_combination_array &W, + const pb_variable &result, + const size_t rot1, + const size_t rot2, + const size_t rot3, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + W(W), + result(result) +{ + result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits")); + compute_bits.resize(32); + for (size_t i = 0; i < 32; ++i) + { + compute_bits[i].reset(new XOR3_gadget(pb, SHA256_GADGET_ROTR(W, i, rot1), SHA256_GADGET_ROTR(W, i, rot2), SHA256_GADGET_ROTR(W, i, rot3), false, result_bits[i], + FMT(this->annotation_prefix, " compute_bits_%zu", i))); + } + + pack_result.reset(new packing_gadget(pb, result_bits, result, FMT(this->annotation_prefix, " pack_result"))); +} + +template +void big_sigma_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < 32; ++i) + { + compute_bits[i]->generate_r1cs_constraints(); + } + + pack_result->generate_r1cs_constraints(false); +} + +template +void big_sigma_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < 32; ++i) + { + compute_bits[i]->generate_r1cs_witness(); + } + + pack_result->generate_r1cs_witness_from_bits(); +} + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +choice_gadget::choice_gadget(protoboard &pb, + const pb_linear_combination_array &X, + const pb_linear_combination_array &Y, + const pb_linear_combination_array &Z, + const pb_variable &result, const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + X(X), + Y(Y), + Z(Z), + result(result) +{ + result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits")); + pack_result.reset(new packing_gadget(pb, result_bits, result, FMT(this->annotation_prefix, " result"))); +} + +template +void choice_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < 32; ++i) + { + /* + result = x * y + (1-x) * z + result - z = x * (y - z) + */ + this->pb.add_r1cs_constraint(r1cs_constraint(X[i], Y[i] - Z[i], result_bits[i] - Z[i]), FMT(this->annotation_prefix, " result_bits_%zu", i)); + } + pack_result->generate_r1cs_constraints(false); +} + +template +void choice_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < 32; ++i) + { + this->pb.val(result_bits[i]) = this->pb.lc_val(X[i]) * this->pb.lc_val(Y[i]) + (FieldT::one() - this->pb.lc_val(X[i])) * this->pb.lc_val(Z[i]); + } + pack_result->generate_r1cs_witness_from_bits(); +} + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +majority_gadget::majority_gadget(protoboard &pb, + const pb_linear_combination_array &X, + const pb_linear_combination_array &Y, + const pb_linear_combination_array &Z, + const pb_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + X(X), + Y(Y), + Z(Z), + result(result) +{ + result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits")); + pack_result.reset(new packing_gadget(pb, result_bits, result, FMT(this->annotation_prefix, " result"))); +} + +template +void majority_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < 32; ++i) + { + /* + 2*result + aux = x + y + z + x, y, z, aux -- bits + aux = x + y + z - 2*result + */ + generate_boolean_r1cs_constraint(this->pb, result_bits[i], FMT(this->annotation_prefix, " result_%zu", i)); + this->pb.add_r1cs_constraint(r1cs_constraint(X[i] + Y[i] + Z[i] - 2 * result_bits[i], + 1 - (X[i] + Y[i] + Z[i] - 2 * result_bits[i]), + 0), + FMT(this->annotation_prefix, " result_bits_%zu", i)); + } + pack_result->generate_r1cs_constraints(false); +} + +template +void majority_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < 32; ++i) + { + const long v = (this->pb.lc_val(X[i]) + this->pb.lc_val(Y[i]) + this->pb.lc_val(Z[i])).as_ulong(); + this->pb.val(result_bits[i]) = FieldT(v / 2); + } + + pack_result->generate_r1cs_witness_from_bits(); +} + +} // libsnark + +#endif // SHA256_AUX_TCC_ diff --git a/src/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp b/src/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp new file mode 100644 index 00000000000..c2f31e3af35 --- /dev/null +++ b/src/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp @@ -0,0 +1,108 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for gadgets for the SHA256 message schedule and round function. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SHA256_COMPONENTS_HPP_ +#define SHA256_COMPONENTS_HPP_ + +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" +#include "gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp" + +namespace libsnark { + +const size_t SHA256_digest_size = 256; +const size_t SHA256_block_size = 512; + +template +pb_linear_combination_array SHA256_default_IV(protoboard &pb); + +template +class sha256_message_schedule_gadget : public gadget { +public: + std::vector > W_bits; + std::vector > > pack_W; + + std::vector > sigma0; + std::vector > sigma1; + std::vector > > compute_sigma0; + std::vector > > compute_sigma1; + std::vector > unreduced_W; + std::vector > > mod_reduce_W; +public: + pb_variable_array M; + pb_variable_array packed_W; + sha256_message_schedule_gadget(protoboard &pb, + const pb_variable_array &M, + const pb_variable_array &packed_W, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +class sha256_round_function_gadget : public gadget { +public: + pb_variable sigma0; + pb_variable sigma1; + std::shared_ptr > compute_sigma0; + std::shared_ptr > compute_sigma1; + pb_variable choice; + pb_variable majority; + std::shared_ptr > compute_choice; + std::shared_ptr > compute_majority; + pb_variable packed_d; + std::shared_ptr > pack_d; + pb_variable packed_h; + std::shared_ptr > pack_h; + pb_variable unreduced_new_a; + pb_variable unreduced_new_e; + std::shared_ptr > mod_reduce_new_a; + std::shared_ptr > mod_reduce_new_e; + pb_variable packed_new_a; + pb_variable packed_new_e; +public: + pb_linear_combination_array a; + pb_linear_combination_array b; + pb_linear_combination_array c; + pb_linear_combination_array d; + pb_linear_combination_array e; + pb_linear_combination_array f; + pb_linear_combination_array g; + pb_linear_combination_array h; + pb_variable W; + long K; + pb_linear_combination_array new_a; + pb_linear_combination_array new_e; + + sha256_round_function_gadget(protoboard &pb, + const pb_linear_combination_array &a, + const pb_linear_combination_array &b, + const pb_linear_combination_array &c, + const pb_linear_combination_array &d, + const pb_linear_combination_array &e, + const pb_linear_combination_array &f, + const pb_linear_combination_array &g, + const pb_linear_combination_array &h, + const pb_variable &W, + const long &K, + const pb_linear_combination_array &new_a, + const pb_linear_combination_array &new_e, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc" + +#endif // SHA256_COMPONENTS_HPP_ diff --git a/src/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc b/src/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc new file mode 100644 index 00000000000..e8f233a544d --- /dev/null +++ b/src/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc @@ -0,0 +1,250 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for gadgets for the SHA256 message schedule and round function. + + See sha256_components.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SHA256_COMPONENTS_TCC_ +#define SHA256_COMPONENTS_TCC_ + +namespace libsnark { + +const unsigned long SHA256_K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +const unsigned long SHA256_H[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 +}; + +template +pb_linear_combination_array SHA256_default_IV(protoboard &pb) +{ + pb_linear_combination_array result; + result.reserve(SHA256_digest_size); + + for (size_t i = 0; i < SHA256_digest_size; ++i) + { + int iv_val = (SHA256_H[i / 32] >> (31-(i % 32))) & 1; + + pb_linear_combination iv_element; + iv_element.assign(pb, iv_val * ONE); + iv_element.evaluate(pb); + + result.emplace_back(iv_element); + } + + return result; +} + +template +sha256_message_schedule_gadget::sha256_message_schedule_gadget(protoboard &pb, + const pb_variable_array &M, + const pb_variable_array &packed_W, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + M(M), + packed_W(packed_W) +{ + W_bits.resize(64); + + pack_W.resize(16); + for (size_t i = 0; i < 16; ++i) + { + W_bits[i] = pb_variable_array(M.rbegin() + (15-i) * 32, M.rbegin() + (16-i) * 32); + pack_W[i].reset(new packing_gadget(pb, W_bits[i], packed_W[i], FMT(this->annotation_prefix, " pack_W_%zu", i))); + } + + /* NB: some of those will be un-allocated */ + sigma0.resize(64); + sigma1.resize(64); + compute_sigma0.resize(64); + compute_sigma1.resize(64); + unreduced_W.resize(64); + mod_reduce_W.resize(64); + + for (size_t i = 16; i < 64; ++i) + { + /* allocate result variables for sigma0/sigma1 invocations */ + sigma0[i].allocate(pb, FMT(this->annotation_prefix, " sigma0_%zu", i)); + sigma1[i].allocate(pb, FMT(this->annotation_prefix, " sigma1_%zu", i)); + + /* compute sigma0/sigma1 */ + compute_sigma0[i].reset(new small_sigma_gadget(pb, W_bits[i-15], sigma0[i], 7, 18, 3, FMT(this->annotation_prefix, " compute_sigma0_%zu", i))); + compute_sigma1[i].reset(new small_sigma_gadget(pb, W_bits[i-2], sigma1[i], 17, 19, 10, FMT(this->annotation_prefix, " compute_sigma1_%zu", i))); + + /* unreduced_W = sigma0(W_{i-15}) + sigma1(W_{i-2}) + W_{i-7} + W_{i-16} before modulo 2^32 */ + unreduced_W[i].allocate(pb, FMT(this->annotation_prefix, "unreduced_W_%zu", i)); + + /* allocate the bit representation of packed_W[i] */ + W_bits[i].allocate(pb, 32, FMT(this->annotation_prefix, " W_bits_%zu", i)); + + /* and finally reduce this into packed and bit representations */ + mod_reduce_W[i].reset(new lastbits_gadget(pb, unreduced_W[i], 32+2, packed_W[i], W_bits[i], FMT(this->annotation_prefix, " mod_reduce_W_%zu", i))); + } +} + +template +void sha256_message_schedule_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < 16; ++i) + { + pack_W[i]->generate_r1cs_constraints(false); // do not enforce bitness here; caller be aware. + } + + for (size_t i = 16; i < 64; ++i) + { + compute_sigma0[i]->generate_r1cs_constraints(); + compute_sigma1[i]->generate_r1cs_constraints(); + + this->pb.add_r1cs_constraint(r1cs_constraint(1, + sigma0[i] + sigma1[i] + packed_W[i-16] + packed_W[i-7], + unreduced_W[i]), + FMT(this->annotation_prefix, " unreduced_W_%zu", i)); + + mod_reduce_W[i]->generate_r1cs_constraints(); + } +} + +template +void sha256_message_schedule_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < 16; ++i) + { + pack_W[i]->generate_r1cs_witness_from_bits(); + } + + for (size_t i = 16; i < 64; ++i) + { + compute_sigma0[i]->generate_r1cs_witness(); + compute_sigma1[i]->generate_r1cs_witness(); + + this->pb.val(unreduced_W[i]) = this->pb.val(sigma0[i]) + this->pb.val(sigma1[i]) + this->pb.val(packed_W[i-16]) + this->pb.val(packed_W[i-7]); + mod_reduce_W[i]->generate_r1cs_witness(); + } +} + +template +sha256_round_function_gadget::sha256_round_function_gadget(protoboard &pb, + const pb_linear_combination_array &a, + const pb_linear_combination_array &b, + const pb_linear_combination_array &c, + const pb_linear_combination_array &d, + const pb_linear_combination_array &e, + const pb_linear_combination_array &f, + const pb_linear_combination_array &g, + const pb_linear_combination_array &h, + const pb_variable &W, + const long &K, + const pb_linear_combination_array &new_a, + const pb_linear_combination_array &new_e, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + a(a), + b(b), + c(c), + d(d), + e(e), + f(f), + g(g), + h(h), + W(W), + K(K), + new_a(new_a), + new_e(new_e) +{ + /* compute sigma0 and sigma1 */ + sigma0.allocate(pb, FMT(this->annotation_prefix, " sigma0")); + sigma1.allocate(pb, FMT(this->annotation_prefix, " sigma1")); + compute_sigma0.reset(new big_sigma_gadget(pb, a, sigma0, 2, 13, 22, FMT(this->annotation_prefix, " compute_sigma0"))); + compute_sigma1.reset(new big_sigma_gadget(pb, e, sigma1, 6, 11, 25, FMT(this->annotation_prefix, " compute_sigma1"))); + + /* compute choice */ + choice.allocate(pb, FMT(this->annotation_prefix, " choice")); + compute_choice.reset(new choice_gadget(pb, e, f, g, choice, FMT(this->annotation_prefix, " compute_choice"))); + + /* compute majority */ + majority.allocate(pb, FMT(this->annotation_prefix, " majority")); + compute_majority.reset(new majority_gadget(pb, a, b, c, majority, FMT(this->annotation_prefix, " compute_majority"))); + + /* pack d */ + packed_d.allocate(pb, FMT(this->annotation_prefix, " packed_d")); + pack_d.reset(new packing_gadget(pb, d, packed_d, FMT(this->annotation_prefix, " pack_d"))); + + /* pack h */ + packed_h.allocate(pb, FMT(this->annotation_prefix, " packed_h")); + pack_h.reset(new packing_gadget(pb, h, packed_h, FMT(this->annotation_prefix, " pack_h"))); + + /* compute the actual results for the round */ + unreduced_new_a.allocate(pb, FMT(this->annotation_prefix, " unreduced_new_a")); + unreduced_new_e.allocate(pb, FMT(this->annotation_prefix, " unreduced_new_e")); + + packed_new_a.allocate(pb, FMT(this->annotation_prefix, " packed_new_a")); + packed_new_e.allocate(pb, FMT(this->annotation_prefix, " packed_new_e")); + + mod_reduce_new_a.reset(new lastbits_gadget(pb, unreduced_new_a, 32+3, packed_new_a, new_a, FMT(this->annotation_prefix, " mod_reduce_new_a"))); + mod_reduce_new_e.reset(new lastbits_gadget(pb, unreduced_new_e, 32+3, packed_new_e, new_e, FMT(this->annotation_prefix, " mod_reduce_new_e"))); +} + +template +void sha256_round_function_gadget::generate_r1cs_constraints() +{ + compute_sigma0->generate_r1cs_constraints(); + compute_sigma1->generate_r1cs_constraints(); + + compute_choice->generate_r1cs_constraints(); + compute_majority->generate_r1cs_constraints(); + + pack_d->generate_r1cs_constraints(false); + pack_h->generate_r1cs_constraints(false); + + this->pb.add_r1cs_constraint(r1cs_constraint(1, + packed_h + sigma1 + choice + K + W + sigma0 + majority, + unreduced_new_a), + FMT(this->annotation_prefix, " unreduced_new_a")); + + this->pb.add_r1cs_constraint(r1cs_constraint(1, + packed_d + packed_h + sigma1 + choice + K + W, + unreduced_new_e), + FMT(this->annotation_prefix, " unreduced_new_e")); + + mod_reduce_new_a->generate_r1cs_constraints(); + mod_reduce_new_e->generate_r1cs_constraints(); +} + +template +void sha256_round_function_gadget::generate_r1cs_witness() +{ + compute_sigma0->generate_r1cs_witness(); + compute_sigma1->generate_r1cs_witness(); + + compute_choice->generate_r1cs_witness(); + compute_majority->generate_r1cs_witness(); + + pack_d->generate_r1cs_witness_from_bits(); + pack_h->generate_r1cs_witness_from_bits(); + + this->pb.val(unreduced_new_a) = this->pb.val(packed_h) + this->pb.val(sigma1) + this->pb.val(choice) + FieldT(K) + this->pb.val(W) + this->pb.val(sigma0) + this->pb.val(majority); + this->pb.val(unreduced_new_e) = this->pb.val(packed_d) + this->pb.val(packed_h) + this->pb.val(sigma1) + this->pb.val(choice) + FieldT(K) + this->pb.val(W); + + mod_reduce_new_a->generate_r1cs_witness(); + mod_reduce_new_e->generate_r1cs_witness(); +} + +} // libsnark + +#endif // SHA256_COMPONENTS_TCC_ diff --git a/src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp b/src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp new file mode 100644 index 00000000000..8cb6365c8a0 --- /dev/null +++ b/src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp @@ -0,0 +1,98 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for top-level SHA256 gadgets. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SHA256_GADGET_HPP_ +#define SHA256_GADGET_HPP_ + +#include "common/data_structures/merkle_tree.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" +#include "gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp" + +namespace libsnark { + +/** + * Gadget for the SHA256 compression function. + */ +template +class sha256_compression_function_gadget : public gadget { +public: + std::vector > round_a; + std::vector > round_b; + std::vector > round_c; + std::vector > round_d; + std::vector > round_e; + std::vector > round_f; + std::vector > round_g; + std::vector > round_h; + + pb_variable_array packed_W; + std::shared_ptr > message_schedule; + std::vector > round_functions; + + pb_variable_array unreduced_output; + pb_variable_array reduced_output; + std::vector > reduce_output; +public: + pb_linear_combination_array prev_output; + pb_variable_array new_block; + digest_variable output; + + sha256_compression_function_gadget(protoboard &pb, + const pb_linear_combination_array &prev_output, + const pb_variable_array &new_block, + const digest_variable &output, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget for the SHA256 compression function, viewed as a 2-to-1 hash + * function, and using the same initialization vector as in SHA256 + * specification. Thus, any collision for + * sha256_two_to_one_hash_gadget trivially extends to a collision for + * full SHA256 (by appending the same padding). + */ +template +class sha256_two_to_one_hash_gadget : public gadget { +public: + typedef bit_vector hash_value_type; + typedef merkle_authentication_path merkle_authentication_path_type; + + std::shared_ptr > f; + + sha256_two_to_one_hash_gadget(protoboard &pb, + const digest_variable &left, + const digest_variable &right, + const digest_variable &output, + const std::string &annotation_prefix); + sha256_two_to_one_hash_gadget(protoboard &pb, + const size_t block_length, + const block_variable &input_block, + const digest_variable &output, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(const bool ensure_output_bitness=true); // TODO: ignored for now + void generate_r1cs_witness(); + + static size_t get_block_len(); + static size_t get_digest_len(); + static bit_vector get_hash(const bit_vector &input); + + static size_t expected_constraints(const bool ensure_output_bitness=true); // TODO: ignored for now +}; + +} // libsnark + +#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc" + +#endif // SHA256_GADGET_HPP_ diff --git a/src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc b/src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc new file mode 100644 index 00000000000..fc7ac982a7c --- /dev/null +++ b/src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc @@ -0,0 +1,230 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for top-level SHA256 gadgets. + + See sha256_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SHA256_GADGET_TCC_ +#define SHA256_GADGET_TCC_ + +namespace libsnark { + +template +sha256_compression_function_gadget::sha256_compression_function_gadget(protoboard &pb, + const pb_linear_combination_array &prev_output, + const pb_variable_array &new_block, + const digest_variable &output, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + prev_output(prev_output), + new_block(new_block), + output(output) +{ + /* message schedule and inputs for it */ + packed_W.allocate(pb, 64, FMT(this->annotation_prefix, " packed_W")); + message_schedule.reset(new sha256_message_schedule_gadget(pb, new_block, packed_W, FMT(this->annotation_prefix, " message_schedule"))); + + /* initalize */ + round_a.push_back(pb_linear_combination_array(prev_output.rbegin() + 7*32, prev_output.rbegin() + 8*32)); + round_b.push_back(pb_linear_combination_array(prev_output.rbegin() + 6*32, prev_output.rbegin() + 7*32)); + round_c.push_back(pb_linear_combination_array(prev_output.rbegin() + 5*32, prev_output.rbegin() + 6*32)); + round_d.push_back(pb_linear_combination_array(prev_output.rbegin() + 4*32, prev_output.rbegin() + 5*32)); + round_e.push_back(pb_linear_combination_array(prev_output.rbegin() + 3*32, prev_output.rbegin() + 4*32)); + round_f.push_back(pb_linear_combination_array(prev_output.rbegin() + 2*32, prev_output.rbegin() + 3*32)); + round_g.push_back(pb_linear_combination_array(prev_output.rbegin() + 1*32, prev_output.rbegin() + 2*32)); + round_h.push_back(pb_linear_combination_array(prev_output.rbegin() + 0*32, prev_output.rbegin() + 1*32)); + + /* do the rounds */ + for (size_t i = 0; i < 64; ++i) + { + round_h.push_back(round_g[i]); + round_g.push_back(round_f[i]); + round_f.push_back(round_e[i]); + round_d.push_back(round_c[i]); + round_c.push_back(round_b[i]); + round_b.push_back(round_a[i]); + + pb_variable_array new_round_a_variables; + new_round_a_variables.allocate(pb, 32, FMT(this->annotation_prefix, " new_round_a_variables_%zu", i+1)); + round_a.emplace_back(new_round_a_variables); + + pb_variable_array new_round_e_variables; + new_round_e_variables.allocate(pb, 32, FMT(this->annotation_prefix, " new_round_e_variables_%zu", i+1)); + round_e.emplace_back(new_round_e_variables); + + round_functions.push_back(sha256_round_function_gadget(pb, + round_a[i], round_b[i], round_c[i], round_d[i], + round_e[i], round_f[i], round_g[i], round_h[i], + packed_W[i], SHA256_K[i], round_a[i+1], round_e[i+1], + FMT(this->annotation_prefix, " round_functions_%zu", i))); + } + + /* finalize */ + unreduced_output.allocate(pb, 8, FMT(this->annotation_prefix, " unreduced_output")); + reduced_output.allocate(pb, 8, FMT(this->annotation_prefix, " reduced_output")); + for (size_t i = 0; i < 8; ++i) + { + reduce_output.push_back(lastbits_gadget(pb, + unreduced_output[i], + 32+1, + reduced_output[i], + pb_variable_array(output.bits.rbegin() + (7-i) * 32, output.bits.rbegin() + (8-i) * 32), + FMT(this->annotation_prefix, " reduce_output_%zu", i))); + } +} + +template +void sha256_compression_function_gadget::generate_r1cs_constraints() +{ + message_schedule->generate_r1cs_constraints(); + for (size_t i = 0; i < 64; ++i) + { + round_functions[i].generate_r1cs_constraints(); + } + + for (size_t i = 0; i < 4; ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(1, + round_functions[3-i].packed_d + round_functions[63-i].packed_new_a, + unreduced_output[i]), + FMT(this->annotation_prefix, " unreduced_output_%zu", i)); + + this->pb.add_r1cs_constraint(r1cs_constraint(1, + round_functions[3-i].packed_h + round_functions[63-i].packed_new_e, + unreduced_output[4+i]), + FMT(this->annotation_prefix, " unreduced_output_%zu", 4+i)); + } + + for (size_t i = 0; i < 8; ++i) + { + reduce_output[i].generate_r1cs_constraints(); + } +} + +template +void sha256_compression_function_gadget::generate_r1cs_witness() +{ + message_schedule->generate_r1cs_witness(); + +#ifdef DEBUG + printf("Input:\n"); + for (size_t j = 0; j < 16; ++j) + { + printf("%lx ", this->pb.val(packed_W[j]).as_ulong()); + } + printf("\n"); +#endif + + for (size_t i = 0; i < 64; ++i) + { + round_functions[i].generate_r1cs_witness(); + } + + for (size_t i = 0; i < 4; ++i) + { + this->pb.val(unreduced_output[i]) = this->pb.val(round_functions[3-i].packed_d) + this->pb.val(round_functions[63-i].packed_new_a); + this->pb.val(unreduced_output[4+i]) = this->pb.val(round_functions[3-i].packed_h) + this->pb.val(round_functions[63-i].packed_new_e); + } + + for (size_t i = 0; i < 8; ++i) + { + reduce_output[i].generate_r1cs_witness(); + } + +#ifdef DEBUG + printf("Output:\n"); + for (size_t j = 0; j < 8; ++j) + { + printf("%lx ", this->pb.val(reduced_output[j]).as_ulong()); + } + printf("\n"); +#endif +} + +template +sha256_two_to_one_hash_gadget::sha256_two_to_one_hash_gadget(protoboard &pb, + const digest_variable &left, + const digest_variable &right, + const digest_variable &output, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + /* concatenate block = left || right */ + pb_variable_array block; + block.insert(block.end(), left.bits.begin(), left.bits.end()); + block.insert(block.end(), right.bits.begin(), right.bits.end()); + + /* compute the hash itself */ + f.reset(new sha256_compression_function_gadget(pb, SHA256_default_IV(pb), block, output, FMT(this->annotation_prefix, " f"))); +} + +template +sha256_two_to_one_hash_gadget::sha256_two_to_one_hash_gadget(protoboard &pb, + const size_t block_length, + const block_variable &input_block, + const digest_variable &output, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + assert(block_length == SHA256_block_size); + assert(input_block.bits.size() == block_length); + f.reset(new sha256_compression_function_gadget(pb, SHA256_default_IV(pb), input_block.bits, output, FMT(this->annotation_prefix, " f"))); +} + +template +void sha256_two_to_one_hash_gadget::generate_r1cs_constraints(const bool ensure_output_bitness) +{ + UNUSED(ensure_output_bitness); + f->generate_r1cs_constraints(); +} + +template +void sha256_two_to_one_hash_gadget::generate_r1cs_witness() +{ + f->generate_r1cs_witness(); +} + +template +size_t sha256_two_to_one_hash_gadget::get_block_len() +{ + return SHA256_block_size; +} + +template +size_t sha256_two_to_one_hash_gadget::get_digest_len() +{ + return SHA256_digest_size; +} + +template +bit_vector sha256_two_to_one_hash_gadget::get_hash(const bit_vector &input) +{ + protoboard pb; + + block_variable input_variable(pb, SHA256_block_size, "input"); + digest_variable output_variable(pb, SHA256_digest_size, "output"); + sha256_two_to_one_hash_gadget f(pb, SHA256_block_size, input_variable, output_variable, "f"); + + input_variable.generate_r1cs_witness(input); + f.generate_r1cs_witness(); + + return output_variable.get_digest(); +} + +template +size_t sha256_two_to_one_hash_gadget::expected_constraints(const bool ensure_output_bitness) +{ + UNUSED(ensure_output_bitness); + return 27280; /* hardcoded for now */ +} + +} // libsnark + +#endif // SHA256_GADGET_TCC_ diff --git a/src/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py b/src/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py new file mode 100644 index 00000000000..452317ffb40 --- /dev/null +++ b/src/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +## +# @author This file is part of libsnark, developed by SCIPR Lab +# and contributors (see AUTHORS). +# @copyright MIT license (see LICENSE file) + +import random +import pypy_sha256 # PyPy's implementation of SHA256 compression function; see copyright and authorship notice within. + +BLOCK_LEN = 512 +BLOCK_BYTES = BLOCK_LEN // 8 +HASH_LEN = 256 +HASH_BYTES = HASH_LEN // 8 + +def gen_random_bytes(n): + return [random.randint(0, 255) for i in xrange(n)] + +def words_to_bytes(arr): + return sum(([x >> 24, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff] for x in arr), []) + +def bytes_to_words(arr): + l = len(arr) + assert l % 4 == 0 + return [(arr[i*4 + 3] << 24) + (arr[i*4+2] << 16) + (arr[i*4+1] << 8) + arr[i*4] for i in xrange(l//4)] + +def cpp_val(s, log_radix=32): + if log_radix == 8: + hexfmt = '0x%02x' + elif log_radix == 32: + hexfmt = '0x%08x' + s = bytes_to_words(s) + else: + raise + return 'int_list_to_bits({%s}, %d)' % (', '.join(hexfmt % x for x in s), log_radix) + +def H_bytes(x): + assert len(x) == BLOCK_BYTES + state = pypy_sha256.sha_init() + state['data'] = words_to_bytes(bytes_to_words(x)) + pypy_sha256.sha_transform(state) + return words_to_bytes(bytes_to_words(words_to_bytes(state['digest']))) + +def generate_sha256_gadget_tests(): + left = gen_random_bytes(HASH_BYTES) + right = gen_random_bytes(HASH_BYTES) + hash = H_bytes(left + right) + + print "const bit_vector left_bv = %s;" % cpp_val(left) + print "const bit_vector right_bv = %s;" % cpp_val(right) + print "const bit_vector hash_bv = %s;" % cpp_val(hash) + +if __name__ == '__main__': + random.seed(0) # for reproducibility + generate_sha256_gadget_tests() + diff --git a/src/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py b/src/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py new file mode 100644 index 00000000000..496989c117c --- /dev/null +++ b/src/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py @@ -0,0 +1,263 @@ +#!/usr/bin/env python +# +# SHA256 compression function implementation below is a verbatim copy of PyPy's implementation from +# https://bitbucket.org/pypy/pypy/raw/f1f064b3faf1e012f7a9a9ab08f18074637ebe8a/lib_pypy/_sha256.py . +# +# It is licensed under the MIT license and copyright PyPy Copyright holders 2003-2015 +# See https://bitbucket.org/pypy/pypy/src/tip/LICENSE for the full copyright notice. +# + +SHA_BLOCKSIZE = 64 +SHA_DIGESTSIZE = 32 + + +def new_shaobject(): + return { + 'digest': [0]*8, + 'count_lo': 0, + 'count_hi': 0, + 'data': [0]* SHA_BLOCKSIZE, + 'local': 0, + 'digestsize': 0 + } + +ROR = lambda x, y: (((x & 0xffffffff) >> (y & 31)) | (x << (32 - (y & 31)))) & 0xffffffff +Ch = lambda x, y, z: (z ^ (x & (y ^ z))) +Maj = lambda x, y, z: (((x | y) & z) | (x & y)) +S = lambda x, n: ROR(x, n) +R = lambda x, n: (x & 0xffffffff) >> n +Sigma0 = lambda x: (S(x, 2) ^ S(x, 13) ^ S(x, 22)) +Sigma1 = lambda x: (S(x, 6) ^ S(x, 11) ^ S(x, 25)) +Gamma0 = lambda x: (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +Gamma1 = lambda x: (S(x, 17) ^ S(x, 19) ^ R(x, 10)) + +def sha_transform(sha_info): + W = [] + + d = sha_info['data'] + for i in range(0,16): + W.append( (d[4*i]<<24) + (d[4*i+1]<<16) + (d[4*i+2]<<8) + d[4*i+3]) + + for i in range(16,64): + W.append( (Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]) & 0xffffffff ) + + ss = sha_info['digest'][:] + + def RND(a,b,c,d,e,f,g,h,i,ki): + t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; + t1 = Sigma0(a) + Maj(a, b, c); + d += t0; + h = t0 + t1; + return d & 0xffffffff, h & 0xffffffff + + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],0,0x428a2f98); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],1,0x71374491); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],2,0xb5c0fbcf); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],3,0xe9b5dba5); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],4,0x3956c25b); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],5,0x59f111f1); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],6,0x923f82a4); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],7,0xab1c5ed5); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],8,0xd807aa98); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],9,0x12835b01); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],10,0x243185be); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],11,0x550c7dc3); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],12,0x72be5d74); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],13,0x80deb1fe); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],14,0x9bdc06a7); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],15,0xc19bf174); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],16,0xe49b69c1); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],17,0xefbe4786); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],18,0x0fc19dc6); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],19,0x240ca1cc); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],20,0x2de92c6f); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],21,0x4a7484aa); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],22,0x5cb0a9dc); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],23,0x76f988da); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],24,0x983e5152); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],25,0xa831c66d); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],26,0xb00327c8); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],27,0xbf597fc7); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],28,0xc6e00bf3); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],29,0xd5a79147); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],30,0x06ca6351); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],31,0x14292967); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],32,0x27b70a85); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],33,0x2e1b2138); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],34,0x4d2c6dfc); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],35,0x53380d13); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],36,0x650a7354); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],37,0x766a0abb); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],38,0x81c2c92e); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],39,0x92722c85); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],40,0xa2bfe8a1); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],41,0xa81a664b); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],42,0xc24b8b70); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],43,0xc76c51a3); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],44,0xd192e819); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],45,0xd6990624); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],46,0xf40e3585); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],47,0x106aa070); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],48,0x19a4c116); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],49,0x1e376c08); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],50,0x2748774c); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],51,0x34b0bcb5); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],52,0x391c0cb3); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],53,0x4ed8aa4a); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],54,0x5b9cca4f); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],55,0x682e6ff3); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],56,0x748f82ee); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],57,0x78a5636f); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],58,0x84c87814); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],59,0x8cc70208); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],60,0x90befffa); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],61,0xa4506ceb); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],62,0xbef9a3f7); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],63,0xc67178f2); + + dig = [] + for i, x in enumerate(sha_info['digest']): + dig.append( (x + ss[i]) & 0xffffffff ) + sha_info['digest'] = dig + +def sha_init(): + sha_info = new_shaobject() + sha_info['digest'] = [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19] + sha_info['count_lo'] = 0 + sha_info['count_hi'] = 0 + sha_info['local'] = 0 + sha_info['digestsize'] = 32 + return sha_info + +def sha224_init(): + sha_info = new_shaobject() + sha_info['digest'] = [0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4] + sha_info['count_lo'] = 0 + sha_info['count_hi'] = 0 + sha_info['local'] = 0 + sha_info['digestsize'] = 28 + return sha_info + +def sha_update(sha_info, buffer): + if isinstance(buffer, str): + raise TypeError("Unicode strings must be encoded before hashing") + count = len(buffer) + buffer_idx = 0 + clo = (sha_info['count_lo'] + (count << 3)) & 0xffffffff + if clo < sha_info['count_lo']: + sha_info['count_hi'] += 1 + sha_info['count_lo'] = clo + + sha_info['count_hi'] += (count >> 29) + + if sha_info['local']: + i = SHA_BLOCKSIZE - sha_info['local'] + if i > count: + i = count + + # copy buffer + sha_info['data'][sha_info['local']:sha_info['local']+i] = buffer[buffer_idx:buffer_idx+i] + + count -= i + buffer_idx += i + + sha_info['local'] += i + if sha_info['local'] == SHA_BLOCKSIZE: + sha_transform(sha_info) + sha_info['local'] = 0 + else: + return + + while count >= SHA_BLOCKSIZE: + # copy buffer + sha_info['data'] = list(buffer[buffer_idx:buffer_idx + SHA_BLOCKSIZE]) + count -= SHA_BLOCKSIZE + buffer_idx += SHA_BLOCKSIZE + sha_transform(sha_info) + + + # copy buffer + pos = sha_info['local'] + sha_info['data'][pos:pos+count] = buffer[buffer_idx:buffer_idx + count] + sha_info['local'] = count + +def sha_final(sha_info): + lo_bit_count = sha_info['count_lo'] + hi_bit_count = sha_info['count_hi'] + count = (lo_bit_count >> 3) & 0x3f + sha_info['data'][count] = 0x80; + count += 1 + if count > SHA_BLOCKSIZE - 8: + # zero the bytes in data after the count + sha_info['data'] = sha_info['data'][:count] + ([0] * (SHA_BLOCKSIZE - count)) + sha_transform(sha_info) + # zero bytes in data + sha_info['data'] = [0] * SHA_BLOCKSIZE + else: + sha_info['data'] = sha_info['data'][:count] + ([0] * (SHA_BLOCKSIZE - count)) + + sha_info['data'][56] = (hi_bit_count >> 24) & 0xff + sha_info['data'][57] = (hi_bit_count >> 16) & 0xff + sha_info['data'][58] = (hi_bit_count >> 8) & 0xff + sha_info['data'][59] = (hi_bit_count >> 0) & 0xff + sha_info['data'][60] = (lo_bit_count >> 24) & 0xff + sha_info['data'][61] = (lo_bit_count >> 16) & 0xff + sha_info['data'][62] = (lo_bit_count >> 8) & 0xff + sha_info['data'][63] = (lo_bit_count >> 0) & 0xff + + sha_transform(sha_info) + + dig = [] + for i in sha_info['digest']: + dig.extend([ ((i>>24) & 0xff), ((i>>16) & 0xff), ((i>>8) & 0xff), (i & 0xff) ]) + return ''.join([chr(i) for i in dig]) + +class sha256(object): + digest_size = digestsize = SHA_DIGESTSIZE + block_size = SHA_BLOCKSIZE + + def __init__(self, s=None): + self._sha = sha_init() + if s: + sha_update(self._sha, s) + + def update(self, s): + sha_update(self._sha, s) + + def digest(self): + return sha_final(self._sha.copy())[:self._sha['digestsize']] + + def hexdigest(self): + return ''.join(['%.2x' % ord(i) for i in self.digest()]) + + def copy(self): + new = sha256.__new__(sha256) + new._sha = self._sha.copy() + return new + +class sha224(sha256): + digest_size = digestsize = 28 + + def __init__(self, s=None): + self._sha = sha224_init() + if s: + sha_update(self._sha, s) + + def copy(self): + new = sha224.__new__(sha224) + new._sha = self._sha.copy() + return new + +def test(): + a_str = "just a test string" + + assert 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' == sha256().hexdigest() + assert 'd7b553c6f09ac85d142415f857c5310f3bbbe7cdd787cce4b985acedd585266f' == sha256(a_str).hexdigest() + assert '8113ebf33c97daa9998762aacafe750c7cefc2b2f173c90c59663a57fe626f21' == sha256(a_str*7).hexdigest() + + s = sha256(a_str) + s.update(a_str) + assert '03d9963e05a094593190b6fc794cb1a3e1ac7d7883f0b5855268afeccc70d461' == s.hexdigest() + +if __name__ == "__main__": + test() diff --git a/src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp b/src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp new file mode 100644 index 00000000000..471928f6ab3 --- /dev/null +++ b/src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp @@ -0,0 +1,46 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/default_types/ec_pp.hpp" +#include "common/utils.hpp" +#include "common/profiling.hpp" +#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" + +using namespace libsnark; + +template +void test_two_to_one() +{ + protoboard pb; + + digest_variable left(pb, SHA256_digest_size, "left"); + digest_variable right(pb, SHA256_digest_size, "right"); + digest_variable output(pb, SHA256_digest_size, "output"); + + sha256_two_to_one_hash_gadget f(pb, left, right, output, "f"); + f.generate_r1cs_constraints(); + printf("Number of constraints for sha256_two_to_one_hash_gadget: %zu\n", pb.num_constraints()); + + const bit_vector left_bv = int_list_to_bits({0x426bc2d8, 0x4dc86782, 0x81e8957a, 0x409ec148, 0xe6cffbe8, 0xafe6ba4f, 0x9c6f1978, 0xdd7af7e9}, 32); + const bit_vector right_bv = int_list_to_bits({0x038cce42, 0xabd366b8, 0x3ede7e00, 0x9130de53, 0x72cdf73d, 0xee825114, 0x8cb48d1b, 0x9af68ad0}, 32); + const bit_vector hash_bv = int_list_to_bits({0xeffd0b7f, 0x1ccba116, 0x2ee816f7, 0x31c62b48, 0x59305141, 0x990e5c0a, 0xce40d33d, 0x0b1167d1}, 32); + + left.generate_r1cs_witness(left_bv); + right.generate_r1cs_witness(right_bv); + + f.generate_r1cs_witness(); + output.generate_r1cs_witness(hash_bv); + + assert(pb.is_satisfied()); +} + +int main(void) +{ + start_profiling(); + default_ec_pp::init_public_params(); + test_two_to_one >(); +} diff --git a/src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp b/src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp new file mode 100644 index 00000000000..0efa7cf4d23 --- /dev/null +++ b/src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp @@ -0,0 +1,38 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_AUTHENTICATION_PATH_VARIABLE_HPP_ +#define MERKLE_AUTHENTICATION_PATH_VARIABLE_HPP_ + +#include "common/data_structures/merkle_tree.hpp" +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" + +namespace libsnark { + +template +class merkle_authentication_path_variable : public gadget { +public: + + const size_t tree_depth; + std::vector > left_digests; + std::vector > right_digests; + + merkle_authentication_path_variable(protoboard &pb, + const size_t tree_depth, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(const size_t address, const merkle_authentication_path &path); + merkle_authentication_path get_authentication_path(const size_t address) const; +}; + +} // libsnark + +#include "gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc" + +#endif // MERKLE_AUTHENTICATION_PATH_VARIABLE_HPP diff --git a/src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc b/src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc new file mode 100644 index 00000000000..d773051ab91 --- /dev/null +++ b/src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc @@ -0,0 +1,76 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_AUTHENTICATION_PATH_VARIABLE_TCC_ +#define MERKLE_AUTHENTICATION_PATH_VARIABLE_TCC_ + +namespace libsnark { + +template +merkle_authentication_path_variable::merkle_authentication_path_variable(protoboard &pb, + const size_t tree_depth, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + tree_depth(tree_depth) +{ + for (size_t i = 0; i < tree_depth; ++i) + { + left_digests.emplace_back(digest_variable(pb, HashT::get_digest_len(), FMT(annotation_prefix, " left_digests_%zu", i))); + right_digests.emplace_back(digest_variable(pb, HashT::get_digest_len(), FMT(annotation_prefix, " right_digests_%zu", i))); + } +} + +template +void merkle_authentication_path_variable::generate_r1cs_constraints() +{ + for (size_t i = 0; i < tree_depth; ++i) + { + left_digests[i].generate_r1cs_constraints(); + right_digests[i].generate_r1cs_constraints(); + } +} + +template +void merkle_authentication_path_variable::generate_r1cs_witness(const size_t address, const merkle_authentication_path &path) +{ + assert(path.size() == tree_depth); + + for (size_t i = 0; i < tree_depth; ++i) + { + if (address & (1ul << (tree_depth-1-i))) + { + left_digests[i].generate_r1cs_witness(path[i]); + } + else + { + right_digests[i].generate_r1cs_witness(path[i]); + } + } +} + +template +merkle_authentication_path merkle_authentication_path_variable::get_authentication_path(const size_t address) const +{ + merkle_authentication_path result; + for (size_t i = 0; i < tree_depth; ++i) + { + if (address & (1ul << (tree_depth-1-i))) + { + result.emplace_back(left_digests[i].get_digest()); + } + else + { + result.emplace_back(right_digests[i].get_digest()); + } + } + + return result; +} + +} // libsnark + +#endif // MERKLE_AUTHENTICATION_PATH_VARIABLE_TCC diff --git a/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp b/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp new file mode 100644 index 00000000000..b1e3a4f053a --- /dev/null +++ b/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp @@ -0,0 +1,73 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the Merkle tree check read gadget. + + The gadget checks the following: given a root R, address A, value V, and + authentication path P, check that P is a valid authentication path for the + value V as the A-th leaf in a Merkle tree with root R. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_TREE_CHECK_READ_GADGET_HPP_ +#define MERKLE_TREE_CHECK_READ_GADGET_HPP_ + +#include "common/data_structures/merkle_tree.hpp" +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" +#include "gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp" +#include "gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp" + +namespace libsnark { + +template +class merkle_tree_check_read_gadget : public gadget { +private: + + std::vector hashers; + std::vector > hasher_inputs; + std::vector > propagators; + std::vector > internal_output; + + std::shared_ptr > computed_root; + std::shared_ptr > check_root; + +public: + + const size_t digest_size; + const size_t tree_depth; + pb_linear_combination_array address_bits; + digest_variable leaf; + digest_variable root; + merkle_authentication_path_variable path; + pb_linear_combination read_successful; + + merkle_tree_check_read_gadget(protoboard &pb, + const size_t tree_depth, + const pb_linear_combination_array &address_bits, + const digest_variable &leaf_digest, + const digest_variable &root_digest, + const merkle_authentication_path_variable &path, + const pb_linear_combination &read_successful, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); + + static size_t root_size_in_bits(); + /* for debugging purposes */ + static size_t expected_constraints(const size_t tree_depth); +}; + +template +void test_merkle_tree_check_read_gadget(); + +} // libsnark + +#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc" + +#endif // MERKLE_TREE_CHECK_READ_GADGET_HPP_ diff --git a/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc b/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc new file mode 100644 index 00000000000..6002a5886d7 --- /dev/null +++ b/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc @@ -0,0 +1,196 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the Merkle tree check read. + + See merkle_tree_check_read_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_TREE_CHECK_READ_GADGET_TCC_ +#define MERKLE_TREE_CHECK_READ_GADGET_TCC_ + +namespace libsnark { + +template +merkle_tree_check_read_gadget::merkle_tree_check_read_gadget(protoboard &pb, + const size_t tree_depth, + const pb_linear_combination_array &address_bits, + const digest_variable &leaf, + const digest_variable &root, + const merkle_authentication_path_variable &path, + const pb_linear_combination &read_successful, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + digest_size(HashT::get_digest_len()), + tree_depth(tree_depth), + address_bits(address_bits), + leaf(leaf), + root(root), + path(path), + read_successful(read_successful) +{ + /* + The tricky part here is ordering. For Merkle tree + authentication paths, path[0] corresponds to one layer below + the root (and path[tree_depth-1] corresponds to the layer + containing the leaf), while address_bits has the reverse order: + address_bits[0] is LSB, and corresponds to layer containing the + leaf, and address_bits[tree_depth-1] is MSB, and corresponds to + the subtree directly under the root. + */ + assert(tree_depth > 0); + assert(tree_depth == address_bits.size()); + + for (size_t i = 0; i < tree_depth-1; ++i) + { + internal_output.emplace_back(digest_variable(pb, digest_size, FMT(this->annotation_prefix, " internal_output_%zu", i))); + } + + computed_root.reset(new digest_variable(pb, digest_size, FMT(this->annotation_prefix, " computed_root"))); + + for (size_t i = 0; i < tree_depth; ++i) + { + block_variable inp(pb, path.left_digests[i], path.right_digests[i], FMT(this->annotation_prefix, " inp_%zu", i)); + hasher_inputs.emplace_back(inp); + hashers.emplace_back(HashT(pb, 2*digest_size, inp, (i == 0 ? *computed_root : internal_output[i-1]), + FMT(this->annotation_prefix, " load_hashers_%zu", i))); + } + + for (size_t i = 0; i < tree_depth; ++i) + { + /* + The propagators take a computed hash value (or leaf in the + base case) and propagate it one layer up, either in the left + or the right slot of authentication_path_variable. + */ + propagators.emplace_back(digest_selector_gadget(pb, digest_size, i < tree_depth - 1 ? internal_output[i] : leaf, + address_bits[tree_depth-1-i], path.left_digests[i], path.right_digests[i], + FMT(this->annotation_prefix, " digest_selector_%zu", i))); + } + + check_root.reset(new bit_vector_copy_gadget(pb, computed_root->bits, root.bits, read_successful, FieldT::capacity(), FMT(annotation_prefix, " check_root"))); +} + +template +void merkle_tree_check_read_gadget::generate_r1cs_constraints() +{ + /* ensure correct hash computations */ + for (size_t i = 0; i < tree_depth; ++i) + { + // Note that we check root outside and have enforced booleanity of path.left_digests/path.right_digests outside in path.generate_r1cs_constraints + hashers[i].generate_r1cs_constraints(false); + } + + /* ensure consistency of path.left_digests/path.right_digests with internal_output */ + for (size_t i = 0; i < tree_depth; ++i) + { + propagators[i].generate_r1cs_constraints(); + } + + check_root->generate_r1cs_constraints(false, false); +} + +template +void merkle_tree_check_read_gadget::generate_r1cs_witness() +{ + /* do the hash computations bottom-up */ + for (int i = tree_depth-1; i >= 0; --i) + { + /* propagate previous input */ + propagators[i].generate_r1cs_witness(); + + /* compute hash */ + hashers[i].generate_r1cs_witness(); + } + + check_root->generate_r1cs_witness(); +} + +template +size_t merkle_tree_check_read_gadget::root_size_in_bits() +{ + return HashT::get_digest_len(); +} + +template +size_t merkle_tree_check_read_gadget::expected_constraints(const size_t tree_depth) +{ + /* NB: this includes path constraints */ + const size_t hasher_constraints = tree_depth * HashT::expected_constraints(false); + const size_t propagator_constraints = tree_depth * HashT::get_digest_len(); + const size_t authentication_path_constraints = 2 * tree_depth * HashT::get_digest_len(); + const size_t check_root_constraints = 3 * div_ceil(HashT::get_digest_len(), FieldT::capacity()); + + return hasher_constraints + propagator_constraints + authentication_path_constraints + check_root_constraints; +} + +template +void test_merkle_tree_check_read_gadget() +{ + /* prepare test */ + const size_t digest_len = HashT::get_digest_len(); + const size_t tree_depth = 16; + std::vector path(tree_depth); + + bit_vector prev_hash(digest_len); + std::generate(prev_hash.begin(), prev_hash.end(), [&]() { return std::rand() % 2; }); + bit_vector leaf = prev_hash; + + bit_vector address_bits; + + size_t address = 0; + for (long level = tree_depth-1; level >= 0; --level) + { + const bool computed_is_right = (std::rand() % 2); + address |= (computed_is_right ? 1ul << (tree_depth-1-level) : 0); + address_bits.push_back(computed_is_right); + bit_vector other(digest_len); + std::generate(other.begin(), other.end(), [&]() { return std::rand() % 2; }); + + bit_vector block = prev_hash; + block.insert(computed_is_right ? block.begin() : block.end(), other.begin(), other.end()); + bit_vector h = HashT::get_hash(block); + + path[level] = other; + + prev_hash = h; + } + bit_vector root = prev_hash; + + /* execute test */ + protoboard pb; + pb_variable_array address_bits_va; + address_bits_va.allocate(pb, tree_depth, "address_bits"); + digest_variable leaf_digest(pb, digest_len, "input_block"); + digest_variable root_digest(pb, digest_len, "output_digest"); + merkle_authentication_path_variable path_var(pb, tree_depth, "path_var"); + merkle_tree_check_read_gadget ml(pb, tree_depth, address_bits_va, leaf_digest, root_digest, path_var, ONE, "ml"); + + path_var.generate_r1cs_constraints(); + ml.generate_r1cs_constraints(); + + address_bits_va.fill_with_bits(pb, address_bits); + assert(address_bits_va.get_field_element_from_bits(pb).as_ulong() == address); + leaf_digest.generate_r1cs_witness(leaf); + path_var.generate_r1cs_witness(address, path); + ml.generate_r1cs_witness(); + + /* make sure that read checker didn't accidentally overwrite anything */ + address_bits_va.fill_with_bits(pb, address_bits); + leaf_digest.generate_r1cs_witness(leaf); + root_digest.generate_r1cs_witness(root); + assert(pb.is_satisfied()); + + const size_t num_constraints = pb.num_constraints(); + const size_t expected_constraints = merkle_tree_check_read_gadget::expected_constraints(tree_depth); + assert(num_constraints == expected_constraints); +} + +} // libsnark + +#endif // MERKLE_TREE_CHECK_READ_GADGET_TCC_ diff --git a/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp b/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp new file mode 100644 index 00000000000..2d6840d6195 --- /dev/null +++ b/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp @@ -0,0 +1,91 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the Merkle tree check read gadget. + + The gadget checks the following: given two roots R1 and R2, address A, two + values V1 and V2, and authentication path P, check that + - P is a valid authentication path for the value V1 as the A-th leaf in a Merkle tree with root R1, and + - P is a valid authentication path for the value V2 as the A-th leaf in a Merkle tree with root R2. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_TREE_CHECK_UPDATE_GADGET_HPP_ +#define MERKLE_TREE_CHECK_UPDATE_GADGET_HPP_ + +#include "common/data_structures/merkle_tree.hpp" +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/hashes/crh_gadget.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" +#include "gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp" +#include "gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp" + +namespace libsnark { + +template +class merkle_tree_check_update_gadget : public gadget { +private: + + std::vector prev_hashers; + std::vector > prev_hasher_inputs; + std::vector > prev_propagators; + std::vector > prev_internal_output; + + std::vector next_hashers; + std::vector > next_hasher_inputs; + std::vector > next_propagators; + std::vector > next_internal_output; + + std::shared_ptr > computed_next_root; + std::shared_ptr > check_next_root; + +public: + + const size_t digest_size; + const size_t tree_depth; + + pb_variable_array address_bits; + digest_variable prev_leaf_digest; + digest_variable prev_root_digest; + merkle_authentication_path_variable prev_path; + digest_variable next_leaf_digest; + digest_variable next_root_digest; + merkle_authentication_path_variable next_path; + pb_linear_combination update_successful; + + /* Note that while it is necessary to generate R1CS constraints + for prev_path, it is not necessary to do so for next_path. See + comment in the implementation of generate_r1cs_constraints() */ + + merkle_tree_check_update_gadget(protoboard &pb, + const size_t tree_depth, + const pb_variable_array &address_bits, + const digest_variable &prev_leaf_digest, + const digest_variable &prev_root_digest, + const merkle_authentication_path_variable &prev_path, + const digest_variable &next_leaf_digest, + const digest_variable &next_root_digest, + const merkle_authentication_path_variable &next_path, + const pb_linear_combination &update_successful, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); + + static size_t root_size_in_bits(); + /* for debugging purposes */ + static size_t expected_constraints(const size_t tree_depth); +}; + +template +void test_merkle_tree_check_update_gadget(); + +} // libsnark + +#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc" + +#endif // MERKLE_TREE_CHECK_UPDATE_GADGET_HPP_ diff --git a/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc b/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc new file mode 100644 index 00000000000..1ac08edbbe8 --- /dev/null +++ b/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc @@ -0,0 +1,265 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the Merkle tree check update gadget. + + See merkle_tree_check_update_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_TREE_CHECK_UPDATE_GADGET_TCC_ +#define MERKLE_TREE_CHECK_UPDATE_GADGET_TCC_ + +namespace libsnark { + +template +merkle_tree_check_update_gadget::merkle_tree_check_update_gadget(protoboard &pb, + const size_t tree_depth, + const pb_variable_array &address_bits, + const digest_variable &prev_leaf_digest, + const digest_variable &prev_root_digest, + const merkle_authentication_path_variable &prev_path, + const digest_variable &next_leaf_digest, + const digest_variable &next_root_digest, + const merkle_authentication_path_variable &next_path, + const pb_linear_combination &update_successful, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + digest_size(HashT::get_digest_len()), + tree_depth(tree_depth), + address_bits(address_bits), + prev_leaf_digest(prev_leaf_digest), + prev_root_digest(prev_root_digest), + prev_path(prev_path), + next_leaf_digest(next_leaf_digest), + next_root_digest(next_root_digest), + next_path(next_path), + update_successful(update_successful) +{ + assert(tree_depth > 0); + assert(tree_depth == address_bits.size()); + + for (size_t i = 0; i < tree_depth-1; ++i) + { + prev_internal_output.emplace_back(digest_variable(pb, digest_size, FMT(this->annotation_prefix, " prev_internal_output_%zu", i))); + next_internal_output.emplace_back(digest_variable(pb, digest_size, FMT(this->annotation_prefix, " next_internal_output_%zu", i))); + } + + computed_next_root.reset(new digest_variable(pb, digest_size, FMT(this->annotation_prefix, " computed_root"))); + + for (size_t i = 0; i < tree_depth; ++i) + { + block_variable prev_inp(pb, prev_path.left_digests[i], prev_path.right_digests[i], FMT(this->annotation_prefix, " prev_inp_%zu", i)); + prev_hasher_inputs.emplace_back(prev_inp); + prev_hashers.emplace_back(HashT(pb, 2*digest_size, prev_inp, (i == 0 ? prev_root_digest : prev_internal_output[i-1]), + FMT(this->annotation_prefix, " prev_hashers_%zu", i))); + + block_variable next_inp(pb, next_path.left_digests[i], next_path.right_digests[i], FMT(this->annotation_prefix, " next_inp_%zu", i)); + next_hasher_inputs.emplace_back(next_inp); + next_hashers.emplace_back(HashT(pb, 2*digest_size, next_inp, (i == 0 ? *computed_next_root : next_internal_output[i-1]), + FMT(this->annotation_prefix, " next_hashers_%zu", i))); + } + + for (size_t i = 0; i < tree_depth; ++i) + { + prev_propagators.emplace_back(digest_selector_gadget(pb, digest_size, i < tree_depth -1 ? prev_internal_output[i] : prev_leaf_digest, + address_bits[tree_depth-1-i], prev_path.left_digests[i], prev_path.right_digests[i], + FMT(this->annotation_prefix, " prev_propagators_%zu", i))); + next_propagators.emplace_back(digest_selector_gadget(pb, digest_size, i < tree_depth -1 ? next_internal_output[i] : next_leaf_digest, + address_bits[tree_depth-1-i], next_path.left_digests[i], next_path.right_digests[i], + FMT(this->annotation_prefix, " next_propagators_%zu", i))); + } + + check_next_root.reset(new bit_vector_copy_gadget(pb, computed_next_root->bits, next_root_digest.bits, update_successful, FieldT::capacity(), FMT(annotation_prefix, " check_next_root"))); +} + +template +void merkle_tree_check_update_gadget::generate_r1cs_constraints() +{ + /* ensure correct hash computations */ + for (size_t i = 0; i < tree_depth; ++i) + { + prev_hashers[i].generate_r1cs_constraints(false); // we check root outside and prev_left/prev_right above + next_hashers[i].generate_r1cs_constraints(true); // however we must check right side hashes + } + + /* ensure consistency of internal_left/internal_right with internal_output */ + for (size_t i = 0; i < tree_depth; ++i) + { + prev_propagators[i].generate_r1cs_constraints(); + next_propagators[i].generate_r1cs_constraints(); + } + + /* ensure that prev auxiliary input and next auxiliary input match */ + for (size_t i = 0; i < tree_depth; ++i) + { + for (size_t j = 0; j < digest_size; ++j) + { + /* + addr * (prev_left - next_left) + (1 - addr) * (prev_right - next_right) = 0 + addr * (prev_left - next_left - prev_right + next_right) = next_right - prev_right + */ + this->pb.add_r1cs_constraint(r1cs_constraint(address_bits[tree_depth-1-i], + prev_path.left_digests[i].bits[j] - next_path.left_digests[i].bits[j] - prev_path.right_digests[i].bits[j] + next_path.right_digests[i].bits[j], + next_path.right_digests[i].bits[j] - prev_path.right_digests[i].bits[j]), + FMT(this->annotation_prefix, " aux_check_%zu_%zu", i, j)); + } + } + + /* Note that while it is necessary to generate R1CS constraints + for prev_path, it is not necessary to do so for next_path. + + This holds, because { next_path.left_inputs[i], + next_path.right_inputs[i] } is a pair { hash_output, + auxiliary_input }. The bitness for hash_output is enforced + above by next_hashers[i].generate_r1cs_constraints. + + Because auxiliary input is the same for prev_path and next_path + (enforced above), we have that auxiliary_input part is also + constrained to be boolean, because prev_path is *all* + constrained to be all boolean. */ + + check_next_root->generate_r1cs_constraints(false, false); +} + +template +void merkle_tree_check_update_gadget::generate_r1cs_witness() +{ + /* do the hash computations bottom-up */ + for (int i = tree_depth-1; i >= 0; --i) + { + /* ensure consistency of prev_path and next_path */ + if (this->pb.val(address_bits[tree_depth-1-i]) == FieldT::one()) + { + next_path.left_digests[i].generate_r1cs_witness(prev_path.left_digests[i].get_digest()); + } + else + { + next_path.right_digests[i].generate_r1cs_witness(prev_path.right_digests[i].get_digest()); + } + + /* propagate previous input */ + prev_propagators[i].generate_r1cs_witness(); + next_propagators[i].generate_r1cs_witness(); + + /* compute hash */ + prev_hashers[i].generate_r1cs_witness(); + next_hashers[i].generate_r1cs_witness(); + } + + check_next_root->generate_r1cs_witness(); +} + +template +size_t merkle_tree_check_update_gadget::root_size_in_bits() +{ + return HashT::get_digest_len(); +} + +template +size_t merkle_tree_check_update_gadget::expected_constraints(const size_t tree_depth) +{ + /* NB: this includes path constraints */ + const size_t prev_hasher_constraints = tree_depth * HashT::expected_constraints(false); + const size_t next_hasher_constraints = tree_depth * HashT::expected_constraints(true); + const size_t prev_authentication_path_constraints = 2 * tree_depth * HashT::get_digest_len(); + const size_t prev_propagator_constraints = tree_depth * HashT::get_digest_len(); + const size_t next_propagator_constraints = tree_depth * HashT::get_digest_len(); + const size_t check_next_root_constraints = 3 * div_ceil(HashT::get_digest_len(), FieldT::capacity()); + const size_t aux_equality_constraints = tree_depth * HashT::get_digest_len(); + + return (prev_hasher_constraints + next_hasher_constraints + prev_authentication_path_constraints + + prev_propagator_constraints + next_propagator_constraints + check_next_root_constraints + + aux_equality_constraints); +} + +template +void test_merkle_tree_check_update_gadget() +{ + /* prepare test */ + const size_t digest_len = HashT::get_digest_len(); + + const size_t tree_depth = 16; + std::vector prev_path(tree_depth); + + bit_vector prev_load_hash(digest_len); + std::generate(prev_load_hash.begin(), prev_load_hash.end(), [&]() { return std::rand() % 2; }); + bit_vector prev_store_hash(digest_len); + std::generate(prev_store_hash.begin(), prev_store_hash.end(), [&]() { return std::rand() % 2; }); + + bit_vector loaded_leaf = prev_load_hash; + bit_vector stored_leaf = prev_store_hash; + + bit_vector address_bits; + + size_t address = 0; + for (long level = tree_depth-1; level >= 0; --level) + { + const bool computed_is_right = (std::rand() % 2); + address |= (computed_is_right ? 1ul << (tree_depth-1-level) : 0); + address_bits.push_back(computed_is_right); + bit_vector other(digest_len); + std::generate(other.begin(), other.end(), [&]() { return std::rand() % 2; }); + + bit_vector load_block = prev_load_hash; + load_block.insert(computed_is_right ? load_block.begin() : load_block.end(), other.begin(), other.end()); + bit_vector store_block = prev_store_hash; + store_block.insert(computed_is_right ? store_block.begin() : store_block.end(), other.begin(), other.end()); + + bit_vector load_h = HashT::get_hash(load_block); + bit_vector store_h = HashT::get_hash(store_block); + + prev_path[level] = other; + + prev_load_hash = load_h; + prev_store_hash = store_h; + } + + bit_vector load_root = prev_load_hash; + bit_vector store_root = prev_store_hash; + + /* execute the test */ + protoboard pb; + pb_variable_array address_bits_va; + address_bits_va.allocate(pb, tree_depth, "address_bits"); + digest_variable prev_leaf_digest(pb, digest_len, "prev_leaf_digest"); + digest_variable prev_root_digest(pb, digest_len, "prev_root_digest"); + merkle_authentication_path_variable prev_path_var(pb, tree_depth, "prev_path_var"); + digest_variable next_leaf_digest(pb, digest_len, "next_leaf_digest"); + digest_variable next_root_digest(pb, digest_len, "next_root_digest"); + merkle_authentication_path_variable next_path_var(pb, tree_depth, "next_path_var"); + merkle_tree_check_update_gadget mls(pb, tree_depth, address_bits_va, + prev_leaf_digest, prev_root_digest, prev_path_var, + next_leaf_digest, next_root_digest, next_path_var, ONE, "mls"); + + prev_path_var.generate_r1cs_constraints(); + mls.generate_r1cs_constraints(); + + address_bits_va.fill_with_bits(pb, address_bits); + assert(address_bits_va.get_field_element_from_bits(pb).as_ulong() == address); + prev_leaf_digest.generate_r1cs_witness(loaded_leaf); + prev_path_var.generate_r1cs_witness(address, prev_path); + next_leaf_digest.generate_r1cs_witness(stored_leaf); + address_bits_va.fill_with_bits(pb, address_bits); + mls.generate_r1cs_witness(); + + /* make sure that update check will check for the right things */ + prev_leaf_digest.generate_r1cs_witness(loaded_leaf); + next_leaf_digest.generate_r1cs_witness(stored_leaf); + prev_root_digest.generate_r1cs_witness(load_root); + next_root_digest.generate_r1cs_witness(store_root); + address_bits_va.fill_with_bits(pb, address_bits); + assert(pb.is_satisfied()); + + const size_t num_constraints = pb.num_constraints(); + const size_t expected_constraints = merkle_tree_check_update_gadget::expected_constraints(tree_depth); + assert(num_constraints == expected_constraints); +} + +} // libsnark + +#endif // MERKLE_TREE_CHECK_UPDATE_GADGET_TCC_ diff --git a/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp b/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp new file mode 100644 index 00000000000..8d52c579b72 --- /dev/null +++ b/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp @@ -0,0 +1,48 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifdef CURVE_BN128 +#include "algebra/curves/bn128/bn128_pp.hpp" +#endif +#include "algebra/curves/edwards/edwards_pp.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp" +#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp" +#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" + +using namespace libsnark; + +template +void test_all_merkle_tree_gadgets() +{ + typedef Fr FieldT; + test_merkle_tree_check_read_gadget >(); + test_merkle_tree_check_read_gadget >(); + + test_merkle_tree_check_update_gadget >(); + test_merkle_tree_check_update_gadget >(); +} + +int main(void) +{ + start_profiling(); + +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + bn128_pp::init_public_params(); + test_all_merkle_tree_gadgets(); +#endif + + edwards_pp::init_public_params(); + test_all_merkle_tree_gadgets(); + + mnt4_pp::init_public_params(); + test_all_merkle_tree_gadgets(); + + mnt6_pp::init_public_params(); + test_all_merkle_tree_gadgets(); +} diff --git a/src/gadgetlib1/pb_variable.hpp b/src/gadgetlib1/pb_variable.hpp new file mode 100644 index 00000000000..fdf64d0140f --- /dev/null +++ b/src/gadgetlib1/pb_variable.hpp @@ -0,0 +1,144 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PB_VARIABLE_HPP_ +#define PB_VARIABLE_HPP_ + +#include +#include +#include +#include "common/utils.hpp" +#include "relations/variable.hpp" + +namespace libsnark { + +typedef size_t lc_index_t; + +template +class protoboard; + +template +class pb_variable : public variable { +public: + pb_variable(const var_index_t index = 0) : variable(index) {}; + + void allocate(protoboard &pb, const std::string &annotation=""); +}; + +template +class pb_variable_array : private std::vector > +{ + typedef std::vector > contents; +public: + using typename contents::iterator; + using typename contents::const_iterator; + using typename contents::reverse_iterator; + using typename contents::const_reverse_iterator; + + using contents::begin; + using contents::end; + using contents::rbegin; + using contents::rend; + using contents::emplace_back; + using contents::insert; + using contents::reserve; + using contents::size; + using contents::empty; + using contents::operator[]; + using contents::resize; + + pb_variable_array() : contents() {}; + pb_variable_array(size_t count, const pb_variable &value) : contents(count, value) {}; + pb_variable_array(typename contents::const_iterator first, typename contents::const_iterator last) : contents(first, last) {}; + pb_variable_array(typename contents::const_reverse_iterator first, typename contents::const_reverse_iterator last) : contents(first, last) {}; + void allocate(protoboard &pb, const size_t n, const std::string &annotation_prefix=""); + + void fill_with_field_elements(protoboard &pb, const std::vector& vals) const; + void fill_with_bits(protoboard &pb, const bit_vector& bits) const; + void fill_with_bits_of_ulong(protoboard &pb, const unsigned long i) const; + void fill_with_bits_of_field_element(protoboard &pb, const FieldT &r) const; + + std::vector get_vals(const protoboard &pb) const; + bit_vector get_bits(const protoboard &pb) const; + + FieldT get_field_element_from_bits(const protoboard &pb) const; +}; + +/* index 0 corresponds to the constant term (used in legacy code) */ +#define ONE pb_variable(0) + +template +class pb_linear_combination : public linear_combination { +public: + bool is_variable; + lc_index_t index; + + pb_linear_combination(); + pb_linear_combination(const pb_variable &var); + + void assign(protoboard &pb, const linear_combination &lc); + void evaluate(protoboard &pb) const; + + bool is_constant() const; + FieldT constant_term() const; +}; + +template +class pb_linear_combination_array : private std::vector > +{ + typedef std::vector > contents; +public: + using typename contents::iterator; + using typename contents::const_iterator; + using typename contents::reverse_iterator; + using typename contents::const_reverse_iterator; + + using contents::begin; + using contents::end; + using contents::rbegin; + using contents::rend; + using contents::emplace_back; + using contents::insert; + using contents::reserve; + using contents::size; + using contents::empty; + using contents::operator[]; + using contents::resize; + + pb_linear_combination_array() : contents() {}; + pb_linear_combination_array(const pb_variable_array &arr) { for (auto &v : arr) this->emplace_back(pb_linear_combination(v)); }; + pb_linear_combination_array(size_t count) : contents(count) {}; + pb_linear_combination_array(size_t count, const pb_linear_combination &value) : contents(count, value) {}; + pb_linear_combination_array(typename contents::const_iterator first, typename contents::const_iterator last) : contents(first, last) {}; + pb_linear_combination_array(typename contents::const_reverse_iterator first, typename contents::const_reverse_iterator last) : contents(first, last) {}; + + void evaluate(protoboard &pb) const; + + void fill_with_field_elements(protoboard &pb, const std::vector& vals) const; + void fill_with_bits(protoboard &pb, const bit_vector& bits) const; + void fill_with_bits_of_ulong(protoboard &pb, const unsigned long i) const; + void fill_with_bits_of_field_element(protoboard &pb, const FieldT &r) const; + + std::vector get_vals(const protoboard &pb) const; + bit_vector get_bits(const protoboard &pb) const; + + FieldT get_field_element_from_bits(const protoboard &pb) const; +}; + +template +linear_combination pb_sum(const pb_linear_combination_array &v); + +template +linear_combination pb_packing_sum(const pb_linear_combination_array &v); + +template +linear_combination pb_coeff_sum(const pb_linear_combination_array &v, const std::vector &coeffs); + +} // libsnark +#include "gadgetlib1/pb_variable.tcc" + +#endif // PB_VARIABLE_HPP_ diff --git a/src/gadgetlib1/pb_variable.tcc b/src/gadgetlib1/pb_variable.tcc new file mode 100644 index 00000000000..b36b3f8d788 --- /dev/null +++ b/src/gadgetlib1/pb_variable.tcc @@ -0,0 +1,330 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PB_VARIABLE_TCC_ +#define PB_VARIABLE_TCC_ +#include +#include "gadgetlib1/protoboard.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +template +void pb_variable::allocate(protoboard &pb, const std::string &annotation) +{ + this->index = pb.allocate_var_index(annotation); +} + +/* allocates pb_variable array in MSB->LSB order */ +template +void pb_variable_array::allocate(protoboard &pb, const size_t n, const std::string &annotation_prefix) +{ +#ifdef DEBUG + assert(annotation_prefix != ""); +#endif + (*this).resize(n); + + for (size_t i = 0; i < n; ++i) + { + (*this)[i].allocate(pb, FMT(annotation_prefix, "_%zu", i)); + } +} + +template +void pb_variable_array::fill_with_field_elements(protoboard &pb, const std::vector& vals) const +{ + assert(this->size() == vals.size()); + for (size_t i = 0; i < vals.size(); ++i) + { + pb.val((*this)[i]) = vals[i]; + } +} + +template +void pb_variable_array::fill_with_bits(protoboard &pb, const bit_vector& bits) const +{ + assert(this->size() == bits.size()); + for (size_t i = 0; i < bits.size(); ++i) + { + pb.val((*this)[i]) = (bits[i] ? FieldT::one() : FieldT::zero()); + } +} + +template +void pb_variable_array::fill_with_bits_of_field_element(protoboard &pb, const FieldT &r) const +{ + const bigint rint = r.as_bigint(); + for (size_t i = 0; i < this->size(); ++i) + { + pb.val((*this)[i]) = rint.test_bit(i) ? FieldT::one() : FieldT::zero(); + } +} + +template +void pb_variable_array::fill_with_bits_of_ulong(protoboard &pb, const unsigned long i) const +{ + this->fill_with_bits_of_field_element(pb, FieldT(i, true)); +} + +template +std::vector pb_variable_array::get_vals(const protoboard &pb) const +{ + std::vector result(this->size()); + for (size_t i = 0; i < this->size(); ++i) + { + result[i] = pb.val((*this)[i]); + } + return result; +} + +template +bit_vector pb_variable_array::get_bits(const protoboard &pb) const +{ + bit_vector result; + for (size_t i = 0; i < this->size(); ++i) + { + const FieldT v = pb.val((*this)[i]); + assert(v == FieldT::zero() || v == FieldT::one()); + result.push_back(v == FieldT::one()); + } + return result; +} + +template +FieldT pb_variable_array::get_field_element_from_bits(const protoboard &pb) const +{ + FieldT result = FieldT::zero(); + + for (size_t i = 0; i < this->size(); ++i) + { + /* push in the new bit */ + const FieldT v = pb.val((*this)[this->size()-1-i]); + assert(v == FieldT::zero() || v == FieldT::one()); + result += result + v; + } + + return result; +} + +template +pb_linear_combination::pb_linear_combination() +{ + this->is_variable = false; + this->index = 0; +} + +template +pb_linear_combination::pb_linear_combination(const pb_variable &var) +{ + this->is_variable = true; + this->index = var.index; + this->terms.emplace_back(linear_term(var)); +} + +template +void pb_linear_combination::assign(protoboard &pb, const linear_combination &lc) +{ + assert(this->is_variable == false); + this->index = pb.allocate_lc_index(); + this->terms = lc.terms; +} + +template +void pb_linear_combination::evaluate(protoboard &pb) const +{ + if (this->is_variable) + { + return; // do nothing + } + + FieldT sum = 0; + for (auto term : this->terms) + { + sum += term.coeff * pb.val(pb_variable(term.index)); + } + + pb.lc_val(*this) = sum; +} + +template +bool pb_linear_combination::is_constant() const +{ + if (is_variable) + { + return (index == 0); + } + else + { + for (auto term : this->terms) + { + if (term.index != 0) + { + return false; + } + } + + return true; + } +} + +template +FieldT pb_linear_combination::constant_term() const +{ + if (is_variable) + { + return (index == 0 ? FieldT::one() : FieldT::zero()); + } + else + { + FieldT result = FieldT::zero(); + for (auto term : this->terms) + { + if (term.index == 0) + { + result += term.coeff; + } + } + return result; + } +} + +template +void pb_linear_combination_array::evaluate(protoboard &pb) const +{ + for (size_t i = 0; i < this->size(); ++i) + { + (*this)[i].evaluate(pb); + } +} + +template +void pb_linear_combination_array::fill_with_field_elements(protoboard &pb, const std::vector& vals) const +{ + assert(this->size() == vals.size()); + for (size_t i = 0; i < vals.size(); ++i) + { + pb.lc_val((*this)[i]) = vals[i]; + } +} + +template +void pb_linear_combination_array::fill_with_bits(protoboard &pb, const bit_vector& bits) const +{ + assert(this->size() == bits.size()); + for (size_t i = 0; i < bits.size(); ++i) + { + pb.lc_val((*this)[i]) = (bits[i] ? FieldT::one() : FieldT::zero()); + } +} + +template +void pb_linear_combination_array::fill_with_bits_of_field_element(protoboard &pb, const FieldT &r) const +{ + const bigint rint = r.as_bigint(); + for (size_t i = 0; i < this->size(); ++i) + { + pb.lc_val((*this)[i]) = rint.test_bit(i) ? FieldT::one() : FieldT::zero(); + } +} + +template +void pb_linear_combination_array::fill_with_bits_of_ulong(protoboard &pb, const unsigned long i) const +{ + this->fill_with_bits_of_field_element(pb, FieldT(i)); +} + +template +std::vector pb_linear_combination_array::get_vals(const protoboard &pb) const +{ + std::vector result(this->size()); + for (size_t i = 0; i < this->size(); ++i) + { + result[i] = pb.lc_val((*this)[i]); + } + return result; +} + +template +bit_vector pb_linear_combination_array::get_bits(const protoboard &pb) const +{ + bit_vector result; + for (size_t i = 0; i < this->size(); ++i) + { + const FieldT v = pb.lc_val((*this)[i]); + assert(v == FieldT::zero() || v == FieldT::one()); + result.push_back(v == FieldT::one()); + } + return result; +} + +template +FieldT pb_linear_combination_array::get_field_element_from_bits(const protoboard &pb) const +{ + FieldT result = FieldT::zero(); + + for (size_t i = 0; i < this->size(); ++i) + { + /* push in the new bit */ + const FieldT v = pb.lc_val((*this)[this->size()-1-i]); + assert(v == FieldT::zero() || v == FieldT::one()); + result += result + v; + } + + return result; +} + +template +linear_combination pb_sum(const pb_linear_combination_array &v) +{ + linear_combination result; + for (auto &term : v) + { + result = result + term; + } + + return result; +} + +template +linear_combination pb_packing_sum(const pb_linear_combination_array &v) +{ + FieldT twoi = FieldT::one(); // will hold 2^i entering each iteration + std::vector > all_terms; + for (auto &lc : v) + { + for (auto &term : lc.terms) + { + all_terms.emplace_back(twoi * term); + } + twoi += twoi; + } + + return linear_combination(all_terms); +} + +template +linear_combination pb_coeff_sum(const pb_linear_combination_array &v, const std::vector &coeffs) +{ + assert(v.size() == coeffs.size()); + std::vector > all_terms; + + auto coeff_it = coeffs.begin(); + for (auto &lc : v) + { + for (auto &term : lc.terms) + { + all_terms.emplace_back((*coeff_it) * term); + } + ++coeff_it; + } + + return linear_combination(all_terms); +} + + +} // libsnark +#endif // PB_VARIABLE_TCC diff --git a/src/gadgetlib1/protoboard.hpp b/src/gadgetlib1/protoboard.hpp new file mode 100644 index 00000000000..a910a6df92d --- /dev/null +++ b/src/gadgetlib1/protoboard.hpp @@ -0,0 +1,75 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PROTOBOARD_HPP_ +#define PROTOBOARD_HPP_ + +#include +#include +#include +#include +#include +#include "gadgetlib1/pb_variable.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +template +class r1cs_constraint; + +template +class r1cs_constraint_system; + +template +class protoboard { +private: + FieldT constant_term; /* only here, because pb.val() needs to be able to return reference to the constant 1 term */ + r1cs_variable_assignment values; /* values[0] will hold the value of the first allocated variable of the protoboard, *NOT* constant 1 */ + var_index_t next_free_var; + lc_index_t next_free_lc; + std::vector lc_values; +public: + r1cs_constraint_system constraint_system; + + protoboard(); + + void clear_values(); + + FieldT& val(const pb_variable &var); + FieldT val(const pb_variable &var) const; + + FieldT& lc_val(const pb_linear_combination &lc); + FieldT lc_val(const pb_linear_combination &lc) const; + + void add_r1cs_constraint(const r1cs_constraint &constr, const std::string &annotation=""); + void augment_variable_annotation(const pb_variable &v, const std::string &postfix); + bool is_satisfied() const; + void dump_variables() const; + + size_t num_constraints() const; + size_t num_inputs() const; + size_t num_variables() const; + + void set_input_sizes(const size_t primary_input_size); + + r1cs_variable_assignment full_variable_assignment() const; + r1cs_primary_input primary_input() const; + r1cs_auxiliary_input auxiliary_input() const; + r1cs_constraint_system get_constraint_system() const; + + friend class pb_variable; + friend class pb_linear_combination; + +private: + var_index_t allocate_var_index(const std::string &annotation=""); + lc_index_t allocate_lc_index(); +}; + +} // libsnark +#include "gadgetlib1/protoboard.tcc" +#endif // PROTOBOARD_HPP_ diff --git a/src/gadgetlib1/protoboard.tcc b/src/gadgetlib1/protoboard.tcc new file mode 100644 index 00000000000..882af28e60b --- /dev/null +++ b/src/gadgetlib1/protoboard.tcc @@ -0,0 +1,189 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PROTOBOARD_TCC_ +#define PROTOBOARD_TCC_ + +#include +#include +#include "common/profiling.hpp" + +namespace libsnark { + +template +protoboard::protoboard() +{ + constant_term = FieldT::one(); + +#ifdef DEBUG + constraint_system.variable_annotations[0] = "ONE"; +#endif + + next_free_var = 1; /* to account for constant 1 term */ + next_free_lc = 0; +} + +template +void protoboard::clear_values() +{ + std::fill(values.begin(), values.end(), FieldT::zero()); +} + +template +var_index_t protoboard::allocate_var_index(const std::string &annotation) +{ +#ifdef DEBUG + assert(annotation != ""); + constraint_system.variable_annotations[next_free_var] = annotation; +#else + UNUSED(annotation); +#endif + ++constraint_system.auxiliary_input_size; + values.emplace_back(FieldT::zero()); + return next_free_var++; +} + +template +lc_index_t protoboard::allocate_lc_index() +{ + lc_values.emplace_back(FieldT::zero()); + return next_free_lc++; +} + +template +FieldT& protoboard::val(const pb_variable &var) +{ + assert(var.index <= values.size()); + return (var.index == 0 ? constant_term : values[var.index-1]); +} + +template +FieldT protoboard::val(const pb_variable &var) const +{ + assert(var.index <= values.size()); + return (var.index == 0 ? constant_term : values[var.index-1]); +} + +template +FieldT& protoboard::lc_val(const pb_linear_combination &lc) +{ + if (lc.is_variable) + { + return this->val(pb_variable(lc.index)); + } + else + { + assert(lc.index < lc_values.size()); + return lc_values[lc.index]; + } +} + +template +FieldT protoboard::lc_val(const pb_linear_combination &lc) const +{ + if (lc.is_variable) + { + return this->val(pb_variable(lc.index)); + } + else + { + assert(lc.index < lc_values.size()); + return lc_values[lc.index]; + } +} + +template +void protoboard::add_r1cs_constraint(const r1cs_constraint &constr, const std::string &annotation) +{ +#ifdef DEBUG + assert(annotation != ""); + constraint_system.constraint_annotations[constraint_system.constraints.size()] = annotation; +#else + UNUSED(annotation); +#endif + constraint_system.constraints.emplace_back(constr); +} + +template +void protoboard::augment_variable_annotation(const pb_variable &v, const std::string &postfix) +{ +#ifdef DEBUG + auto it = constraint_system.variable_annotations.find(v.index); + constraint_system.variable_annotations[v.index] = (it == constraint_system.variable_annotations.end() ? "" : it->second + " ") + postfix; +#endif +} + +template +bool protoboard::is_satisfied() const +{ + return constraint_system.is_satisfied(primary_input(), auxiliary_input()); +} + +template +void protoboard::dump_variables() const +{ +#ifdef DEBUG + for (size_t i = 0; i < constraint_system.num_variables; ++i) + { + printf("%-40s --> ", constraint_system.variable_annotations[i].c_str()); + values[i].as_bigint().print_hex(); + } +#endif +} + +template +size_t protoboard::num_constraints() const +{ + return constraint_system.num_constraints(); +} + +template +size_t protoboard::num_inputs() const +{ + return constraint_system.num_inputs(); +} + +template +size_t protoboard::num_variables() const +{ + return next_free_var - 1; +} + +template +void protoboard::set_input_sizes(const size_t primary_input_size) +{ + assert(primary_input_size <= num_variables()); + constraint_system.primary_input_size = primary_input_size; + constraint_system.auxiliary_input_size = num_variables() - primary_input_size; +} + +template +r1cs_variable_assignment protoboard::full_variable_assignment() const +{ + return values; +} + +template +r1cs_primary_input protoboard::primary_input() const +{ + return r1cs_primary_input(values.begin(), values.begin() + num_inputs()); +} + +template +r1cs_auxiliary_input protoboard::auxiliary_input() const +{ + return r1cs_primary_input(values.begin() + num_inputs(), values.end()); +} + +template +r1cs_constraint_system protoboard::get_constraint_system() const +{ + return constraint_system; +} + +} // libsnark +#endif // PROTOBOARD_TCC_ diff --git a/src/reductions/r1cs_to_qap/r1cs_to_qap.hpp b/src/reductions/r1cs_to_qap/r1cs_to_qap.hpp new file mode 100644 index 00000000000..b3cde710c58 --- /dev/null +++ b/src/reductions/r1cs_to_qap/r1cs_to_qap.hpp @@ -0,0 +1,70 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a R1CS-to-QAP reduction, that is, constructing + a QAP ("Quadratic Arithmetic Program") from a R1CS ("Rank-1 Constraint System"). + + QAPs are defined in \[GGPR13], and construced for R1CS also in \[GGPR13]. + + The implementation of the reduction follows, extends, and optimizes + the efficient approach described in Appendix E of \[BCGTV13]. + + References: + + \[BCGTV13] + "SNARKs for C: Verifying Program Executions Succinctly and in Zero Knowledge", + Eli Ben-Sasson, Alessandro Chiesa, Daniel Genkin, Eran Tromer, Madars Virza, + CRYPTO 2013, + + + \[GGPR13]: + "Quadratic span programs and succinct NIZKs without PCPs", + Rosario Gennaro, Craig Gentry, Bryan Parno, Mariana Raykova, + EUROCRYPT 2013, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_TO_QAP_HPP_ +#define R1CS_TO_QAP_HPP_ + +#include "relations/arithmetic_programs/qap/qap.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" + +namespace libsnark { + +/** + * Instance map for the R1CS-to-QAP reduction. + */ +template +qap_instance r1cs_to_qap_instance_map(const r1cs_constraint_system &cs); + +/** + * Instance map for the R1CS-to-QAP reduction followed by evaluation of the resulting QAP instance. + */ +template +qap_instance_evaluation r1cs_to_qap_instance_map_with_evaluation(const r1cs_constraint_system &cs, + const FieldT &t); + +/** + * Witness map for the R1CS-to-QAP reduction. + * + * The witness map takes zero knowledge into account when d1,d2,d3 are random. + */ +template +qap_witness r1cs_to_qap_witness_map(const r1cs_constraint_system &cs, + const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input, + const FieldT &d1, + const FieldT &d2, + const FieldT &d3); + +} // libsnark + +#include "reductions/r1cs_to_qap/r1cs_to_qap.tcc" + +#endif // R1CS_TO_QAP_HPP_ diff --git a/src/reductions/r1cs_to_qap/r1cs_to_qap.tcc b/src/reductions/r1cs_to_qap/r1cs_to_qap.tcc new file mode 100644 index 00000000000..3d0bee27337 --- /dev/null +++ b/src/reductions/r1cs_to_qap/r1cs_to_qap.tcc @@ -0,0 +1,338 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a R1CS-to-QAP reduction. + + See r1cs_to_qap.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_TO_QAP_TCC_ +#define R1CS_TO_QAP_TCC_ + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/evaluation_domain/evaluation_domain.hpp" + +namespace libsnark { + +/** + * Instance map for the R1CS-to-QAP reduction. + * + * Namely, given a R1CS constraint system cs, construct a QAP instance for which: + * A := (A_0(z),A_1(z),...,A_m(z)) + * B := (B_0(z),B_1(z),...,B_m(z)) + * C := (C_0(z),C_1(z),...,C_m(z)) + * where + * m = number of variables of the QAP + * and + * each A_i,B_i,C_i is expressed in the Lagrange basis. + */ +template +qap_instance r1cs_to_qap_instance_map(const r1cs_constraint_system &cs) +{ + enter_block("Call to r1cs_to_qap_instance_map"); + + const std::shared_ptr > domain = get_evaluation_domain(cs.num_constraints() + cs.num_inputs() + 1); + + std::vector > A_in_Lagrange_basis(cs.num_variables()+1); + std::vector > B_in_Lagrange_basis(cs.num_variables()+1); + std::vector > C_in_Lagrange_basis(cs.num_variables()+1); + + enter_block("Compute polynomials A, B, C in Lagrange basis"); + /** + * add and process the constraints + * input_i * 0 = 0 + * to ensure soundness of input consistency + */ + for (size_t i = 0; i <= cs.num_inputs(); ++i) + { + A_in_Lagrange_basis[i][cs.num_constraints() + i] = FieldT::one(); + } + /* process all other constraints */ + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + for (size_t j = 0; j < cs.constraints[i].a.terms.size(); ++j) + { + A_in_Lagrange_basis[cs.constraints[i].a.terms[j].index][i] += + cs.constraints[i].a.terms[j].coeff; + } + + for (size_t j = 0; j < cs.constraints[i].b.terms.size(); ++j) + { + B_in_Lagrange_basis[cs.constraints[i].b.terms[j].index][i] += + cs.constraints[i].b.terms[j].coeff; + } + + for (size_t j = 0; j < cs.constraints[i].c.terms.size(); ++j) + { + C_in_Lagrange_basis[cs.constraints[i].c.terms[j].index][i] += + cs.constraints[i].c.terms[j].coeff; + } + } + leave_block("Compute polynomials A, B, C in Lagrange basis"); + + leave_block("Call to r1cs_to_qap_instance_map"); + + return qap_instance(domain, + cs.num_variables(), + domain->m, + cs.num_inputs(), + std::move(A_in_Lagrange_basis), + std::move(B_in_Lagrange_basis), + std::move(C_in_Lagrange_basis)); +} + +/** + * Instance map for the R1CS-to-QAP reduction followed by evaluation of the resulting QAP instance. + * + * Namely, given a R1CS constraint system cs and a field element t, construct + * a QAP instance (evaluated at t) for which: + * At := (A_0(t),A_1(t),...,A_m(t)) + * Bt := (B_0(t),B_1(t),...,B_m(t)) + * Ct := (C_0(t),C_1(t),...,C_m(t)) + * Ht := (1,t,t^2,...,t^n) + * Zt := Z(t) = "vanishing polynomial of a certain set S, evaluated at t" + * where + * m = number of variables of the QAP + * n = degree of the QAP + */ +template +qap_instance_evaluation r1cs_to_qap_instance_map_with_evaluation(const r1cs_constraint_system &cs, + const FieldT &t) +{ + enter_block("Call to r1cs_to_qap_instance_map_with_evaluation"); + + const std::shared_ptr > domain = get_evaluation_domain(cs.num_constraints() + cs.num_inputs() + 1); + + std::vector At, Bt, Ct, Ht; + + At.resize(cs.num_variables()+1, FieldT::zero()); + Bt.resize(cs.num_variables()+1, FieldT::zero()); + Ct.resize(cs.num_variables()+1, FieldT::zero()); + Ht.reserve(domain->m+1); + + const FieldT Zt = domain->compute_Z(t); + + enter_block("Compute evaluations of A, B, C, H at t"); + const std::vector u = domain->lagrange_coeffs(t); + /** + * add and process the constraints + * input_i * 0 = 0 + * to ensure soundness of input consistency + */ + for (size_t i = 0; i <= cs.num_inputs(); ++i) + { + At[i] = u[cs.num_constraints() + i]; + } + /* process all other constraints */ + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + for (size_t j = 0; j < cs.constraints[i].a.terms.size(); ++j) + { + At[cs.constraints[i].a.terms[j].index] += + u[i]*cs.constraints[i].a.terms[j].coeff; + } + + for (size_t j = 0; j < cs.constraints[i].b.terms.size(); ++j) + { + Bt[cs.constraints[i].b.terms[j].index] += + u[i]*cs.constraints[i].b.terms[j].coeff; + } + + for (size_t j = 0; j < cs.constraints[i].c.terms.size(); ++j) + { + Ct[cs.constraints[i].c.terms[j].index] += + u[i]*cs.constraints[i].c.terms[j].coeff; + } + } + + FieldT ti = FieldT::one(); + for (size_t i = 0; i < domain->m+1; ++i) + { + Ht.emplace_back(ti); + ti *= t; + } + leave_block("Compute evaluations of A, B, C, H at t"); + + leave_block("Call to r1cs_to_qap_instance_map_with_evaluation"); + + return qap_instance_evaluation(domain, + cs.num_variables(), + domain->m, + cs.num_inputs(), + t, + std::move(At), + std::move(Bt), + std::move(Ct), + std::move(Ht), + Zt); +} + +/** + * Witness map for the R1CS-to-QAP reduction. + * + * The witness map takes zero knowledge into account when d1,d2,d3 are random. + * + * More precisely, compute the coefficients + * h_0,h_1,...,h_n + * of the polynomial + * H(z) := (A(z)*B(z)-C(z))/Z(z) + * where + * A(z) := A_0(z) + \sum_{k=1}^{m} w_k A_k(z) + d1 * Z(z) + * B(z) := B_0(z) + \sum_{k=1}^{m} w_k B_k(z) + d2 * Z(z) + * C(z) := C_0(z) + \sum_{k=1}^{m} w_k C_k(z) + d3 * Z(z) + * Z(z) := "vanishing polynomial of set S" + * and + * m = number of variables of the QAP + * n = degree of the QAP + * + * This is done as follows: + * (1) compute evaluations of A,B,C on S = {sigma_1,...,sigma_n} + * (2) compute coefficients of A,B,C + * (3) compute evaluations of A,B,C on T = "coset of S" + * (4) compute evaluation of H on T + * (5) compute coefficients of H + * (6) patch H to account for d1,d2,d3 (i.e., add coefficients of the polynomial (A d2 + B d1 - d3) + d1*d2*Z ) + * + * The code below is not as simple as the above high-level description due to + * some reshuffling to save space. + */ +template +qap_witness r1cs_to_qap_witness_map(const r1cs_constraint_system &cs, + const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input, + const FieldT &d1, + const FieldT &d2, + const FieldT &d3) +{ + enter_block("Call to r1cs_to_qap_witness_map"); + + /* sanity check */ + assert(cs.is_satisfied(primary_input, auxiliary_input)); + + const std::shared_ptr > domain = get_evaluation_domain(cs.num_constraints() + cs.num_inputs() + 1); + + r1cs_variable_assignment full_variable_assignment = primary_input; + full_variable_assignment.insert(full_variable_assignment.end(), auxiliary_input.begin(), auxiliary_input.end()); + + enter_block("Compute evaluation of polynomials A, B on set S"); + std::vector aA(domain->m, FieldT::zero()), aB(domain->m, FieldT::zero()); + + /* account for the additional constraints input_i * 0 = 0 */ + for (size_t i = 0; i <= cs.num_inputs(); ++i) + { + aA[i+cs.num_constraints()] = (i > 0 ? full_variable_assignment[i-1] : FieldT::one()); + } + /* account for all other constraints */ + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + aA[i] += cs.constraints[i].a.evaluate(full_variable_assignment); + aB[i] += cs.constraints[i].b.evaluate(full_variable_assignment); + } + leave_block("Compute evaluation of polynomials A, B on set S"); + + enter_block("Compute coefficients of polynomial A"); + domain->iFFT(aA); + leave_block("Compute coefficients of polynomial A"); + + enter_block("Compute coefficients of polynomial B"); + domain->iFFT(aB); + leave_block("Compute coefficients of polynomial B"); + + enter_block("Compute ZK-patch"); + std::vector coefficients_for_H(domain->m+1, FieldT::zero()); +#ifdef MULTICORE +#pragma omp parallel for +#endif + /* add coefficients of the polynomial (d2*A + d1*B - d3) + d1*d2*Z */ + for (size_t i = 0; i < domain->m; ++i) + { + coefficients_for_H[i] = d2*aA[i] + d1*aB[i]; + } + coefficients_for_H[0] -= d3; + domain->add_poly_Z(d1*d2, coefficients_for_H); + leave_block("Compute ZK-patch"); + + enter_block("Compute evaluation of polynomial A on set T"); + domain->cosetFFT(aA, FieldT::multiplicative_generator); + leave_block("Compute evaluation of polynomial A on set T"); + + enter_block("Compute evaluation of polynomial B on set T"); + domain->cosetFFT(aB, FieldT::multiplicative_generator); + leave_block("Compute evaluation of polynomial B on set T"); + + enter_block("Compute evaluation of polynomial H on set T"); + std::vector &H_tmp = aA; // can overwrite aA because it is not used later +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < domain->m; ++i) + { + H_tmp[i] = aA[i]*aB[i]; + } + std::vector().swap(aB); // destroy aB + + enter_block("Compute evaluation of polynomial C on set S"); + std::vector aC(domain->m, FieldT::zero()); + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + aC[i] += cs.constraints[i].c.evaluate(full_variable_assignment); + } + leave_block("Compute evaluation of polynomial C on set S"); + + enter_block("Compute coefficients of polynomial C"); + domain->iFFT(aC); + leave_block("Compute coefficients of polynomial C"); + + enter_block("Compute evaluation of polynomial C on set T"); + domain->cosetFFT(aC, FieldT::multiplicative_generator); + leave_block("Compute evaluation of polynomial C on set T"); + +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < domain->m; ++i) + { + H_tmp[i] = (H_tmp[i]-aC[i]); + } + + enter_block("Divide by Z on set T"); + domain->divide_by_Z_on_coset(H_tmp); + leave_block("Divide by Z on set T"); + + leave_block("Compute evaluation of polynomial H on set T"); + + enter_block("Compute coefficients of polynomial H"); + domain->icosetFFT(H_tmp, FieldT::multiplicative_generator); + leave_block("Compute coefficients of polynomial H"); + + enter_block("Compute sum of H and ZK-patch"); +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < domain->m; ++i) + { + coefficients_for_H[i] += H_tmp[i]; + } + leave_block("Compute sum of H and ZK-patch"); + + leave_block("Call to r1cs_to_qap_witness_map"); + + return qap_witness(cs.num_variables(), + domain->m, + cs.num_inputs(), + d1, + d2, + d3, + full_variable_assignment, + std::move(coefficients_for_H)); +} + +} // libsnark + +#endif // R1CS_TO_QAP_TCC_ diff --git a/src/relations/arithmetic_programs/qap/qap.hpp b/src/relations/arithmetic_programs/qap/qap.hpp new file mode 100644 index 00000000000..4991d203b36 --- /dev/null +++ b/src/relations/arithmetic_programs/qap/qap.hpp @@ -0,0 +1,193 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a QAP ("Quadratic Arithmetic Program"). + + QAPs are defined in \[GGPR13]. + + References: + + \[GGPR13]: + "Quadratic span programs and succinct NIZKs without PCPs", + Rosario Gennaro, Craig Gentry, Bryan Parno, Mariana Raykova, + EUROCRYPT 2013, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef QAP_HPP_ +#define QAP_HPP_ + +#include "algebra/evaluation_domain/evaluation_domain.hpp" + +namespace libsnark { + +/* forward declaration */ +template +class qap_witness; + +/** + * A QAP instance. + * + * Specifically, the datastructure stores: + * - a choice of domain (corresponding to a certain subset of the field); + * - the number of variables, the degree, and the number of inputs; and + * - coefficients of the A,B,C polynomials in the Lagrange basis. + * + * There is no need to store the Z polynomial because it is uniquely + * determined by the domain (as Z is its vanishing polynomial). + */ +template +class qap_instance { +private: + size_t num_variables_; + size_t degree_; + size_t num_inputs_; + +public: + std::shared_ptr > domain; + + std::vector > A_in_Lagrange_basis; + std::vector > B_in_Lagrange_basis; + std::vector > C_in_Lagrange_basis; + + qap_instance(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const std::vector > &A_in_Lagrange_basis, + const std::vector > &B_in_Lagrange_basis, + const std::vector > &C_in_Lagrange_basis); + + qap_instance(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + std::vector > &&A_in_Lagrange_basis, + std::vector > &&B_in_Lagrange_basis, + std::vector > &&C_in_Lagrange_basis); + + qap_instance(const qap_instance &other) = default; + qap_instance(qap_instance &&other) = default; + qap_instance& operator=(const qap_instance &other) = default; + qap_instance& operator=(qap_instance &&other) = default; + + size_t num_variables() const; + size_t degree() const; + size_t num_inputs() const; + + bool is_satisfied(const qap_witness &witness) const; +}; + +/** + * A QAP instance evaluation is a QAP instance that is evaluated at a field element t. + * + * Specifically, the datastructure stores: + * - a choice of domain (corresponding to a certain subset of the field); + * - the number of variables, the degree, and the number of inputs; + * - a field element t; + * - evaluations of the A,B,C (and Z) polynomials at t; + * - evaluations of all monomials of t; + * - counts about how many of the above evaluations are in fact non-zero. + */ +template +class qap_instance_evaluation { +private: + size_t num_variables_; + size_t degree_; + size_t num_inputs_; +public: + std::shared_ptr > domain; + + FieldT t; + + std::vector At, Bt, Ct, Ht; + + FieldT Zt; + + qap_instance_evaluation(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &t, + const std::vector &At, + const std::vector &Bt, + const std::vector &Ct, + const std::vector &Ht, + const FieldT &Zt); + qap_instance_evaluation(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &t, + std::vector &&At, + std::vector &&Bt, + std::vector &&Ct, + std::vector &&Ht, + const FieldT &Zt); + + qap_instance_evaluation(const qap_instance_evaluation &other) = default; + qap_instance_evaluation(qap_instance_evaluation &&other) = default; + qap_instance_evaluation& operator=(const qap_instance_evaluation &other) = default; + qap_instance_evaluation& operator=(qap_instance_evaluation &&other) = default; + + size_t num_variables() const; + size_t degree() const; + size_t num_inputs() const; + + bool is_satisfied(const qap_witness &witness) const; +}; + +/** + * A QAP witness. + */ +template +class qap_witness { +private: + size_t num_variables_; + size_t degree_; + size_t num_inputs_; + +public: + FieldT d1, d2, d3; + + std::vector coefficients_for_ABCs; + std::vector coefficients_for_H; + + qap_witness(const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &d1, + const FieldT &d2, + const FieldT &d3, + const std::vector &coefficients_for_ABCs, + const std::vector &coefficients_for_H); + + qap_witness(const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &d1, + const FieldT &d2, + const FieldT &d3, + const std::vector &coefficients_for_ABCs, + std::vector &&coefficients_for_H); + + qap_witness(const qap_witness &other) = default; + qap_witness(qap_witness &&other) = default; + qap_witness& operator=(const qap_witness &other) = default; + qap_witness& operator=(qap_witness &&other) = default; + + size_t num_variables() const; + size_t degree() const; + size_t num_inputs() const; +}; + +} // libsnark + +#include "relations/arithmetic_programs/qap/qap.tcc" + +#endif // QAP_HPP_ diff --git a/src/relations/arithmetic_programs/qap/qap.tcc b/src/relations/arithmetic_programs/qap/qap.tcc new file mode 100644 index 00000000000..a4a3c96a25d --- /dev/null +++ b/src/relations/arithmetic_programs/qap/qap.tcc @@ -0,0 +1,324 @@ +/** @file +***************************************************************************** + +Implementation of interfaces for a QAP ("Quadratic Arithmetic Program"). + +See qap.hpp . + +***************************************************************************** +* @author This file is part of libsnark, developed by SCIPR Lab +* and contributors (see AUTHORS). +* @copyright MIT license (see LICENSE file) +*****************************************************************************/ + +#ifndef QAP_TCC_ +#define QAP_TCC_ + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/evaluation_domain/evaluation_domain.hpp" +#include "algebra/scalar_multiplication/multiexp.hpp" + +namespace libsnark { + +template +qap_instance::qap_instance(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const std::vector > &A_in_Lagrange_basis, + const std::vector > &B_in_Lagrange_basis, + const std::vector > &C_in_Lagrange_basis) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + domain(domain), + A_in_Lagrange_basis(A_in_Lagrange_basis), + B_in_Lagrange_basis(B_in_Lagrange_basis), + C_in_Lagrange_basis(C_in_Lagrange_basis) +{ +} + +template +qap_instance::qap_instance(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + std::vector > &&A_in_Lagrange_basis, + std::vector > &&B_in_Lagrange_basis, + std::vector > &&C_in_Lagrange_basis) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + domain(domain), + A_in_Lagrange_basis(std::move(A_in_Lagrange_basis)), + B_in_Lagrange_basis(std::move(B_in_Lagrange_basis)), + C_in_Lagrange_basis(std::move(C_in_Lagrange_basis)) +{ +} + +template +size_t qap_instance::num_variables() const +{ + return num_variables_; +} + +template +size_t qap_instance::degree() const +{ + return degree_; +} + +template +size_t qap_instance::num_inputs() const +{ + return num_inputs_; +} + +template +bool qap_instance::is_satisfied(const qap_witness &witness) const +{ + const FieldT t = FieldT::random_element(); + + std::vector At(this->num_variables()+1, FieldT::zero()); + std::vector Bt(this->num_variables()+1, FieldT::zero()); + std::vector Ct(this->num_variables()+1, FieldT::zero()); + std::vector Ht(this->degree()+1); + + const FieldT Zt = this->domain->compute_Z(t); + + const std::vector u = this->domain->lagrange_coeffs(t); + + for (size_t i = 0; i < this->num_variables()+1; ++i) + { + for (auto &el : A_in_Lagrange_basis[i]) + { + At[i] += u[el.first] * el.second; + } + + for (auto &el : B_in_Lagrange_basis[i]) + { + Bt[i] += u[el.first] * el.second; + } + + for (auto &el : C_in_Lagrange_basis[i]) + { + Ct[i] += u[el.first] * el.second; + } + } + + FieldT ti = FieldT::one(); + for (size_t i = 0; i < this->degree()+1; ++i) + { + Ht[i] = ti; + ti *= t; + } + + const qap_instance_evaluation eval_qap_inst(this->domain, + this->num_variables(), + this->degree(), + this->num_inputs(), + t, + std::move(At), + std::move(Bt), + std::move(Ct), + std::move(Ht), + Zt); + return eval_qap_inst.is_satisfied(witness); +} + +template +qap_instance_evaluation::qap_instance_evaluation(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &t, + const std::vector &At, + const std::vector &Bt, + const std::vector &Ct, + const std::vector &Ht, + const FieldT &Zt) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + domain(domain), + t(t), + At(At), + Bt(Bt), + Ct(Ct), + Ht(Ht), + Zt(Zt) +{ +} + +template +qap_instance_evaluation::qap_instance_evaluation(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &t, + std::vector &&At, + std::vector &&Bt, + std::vector &&Ct, + std::vector &&Ht, + const FieldT &Zt) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + domain(domain), + t(t), + At(std::move(At)), + Bt(std::move(Bt)), + Ct(std::move(Ct)), + Ht(std::move(Ht)), + Zt(Zt) +{ +} + +template +size_t qap_instance_evaluation::num_variables() const +{ + return num_variables_; +} + +template +size_t qap_instance_evaluation::degree() const +{ + return degree_; +} + +template +size_t qap_instance_evaluation::num_inputs() const +{ + return num_inputs_; +} + +template +bool qap_instance_evaluation::is_satisfied(const qap_witness &witness) const +{ + + if (this->num_variables() != witness.num_variables()) + { + return false; + } + + if (this->degree() != witness.degree()) + { + return false; + } + + if (this->num_inputs() != witness.num_inputs()) + { + return false; + } + + if (this->num_variables() != witness.coefficients_for_ABCs.size()) + { + return false; + } + + if (this->degree()+1 != witness.coefficients_for_H.size()) + { + return false; + } + + if (this->At.size() != this->num_variables()+1 || this->Bt.size() != this->num_variables()+1 || this->Ct.size() != this->num_variables()+1) + { + return false; + } + + if (this->Ht.size() != this->degree()+1) + { + return false; + } + + if (this->Zt != this->domain->compute_Z(this->t)) + { + return false; + } + + FieldT ans_A = this->At[0] + witness.d1*this->Zt; + FieldT ans_B = this->Bt[0] + witness.d2*this->Zt; + FieldT ans_C = this->Ct[0] + witness.d3*this->Zt; + FieldT ans_H = FieldT::zero(); + + ans_A = ans_A + naive_plain_exp(this->At.begin()+1, this->At.begin()+1+this->num_variables(), + witness.coefficients_for_ABCs.begin(), witness.coefficients_for_ABCs.begin()+this->num_variables()); + ans_B = ans_B + naive_plain_exp(this->Bt.begin()+1, this->Bt.begin()+1+this->num_variables(), + witness.coefficients_for_ABCs.begin(), witness.coefficients_for_ABCs.begin()+this->num_variables()); + ans_C = ans_C + naive_plain_exp(this->Ct.begin()+1, this->Ct.begin()+1+this->num_variables(), + witness.coefficients_for_ABCs.begin(), witness.coefficients_for_ABCs.begin()+this->num_variables()); + ans_H = ans_H + naive_plain_exp(this->Ht.begin(), this->Ht.begin()+this->degree()+1, + witness.coefficients_for_H.begin(), witness.coefficients_for_H.begin()+this->degree()+1); + + if (ans_A * ans_B - ans_C != ans_H * this->Zt) + { + return false; + } + + return true; +} + +template +qap_witness::qap_witness(const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &d1, + const FieldT &d2, + const FieldT &d3, + const std::vector &coefficients_for_ABCs, + const std::vector &coefficients_for_H) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + d1(d1), + d2(d2), + d3(d3), + coefficients_for_ABCs(coefficients_for_ABCs), + coefficients_for_H(coefficients_for_H) +{ +} + +template +qap_witness::qap_witness(const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &d1, + const FieldT &d2, + const FieldT &d3, + const std::vector &coefficients_for_ABCs, + std::vector &&coefficients_for_H) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + d1(d1), + d2(d2), + d3(d3), + coefficients_for_ABCs(coefficients_for_ABCs), + coefficients_for_H(std::move(coefficients_for_H)) +{ +} + + +template +size_t qap_witness::num_variables() const +{ + return num_variables_; +} + +template +size_t qap_witness::degree() const +{ + return degree_; +} + +template +size_t qap_witness::num_inputs() const +{ + return num_inputs_; +} + + +} // libsnark + +#endif // QAP_TCC_ diff --git a/src/relations/arithmetic_programs/qap/tests/test_qap.cpp b/src/relations/arithmetic_programs/qap/tests/test_qap.cpp new file mode 100644 index 00000000000..d8aaddaa704 --- /dev/null +++ b/src/relations/arithmetic_programs/qap/tests/test_qap.cpp @@ -0,0 +1,115 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#include +#include +#include + +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#include "algebra/fields/field_utils.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "reductions/r1cs_to_qap/r1cs_to_qap.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" + +using namespace libsnark; + +template +void test_qap(const size_t qap_degree, const size_t num_inputs, const bool binary_input) +{ + /* + We construct an instance where the QAP degree is qap_degree. + So we generate an instance of R1CS where the number of constraints qap_degree - num_inputs - 1. + See the transformation from R1CS to QAP for why this is the case. + So we need that qap_degree >= num_inputs + 1. + */ + assert(num_inputs + 1 <= qap_degree); + enter_block("Call to test_qap"); + + const size_t num_constraints = qap_degree - num_inputs - 1; + + print_indent(); printf("* QAP degree: %zu\n", qap_degree); + print_indent(); printf("* Number of inputs: %zu\n", num_inputs); + print_indent(); printf("* Number of R1CS constraints: %zu\n", num_constraints); + print_indent(); printf("* Input type: %s\n", binary_input ? "binary" : "field"); + + enter_block("Generate constraint system and assignment"); + r1cs_example example; + if (binary_input) + { + example = generate_r1cs_example_with_binary_input(num_constraints, num_inputs); + } + else + { + example = generate_r1cs_example_with_field_input(num_constraints, num_inputs); + } + leave_block("Generate constraint system and assignment"); + + enter_block("Check satisfiability of constraint system"); + assert(example.constraint_system.is_satisfied(example.primary_input, example.auxiliary_input)); + leave_block("Check satisfiability of constraint system"); + + const FieldT t = FieldT::random_element(), + d1 = FieldT::random_element(), + d2 = FieldT::random_element(), + d3 = FieldT::random_element(); + + enter_block("Compute QAP instance 1"); + qap_instance qap_inst_1 = r1cs_to_qap_instance_map(example.constraint_system); + leave_block("Compute QAP instance 1"); + + enter_block("Compute QAP instance 2"); + qap_instance_evaluation qap_inst_2 = r1cs_to_qap_instance_map_with_evaluation(example.constraint_system, t); + leave_block("Compute QAP instance 2"); + + enter_block("Compute QAP witness"); + qap_witness qap_wit = r1cs_to_qap_witness_map(example.constraint_system, example.primary_input, example.auxiliary_input, d1, d2, d3); + leave_block("Compute QAP witness"); + + enter_block("Check satisfiability of QAP instance 1"); + assert(qap_inst_1.is_satisfied(qap_wit)); + leave_block("Check satisfiability of QAP instance 1"); + + enter_block("Check satisfiability of QAP instance 2"); + assert(qap_inst_2.is_satisfied(qap_wit)); + leave_block("Check satisfiability of QAP instance 2"); + + leave_block("Call to test_qap"); +} + +int main() +{ + start_profiling(); + + mnt6_pp::init_public_params(); + + const size_t num_inputs = 10; + + const size_t basic_domain_size = 1ul< >(basic_domain_size, num_inputs, true); + test_qap >(step_domain_size, num_inputs, true); + test_qap >(extended_domain_size, num_inputs, true); + test_qap >(extended_domain_size_special, num_inputs, true); + + leave_block("Test QAP with binary input"); + + enter_block("Test QAP with field input"); + + test_qap >(basic_domain_size, num_inputs, false); + test_qap >(step_domain_size, num_inputs, false); + test_qap >(extended_domain_size, num_inputs, false); + test_qap >(extended_domain_size_special, num_inputs, false); + + leave_block("Test QAP with field input"); +} diff --git a/src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp b/src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp new file mode 100644 index 00000000000..47003e95938 --- /dev/null +++ b/src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp @@ -0,0 +1,73 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a R1CS example, as well as functions to sample + R1CS examples with prescribed parameters (according to some distribution). + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_EXAMPLES_HPP_ +#define R1CS_EXAMPLES_HPP_ + +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" + +namespace libsnark { + +/** + * A R1CS example comprises a R1CS constraint system, R1CS input, and R1CS witness. + */ +template +struct r1cs_example { + r1cs_constraint_system constraint_system; + r1cs_primary_input primary_input; + r1cs_auxiliary_input auxiliary_input; + + r1cs_example() = default; + r1cs_example(const r1cs_example &other) = default; + r1cs_example(const r1cs_constraint_system &constraint_system, + const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input) : + constraint_system(constraint_system), + primary_input(primary_input), + auxiliary_input(auxiliary_input) + {}; + r1cs_example(r1cs_constraint_system &&constraint_system, + r1cs_primary_input &&primary_input, + r1cs_auxiliary_input &&auxiliary_input) : + constraint_system(std::move(constraint_system)), + primary_input(std::move(primary_input)), + auxiliary_input(std::move(auxiliary_input)) + {}; +}; + +/** + * Generate a R1CS example such that: + * - the number of constraints of the R1CS constraint system is num_constraints; + * - the number of variables of the R1CS constraint system is (approximately) num_constraints; + * - the number of inputs of the R1CS constraint system is num_inputs; + * - the R1CS input consists of ``full'' field elements (typically require the whole log|Field| bits to represent). + */ +template +r1cs_example generate_r1cs_example_with_field_input(const size_t num_constraints, + const size_t num_inputs); + +/** + * Generate a R1CS example such that: + * - the number of constraints of the R1CS constraint system is num_constraints; + * - the number of variables of the R1CS constraint system is (approximately) num_constraints; + * - the number of inputs of the R1CS constraint system is num_inputs; + * - the R1CS input consists of binary values (as opposed to ``full'' field elements). + */ +template +r1cs_example generate_r1cs_example_with_binary_input(const size_t num_constraints, + const size_t num_inputs); + +} // libsnark + +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc" + +#endif // R1CS_EXAMPLES_HPP_ diff --git a/src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc b/src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc new file mode 100644 index 00000000000..defa0772173 --- /dev/null +++ b/src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc @@ -0,0 +1,164 @@ +/** @file + ***************************************************************************** + + Implementation of functions to sample R1CS examples with prescribed parameters + (according to some distribution). + + See r1cs_examples.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_EXAMPLES_TCC_ +#define R1CS_EXAMPLES_TCC_ + +#include + +#include "common/utils.hpp" + +namespace libsnark { + +template +r1cs_example generate_r1cs_example_with_field_input(const size_t num_constraints, + const size_t num_inputs) +{ + enter_block("Call to generate_r1cs_example_with_field_input"); + + assert(num_inputs <= num_constraints + 2); + + r1cs_constraint_system cs; + cs.primary_input_size = num_inputs; + cs.auxiliary_input_size = 2 + num_constraints - num_inputs; // TODO: explain this + + r1cs_variable_assignment full_variable_assignment; + FieldT a = FieldT::random_element(); + FieldT b = FieldT::random_element(); + full_variable_assignment.push_back(a); + full_variable_assignment.push_back(b); + + for (size_t i = 0; i < num_constraints-1; ++i) + { + linear_combination A, B, C; + + if (i % 2) + { + // a * b = c + A.add_term(i+1, 1); + B.add_term(i+2, 1); + C.add_term(i+3, 1); + FieldT tmp = a*b; + full_variable_assignment.push_back(tmp); + a = b; b = tmp; + } + else + { + // a + b = c + B.add_term(0, 1); + A.add_term(i+1, 1); + A.add_term(i+2, 1); + C.add_term(i+3, 1); + FieldT tmp = a+b; + full_variable_assignment.push_back(tmp); + a = b; b = tmp; + } + + cs.add_constraint(r1cs_constraint(A, B, C)); + } + + linear_combination A, B, C; + FieldT fin = FieldT::zero(); + for (size_t i = 1; i < cs.num_variables(); ++i) + { + A.add_term(i, 1); + B.add_term(i, 1); + fin = fin + full_variable_assignment[i-1]; + } + C.add_term(cs.num_variables(), 1); + cs.add_constraint(r1cs_constraint(A, B, C)); + full_variable_assignment.push_back(fin.squared()); + + /* split variable assignment */ + r1cs_primary_input primary_input(full_variable_assignment.begin(), full_variable_assignment.begin() + num_inputs); + r1cs_primary_input auxiliary_input(full_variable_assignment.begin() + num_inputs, full_variable_assignment.end()); + + /* sanity checks */ + assert(cs.num_variables() == full_variable_assignment.size()); + assert(cs.num_variables() >= num_inputs); + assert(cs.num_inputs() == num_inputs); + assert(cs.num_constraints() == num_constraints); + assert(cs.is_satisfied(primary_input, auxiliary_input)); + + leave_block("Call to generate_r1cs_example_with_field_input"); + + return r1cs_example(std::move(cs), std::move(primary_input), std::move(auxiliary_input)); +} + +template +r1cs_example generate_r1cs_example_with_binary_input(const size_t num_constraints, + const size_t num_inputs) +{ + enter_block("Call to generate_r1cs_example_with_binary_input"); + + assert(num_inputs >= 1); + + r1cs_constraint_system cs; + cs.primary_input_size = num_inputs; + cs.auxiliary_input_size = num_constraints; /* we will add one auxiliary variable per constraint */ + + r1cs_variable_assignment full_variable_assignment; + for (size_t i = 0; i < num_inputs; ++i) + { + full_variable_assignment.push_back(FieldT(std::rand() % 2)); + } + + size_t lastvar = num_inputs-1; + for (size_t i = 0; i < num_constraints; ++i) + { + ++lastvar; + const size_t u = (i == 0 ? std::rand() % num_inputs : std::rand() % i); + const size_t v = (i == 0 ? std::rand() % num_inputs : std::rand() % i); + + /* chose two random bits and XOR them together: + res = u + v - 2 * u * v + 2 * u * v = u + v - res + */ + linear_combination A, B, C; + A.add_term(u+1, 2); + B.add_term(v+1, 1); + if (u == v) + { + C.add_term(u+1, 2); + } + else + { + C.add_term(u+1, 1); + C.add_term(v+1, 1); + } + C.add_term(lastvar+1, -FieldT::one()); + + cs.add_constraint(r1cs_constraint(A, B, C)); + full_variable_assignment.push_back(full_variable_assignment[u] + full_variable_assignment[v] - full_variable_assignment[u] * full_variable_assignment[v] - full_variable_assignment[u] * full_variable_assignment[v]); + } + + /* split variable assignment */ + r1cs_primary_input primary_input(full_variable_assignment.begin(), full_variable_assignment.begin() + num_inputs); + r1cs_primary_input auxiliary_input(full_variable_assignment.begin() + num_inputs, full_variable_assignment.end()); + + /* sanity checks */ + assert(cs.num_variables() == full_variable_assignment.size()); + assert(cs.num_variables() >= num_inputs); + assert(cs.num_inputs() == num_inputs); + assert(cs.num_constraints() == num_constraints); + assert(cs.is_satisfied(primary_input, auxiliary_input)); + + leave_block("Call to generate_r1cs_example_with_binary_input"); + + return r1cs_example(std::move(cs), std::move(primary_input), std::move(auxiliary_input)); +} + +} // libsnark + +#endif // R1CS_EXAMPLES_TCC diff --git a/src/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp b/src/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp new file mode 100644 index 00000000000..ca3acb3a9e6 --- /dev/null +++ b/src/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp @@ -0,0 +1,153 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for: + - a R1CS constraint, + - a R1CS variable assignment, and + - a R1CS constraint system. + + Above, R1CS stands for "Rank-1 Constraint System". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_HPP_ +#define R1CS_HPP_ + +#include +#include +#include +#include +#include + +#include "relations/variable.hpp" + +namespace libsnark { + +/************************* R1CS constraint ***********************************/ + +template +class r1cs_constraint; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_constraint &c); + +template +std::istream& operator>>(std::istream &in, r1cs_constraint &c); + +/** + * A R1CS constraint is a formal expression of the form + * + * < A , X > * < B , X > = < C , X > , + * + * where X = (x_0,x_1,...,x_m) is a vector of formal variables and A,B,C each + * consist of 1+m elements in . + * + * A R1CS constraint is used to construct a R1CS constraint system (see below). + */ +template +class r1cs_constraint { +public: + + linear_combination a, b, c; + + r1cs_constraint() {}; + r1cs_constraint(const linear_combination &a, + const linear_combination &b, + const linear_combination &c); + + r1cs_constraint(const std::initializer_list > &A, + const std::initializer_list > &B, + const std::initializer_list > &C); + + bool operator==(const r1cs_constraint &other) const; + + friend std::ostream& operator<< (std::ostream &out, const r1cs_constraint &c); + friend std::istream& operator>> (std::istream &in, r1cs_constraint &c); +}; + +/************************* R1CS variable assignment **************************/ + +/** + * A R1CS variable assignment is a vector of elements that represents + * a candidate solution to a R1CS constraint system (see below). + */ + +/* TODO: specify that it does *NOT* include the constant 1 */ +template +using r1cs_primary_input = std::vector; + +template +using r1cs_auxiliary_input = std::vector; + +template +using r1cs_variable_assignment = std::vector; /* note the changed name! (TODO: remove this comment after primary_input transition is complete) */ + +/************************* R1CS constraint system ****************************/ + +template +class r1cs_constraint_system; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_constraint_system &cs); + +template +std::istream& operator>>(std::istream &in, r1cs_constraint_system &cs); + +/** + * A system of R1CS constraints looks like + * + * { < A_k , X > * < B_k , X > = < C_k , X > }_{k=1}^{n} . + * + * In other words, the system is satisfied if and only if there exist a + * USCS variable assignment for which each R1CS constraint is satisfied. + * + * NOTE: + * The 0-th variable (i.e., "x_{0}") always represents the constant 1. + * Thus, the 0-th variable is not included in num_variables. + */ +template +class r1cs_constraint_system { +public: + size_t primary_input_size; + size_t auxiliary_input_size; + + std::vector > constraints; + + r1cs_constraint_system() : primary_input_size(0), auxiliary_input_size(0) {} + + size_t num_inputs() const; + size_t num_variables() const; + size_t num_constraints() const; + +#ifdef DEBUG + std::map constraint_annotations; + std::map variable_annotations; +#endif + + bool is_valid() const; + bool is_satisfied(const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input) const; + + void add_constraint(const r1cs_constraint &c); + void add_constraint(const r1cs_constraint &c, const std::string &annotation); + + void swap_AB_if_beneficial(); + + bool operator==(const r1cs_constraint_system &other) const; + + friend std::ostream& operator<< (std::ostream &out, const r1cs_constraint_system &cs); + friend std::istream& operator>> (std::istream &in, r1cs_constraint_system &cs); + + void report_linear_constraint_statistics() const; +}; + + +} // libsnark + +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.tcc" + +#endif // R1CS_HPP_ diff --git a/src/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc b/src/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc new file mode 100644 index 00000000000..0faa56a87f1 --- /dev/null +++ b/src/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc @@ -0,0 +1,310 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for: + - a R1CS constraint, + - a R1CS variable assignment, and + - a R1CS constraint system. + + See r1cs.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_TCC_ +#define R1CS_TCC_ + +#include +#include +#include +#include "common/utils.hpp" +#include "common/profiling.hpp" +#include "algebra/fields/bigint.hpp" + +namespace libsnark { + +template +r1cs_constraint::r1cs_constraint(const linear_combination &a, + const linear_combination &b, + const linear_combination &c) : + a(a), b(b), c(c) +{ +} + +template +r1cs_constraint::r1cs_constraint(const std::initializer_list > &A, + const std::initializer_list > &B, + const std::initializer_list > &C) +{ + for (auto lc_A : A) + { + a.terms.insert(a.terms.end(), lc_A.terms.begin(), lc_A.terms.end()); + } + for (auto lc_B : B) + { + b.terms.insert(b.terms.end(), lc_B.terms.begin(), lc_B.terms.end()); + } + for (auto lc_C : C) + { + c.terms.insert(c.terms.end(), lc_C.terms.begin(), lc_C.terms.end()); + } +} + +template +bool r1cs_constraint::operator==(const r1cs_constraint &other) const +{ + return (this->a == other.a && + this->b == other.b && + this->c == other.c); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_constraint &c) +{ + out << c.a; + out << c.b; + out << c.c; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_constraint &c) +{ + in >> c.a; + in >> c.b; + in >> c.c; + + return in; +} + +template +size_t r1cs_constraint_system::num_inputs() const +{ + return primary_input_size; +} + +template +size_t r1cs_constraint_system::num_variables() const +{ + return primary_input_size + auxiliary_input_size; +} + + +template +size_t r1cs_constraint_system::num_constraints() const +{ + return constraints.size(); +} + +template +bool r1cs_constraint_system::is_valid() const +{ + if (this->num_inputs() > this->num_variables()) return false; + + for (size_t c = 0; c < constraints.size(); ++c) + { + if (!(constraints[c].a.is_valid(this->num_variables()) && + constraints[c].b.is_valid(this->num_variables()) && + constraints[c].c.is_valid(this->num_variables()))) + { + return false; + } + } + + return true; +} + +template +void dump_r1cs_constraint(const r1cs_constraint &constraint, + const r1cs_variable_assignment &full_variable_assignment, + const std::map &variable_annotations) +{ + printf("terms for a:\n"); constraint.a.print_with_assignment(full_variable_assignment, variable_annotations); + printf("terms for b:\n"); constraint.b.print_with_assignment(full_variable_assignment, variable_annotations); + printf("terms for c:\n"); constraint.c.print_with_assignment(full_variable_assignment, variable_annotations); +} + +template +bool r1cs_constraint_system::is_satisfied(const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input) const +{ + assert(primary_input.size() == num_inputs()); + assert(primary_input.size() + auxiliary_input.size() == num_variables()); + + r1cs_variable_assignment full_variable_assignment = primary_input; + full_variable_assignment.insert(full_variable_assignment.end(), auxiliary_input.begin(), auxiliary_input.end()); + + for (size_t c = 0; c < constraints.size(); ++c) + { + const FieldT ares = constraints[c].a.evaluate(full_variable_assignment); + const FieldT bres = constraints[c].b.evaluate(full_variable_assignment); + const FieldT cres = constraints[c].c.evaluate(full_variable_assignment); + + if (!(ares*bres == cres)) + { +#ifdef DEBUG + auto it = constraint_annotations.find(c); + printf("constraint %zu (%s) unsatisfied\n", c, (it == constraint_annotations.end() ? "no annotation" : it->second.c_str())); + printf(" = "); ares.print(); + printf(" = "); bres.print(); + printf(" = "); cres.print(); + printf("constraint was:\n"); + dump_r1cs_constraint(constraints[c], full_variable_assignment, variable_annotations); +#endif // DEBUG + return false; + } + } + + return true; +} + +template +void r1cs_constraint_system::add_constraint(const r1cs_constraint &c) +{ + constraints.emplace_back(c); +} + +template +void r1cs_constraint_system::add_constraint(const r1cs_constraint &c, const std::string &annotation) +{ +#ifdef DEBUG + constraint_annotations[constraints.size()] = annotation; +#endif + constraints.emplace_back(c); +} + +template +void r1cs_constraint_system::swap_AB_if_beneficial() +{ + enter_block("Call to r1cs_constraint_system::swap_AB_if_beneficial"); + + enter_block("Estimate densities"); + bit_vector touched_by_A(this->num_variables() + 1, false), touched_by_B(this->num_variables() + 1, false); + + for (size_t i = 0; i < this->constraints.size(); ++i) + { + for (size_t j = 0; j < this->constraints[i].a.terms.size(); ++j) + { + touched_by_A[this->constraints[i].a.terms[j].index] = true; + } + + for (size_t j = 0; j < this->constraints[i].b.terms.size(); ++j) + { + touched_by_B[this->constraints[i].b.terms[j].index] = true; + } + } + + size_t non_zero_A_count = 0, non_zero_B_count = 0; + for (size_t i = 0; i < this->num_variables() + 1; ++i) + { + non_zero_A_count += touched_by_A[i] ? 1 : 0; + non_zero_B_count += touched_by_B[i] ? 1 : 0; + } + + if (!inhibit_profiling_info) + { + print_indent(); printf("* Non-zero A-count (estimate): %zu\n", non_zero_A_count); + print_indent(); printf("* Non-zero B-count (estimate): %zu\n", non_zero_B_count); + } + leave_block("Estimate densities"); + + if (non_zero_B_count > non_zero_A_count) + { + enter_block("Perform the swap"); + for (size_t i = 0; i < this->constraints.size(); ++i) + { + std::swap(this->constraints[i].a, this->constraints[i].b); + } + leave_block("Perform the swap"); + } + else + { + print_indent(); printf("Swap is not beneficial, not performing\n"); + } + + leave_block("Call to r1cs_constraint_system::swap_AB_if_beneficial"); +} + +template +bool r1cs_constraint_system::operator==(const r1cs_constraint_system &other) const +{ + return (this->constraints == other.constraints && + this->primary_input_size == other.primary_input_size && + this->auxiliary_input_size == other.auxiliary_input_size); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_constraint_system &cs) +{ + out << cs.primary_input_size << "\n"; + out << cs.auxiliary_input_size << "\n"; + + out << cs.num_constraints() << "\n"; + for (const r1cs_constraint& c : cs.constraints) + { + out << c; + } + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_constraint_system &cs) +{ + in >> cs.primary_input_size; + in >> cs.auxiliary_input_size; + + cs.constraints.clear(); + + size_t s; + in >> s; + + char b; + in.read(&b, 1); + + cs.constraints.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + r1cs_constraint c; + in >> c; + cs.constraints.emplace_back(c); + } + + return in; +} + +template +void r1cs_constraint_system::report_linear_constraint_statistics() const +{ +#ifdef DEBUG + for (size_t i = 0; i < constraints.size(); ++i) + { + auto &constr = constraints[i]; + bool a_is_const = true; + for (auto &t : constr.a.terms) + { + a_is_const = a_is_const && (t.index == 0); + } + + bool b_is_const = true; + for (auto &t : constr.b.terms) + { + b_is_const = b_is_const && (t.index == 0); + } + + if (a_is_const || b_is_const) + { + auto it = constraint_annotations.find(i); + printf("%s\n", (it == constraint_annotations.end() ? FORMAT("", "constraint_%zu", i) : it->second).c_str()); + } + } +#endif +} + +} // libsnark +#endif // R1CS_TCC_ diff --git a/src/relations/variable.hpp b/src/relations/variable.hpp new file mode 100644 index 00000000000..a9a1449b81e --- /dev/null +++ b/src/relations/variable.hpp @@ -0,0 +1,213 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for: + - a variable (i.e., x_i), + - a linear term (i.e., a_i * x_i), and + - a linear combination (i.e., sum_i a_i * x_i). + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef VARIABLE_HPP_ +#define VARIABLE_HPP_ + +#include +#include +#include +#include + +namespace libsnark { + +/** + * Mnemonic typedefs. + */ +typedef size_t var_index_t; +typedef long integer_coeff_t; + +/** + * Forward declaration. + */ +template +class linear_term; + +/** + * Forward declaration. + */ +template +class linear_combination; + +/********************************* Variable **********************************/ + +/** + * A variable represents a formal expresison of the form "x_{index}". + */ +template +class variable { +public: + + var_index_t index; + + variable(const var_index_t index = 0) : index(index) {}; + + linear_term operator*(const integer_coeff_t int_coeff) const; + linear_term operator*(const FieldT &field_coeff) const; + + linear_combination operator+(const linear_combination &other) const; + linear_combination operator-(const linear_combination &other) const; + + linear_term operator-() const; + + bool operator==(const variable &other) const; +}; + +template +linear_term operator*(const integer_coeff_t int_coeff, const variable &var); + +template +linear_term operator*(const FieldT &field_coeff, const variable &var); + +template +linear_combination operator+(const integer_coeff_t int_coeff, const variable &var); + +template +linear_combination operator+(const FieldT &field_coeff, const variable &var); + +template +linear_combination operator-(const integer_coeff_t int_coeff, const variable &var); + +template +linear_combination operator-(const FieldT &field_coeff, const variable &var); + + +/****************************** Linear term **********************************/ + +/** + * A linear term represents a formal expression of the form "coeff * x_{index}". + */ +template +class linear_term { +public: + + var_index_t index = 0; + FieldT coeff; + + linear_term() {}; + linear_term(const variable &var); + linear_term(const variable &var, const integer_coeff_t int_coeff); + linear_term(const variable &var, const FieldT &field_coeff); + + linear_term operator*(const integer_coeff_t int_coeff) const; + linear_term operator*(const FieldT &field_coeff) const; + + linear_combination operator+(const linear_combination &other) const; + linear_combination operator-(const linear_combination &other) const; + + linear_term operator-() const; + + bool operator==(const linear_term &other) const; +}; + +template +linear_term operator*(const integer_coeff_t int_coeff, const linear_term <); + +template +linear_term operator*(const FieldT &field_coeff, const linear_term <); + +template +linear_combination operator+(const integer_coeff_t int_coeff, const linear_term <); + +template +linear_combination operator+(const FieldT &field_coeff, const linear_term <); + +template +linear_combination operator-(const integer_coeff_t int_coeff, const linear_term <); + +template +linear_combination operator-(const FieldT &field_coeff, const linear_term <); + + +/***************************** Linear combination ****************************/ + +template +class linear_combination; + +template +std::ostream& operator<<(std::ostream &out, const linear_combination &lc); + +template +std::istream& operator>>(std::istream &in, linear_combination &lc); + +/** + * A linear combination represents a formal expression of the form "sum_i coeff_i * x_{index_i}". + */ +template +class linear_combination { +public: + + std::vector > terms; + + linear_combination() {}; + linear_combination(const integer_coeff_t int_coeff); + linear_combination(const FieldT &field_coeff); + linear_combination(const variable &var); + linear_combination(const linear_term <); + linear_combination(const std::vector > &all_terms); + + /* for supporting range-based for loops over linear_combination */ + typename std::vector >::const_iterator begin() const; + typename std::vector >::const_iterator end() const; + + void add_term(const variable &var); + void add_term(const variable &var, const integer_coeff_t int_coeff); + void add_term(const variable &var, const FieldT &field_coeff); + + void add_term(const linear_term <); + + FieldT evaluate(const std::vector &assignment) const; + + linear_combination operator*(const integer_coeff_t int_coeff) const; + linear_combination operator*(const FieldT &field_coeff) const; + + linear_combination operator+(const linear_combination &other) const; + + linear_combination operator-(const linear_combination &other) const; + linear_combination operator-() const; + + bool operator==(const linear_combination &other) const; + + bool is_valid(const size_t num_variables) const; + + void print(const std::map &variable_annotations = std::map()) const; + void print_with_assignment(const std::vector &full_assignment, const std::map &variable_annotations = std::map()) const; + + friend std::ostream& operator<< (std::ostream &out, const linear_combination &lc); + friend std::istream& operator>> (std::istream &in, linear_combination &lc); +}; + +template +linear_combination operator*(const integer_coeff_t int_coeff, const linear_combination &lc); + +template +linear_combination operator*(const FieldT &field_coeff, const linear_combination &lc); + +template +linear_combination operator+(const integer_coeff_t int_coeff, const linear_combination &lc); + +template +linear_combination operator+(const FieldT &field_coeff, const linear_combination &lc); + +template +linear_combination operator-(const integer_coeff_t int_coeff, const linear_combination &lc); + +template +linear_combination operator-(const FieldT &field_coeff, const linear_combination &lc); + +} // libsnark + +#include "relations/variable.tcc" + +#endif // VARIABLE_HPP_ diff --git a/src/relations/variable.tcc b/src/relations/variable.tcc new file mode 100644 index 00000000000..4c4cab97f59 --- /dev/null +++ b/src/relations/variable.tcc @@ -0,0 +1,512 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for: + - a variable (i.e., x_i), + - a linear term (i.e., a_i * x_i), and + - a linear combination (i.e., sum_i a_i * x_i). + + See variabe.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef VARIABLE_TCC_ +#define VARIABLE_TCC_ + +#include +#include + +#include "algebra/fields/bigint.hpp" + +namespace libsnark { + +template +linear_term variable::operator*(const integer_coeff_t int_coeff) const +{ + return linear_term(*this, int_coeff); +} + +template +linear_term variable::operator*(const FieldT &field_coeff) const +{ + return linear_term(*this, field_coeff); +} + +template +linear_combination variable::operator+(const linear_combination &other) const +{ + linear_combination result; + + result.add_term(*this); + result.terms.insert(result.terms.begin(), other.terms.begin(), other.terms.end()); + + return result; +} + +template +linear_combination variable::operator-(const linear_combination &other) const +{ + return (*this) + (-other); +} + +template +linear_term variable::operator-() const +{ + return linear_term(*this, -FieldT::one()); +} + +template +bool variable::operator==(const variable &other) const +{ + return (this->index == other.index); +} + +template +linear_term operator*(const integer_coeff_t int_coeff, const variable &var) +{ + return linear_term(var, int_coeff); +} + +template +linear_term operator*(const FieldT &field_coeff, const variable &var) +{ + return linear_term(var, field_coeff); +} + +template +linear_combination operator+(const integer_coeff_t int_coeff, const variable &var) +{ + return linear_combination(int_coeff) + var; +} + +template +linear_combination operator+(const FieldT &field_coeff, const variable &var) +{ + return linear_combination(field_coeff) + var; +} + +template +linear_combination operator-(const integer_coeff_t int_coeff, const variable &var) +{ + return linear_combination(int_coeff) - var; +} + +template +linear_combination operator-(const FieldT &field_coeff, const variable &var) +{ + return linear_combination(field_coeff) - var; +} + +template +linear_term::linear_term(const variable &var) : + index(var.index), coeff(FieldT::one()) +{ +} + +template +linear_term::linear_term(const variable &var, const integer_coeff_t int_coeff) : + index(var.index), coeff(FieldT(int_coeff)) +{ +} + +template +linear_term::linear_term(const variable &var, const FieldT &coeff) : + index(var.index), coeff(coeff) +{ +} + +template +linear_term linear_term::operator*(const integer_coeff_t int_coeff) const +{ + return (this->operator*(FieldT(int_coeff))); +} + +template +linear_term linear_term::operator*(const FieldT &field_coeff) const +{ + return linear_term(this->index, field_coeff * this->coeff); +} + +template +linear_combination operator+(const integer_coeff_t int_coeff, const linear_term <) +{ + return linear_combination(int_coeff) + lt; +} + +template +linear_combination operator+(const FieldT &field_coeff, const linear_term <) +{ + return linear_combination(field_coeff) + lt; +} + +template +linear_combination operator-(const integer_coeff_t int_coeff, const linear_term <) +{ + return linear_combination(int_coeff) - lt; +} + +template +linear_combination operator-(const FieldT &field_coeff, const linear_term <) +{ + return linear_combination(field_coeff) - lt; +} + +template +linear_combination linear_term::operator+(const linear_combination &other) const +{ + return linear_combination(*this) + other; +} + +template +linear_combination linear_term::operator-(const linear_combination &other) const +{ + return (*this) + (-other); +} + +template +linear_term linear_term::operator-() const +{ + return linear_term(this->index, -this->coeff); +} + +template +bool linear_term::operator==(const linear_term &other) const +{ + return (this->index == other.index && + this->coeff == other.coeff); +} + +template +linear_term operator*(const integer_coeff_t int_coeff, const linear_term <) +{ + return FieldT(int_coeff) * lt; +} + +template +linear_term operator*(const FieldT &field_coeff, const linear_term <) +{ + return linear_term(lt.index, field_coeff * lt.coeff); +} + +template +linear_combination::linear_combination(const integer_coeff_t int_coeff) +{ + this->add_term(linear_term(0, int_coeff)); +} + +template +linear_combination::linear_combination(const FieldT &field_coeff) +{ + this->add_term(linear_term(0, field_coeff)); +} + +template +linear_combination::linear_combination(const variable &var) +{ + this->add_term(var); +} + +template +linear_combination::linear_combination(const linear_term <) +{ + this->add_term(lt); +} + +template +typename std::vector >::const_iterator linear_combination::begin() const +{ + return terms.begin(); +} + +template +typename std::vector >::const_iterator linear_combination::end() const +{ + return terms.end(); +} + +template +void linear_combination::add_term(const variable &var) +{ + this->terms.emplace_back(linear_term(var.index, FieldT::one())); +} + +template +void linear_combination::add_term(const variable &var, const integer_coeff_t int_coeff) +{ + this->terms.emplace_back(linear_term(var.index, int_coeff)); +} + +template +void linear_combination::add_term(const variable &var, const FieldT &coeff) +{ + this->terms.emplace_back(linear_term(var.index, coeff)); +} + +template +void linear_combination::add_term(const linear_term &other) +{ + this->terms.emplace_back(other); +} + +template +linear_combination linear_combination::operator*(const integer_coeff_t int_coeff) const +{ + return (*this) * FieldT(int_coeff); +} + +template +FieldT linear_combination::evaluate(const std::vector &assignment) const +{ + FieldT acc = FieldT::zero(); + for (auto < : terms) + { + acc += (lt.index == 0 ? FieldT::one() : assignment[lt.index-1]) * lt.coeff; + } + return acc; +} + +template +linear_combination linear_combination::operator*(const FieldT &field_coeff) const +{ + linear_combination result; + result.terms.reserve(this->terms.size()); + for (const linear_term < : this->terms) + { + result.terms.emplace_back(lt * field_coeff); + } + return result; +} + +template +linear_combination linear_combination::operator+(const linear_combination &other) const +{ + linear_combination result; + + auto it1 = this->terms.begin(); + auto it2 = other.terms.begin(); + + /* invariant: it1 and it2 always point to unprocessed items in the corresponding linear combinations */ + while (it1 != this->terms.end() && it2 != other.terms.end()) + { + if (it1->index < it2->index) + { + result.terms.emplace_back(*it1); + ++it1; + } + else if (it1->index > it2->index) + { + result.terms.emplace_back(*it2); + ++it2; + } + else + { + /* it1->index == it2->index */ + result.terms.emplace_back(linear_term(variable(it1->index), it1->coeff + it2->coeff)); + ++it1; + ++it2; + } + } + + if (it1 != this->terms.end()) + { + result.terms.insert(result.terms.end(), it1, this->terms.end()); + } + else + { + result.terms.insert(result.terms.end(), it2, other.terms.end()); + } + + return result; +} + +template +linear_combination linear_combination::operator-(const linear_combination &other) const +{ + return (*this) + (-other); +} + +template +linear_combination linear_combination::operator-() const +{ + return (*this) * (-FieldT::one()); +} + +template +bool linear_combination::operator==(const linear_combination &other) const +{ + return (this->terms == other.terms); +} + +template +bool linear_combination::is_valid(const size_t num_variables) const +{ + /* check that all terms in linear combination are sorted */ + for (size_t i = 1; i < terms.size(); ++i) + { + if (terms[i-1].index >= terms[i].index) + { + return false; + } + } + + /* check that the variables are in proper range. as the variables + are sorted, it suffices to check the last term */ + if ((--terms.end())->index >= num_variables) + { + return false; + } + + return true; +} + +template +void linear_combination::print(const std::map &variable_annotations) const +{ + for (auto < : terms) + { + if (lt.index == 0) + { + printf(" 1 * "); + lt.coeff.print(); + } + else + { + auto it = variable_annotations.find(lt.index); + printf(" x_%zu (%s) * ", lt.index, (it == variable_annotations.end() ? "no annotation" : it->second.c_str())); + lt.coeff.print(); + } + } +} + +template +void linear_combination::print_with_assignment(const std::vector &full_assignment, const std::map &variable_annotations) const +{ + for (auto < : terms) + { + if (lt.index == 0) + { + printf(" 1 * "); + lt.coeff.print(); + } + else + { + printf(" x_%zu * ", lt.index); + lt.coeff.print(); + + auto it = variable_annotations.find(lt.index); + printf(" where x_%zu (%s) was assigned value ", lt.index, + (it == variable_annotations.end() ? "no annotation" : it->second.c_str())); + full_assignment[lt.index-1].print(); + printf(" i.e. negative of "); + (-full_assignment[lt.index-1]).print(); + } + } +} + +template +std::ostream& operator<<(std::ostream &out, const linear_combination &lc) +{ + out << lc.terms.size() << "\n"; + for (const linear_term& lt : lc.terms) + { + out << lt.index << "\n"; + out << lt.coeff << OUTPUT_NEWLINE; + } + + return out; +} + +template +std::istream& operator>>(std::istream &in, linear_combination &lc) +{ + lc.terms.clear(); + + size_t s; + in >> s; + + consume_newline(in); + + lc.terms.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + linear_term lt; + in >> lt.index; + consume_newline(in); + in >> lt.coeff; + consume_OUTPUT_NEWLINE(in); + lc.terms.emplace_back(lt); + } + + return in; +} + +template +linear_combination operator*(const integer_coeff_t int_coeff, const linear_combination &lc) +{ + return lc * int_coeff; +} + +template +linear_combination operator*(const FieldT &field_coeff, const linear_combination &lc) +{ + return lc * field_coeff; +} + +template +linear_combination operator+(const integer_coeff_t int_coeff, const linear_combination &lc) +{ + return linear_combination(int_coeff) + lc; +} + +template +linear_combination operator+(const FieldT &field_coeff, const linear_combination &lc) +{ + return linear_combination(field_coeff) + lc; +} + +template +linear_combination operator-(const integer_coeff_t int_coeff, const linear_combination &lc) +{ + return linear_combination(int_coeff) - lc; +} + +template +linear_combination operator-(const FieldT &field_coeff, const linear_combination &lc) +{ + return linear_combination(field_coeff) - lc; +} + +template +linear_combination::linear_combination(const std::vector > &all_terms) +{ + if (all_terms.empty()) + { + return; + } + + terms = all_terms; + std::sort(terms.begin(), terms.end(), [](linear_term a, linear_term b) { return a.index < b.index; }); + + auto result_it = terms.begin(); + for (auto it = ++terms.begin(); it != terms.end(); ++it) + { + if (it->index == result_it->index) + { + result_it->coeff += it->coeff; + } + else + { + *(++result_it) = *it; + } + } + terms.resize((result_it - terms.begin()) + 1); +} + +} // libsnark + +#endif // VARIABLE_TCC diff --git a/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp b/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp new file mode 100644 index 00000000000..fcd28abf3bd --- /dev/null +++ b/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp @@ -0,0 +1,35 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the R1CS ppzkSNARK for + a given R1CS example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_PPZKSNARK_HPP_ +#define RUN_R1CS_PPZKSNARK_HPP_ + +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" + +namespace libsnark { + +/** + * Runs the ppzkSNARK (generator, prover, and verifier) for a given + * R1CS example (specified by a constraint system, input, and witness). + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + */ +template +bool run_r1cs_ppzksnark(const r1cs_example > &example, + const bool test_serialization); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc" + +#endif // RUN_R1CS_PPZKSNARK_HPP_ diff --git a/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc b/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc new file mode 100644 index 00000000000..9bc87586910 --- /dev/null +++ b/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc @@ -0,0 +1,114 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the R1CS ppzkSNARK for + a given R1CS example. + + See run_r1cs_ppzksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_PPZKSNARK_TCC_ +#define RUN_R1CS_PPZKSNARK_TCC_ + +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" + +#include +#include + +#include "common/profiling.hpp" + +namespace libsnark { + +template +typename std::enable_if::type +test_affine_verifier(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof, + const bool expected_answer) +{ + print_header("R1CS ppzkSNARK Affine Verifier"); + const bool answer = r1cs_ppzksnark_affine_verifier_weak_IC(vk, primary_input, proof); + assert(answer == expected_answer); +} + +template +typename std::enable_if::type +test_affine_verifier(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof, + const bool expected_answer) +{ + UNUSED(vk, primary_input, proof, expected_answer); + print_header("R1CS ppzkSNARK Affine Verifier"); + printf("Affine verifier is not supported; not testing anything.\n"); +} + +/** + * The code below provides an example of all stages of running a R1CS ppzkSNARK. + * + * Of course, in a real-life scenario, we would have three distinct entities, + * mangled into one in the demonstration below. The three entities are as follows. + * (1) The "generator", which runs the ppzkSNARK generator on input a given + * constraint system CS to create a proving and a verification key for CS. + * (2) The "prover", which runs the ppzkSNARK prover on input the proving key, + * a primary input for CS, and an auxiliary input for CS. + * (3) The "verifier", which runs the ppzkSNARK verifier on input the verification key, + * a primary input for CS, and a proof. + */ +template +bool run_r1cs_ppzksnark(const r1cs_example > &example, + const bool test_serialization) +{ + enter_block("Call to run_r1cs_ppzksnark"); + + print_header("R1CS ppzkSNARK Generator"); + r1cs_ppzksnark_keypair keypair = r1cs_ppzksnark_generator(example.constraint_system); + printf("\n"); print_indent(); print_mem("after generator"); + + print_header("Preprocess verification key"); + r1cs_ppzksnark_processed_verification_key pvk = r1cs_ppzksnark_verifier_process_vk(keypair.vk); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + pvk = reserialize >(pvk); + leave_block("Test serialization of keys"); + } + + print_header("R1CS ppzkSNARK Prover"); + r1cs_ppzksnark_proof proof = r1cs_ppzksnark_prover(keypair.pk, example.primary_input, example.auxiliary_input); + printf("\n"); print_indent(); print_mem("after prover"); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + print_header("R1CS ppzkSNARK Verifier"); + const bool ans = r1cs_ppzksnark_verifier_strong_IC(keypair.vk, example.primary_input, proof); + printf("\n"); print_indent(); print_mem("after verifier"); + printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL")); + + print_header("R1CS ppzkSNARK Online Verifier"); + const bool ans2 = r1cs_ppzksnark_online_verifier_strong_IC(pvk, example.primary_input, proof); + assert(ans == ans2); + + test_affine_verifier(keypair.vk, example.primary_input, proof, ans); + + leave_block("Call to run_r1cs_ppzksnark"); + + return ans; +} + +} // libsnark + +#endif // RUN_R1CS_PPZKSNARK_TCC_ diff --git a/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp b/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp new file mode 100644 index 00000000000..5c54150289e --- /dev/null +++ b/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp @@ -0,0 +1,71 @@ +/** @file + ***************************************************************************** + Profiling program that exercises the ppzkSNARK (first generator, then prover, + then verifier) on a synthetic R1CS instance. + + The command + + $ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 Fr + + exercises the ppzkSNARK (first generator, then prover, then verifier) on an R1CS instance with 1000 equations and an input consisting of 10 field elements. + + (If you get the error `zmInit ERR:can't protect`, see the discussion [above](#elliptic-curve-choices).) + + The command + + $ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 bytes + + does the same but now the input consists of 10 bytes. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include + +#include "common/default_types/r1cs_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp" + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + default_r1cs_ppzksnark_pp::init_public_params(); + start_profiling(); + + if (argc == 2 && strcmp(argv[1], "-v") == 0) + { + print_compilation_info(); + return 0; + } + + if (argc != 3 && argc != 4) + { + printf("usage: %s num_constraints input_size [Fr|bytes]\n", argv[0]); + return 1; + } + const int num_constraints = atoi(argv[1]); + int input_size = atoi(argv[2]); + if (argc == 4) + { + assert(strcmp(argv[3], "Fr") == 0 || strcmp(argv[3], "bytes") == 0); + if (strcmp(argv[3], "bytes") == 0) + { + input_size = div_ceil(8 * input_size, Fr::capacity()); + } + } + + enter_block("Generate R1CS example"); + r1cs_example > example = generate_r1cs_example_with_field_input >(num_constraints, input_size); + leave_block("Generate R1CS example"); + + print_header("(enter) Profile R1CS ppzkSNARK"); + const bool test_serialization = true; + run_r1cs_ppzksnark(example, test_serialization); + print_header("(leave) Profile R1CS ppzkSNARK"); +} diff --git a/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp b/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp new file mode 100644 index 00000000000..a068b09fde1 --- /dev/null +++ b/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp @@ -0,0 +1,479 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a ppzkSNARK for R1CS. + + This includes: + - class for proving key + - class for verification key + - class for processed verification key + - class for key pair (proving key & verification key) + - class for proof + - generator algorithm + - prover algorithm + - verifier algorithm (with strong or weak input consistency) + - online verifier algorithm (with strong or weak input consistency) + + The implementation instantiates (a modification of) the protocol of \[PGHR13], + by following extending, and optimizing the approach described in \[BCTV14]. + + + Acronyms: + + - R1CS = "Rank-1 Constraint Systems" + - ppzkSNARK = "PreProcessing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" + + References: + + \[BCTV14]: + "Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture", + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + USENIX Security 2014, + + + \[PGHR13]: + "Pinocchio: Nearly practical verifiable computation", + Bryan Parno, Craig Gentry, Jon Howell, Mariana Raykova, + IEEE S&P 2013, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKSNARK_HPP_ +#define R1CS_PPZKSNARK_HPP_ + +#include + +#include "algebra/curves/public_params.hpp" +#include "common/data_structures/accumulation_vector.hpp" +#include "algebra/knowledge_commitment/knowledge_commitment.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp" + +namespace libsnark { + +/******************************** Proving key ********************************/ + +template +class r1cs_ppzksnark_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proving_key &pk); + +/** + * A proving key for the R1CS ppzkSNARK. + */ +template +class r1cs_ppzksnark_proving_key { +public: + knowledge_commitment_vector, G1 > A_query; + knowledge_commitment_vector, G1 > B_query; + knowledge_commitment_vector, G1 > C_query; + G1_vector H_query; + G1_vector K_query; + + r1cs_ppzksnark_proving_key() {}; + r1cs_ppzksnark_proving_key& operator=(const r1cs_ppzksnark_proving_key &other) = default; + r1cs_ppzksnark_proving_key(const r1cs_ppzksnark_proving_key &other) = default; + r1cs_ppzksnark_proving_key(r1cs_ppzksnark_proving_key &&other) = default; + r1cs_ppzksnark_proving_key(knowledge_commitment_vector, G1 > &&A_query, + knowledge_commitment_vector, G1 > &&B_query, + knowledge_commitment_vector, G1 > &&C_query, + G1_vector &&H_query, + G1_vector &&K_query) : + A_query(std::move(A_query)), + B_query(std::move(B_query)), + C_query(std::move(C_query)), + H_query(std::move(H_query)), + K_query(std::move(K_query)) + {}; + + size_t G1_size() const + { + return 2*(A_query.domain_size() + C_query.domain_size()) + B_query.domain_size() + H_query.size() + K_query.size(); + } + + size_t G2_size() const + { + return B_query.domain_size(); + } + + size_t G1_sparse_size() const + { + return 2*(A_query.size() + C_query.size()) + B_query.size() + H_query.size() + K_query.size(); + } + + size_t G2_sparse_size() const + { + return B_query.size(); + } + + size_t size_in_bits() const + { + return A_query.size_in_bits() + B_query.size_in_bits() + C_query.size_in_bits() + libsnark::size_in_bits(H_query) + libsnark::size_in_bits(K_query); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in PK: %zu\n", this->G1_size()); + print_indent(); printf("* Non-zero G1 elements in PK: %zu\n", this->G1_sparse_size()); + print_indent(); printf("* G2 elements in PK: %zu\n", this->G2_size()); + print_indent(); printf("* Non-zero G2 elements in PK: %zu\n", this->G2_sparse_size()); + print_indent(); printf("* PK size in bits: %zu\n", this->size_in_bits()); + } + + bool operator==(const r1cs_ppzksnark_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzksnark_proving_key &pk); + friend std::istream& operator>> (std::istream &in, r1cs_ppzksnark_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +template +class r1cs_ppzksnark_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_verification_key &vk); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_verification_key &vk); + +/** + * A verification key for the R1CS ppzkSNARK. + */ +template +class r1cs_ppzksnark_verification_key { +public: + G2 alphaA_g2; + G1 alphaB_g1; + G2 alphaC_g2; + G2 gamma_g2; + G1 gamma_beta_g1; + G2 gamma_beta_g2; + G2 rC_Z_g2; + + accumulation_vector > encoded_IC_query; + + r1cs_ppzksnark_verification_key() = default; + r1cs_ppzksnark_verification_key(const G2 &alphaA_g2, + const G1 &alphaB_g1, + const G2 &alphaC_g2, + const G2 &gamma_g2, + const G1 &gamma_beta_g1, + const G2 &gamma_beta_g2, + const G2 &rC_Z_g2, + const accumulation_vector > &eIC) : + alphaA_g2(alphaA_g2), + alphaB_g1(alphaB_g1), + alphaC_g2(alphaC_g2), + gamma_g2(gamma_g2), + gamma_beta_g1(gamma_beta_g1), + gamma_beta_g2(gamma_beta_g2), + rC_Z_g2(rC_Z_g2), + encoded_IC_query(eIC) + {}; + + size_t G1_size() const + { + return 2 + encoded_IC_query.size(); + } + + size_t G2_size() const + { + return 5; + } + + size_t size_in_bits() const + { + return (2 * G1::size_in_bits() + encoded_IC_query.size_in_bits() + 5 * G2::size_in_bits()); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in VK: %zu\n", this->G1_size()); + print_indent(); printf("* G2 elements in VK: %zu\n", this->G2_size()); + print_indent(); printf("* VK size in bits: %zu\n", this->size_in_bits()); + } + + bool operator==(const r1cs_ppzksnark_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzksnark_verification_key &vk); + friend std::istream& operator>> (std::istream &in, r1cs_ppzksnark_verification_key &vk); + + static r1cs_ppzksnark_verification_key dummy_verification_key(const size_t input_size); +}; + + +/************************ Processed verification key *************************/ + +template +class r1cs_ppzksnark_processed_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_processed_verification_key &pvk); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_processed_verification_key &pvk); + +/** + * A processed verification key for the R1CS ppzkSNARK. + * + * Compared to a (non-processed) verification key, a processed verification key + * contains a small constant amount of additional pre-computed information that + * enables a faster verification time. + */ +template +class r1cs_ppzksnark_processed_verification_key { +public: + G2_precomp pp_G2_one_precomp; + G2_precomp vk_alphaA_g2_precomp; + G1_precomp vk_alphaB_g1_precomp; + G2_precomp vk_alphaC_g2_precomp; + G2_precomp vk_rC_Z_g2_precomp; + G2_precomp vk_gamma_g2_precomp; + G1_precomp vk_gamma_beta_g1_precomp; + G2_precomp vk_gamma_beta_g2_precomp; + + accumulation_vector > encoded_IC_query; + + bool operator==(const r1cs_ppzksnark_processed_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzksnark_processed_verification_key &pvk); + friend std::istream& operator>> (std::istream &in, r1cs_ppzksnark_processed_verification_key &pvk); +}; + + +/********************************** Key pair *********************************/ + +/** + * A key pair for the R1CS ppzkSNARK, which consists of a proving key and a verification key. + */ +template +class r1cs_ppzksnark_keypair { +public: + r1cs_ppzksnark_proving_key pk; + r1cs_ppzksnark_verification_key vk; + + r1cs_ppzksnark_keypair() = default; + r1cs_ppzksnark_keypair(const r1cs_ppzksnark_keypair &other) = default; + r1cs_ppzksnark_keypair(r1cs_ppzksnark_proving_key &&pk, + r1cs_ppzksnark_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {} + + r1cs_ppzksnark_keypair(r1cs_ppzksnark_keypair &&other) = default; +}; + + +/*********************************** Proof ***********************************/ + +template +class r1cs_ppzksnark_proof; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proof &proof); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proof &proof); + +/** + * A proof for the R1CS ppzkSNARK. + * + * While the proof has a structure, externally one merely opaquely produces, + * seralizes/deserializes, and verifies proofs. We only expose some information + * about the structure for statistics purposes. + */ +template +class r1cs_ppzksnark_proof { +public: + knowledge_commitment, G1 > g_A; + knowledge_commitment, G1 > g_B; + knowledge_commitment, G1 > g_C; + G1 g_H; + G1 g_K; + + r1cs_ppzksnark_proof() + { + // invalid proof with valid curve points + this->g_A.g = G1 ::one(); + this->g_A.h = G1::one(); + this->g_B.g = G2 ::one(); + this->g_B.h = G1::one(); + this->g_C.g = G1 ::one(); + this->g_C.h = G1::one(); + this->g_H = G1::one(); + this->g_K = G1::one(); + } + r1cs_ppzksnark_proof(knowledge_commitment, G1 > &&g_A, + knowledge_commitment, G1 > &&g_B, + knowledge_commitment, G1 > &&g_C, + G1 &&g_H, + G1 &&g_K) : + g_A(std::move(g_A)), + g_B(std::move(g_B)), + g_C(std::move(g_C)), + g_H(std::move(g_H)), + g_K(std::move(g_K)) + {}; + + size_t G1_size() const + { + return 7; + } + + size_t G2_size() const + { + return 1; + } + + size_t size_in_bits() const + { + return G1_size() * G1::size_in_bits() + G2_size() * G2::size_in_bits(); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in proof: %zu\n", this->G1_size()); + print_indent(); printf("* G2 elements in proof: %zu\n", this->G2_size()); + print_indent(); printf("* Proof size in bits: %zu\n", this->size_in_bits()); + } + + bool is_well_formed() const + { + return (g_A.g.is_well_formed() && g_A.h.is_well_formed() && + g_B.g.is_well_formed() && g_B.h.is_well_formed() && + g_C.g.is_well_formed() && g_C.h.is_well_formed() && + g_H.is_well_formed() && + g_K.is_well_formed()); + } + + bool operator==(const r1cs_ppzksnark_proof &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzksnark_proof &proof); + friend std::istream& operator>> (std::istream &in, r1cs_ppzksnark_proof &proof); +}; + + +/***************************** Main algorithms *******************************/ + +/** + * A generator algorithm for the R1CS ppzkSNARK. + * + * Given a R1CS constraint system CS, this algorithm produces proving and verification keys for CS. + */ +template +r1cs_ppzksnark_keypair r1cs_ppzksnark_generator(const r1cs_ppzksnark_constraint_system &cs); + +template +r1cs_ppzksnark_keypair r1cs_ppzksnark_generator( + const r1cs_ppzksnark_constraint_system &cs, + const Fr& t, + const Fr& alphaA, + const Fr& alphaB, + const Fr& alphaC, + const Fr& rA, + const Fr& rB, + const Fr& beta, + const Fr& gamma +); + +/** + * A prover algorithm for the R1CS ppzkSNARK. + * + * Given a R1CS primary input X and a R1CS auxiliary input Y, this algorithm + * produces a proof (of knowledge) that attests to the following statement: + * ``there exists Y such that CS(X,Y)=0''. + * Above, CS is the R1CS constraint system that was given as input to the generator algorithm. + */ +template +r1cs_ppzksnark_proof r1cs_ppzksnark_prover(const r1cs_ppzksnark_proving_key &pk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_auxiliary_input &auxiliary_input); + +/* + Below are four variants of verifier algorithm for the R1CS ppzkSNARK. + + These are the four cases that arise from the following two choices: + + (1) The verifier accepts a (non-processed) verification key or, instead, a processed verification key. + In the latter case, we call the algorithm an "online verifier". + + (2) The verifier checks for "weak" input consistency or, instead, "strong" input consistency. + Strong input consistency requires that |primary_input| = CS.num_inputs, whereas + weak input consistency requires that |primary_input| <= CS.num_inputs (and + the primary input is implicitly padded with zeros up to length CS.num_inputs). + */ + +/** + * A verifier algorithm for the R1CS ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has weak input consistency. + */ +template +bool r1cs_ppzksnark_verifier_weak_IC(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the R1CS ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has strong input consistency. + */ +template +bool r1cs_ppzksnark_verifier_strong_IC(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof); + +/** + * Convert a (non-processed) verification key into a processed verification key. + */ +template +r1cs_ppzksnark_processed_verification_key r1cs_ppzksnark_verifier_process_vk(const r1cs_ppzksnark_verification_key &vk); + +/** + * A verifier algorithm for the R1CS ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has weak input consistency. + */ +template +bool r1cs_ppzksnark_online_verifier_weak_IC(const r1cs_ppzksnark_processed_verification_key &pvk, + const r1cs_ppzksnark_primary_input &input, + const r1cs_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the R1CS ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has strong input consistency. + */ +template +bool r1cs_ppzksnark_online_verifier_strong_IC(const r1cs_ppzksnark_processed_verification_key &pvk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof); + +/****************************** Miscellaneous ********************************/ + +/** + * For debugging purposes (of r1cs_ppzksnark_r1cs_ppzksnark_verifier_gadget): + * + * A verifier algorithm for the R1CS ppzkSNARK that: + * (1) accepts a non-processed verification key, + * (2) has weak input consistency, and + * (3) uses affine coordinates for elliptic-curve computations. + */ +template +bool r1cs_ppzksnark_affine_verifier_weak_IC(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof); + + +} // libsnark + +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc" + +#endif // R1CS_PPZKSNARK_HPP_ diff --git a/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc b/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc new file mode 100644 index 00000000000..aeb2bbb858f --- /dev/null +++ b/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc @@ -0,0 +1,762 @@ +/** @file +***************************************************************************** + +Implementation of interfaces for a ppzkSNARK for R1CS. + +See r1cs_ppzksnark.hpp . + +***************************************************************************** +* @author This file is part of libsnark, developed by SCIPR Lab +* and contributors (see AUTHORS). +* @copyright MIT license (see LICENSE file) +*****************************************************************************/ + +#ifndef R1CS_PPZKSNARK_TCC_ +#define R1CS_PPZKSNARK_TCC_ + +#include +#include +#include +#include +#include + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/scalar_multiplication/multiexp.hpp" +#include "algebra/scalar_multiplication/kc_multiexp.hpp" +#include "reductions/r1cs_to_qap/r1cs_to_qap.hpp" + +namespace libsnark { + +template +bool r1cs_ppzksnark_proving_key::operator==(const r1cs_ppzksnark_proving_key &other) const +{ + return (this->A_query == other.A_query && + this->B_query == other.B_query && + this->C_query == other.C_query && + this->H_query == other.H_query && + this->K_query == other.K_query); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proving_key &pk) +{ + out << pk.A_query; + out << pk.B_query; + out << pk.C_query; + out << pk.H_query; + out << pk.K_query; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proving_key &pk) +{ + in >> pk.A_query; + in >> pk.B_query; + in >> pk.C_query; + in >> pk.H_query; + in >> pk.K_query; + + return in; +} + +template +bool r1cs_ppzksnark_verification_key::operator==(const r1cs_ppzksnark_verification_key &other) const +{ + return (this->alphaA_g2 == other.alphaA_g2 && + this->alphaB_g1 == other.alphaB_g1 && + this->alphaC_g2 == other.alphaC_g2 && + this->gamma_g2 == other.gamma_g2 && + this->gamma_beta_g1 == other.gamma_beta_g1 && + this->gamma_beta_g2 == other.gamma_beta_g2 && + this->rC_Z_g2 == other.rC_Z_g2 && + this->encoded_IC_query == other.encoded_IC_query); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_verification_key &vk) +{ + out << vk.alphaA_g2 << OUTPUT_NEWLINE; + out << vk.alphaB_g1 << OUTPUT_NEWLINE; + out << vk.alphaC_g2 << OUTPUT_NEWLINE; + out << vk.gamma_g2 << OUTPUT_NEWLINE; + out << vk.gamma_beta_g1 << OUTPUT_NEWLINE; + out << vk.gamma_beta_g2 << OUTPUT_NEWLINE; + out << vk.rC_Z_g2 << OUTPUT_NEWLINE; + out << vk.encoded_IC_query << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_verification_key &vk) +{ + in >> vk.alphaA_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.alphaB_g1; + consume_OUTPUT_NEWLINE(in); + in >> vk.alphaC_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.gamma_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.gamma_beta_g1; + consume_OUTPUT_NEWLINE(in); + in >> vk.gamma_beta_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.rC_Z_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.encoded_IC_query; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +bool r1cs_ppzksnark_processed_verification_key::operator==(const r1cs_ppzksnark_processed_verification_key &other) const +{ + return (this->pp_G2_one_precomp == other.pp_G2_one_precomp && + this->vk_alphaA_g2_precomp == other.vk_alphaA_g2_precomp && + this->vk_alphaB_g1_precomp == other.vk_alphaB_g1_precomp && + this->vk_alphaC_g2_precomp == other.vk_alphaC_g2_precomp && + this->vk_rC_Z_g2_precomp == other.vk_rC_Z_g2_precomp && + this->vk_gamma_g2_precomp == other.vk_gamma_g2_precomp && + this->vk_gamma_beta_g1_precomp == other.vk_gamma_beta_g1_precomp && + this->vk_gamma_beta_g2_precomp == other.vk_gamma_beta_g2_precomp && + this->encoded_IC_query == other.encoded_IC_query); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_processed_verification_key &pvk) +{ + out << pvk.pp_G2_one_precomp << OUTPUT_NEWLINE; + out << pvk.vk_alphaA_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_alphaB_g1_precomp << OUTPUT_NEWLINE; + out << pvk.vk_alphaC_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_rC_Z_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_gamma_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_gamma_beta_g1_precomp << OUTPUT_NEWLINE; + out << pvk.vk_gamma_beta_g2_precomp << OUTPUT_NEWLINE; + out << pvk.encoded_IC_query << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_processed_verification_key &pvk) +{ + in >> pvk.pp_G2_one_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_alphaA_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_alphaB_g1_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_alphaC_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_rC_Z_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_gamma_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_gamma_beta_g1_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_gamma_beta_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.encoded_IC_query; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +bool r1cs_ppzksnark_proof::operator==(const r1cs_ppzksnark_proof &other) const +{ + return (this->g_A == other.g_A && + this->g_B == other.g_B && + this->g_C == other.g_C && + this->g_H == other.g_H && + this->g_K == other.g_K); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proof &proof) +{ + out << proof.g_A << OUTPUT_NEWLINE; + out << proof.g_B << OUTPUT_NEWLINE; + out << proof.g_C << OUTPUT_NEWLINE; + out << proof.g_H << OUTPUT_NEWLINE; + out << proof.g_K << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proof &proof) +{ + in >> proof.g_A; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_B; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_C; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_H; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_K; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +r1cs_ppzksnark_verification_key r1cs_ppzksnark_verification_key::dummy_verification_key(const size_t input_size) +{ + r1cs_ppzksnark_verification_key result; + result.alphaA_g2 = Fr::random_element() * G2::one(); + result.alphaB_g1 = Fr::random_element() * G1::one(); + result.alphaC_g2 = Fr::random_element() * G2::one(); + result.gamma_g2 = Fr::random_element() * G2::one(); + result.gamma_beta_g1 = Fr::random_element() * G1::one(); + result.gamma_beta_g2 = Fr::random_element() * G2::one(); + result.rC_Z_g2 = Fr::random_element() * G2::one(); + + G1 base = Fr::random_element() * G1::one(); + G1_vector v; + for (size_t i = 0; i < input_size; ++i) + { + v.emplace_back(Fr::random_element() * G1::one()); + } + + result.encoded_IC_query = accumulation_vector >(std::move(base), std::move(v)); + + return result; +} + +template +r1cs_ppzksnark_keypair r1cs_ppzksnark_generator(const r1cs_ppzksnark_constraint_system &cs) +{ + /* draw random element at which the QAP is evaluated */ + const Fr t = Fr::random_element(); + + const Fr alphaA = Fr::random_element(), + alphaB = Fr::random_element(), + alphaC = Fr::random_element(), + rA = Fr::random_element(), + rB = Fr::random_element(), + beta = Fr::random_element(), + gamma = Fr::random_element(); + + return r1cs_ppzksnark_generator(cs, t, alphaA, alphaB, alphaC, rA, rB, beta, gamma); +} + +template +r1cs_ppzksnark_keypair r1cs_ppzksnark_generator( + const r1cs_ppzksnark_constraint_system &cs, + const Fr& t, + const Fr& alphaA, + const Fr& alphaB, + const Fr& alphaC, + const Fr& rA, + const Fr& rB, + const Fr& beta, + const Fr& gamma +) +{ + enter_block("Call to r1cs_ppzksnark_generator"); + + /* make the B_query "lighter" if possible */ + r1cs_ppzksnark_constraint_system cs_copy(cs); + cs_copy.swap_AB_if_beneficial(); + + qap_instance_evaluation > qap_inst = r1cs_to_qap_instance_map_with_evaluation(cs_copy, t); + + print_indent(); printf("* QAP number of variables: %zu\n", qap_inst.num_variables()); + print_indent(); printf("* QAP pre degree: %zu\n", cs_copy.constraints.size()); + print_indent(); printf("* QAP degree: %zu\n", qap_inst.degree()); + print_indent(); printf("* QAP number of input variables: %zu\n", qap_inst.num_inputs()); + + enter_block("Compute query densities"); + size_t non_zero_At = 0, non_zero_Bt = 0, non_zero_Ct = 0, non_zero_Ht = 0; + for (size_t i = 0; i < qap_inst.num_variables()+1; ++i) + { + if (!qap_inst.At[i].is_zero()) + { + ++non_zero_At; + } + if (!qap_inst.Bt[i].is_zero()) + { + ++non_zero_Bt; + } + if (!qap_inst.Ct[i].is_zero()) + { + ++non_zero_Ct; + } + } + for (size_t i = 0; i < qap_inst.degree()+1; ++i) + { + if (!qap_inst.Ht[i].is_zero()) + { + ++non_zero_Ht; + } + } + leave_block("Compute query densities"); + + Fr_vector At = std::move(qap_inst.At); // qap_inst.At is now in unspecified state, but we do not use it later + Fr_vector Bt = std::move(qap_inst.Bt); // qap_inst.Bt is now in unspecified state, but we do not use it later + Fr_vector Ct = std::move(qap_inst.Ct); // qap_inst.Ct is now in unspecified state, but we do not use it later + Fr_vector Ht = std::move(qap_inst.Ht); // qap_inst.Ht is now in unspecified state, but we do not use it later + + /* append Zt to At,Bt,Ct with */ + At.emplace_back(qap_inst.Zt); + Bt.emplace_back(qap_inst.Zt); + Ct.emplace_back(qap_inst.Zt); + + const Fr rC = rA * rB; + + // consrtuct the same-coefficient-check query (must happen before zeroing out the prefix of At) + Fr_vector Kt; + Kt.reserve(qap_inst.num_variables()+4); + for (size_t i = 0; i < qap_inst.num_variables()+1; ++i) + { + Kt.emplace_back( beta * (rA * At[i] + rB * Bt[i] + rC * Ct[i] ) ); + } + Kt.emplace_back(beta * rA * qap_inst.Zt); + Kt.emplace_back(beta * rB * qap_inst.Zt); + Kt.emplace_back(beta * rC * qap_inst.Zt); + + /* zero out prefix of At and stick it into IC coefficients */ + Fr_vector IC_coefficients; + IC_coefficients.reserve(qap_inst.num_inputs() + 1); + for (size_t i = 0; i < qap_inst.num_inputs() + 1; ++i) + { + IC_coefficients.emplace_back(At[i]); + assert(!IC_coefficients[i].is_zero()); + At[i] = Fr::zero(); + } + + const size_t g1_exp_count = 2*(non_zero_At - qap_inst.num_inputs() + non_zero_Ct) + non_zero_Bt + non_zero_Ht + Kt.size(); + const size_t g2_exp_count = non_zero_Bt; + + size_t g1_window = get_exp_window_size >(g1_exp_count); + size_t g2_window = get_exp_window_size >(g2_exp_count); + print_indent(); printf("* G1 window: %zu\n", g1_window); + print_indent(); printf("* G2 window: %zu\n", g2_window); + +#ifdef MULTICORE + const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() +#else + const size_t chunks = 1; +#endif + + enter_block("Generating G1 multiexp table"); + window_table > g1_table = get_window_table(Fr::size_in_bits(), g1_window, G1::one()); + leave_block("Generating G1 multiexp table"); + + enter_block("Generating G2 multiexp table"); + window_table > g2_table = get_window_table(Fr::size_in_bits(), g2_window, G2::one()); + leave_block("Generating G2 multiexp table"); + + enter_block("Generate R1CS proving key"); + + enter_block("Generate knowledge commitments"); + enter_block("Compute the A-query", false); + knowledge_commitment_vector, G1 > A_query = kc_batch_exp(Fr::size_in_bits(), g1_window, g1_window, g1_table, g1_table, rA, rA*alphaA, At, chunks); + leave_block("Compute the A-query", false); + + enter_block("Compute the B-query", false); + knowledge_commitment_vector, G1 > B_query = kc_batch_exp(Fr::size_in_bits(), g2_window, g1_window, g2_table, g1_table, rB, rB*alphaB, Bt, chunks); + leave_block("Compute the B-query", false); + + enter_block("Compute the C-query", false); + knowledge_commitment_vector, G1 > C_query = kc_batch_exp(Fr::size_in_bits(), g1_window, g1_window, g1_table, g1_table, rC, rC*alphaC, Ct, chunks); + leave_block("Compute the C-query", false); + + enter_block("Compute the H-query", false); + G1_vector H_query = batch_exp(Fr::size_in_bits(), g1_window, g1_table, Ht); + leave_block("Compute the H-query", false); + + enter_block("Compute the K-query", false); + G1_vector K_query = batch_exp(Fr::size_in_bits(), g1_window, g1_table, Kt); +#ifdef USE_MIXED_ADDITION + batch_to_special >(K_query); +#endif + leave_block("Compute the K-query", false); + + leave_block("Generate knowledge commitments"); + + leave_block("Generate R1CS proving key"); + + enter_block("Generate R1CS verification key"); + G2 alphaA_g2 = alphaA * G2::one(); + G1 alphaB_g1 = alphaB * G1::one(); + G2 alphaC_g2 = alphaC * G2::one(); + G2 gamma_g2 = gamma * G2::one(); + G1 gamma_beta_g1 = (gamma * beta) * G1::one(); + G2 gamma_beta_g2 = (gamma * beta) * G2::one(); + G2 rC_Z_g2 = (rC * qap_inst.Zt) * G2::one(); + + enter_block("Encode IC query for R1CS verification key"); + G1 encoded_IC_base = (rA * IC_coefficients[0]) * G1::one(); + Fr_vector multiplied_IC_coefficients; + multiplied_IC_coefficients.reserve(qap_inst.num_inputs()); + for (size_t i = 1; i < qap_inst.num_inputs() + 1; ++i) + { + multiplied_IC_coefficients.emplace_back(rA * IC_coefficients[i]); + } + G1_vector encoded_IC_values = batch_exp(Fr::size_in_bits(), g1_window, g1_table, multiplied_IC_coefficients); + + leave_block("Encode IC query for R1CS verification key"); + leave_block("Generate R1CS verification key"); + + leave_block("Call to r1cs_ppzksnark_generator"); + + accumulation_vector > encoded_IC_query(std::move(encoded_IC_base), std::move(encoded_IC_values)); + + r1cs_ppzksnark_verification_key vk = r1cs_ppzksnark_verification_key(alphaA_g2, + alphaB_g1, + alphaC_g2, + gamma_g2, + gamma_beta_g1, + gamma_beta_g2, + rC_Z_g2, + encoded_IC_query); + r1cs_ppzksnark_proving_key pk = r1cs_ppzksnark_proving_key(std::move(A_query), + std::move(B_query), + std::move(C_query), + std::move(H_query), + std::move(K_query)); + + pk.print_size(); + vk.print_size(); + + return r1cs_ppzksnark_keypair(std::move(pk), std::move(vk)); +} + +template +r1cs_ppzksnark_proof r1cs_ppzksnark_prover(const r1cs_ppzksnark_proving_key &pk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_auxiliary_input &auxiliary_input, + const r1cs_ppzksnark_constraint_system &constraint_system) +{ + enter_block("Call to r1cs_ppzksnark_prover"); + +#ifdef DEBUG + assert(constraint_system.is_satisfied(primary_input, auxiliary_input)); +#endif + + const Fr d1 = Fr::random_element(), + d2 = Fr::random_element(), + d3 = Fr::random_element(); + + enter_block("Compute the polynomial H"); + const qap_witness > qap_wit = r1cs_to_qap_witness_map(constraint_system, primary_input, auxiliary_input, d1, d2, d3); + leave_block("Compute the polynomial H"); + +#ifdef DEBUG + const Fr t = Fr::random_element(); + qap_instance_evaluation > qap_inst = r1cs_to_qap_instance_map_with_evaluation(constraint_system, t); + assert(qap_inst.is_satisfied(qap_wit)); +#endif + + knowledge_commitment, G1 > g_A = pk.A_query[0] + qap_wit.d1*pk.A_query[qap_wit.num_variables()+1]; + knowledge_commitment, G1 > g_B = pk.B_query[0] + qap_wit.d2*pk.B_query[qap_wit.num_variables()+1]; + knowledge_commitment, G1 > g_C = pk.C_query[0] + qap_wit.d3*pk.C_query[qap_wit.num_variables()+1]; + + G1 g_H = G1::zero(); + G1 g_K = (pk.K_query[0] + + qap_wit.d1*pk.K_query[qap_wit.num_variables()+1] + + qap_wit.d2*pk.K_query[qap_wit.num_variables()+2] + + qap_wit.d3*pk.K_query[qap_wit.num_variables()+3]); + +#ifdef DEBUG + for (size_t i = 0; i < qap_wit.num_inputs() + 1; ++i) + { + assert(pk.A_query[i].g == G1::zero()); + } + assert(pk.A_query.domain_size() == qap_wit.num_variables()+2); + assert(pk.B_query.domain_size() == qap_wit.num_variables()+2); + assert(pk.C_query.domain_size() == qap_wit.num_variables()+2); + assert(pk.H_query.size() == qap_wit.degree()+1); + assert(pk.K_query.size() == qap_wit.num_variables()+4); +#endif + +#ifdef MULTICORE + const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() +#else + const size_t chunks = 1; +#endif + + enter_block("Compute the proof"); + + enter_block("Compute answer to A-query", false); + g_A = g_A + kc_multi_exp_with_mixed_addition, G1, Fr >(pk.A_query, + 1, 1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin(), qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, true); + leave_block("Compute answer to A-query", false); + + enter_block("Compute answer to B-query", false); + g_B = g_B + kc_multi_exp_with_mixed_addition, G1, Fr >(pk.B_query, + 1, 1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin(), qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, true); + leave_block("Compute answer to B-query", false); + + enter_block("Compute answer to C-query", false); + g_C = g_C + kc_multi_exp_with_mixed_addition, G1, Fr >(pk.C_query, + 1, 1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin(), qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, true); + leave_block("Compute answer to C-query", false); + + enter_block("Compute answer to H-query", false); + g_H = g_H + multi_exp, Fr >(pk.H_query.begin(), pk.H_query.begin()+qap_wit.degree()+1, + qap_wit.coefficients_for_H.begin(), qap_wit.coefficients_for_H.begin()+qap_wit.degree()+1, + chunks, true); + leave_block("Compute answer to H-query", false); + + enter_block("Compute answer to K-query", false); + g_K = g_K + multi_exp_with_mixed_addition, Fr >(pk.K_query.begin()+1, pk.K_query.begin()+1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin(), qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, true); + leave_block("Compute answer to K-query", false); + + leave_block("Compute the proof"); + + leave_block("Call to r1cs_ppzksnark_prover"); + + r1cs_ppzksnark_proof proof = r1cs_ppzksnark_proof(std::move(g_A), std::move(g_B), std::move(g_C), std::move(g_H), std::move(g_K)); + //proof.print_size(); + + return proof; +} + +template +r1cs_ppzksnark_processed_verification_key r1cs_ppzksnark_verifier_process_vk(const r1cs_ppzksnark_verification_key &vk) +{ + enter_block("Call to r1cs_ppzksnark_verifier_process_vk"); + + r1cs_ppzksnark_processed_verification_key pvk; + pvk.pp_G2_one_precomp = ppT::precompute_G2(G2::one()); + pvk.vk_alphaA_g2_precomp = ppT::precompute_G2(vk.alphaA_g2); + pvk.vk_alphaB_g1_precomp = ppT::precompute_G1(vk.alphaB_g1); + pvk.vk_alphaC_g2_precomp = ppT::precompute_G2(vk.alphaC_g2); + pvk.vk_rC_Z_g2_precomp = ppT::precompute_G2(vk.rC_Z_g2); + pvk.vk_gamma_g2_precomp = ppT::precompute_G2(vk.gamma_g2); + pvk.vk_gamma_beta_g1_precomp = ppT::precompute_G1(vk.gamma_beta_g1); + pvk.vk_gamma_beta_g2_precomp = ppT::precompute_G2(vk.gamma_beta_g2); + + pvk.encoded_IC_query = vk.encoded_IC_query; + + leave_block("Call to r1cs_ppzksnark_verifier_process_vk"); + + return pvk; +} + +template +bool r1cs_ppzksnark_online_verifier_weak_IC(const r1cs_ppzksnark_processed_verification_key &pvk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof) +{ + assert(pvk.encoded_IC_query.domain_size() >= primary_input.size()); + + const accumulation_vector > accumulated_IC = pvk.encoded_IC_query.template accumulate_chunk >(primary_input.begin(), primary_input.end(), 0); + const G1 &acc = accumulated_IC.first; + + if (!proof.is_well_formed()) + { + return false; + } + + G1_precomp proof_g_A_g_precomp = ppT::precompute_G1(proof.g_A.g); + G1_precomp proof_g_A_h_precomp = ppT::precompute_G1(proof.g_A.h); + Fqk kc_A_1 = ppT::miller_loop(proof_g_A_g_precomp, pvk.vk_alphaA_g2_precomp); + Fqk kc_A_2 = ppT::miller_loop(proof_g_A_h_precomp, pvk.pp_G2_one_precomp); + GT kc_A = ppT::final_exponentiation(kc_A_1 * kc_A_2.unitary_inverse()); + if (kc_A != GT::one()) + { + return false; + } + + G2_precomp proof_g_B_g_precomp = ppT::precompute_G2(proof.g_B.g); + G1_precomp proof_g_B_h_precomp = ppT::precompute_G1(proof.g_B.h); + Fqk kc_B_1 = ppT::miller_loop(pvk.vk_alphaB_g1_precomp, proof_g_B_g_precomp); + Fqk kc_B_2 = ppT::miller_loop(proof_g_B_h_precomp, pvk.pp_G2_one_precomp); + GT kc_B = ppT::final_exponentiation(kc_B_1 * kc_B_2.unitary_inverse()); + if (kc_B != GT::one()) + { + return false; + } + + G1_precomp proof_g_C_g_precomp = ppT::precompute_G1(proof.g_C.g); + G1_precomp proof_g_C_h_precomp = ppT::precompute_G1(proof.g_C.h); + Fqk kc_C_1 = ppT::miller_loop(proof_g_C_g_precomp, pvk.vk_alphaC_g2_precomp); + Fqk kc_C_2 = ppT::miller_loop(proof_g_C_h_precomp, pvk.pp_G2_one_precomp); + GT kc_C = ppT::final_exponentiation(kc_C_1 * kc_C_2.unitary_inverse()); + if (kc_C != GT::one()) + { + return false; + } + + // check that g^((A+acc)*B)=g^(H*\Prod(t-\sigma)+C) + // equivalently, via pairings, that e(g^(A+acc), g^B) = e(g^H, g^Z) + e(g^C, g^1) + G1_precomp proof_g_A_g_acc_precomp = ppT::precompute_G1(proof.g_A.g + acc); + G1_precomp proof_g_H_precomp = ppT::precompute_G1(proof.g_H); + Fqk QAP_1 = ppT::miller_loop(proof_g_A_g_acc_precomp, proof_g_B_g_precomp); + Fqk QAP_23 = ppT::double_miller_loop(proof_g_H_precomp, pvk.vk_rC_Z_g2_precomp, proof_g_C_g_precomp, pvk.pp_G2_one_precomp); + GT QAP = ppT::final_exponentiation(QAP_1 * QAP_23.unitary_inverse()); + if (QAP != GT::one()) + { + return false; + } + + G1_precomp proof_g_K_precomp = ppT::precompute_G1(proof.g_K); + G1_precomp proof_g_A_g_acc_C_precomp = ppT::precompute_G1((proof.g_A.g + acc) + proof.g_C.g); + Fqk K_1 = ppT::miller_loop(proof_g_K_precomp, pvk.vk_gamma_g2_precomp); + Fqk K_23 = ppT::double_miller_loop(proof_g_A_g_acc_C_precomp, pvk.vk_gamma_beta_g2_precomp, pvk.vk_gamma_beta_g1_precomp, proof_g_B_g_precomp); + GT K = ppT::final_exponentiation(K_1 * K_23.unitary_inverse()); + if (K != GT::one()) + { + return false; + } + + return true; +} + +template +bool r1cs_ppzksnark_verifier_weak_IC(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof) +{ + enter_block("Call to r1cs_ppzksnark_verifier_weak_IC"); + r1cs_ppzksnark_processed_verification_key pvk = r1cs_ppzksnark_verifier_process_vk(vk); + bool result = r1cs_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof); + leave_block("Call to r1cs_ppzksnark_verifier_weak_IC"); + return result; +} + +template +bool r1cs_ppzksnark_online_verifier_strong_IC(const r1cs_ppzksnark_processed_verification_key &pvk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof) +{ + bool result = true; + enter_block("Call to r1cs_ppzksnark_online_verifier_strong_IC"); + + if (pvk.encoded_IC_query.domain_size() != primary_input.size()) + { + print_indent(); printf("Input length differs from expected (got %zu, expected %zu).\n", primary_input.size(), pvk.encoded_IC_query.domain_size()); + result = false; + } + else + { + result = r1cs_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof); + } + + leave_block("Call to r1cs_ppzksnark_online_verifier_strong_IC"); + return result; +} + +template +bool r1cs_ppzksnark_verifier_strong_IC(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof) +{ + enter_block("Call to r1cs_ppzksnark_verifier_strong_IC"); + r1cs_ppzksnark_processed_verification_key pvk = r1cs_ppzksnark_verifier_process_vk(vk); + bool result = r1cs_ppzksnark_online_verifier_strong_IC(pvk, primary_input, proof); + leave_block("Call to r1cs_ppzksnark_verifier_strong_IC"); + return result; +} + +template +bool r1cs_ppzksnark_affine_verifier_weak_IC(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof) +{ + enter_block("Call to r1cs_ppzksnark_affine_verifier_weak_IC"); + assert(vk.encoded_IC_query.domain_size() >= primary_input.size()); + + affine_ate_G2_precomp pvk_pp_G2_one_precomp = ppT::affine_ate_precompute_G2(G2::one()); + affine_ate_G2_precomp pvk_vk_alphaA_g2_precomp = ppT::affine_ate_precompute_G2(vk.alphaA_g2); + affine_ate_G1_precomp pvk_vk_alphaB_g1_precomp = ppT::affine_ate_precompute_G1(vk.alphaB_g1); + affine_ate_G2_precomp pvk_vk_alphaC_g2_precomp = ppT::affine_ate_precompute_G2(vk.alphaC_g2); + affine_ate_G2_precomp pvk_vk_rC_Z_g2_precomp = ppT::affine_ate_precompute_G2(vk.rC_Z_g2); + affine_ate_G2_precomp pvk_vk_gamma_g2_precomp = ppT::affine_ate_precompute_G2(vk.gamma_g2); + affine_ate_G1_precomp pvk_vk_gamma_beta_g1_precomp = ppT::affine_ate_precompute_G1(vk.gamma_beta_g1); + affine_ate_G2_precomp pvk_vk_gamma_beta_g2_precomp = ppT::affine_ate_precompute_G2(vk.gamma_beta_g2); + + enter_block("Compute input-dependent part of A"); + const accumulation_vector > accumulated_IC = vk.encoded_IC_query.template accumulate_chunk >(primary_input.begin(), primary_input.end(), 0); + assert(accumulated_IC.is_fully_accumulated()); + const G1 &acc = accumulated_IC.first; + leave_block("Compute input-dependent part of A"); + + bool result = true; + enter_block("Check knowledge commitment for A is valid"); + affine_ate_G1_precomp proof_g_A_g_precomp = ppT::affine_ate_precompute_G1(proof.g_A.g); + affine_ate_G1_precomp proof_g_A_h_precomp = ppT::affine_ate_precompute_G1(proof.g_A.h); + Fqk kc_A_miller = ppT::affine_ate_e_over_e_miller_loop(proof_g_A_g_precomp, pvk_vk_alphaA_g2_precomp, proof_g_A_h_precomp, pvk_pp_G2_one_precomp); + GT kc_A = ppT::final_exponentiation(kc_A_miller); + + if (kc_A != GT::one()) + { + print_indent(); printf("Knowledge commitment for A query incorrect.\n"); + result = false; + } + leave_block("Check knowledge commitment for A is valid"); + + enter_block("Check knowledge commitment for B is valid"); + affine_ate_G2_precomp proof_g_B_g_precomp = ppT::affine_ate_precompute_G2(proof.g_B.g); + affine_ate_G1_precomp proof_g_B_h_precomp = ppT::affine_ate_precompute_G1(proof.g_B.h); + Fqk kc_B_miller = ppT::affine_ate_e_over_e_miller_loop(pvk_vk_alphaB_g1_precomp, proof_g_B_g_precomp, proof_g_B_h_precomp, pvk_pp_G2_one_precomp); + GT kc_B = ppT::final_exponentiation(kc_B_miller); + if (kc_B != GT::one()) + { + print_indent(); printf("Knowledge commitment for B query incorrect.\n"); + result = false; + } + leave_block("Check knowledge commitment for B is valid"); + + enter_block("Check knowledge commitment for C is valid"); + affine_ate_G1_precomp proof_g_C_g_precomp = ppT::affine_ate_precompute_G1(proof.g_C.g); + affine_ate_G1_precomp proof_g_C_h_precomp = ppT::affine_ate_precompute_G1(proof.g_C.h); + Fqk kc_C_miller = ppT::affine_ate_e_over_e_miller_loop(proof_g_C_g_precomp, pvk_vk_alphaC_g2_precomp, proof_g_C_h_precomp, pvk_pp_G2_one_precomp); + GT kc_C = ppT::final_exponentiation(kc_C_miller); + if (kc_C != GT::one()) + { + print_indent(); printf("Knowledge commitment for C query incorrect.\n"); + result = false; + } + leave_block("Check knowledge commitment for C is valid"); + + enter_block("Check QAP divisibility"); + affine_ate_G1_precomp proof_g_A_g_acc_precomp = ppT::affine_ate_precompute_G1(proof.g_A.g + acc); + affine_ate_G1_precomp proof_g_H_precomp = ppT::affine_ate_precompute_G1(proof.g_H); + Fqk QAP_miller = ppT::affine_ate_e_times_e_over_e_miller_loop(proof_g_H_precomp, pvk_vk_rC_Z_g2_precomp, proof_g_C_g_precomp, pvk_pp_G2_one_precomp, proof_g_A_g_acc_precomp, proof_g_B_g_precomp); + GT QAP = ppT::final_exponentiation(QAP_miller); + if (QAP != GT::one()) + { + print_indent(); printf("QAP divisibility check failed.\n"); + result = false; + } + leave_block("Check QAP divisibility"); + + enter_block("Check same coefficients were used"); + affine_ate_G1_precomp proof_g_K_precomp = ppT::affine_ate_precompute_G1(proof.g_K); + affine_ate_G1_precomp proof_g_A_g_acc_C_precomp = ppT::affine_ate_precompute_G1((proof.g_A.g + acc) + proof.g_C.g); + Fqk K_miller = ppT::affine_ate_e_times_e_over_e_miller_loop(proof_g_A_g_acc_C_precomp, pvk_vk_gamma_beta_g2_precomp, pvk_vk_gamma_beta_g1_precomp, proof_g_B_g_precomp, proof_g_K_precomp, pvk_vk_gamma_g2_precomp); + GT K = ppT::final_exponentiation(K_miller); + if (K != GT::one()) + { + print_indent(); printf("Same-coefficient check failed.\n"); + result = false; + } + leave_block("Check same coefficients were used"); + + leave_block("Call to r1cs_ppzksnark_affine_verifier_weak_IC"); + + return result; +} + +} // libsnark +#endif // R1CS_PPZKSNARK_TCC_ diff --git a/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp b/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp new file mode 100644 index 00000000000..4054b8e3b2f --- /dev/null +++ b/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp @@ -0,0 +1,34 @@ +/** @file + ***************************************************************************** + + Declaration of public-parameter selector for the R1CS ppzkSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKSNARK_PARAMS_HPP_ +#define R1CS_PPZKSNARK_PARAMS_HPP_ + +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" + +namespace libsnark { + +/** + * Below are various template aliases (used for convenience). + */ + +template +using r1cs_ppzksnark_constraint_system = r1cs_constraint_system >; + +template +using r1cs_ppzksnark_primary_input = r1cs_primary_input >; + +template +using r1cs_ppzksnark_auxiliary_input = r1cs_auxiliary_input >; + +} // libsnark + +#endif // R1CS_PPZKSNARK_PARAMS_HPP_ diff --git a/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp b/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp new file mode 100644 index 00000000000..6f8b575f207 --- /dev/null +++ b/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp @@ -0,0 +1,42 @@ +/** @file + ***************************************************************************** + Test program that exercises the ppzkSNARK (first generator, then + prover, then verifier) on a synthetic R1CS instance. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include + +#include "common/default_types/r1cs_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp" + +using namespace libsnark; + +template +void test_r1cs_ppzksnark(size_t num_constraints, + size_t input_size) +{ + print_header("(enter) Test R1CS ppzkSNARK"); + + const bool test_serialization = true; + r1cs_example > example = generate_r1cs_example_with_binary_input >(num_constraints, input_size); + const bool bit = run_r1cs_ppzksnark(example, test_serialization); + assert(bit); + + print_header("(leave) Test R1CS ppzkSNARK"); +} + +int main() +{ + default_r1cs_ppzksnark_pp::init_public_params(); + start_profiling(); + + test_r1cs_ppzksnark(1000, 100); +} From 26a8f68ea8a021c1fa096fd4528b6b98e89a2e62 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Mon, 10 Apr 2017 14:25:04 -0600 Subject: [PATCH 007/177] Remove libsnark from depends system and integrate it into build system. --- configure.ac | 20 ++------------------ depends/packages/libsnark.mk | 17 ----------------- depends/packages/packages.mk | 2 +- src/Makefile.am | 16 +++++++++++++--- src/Makefile.gtest.include | 2 +- src/Makefile.test.include | 2 +- src/Makefile.zcash.include | 3 +++ 7 files changed, 21 insertions(+), 41 deletions(-) delete mode 100644 depends/packages/libsnark.mk diff --git a/configure.ac b/configure.ac index 129ddcde584..80e5e577e79 100644 --- a/configure.ac +++ b/configure.ac @@ -757,28 +757,12 @@ AC_CHECK_LIB([gmp],[[__gmpn_sub_n]],GMP_LIBS=-lgmp, [AC_MSG_ERROR(libgmp missing AC_CHECK_HEADER([gmpxx.h],,AC_MSG_ERROR(libgmpxx headers missing)) AC_CHECK_LIB([gmpxx],[main],GMPXX_LIBS=-lgmpxx, [AC_MSG_ERROR(libgmpxx missing)]) -# libsnark header layout is broken unless cpp's -I is passed with the -# libsnark directory, so for now we use this hideous workaround: -echo 'Hunting for libsnark include directory...' -[LIBSNARK_INCDIR="$(echo "$CPPFLAGS" | sed 's,^.*-I\([^ ]*/include\).*$,\1/libsnark,')"] -if test -d "$LIBSNARK_INCDIR"; then - echo "Found libsnark include directory: $LIBSNARK_INCDIR" -else - AC_MSG_ERROR(libsnark include directory not found) -fi - -CPPFLAGS="-I$LIBSNARK_INCDIR $CPPFLAGS" - -# Now check for libsnark compilability using traditional autoconf tests: -AC_CHECK_HEADER([libsnark/gadgetlib1/gadget.hpp],,AC_MSG_ERROR(libsnark headers missing)) -AC_CHECK_LIB([snark],[main],LIBSNARK_LIBS=-lsnark, [AC_MSG_ERROR(libsnark missing)], [-lgmpxx]) - RUST_LIBS="" if test x$enable_rust != xno; then RUST_LIBS="-lrustzcash" fi -LIBZCASH_LIBS="-lsnark -lgmp -lgmpxx -lboost_system-mt -lcrypto -lsodium -fopenmp $RUST_LIBS" +LIBZCASH_LIBS="-lgmp -lgmpxx -lboost_system-mt -lcrypto -lsodium -fopenmp $RUST_LIBS" CXXFLAGS_TEMP="$CXXFLAGS" LIBS_TEMP="$LIBS" @@ -944,7 +928,7 @@ unset PKG_CONFIG_LIBDIR PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP" ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no --enable-module-recovery" -AC_CONFIG_SUBDIRS([src/secp256k1 src/univalue]) +AC_CONFIG_SUBDIRS([src/secp256k1 src/snark src/univalue]) AC_OUTPUT diff --git a/depends/packages/libsnark.mk b/depends/packages/libsnark.mk deleted file mode 100644 index 4a7d86bbb5a..00000000000 --- a/depends/packages/libsnark.mk +++ /dev/null @@ -1,17 +0,0 @@ -package=libsnark -$(package)_version=0.1 -$(package)_download_path=https://github.com/zcash/$(package)/archive/ -$(package)_file_name=$(package)-$($(package)_git_commit).tar.gz -$(package)_download_file=$($(package)_git_commit).tar.gz -$(package)_sha256_hash=dad153fe46e2e1f33557a195cbe7d69aed8b19ed9befc08ddcb8c6d3c025941f -$(package)_git_commit=9ada3f84ab484c57b2247c2f41091fd6a0916573 - -$(package)_dependencies=libgmp libsodium - -define $(package)_build_cmds - CXXFLAGS="-fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1" $(MAKE) lib DEPINST=$(host_prefix) CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT OPTFLAGS="-O2 -march=x86-64" -endef - -define $(package)_stage_cmds - $(MAKE) install STATIC=1 DEPINST=$(host_prefix) PREFIX=$($(package)_staging_dir)$(host_prefix) CURVE=ALT_BN128 NO_SUPERCOP=1 -endef diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index 91873bf9ffd..0b7905e4ff0 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -1,6 +1,6 @@ rust_packages := rust librustzcash proton_packages := proton -zcash_packages := libsnark libgmp libsodium +zcash_packages := libgmp libsodium packages := boost openssl libevent zeromq $(zcash_packages) googletest googlemock native_packages := native_ccache diff --git a/src/Makefile.am b/src/Makefile.am index 4f4b2876443..1d87506fbf1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -DIST_SUBDIRS = secp256k1 univalue +DIST_SUBDIRS = secp256k1 snark univalue AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) @@ -21,6 +21,8 @@ BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include +BITCOIN_INCLUDES += -I$(srcdir)/snark/build/include +BITCOIN_INCLUDES += -I$(srcdir)/snark/build/include/libsnark BITCOIN_INCLUDES += -I$(srcdir)/univalue/include LIBBITCOIN_SERVER=libbitcoin_server.a @@ -30,12 +32,18 @@ LIBBITCOIN_CLI=libbitcoin_cli.a LIBBITCOIN_UTIL=libbitcoin_util.a LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a LIBSECP256K1=secp256k1/libsecp256k1.la +LIBSNARK=snark/build/lib/libsnark.a LIBUNIVALUE=univalue/libunivalue.la LIBZCASH=libzcash.a -$(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) +# libsnark is added as a dependency here solely to ensure it is built early, so +# that its header files are collated for use in later build steps. +$(LIBSECP256K1): $(LIBSNARK) $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) +$(LIBSNARK): $(wildcard snark/src/*) + CXXFLAGS="-fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1" $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C snark/ install PREFIX=$(srcdir)/build DEPINST=$(prefix) CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT OPTFLAGS="-O2 -march=x86-64" + $(LIBUNIVALUE): $(wildcard univalue/lib/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue/ @@ -394,6 +402,7 @@ zcashd_LDADD = \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) \ $(LIBZCASH) \ + $(LIBSNARK) \ $(LIBLEVELDB) \ $(LIBMEMENV) \ $(LIBSECP256K1) @@ -413,7 +422,6 @@ zcashd_LDADD += \ $(CRYPTO_LIBS) \ $(EVENT_PTHREADS_LIBS) \ $(EVENT_LIBS) \ - $(LIBZCASH) \ $(LIBBITCOIN_CRYPTO) \ $(LIBZCASH_LIBS) @@ -439,6 +447,7 @@ zcash_cli_LDADD = \ $(CRYPTO_LIBS) \ $(EVENT_LIBS) \ $(LIBZCASH) \ + $(LIBSNARK) \ $(LIBBITCOIN_CRYPTO) \ $(LIBZCASH_LIBS) # @@ -459,6 +468,7 @@ zcash_tx_LDADD = \ $(LIBBITCOIN_UTIL) \ $(LIBSECP256K1) \ $(LIBZCASH) \ + $(LIBSNARK) \ $(LIBBITCOIN_CRYPTO) \ $(LIBZCASH_LIBS) diff --git a/src/Makefile.gtest.include b/src/Makefile.gtest.include index 9e1e590deaf..d92feaa20b1 100644 --- a/src/Makefile.gtest.include +++ b/src/Makefile.gtest.include @@ -55,7 +55,7 @@ if ENABLE_WALLET zcash_gtest_LDADD += $(LIBBITCOIN_WALLET) endif -zcash_gtest_LDADD += $(LIBZCASH_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(LIBZCASH) $(LIBZCASH_LIBS) +zcash_gtest_LDADD += $(LIBZCASH_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(LIBZCASH) $(LIBSNARK) $(LIBZCASH_LIBS) if ENABLE_PROTON zcash_gtest_LDADD += $(LIBBITCOIN_PROTON) $(PROTON_LIBS) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index f5d4d10b7a2..4b85dd502bc 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -106,7 +106,7 @@ if ENABLE_WALLET test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET) endif -test_test_bitcoin_LDADD += $(LIBZCASH_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(LIBZCASH) $(LIBZCASH_LIBS) +test_test_bitcoin_LDADD += $(LIBZCASH_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(LIBZCASH) $(LIBSNARK) $(LIBZCASH_LIBS) test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static if ENABLE_ZMQ diff --git a/src/Makefile.zcash.include b/src/Makefile.zcash.include index 7325fdcff1c..e5752cb2f4b 100644 --- a/src/Makefile.zcash.include +++ b/src/Makefile.zcash.include @@ -7,15 +7,18 @@ zcash_GenerateParams_SOURCES = zcash/GenerateParams.cpp zcash_GenerateParams_LDADD = \ $(BOOST_LIBS) \ $(LIBZCASH) \ + $(LIBSNARK) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) \ $(LIBZCASH_LIBS) # tool for profiling the creation of joinsplits zcash_CreateJoinSplit_SOURCES = zcash/CreateJoinSplit.cpp +zcash_CreateJoinSplit_CPPFLAGS = $(BITCOIN_INCLUDES) zcash_CreateJoinSplit_LDADD = \ $(LIBBITCOIN_COMMON) \ $(LIBZCASH) \ + $(LIBSNARK) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) \ $(BOOST_LIBS) \ From 24d98cece02321bee53c7db35846e9981684d8ec Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 2 Aug 2017 15:49:48 +0100 Subject: [PATCH 008/177] Add libsnark compile flag to not copy DEPINST to PREFIX This is useful for Zcash, where DEPINST is its depends folder, not libsnark's internal dependency folder. --- src/Makefile.am | 2 +- src/snark/Makefile | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index 1d87506fbf1..ab3c7bc4c55 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -42,7 +42,7 @@ $(LIBSECP256K1): $(LIBSNARK) $(wildcard secp256k1/src/*) $(wildcard secp256k1/in $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) $(LIBSNARK): $(wildcard snark/src/*) - CXXFLAGS="-fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1" $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C snark/ install PREFIX=$(srcdir)/build DEPINST=$(prefix) CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT OPTFLAGS="-O2 -march=x86-64" + CXXFLAGS="-fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1" $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C snark/ install PREFIX=$(srcdir)/build DEPINST=$(prefix) CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT NO_COPY_DEPINST=1 OPTFLAGS="-O2 -march=x86-64" $(LIBUNIVALUE): $(wildcard univalue/lib/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue/ diff --git a/src/snark/Makefile b/src/snark/Makefile index 13e54da68b5..fe565a9060f 100644 --- a/src/snark/Makefile +++ b/src/snark/Makefile @@ -253,8 +253,10 @@ $(HEADERS_DEST): $(PREFIX)/include/libsnark/%: src/% install: $(INSTALL_LIBS) $(HEADERS_DEST) $(DEPINST_EXISTS) mkdir -p $(PREFIX)/lib cp -v $(INSTALL_LIBS) $(PREFIX)/lib/ +ifneq ($(NO_COPY_DEPINST),1) cp -rv $(DEPINST)/include $(PREFIX) endif +endif doxy: doxygen doxygen.conf From 2c016e06c723df8b01e9739d450cdb8a8a58a669 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 2 Oct 2017 21:37:13 +0100 Subject: [PATCH 009/177] Add Ansible playbook for grind workers --- contrib/ci-workers/grind.yml | 27 +++++++++++++++++++++++++++ contrib/ci-workers/vars/default.yml | 5 +++++ 2 files changed, 32 insertions(+) create mode 100644 contrib/ci-workers/grind.yml diff --git a/contrib/ci-workers/grind.yml b/contrib/ci-workers/grind.yml new file mode 100644 index 00000000000..ef7e5758e06 --- /dev/null +++ b/contrib/ci-workers/grind.yml @@ -0,0 +1,27 @@ +--- +# Configure a Buildbot worker +- include: unix.yml + +- name: Install grind-specific worker dependencies + hosts: zcash-ci-worker-unix + become: true + + vars_files: + - vars/default.yml + + tasks: + - name: Get dependencies for distribution + include_vars: "{{ item }}" + with_first_found: + - files: + - "vars/{{ ansible_distribution }}-{{ ansible_distribution_version }}.yml" + - "vars/{{ ansible_distribution }}-{{ ansible_distribution_major_version | int }}.yml" + - "vars/{{ ansible_distribution }}.yml" + - "vars/{{ ansible_os_family }}.yml" + skip: true + + - name: Install required packages + package: + name: "{{ item }}" + state: present + with_items: "{{ grind_deps }}" diff --git a/contrib/ci-workers/vars/default.yml b/contrib/ci-workers/vars/default.yml index 67da0e51dfe..38c5afc8e58 100644 --- a/contrib/ci-workers/vars/default.yml +++ b/contrib/ci-workers/vars/default.yml @@ -29,6 +29,11 @@ link_deps: # Additional distribution-specific dependencies dist_deps: [] +# Additional grind-specific dependencies +grind_deps: + - lcov + - valgrind + # Python modules required for a Zcash Buildbot worker buildbot_modules: - pip # Needs to be updated first so Buildbot installs From 243b6a9d4b54485ca4ff056fc35b77767e8ba06e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 3 Oct 2017 17:35:32 +0100 Subject: [PATCH 010/177] Add connections in BIP65 and BIP66 tests to the test manager Fixes a bug in the tests causing them to silently pass instead of correctly reporting other errors. Introduced in 4a785b0a5ba9689e0a76f202c34e0d310a7487d7 during the test rewrites. --- qa/rpc-tests/bip65-cltv-p2p.py | 2 +- qa/rpc-tests/bipdersig-p2p.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/qa/rpc-tests/bip65-cltv-p2p.py b/qa/rpc-tests/bip65-cltv-p2p.py index 6f31c7663aa..8fef45afee5 100755 --- a/qa/rpc-tests/bip65-cltv-p2p.py +++ b/qa/rpc-tests/bip65-cltv-p2p.py @@ -38,7 +38,7 @@ def setup_network(self): def run_test(self): test = TestManager(self, self.options.tmpdir) - # Don't call test.add_all_connections because there is only one node. + test.add_all_connections(self.nodes) NetworkThread().start() # Start up network handling in another thread test.run() diff --git a/qa/rpc-tests/bipdersig-p2p.py b/qa/rpc-tests/bipdersig-p2p.py index 9604cdbdd61..523a694bf28 100755 --- a/qa/rpc-tests/bipdersig-p2p.py +++ b/qa/rpc-tests/bipdersig-p2p.py @@ -37,7 +37,7 @@ def setup_network(self): def run_test(self): test = TestManager(self, self.options.tmpdir) - # Don't call test.add_all_connections because there is only one node. + test.add_all_connections(self.nodes) NetworkThread().start() # Start up network handling in another thread test.run() From 99dd50c30c7596f60afe1773a90d3ecda47b766b Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 4 Oct 2017 12:48:50 +0100 Subject: [PATCH 011/177] Add benchmark for listunspent Closes #2645. --- qa/zcash/performance-measurements.sh | 10 ++++++++-- src/wallet/rpcwallet.cpp | 2 ++ src/zcbenchmarks.cpp | 9 +++++++++ src/zcbenchmarks.h | 1 + 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/qa/zcash/performance-measurements.sh b/qa/zcash/performance-measurements.sh index 60f92dd1d28..ac6d06e8679 100755 --- a/qa/zcash/performance-measurements.sh +++ b/qa/zcash/performance-measurements.sh @@ -56,7 +56,7 @@ function use_200k_benchmark { function zcashd_start { case "$1" in - sendtoaddress|loadwallet) + sendtoaddress|loadwallet|listunspent) case "$2" in 200k-recv) use_200k_benchmark 0 @@ -86,7 +86,7 @@ function zcashd_stop { function zcashd_massif_start { case "$1" in - sendtoaddress|loadwallet) + sendtoaddress|loadwallet|listunspent) case "$2" in 200k-recv) use_200k_benchmark 0 @@ -206,6 +206,9 @@ case "$1" in loadwallet) zcash_rpc zcbenchmark loadwallet 10 ;; + listunspent) + zcash_rpc zcbenchmark listunspent 10 + ;; *) zcashd_stop echo "Bad arguments to time." @@ -250,6 +253,9 @@ case "$1" in loadwallet) # The initial load is sufficient for measurement ;; + listunspent) + zcash_rpc zcbenchmark listunspent 1 + ;; *) zcashd_massif_stop echo "Bad arguments to memory." diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 55669f74fd4..332f96b2144 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2609,6 +2609,8 @@ UniValue zc_benchmark(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode"); } sample_times.push_back(benchmark_loadwallet()); + } else if (benchmarktype == "listunspent") { + sample_times.push_back(benchmark_listunspent()); } else { throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype"); } diff --git a/src/zcbenchmarks.cpp b/src/zcbenchmarks.cpp index 5c20a67e3f9..1cb880ea106 100644 --- a/src/zcbenchmarks.cpp +++ b/src/zcbenchmarks.cpp @@ -465,3 +465,12 @@ double benchmark_loadwallet() post_wallet_load(); return res; } + +double benchmark_listunspent() +{ + UniValue params(UniValue::VARR); + struct timeval tv_start; + timer_start(tv_start); + auto unspent = listunspent(params, false); + return timer_stop(tv_start); +} diff --git a/src/zcbenchmarks.h b/src/zcbenchmarks.h index a2672daa09f..ac87d032627 100644 --- a/src/zcbenchmarks.h +++ b/src/zcbenchmarks.h @@ -18,5 +18,6 @@ extern double benchmark_increment_note_witnesses(size_t nTxs); extern double benchmark_connectblock_slow(); extern double benchmark_sendtoaddress(CAmount amount); extern double benchmark_loadwallet(); +extern double benchmark_listunspent(); #endif From d2c1e4a807480dfc9c8f10cb27dd219e165f7307 Mon Sep 17 00:00:00 2001 From: Bruno Arueira Date: Thu, 3 Nov 2016 17:01:16 -0200 Subject: [PATCH 012/177] Removes out bitcoin mention in favor for zcash Bitcoin Core => Zcash bitcoin address => Zcash address bitcoinaddress => zcashaddress Closes #1756 --- src/init.cpp | 8 ++++++-- src/key.cpp | 2 +- src/rpcblockchain.cpp | 8 ++++---- src/rpcmisc.cpp | 18 +++++++++--------- src/rpcnet.cpp | 2 +- src/rpcrawtransaction.cpp | 4 ++-- src/wallet/rpcwallet.cpp | 32 ++++++++++++++++---------------- 7 files changed, 39 insertions(+), 35 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 3797e806d25..add8bde5386 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -419,6 +419,10 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-walletnotify=", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)")); strUsage += HelpMessageOpt("-zapwallettxes=", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") + " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)")); +<<<<<<< HEAD +======= + +>>>>>>> Removes out bitcoin mention in favor for zcash #endif #if ENABLE_ZMQ @@ -1487,10 +1491,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) InitWarning(msg); } else if (nLoadWalletRet == DB_TOO_NEW) - strErrors << _("Error loading wallet.dat: Wallet requires newer version of Bitcoin Core") << "\n"; + strErrors << _("Error loading wallet.dat: Wallet requires newer version of Zcash") << "\n"; else if (nLoadWalletRet == DB_NEED_REWRITE) { - strErrors << _("Wallet needed to be rewritten: restart Bitcoin Core to complete") << "\n"; + strErrors << _("Wallet needed to be rewritten: restart Zcash to complete") << "\n"; LogPrintf("%s", strErrors.str()); return InitError(strErrors.str()); } diff --git a/src/key.cpp b/src/key.cpp index a431316138b..4cf693a97a5 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -221,7 +221,7 @@ bool CKey::VerifyPubKey(const CPubKey& pubkey) const { return false; } unsigned char rnd[8]; - std::string str = "Bitcoin key verification\n"; + std::string str = "Zcash key verification\n"; GetRandBytes(rnd, sizeof(rnd)); uint256 hash; CHash256().Write((unsigned char*)str.data(), str.size()).Write(rnd, sizeof(rnd)).Finalize(hash.begin()); diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 6d8c911e3a9..bc3869db764 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -519,13 +519,13 @@ UniValue gettxout(const UniValue& params, bool fHelp) " \"hex\" : \"hex\", (string) \n" " \"reqSigs\" : n, (numeric) Number of required signatures\n" " \"type\" : \"pubkeyhash\", (string) The type, eg pubkeyhash\n" - " \"addresses\" : [ (array of string) array of bitcoin addresses\n" - " \"bitcoinaddress\" (string) bitcoin address\n" + " \"addresses\" : [ (array of string) array of zcash addresses\n" + " \"zcashaddress\" (string) zcash address\n" " ,...\n" " ]\n" " },\n" - " \"version\" : n, (numeric) The version\n" - " \"coinbase\" : true|false (boolean) Coinbase or not\n" + " \"version\" : n, (numeric) The version\n" + " \"coinbase\" : true|false (boolean) Coinbase or not\n" "}\n" "\nExamples:\n" diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index 9980ce1ed56..ba5feb0b8bc 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -51,7 +51,7 @@ UniValue getinfo(const UniValue& params, bool fHelp) " \"version\": xxxxx, (numeric) the server version\n" " \"protocolversion\": xxxxx, (numeric) the protocol version\n" " \"walletversion\": xxxxx, (numeric) the wallet version\n" - " \"balance\": xxxxxxx, (numeric) the total bitcoin balance of the wallet\n" + " \"balance\": xxxxxxx, (numeric) the total zcash balance of the wallet\n" " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n" " \"timeoffset\": xxxxx, (numeric) the time offset\n" " \"connections\": xxxxx, (numeric) the number of connections\n" @@ -152,14 +152,14 @@ UniValue validateaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( - "validateaddress \"bitcoinaddress\"\n" - "\nReturn information about the given bitcoin address.\n" + "validateaddress \"zcashaddress\"\n" + "\nReturn information about the given zcash address.\n" "\nArguments:\n" - "1. \"bitcoinaddress\" (string, required) The bitcoin address to validate\n" + "1. \"zcashaddress\" (string, required) The zcash address to validate\n" "\nResult:\n" "{\n" " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n" - " \"address\" : \"bitcoinaddress\", (string) The bitcoin address validated\n" + " \"address\" : \"zcashaddress\", (string) The zcash address validated\n" " \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n" " \"ismine\" : true|false, (boolean) If the address is yours or not\n" " \"isscript\" : true|false, (boolean) If the key is a script\n" @@ -342,9 +342,9 @@ UniValue createmultisig(const UniValue& params, bool fHelp) "\nArguments:\n" "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n" - "2. \"keys\" (string, required) A json array of keys which are bitcoin addresses or hex-encoded public keys\n" + "2. \"keys\" (string, required) A json array of keys which are zcash addresses or hex-encoded public keys\n" " [\n" - " \"key\" (string) bitcoin address or hex-encoded public key\n" + " \"key\" (string) zcash address or hex-encoded public key\n" " ,...\n" " ]\n" @@ -379,10 +379,10 @@ UniValue verifymessage(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 3) throw runtime_error( - "verifymessage \"bitcoinaddress\" \"signature\" \"message\"\n" + "verifymessage \"zcashaddress\" \"signature\" \"message\"\n" "\nVerify a signed message\n" "\nArguments:\n" - "1. \"bitcoinaddress\" (string, required) The bitcoin address to use for the signature.\n" + "1. \"zcashaddress\" (string, required) The zcash address to use for the signature.\n" "2. \"signature\" (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n" "3. \"message\" (string, required) The message that was signed.\n" "\nResult:\n" diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 71152a2e2a5..3370aae379b 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -255,7 +255,7 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) " \"connected\" : true|false, (boolean) If connected\n" " \"addresses\" : [\n" " {\n" - " \"address\" : \"192.168.0.201:8233\", (string) The bitcoin server host and port\n" + " \"address\" : \"192.168.0.201:8233\", (string) The zcash server host and port\n" " \"connected\" : \"outbound\" (string) connection, inbound or outbound\n" " }\n" " ,...\n" diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 83cb8e877f0..4183a67ac4f 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -212,7 +212,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp) " \"reqSigs\" : n, (numeric) The required sigs\n" " \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n" " \"addresses\" : [ (json array of string)\n" - " \"bitcoinaddress\" (string) bitcoin address\n" + " \"zcashaddress\" (string) zcash address\n" " ,...\n" " ]\n" " }\n" @@ -582,7 +582,7 @@ UniValue decodescript(const UniValue& params, bool fHelp) " \"type\":\"type\", (string) The output type\n" " \"reqSigs\": n, (numeric) The required signatures\n" " \"addresses\": [ (json array of string)\n" - " \"address\" (string) bitcoin address\n" + " \"address\" (string) zcash address\n" " ,...\n" " ],\n" " \"p2sh\",\"address\" (string) script address\n" diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 55669f74fd4..5ce5470e8a0 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -119,7 +119,7 @@ UniValue getnewaddress(const UniValue& params, bool fHelp) "\nArguments:\n" "1. \"account\" (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n" "\nResult:\n" - "\"zcashaddress\" (string) The new zcash address\n" + "\"zcashaddress\" (string) The new Zcash address\n" "\nExamples:\n" + HelpExampleCli("getnewaddress", "") + HelpExampleRpc("getnewaddress", "") @@ -196,7 +196,7 @@ UniValue getaccountaddress(const UniValue& params, bool fHelp) "\nArguments:\n" "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n" "\nResult:\n" - "\"zcashaddress\" (string) The account zcash address\n" + "\"zcashaddress\" (string) The account Zcash address\n" "\nExamples:\n" + HelpExampleCli("getaccountaddress", "") + HelpExampleCli("getaccountaddress", "\"\"") @@ -261,7 +261,7 @@ UniValue setaccount(const UniValue& params, bool fHelp) "setaccount \"zcashaddress\" \"account\"\n" "\nDEPRECATED. Sets the account associated with the given address.\n" "\nArguments:\n" - "1. \"zcashaddress\" (string, required) The zcash address to be associated with an account.\n" + "1. \"zcashaddress\" (string, required) The Zcash address to be associated with an account.\n" "2. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n" "\nExamples:\n" + HelpExampleCli("setaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"tabby\"") @@ -307,7 +307,7 @@ UniValue getaccount(const UniValue& params, bool fHelp) "getaccount \"zcashaddress\"\n" "\nDEPRECATED. Returns the account associated with the given address.\n" "\nArguments:\n" - "1. \"zcashaddress\" (string, required) The zcash address for account lookup.\n" + "1. \"zcashaddress\" (string, required) The Zcash address for account lookup.\n" "\nResult:\n" "\"accountname\" (string) the account address\n" "\nExamples:\n" @@ -342,7 +342,7 @@ UniValue getaddressesbyaccount(const UniValue& params, bool fHelp) "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n" "\nResult:\n" "[ (json array of string)\n" - " \"zcashaddress\" (string) a zcash address associated with the given account\n" + " \"zcashaddress\" (string) a Zcash address associated with the given account\n" " ,...\n" "]\n" "\nExamples:\n" @@ -517,7 +517,7 @@ UniValue signmessage(const UniValue& params, bool fHelp) "\nSign a message with the private key of an address" + HelpRequiringPassphrase() + "\n" "\nArguments:\n" - "1. \"zcashaddress\" (string, required) The zcash address to use for the private key.\n" + "1. \"zcashaddress\" (string, required) The Zcash address to use for the private key.\n" "2. \"message\" (string, required) The message to create a signature of.\n" "\nResult:\n" "\"signature\" (string) The signature of the message encoded in base 64\n" @@ -572,7 +572,7 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp) "getreceivedbyaddress \"zcashaddress\" ( minconf )\n" "\nReturns the total amount received by the given zcashaddress in transactions with at least minconf confirmations.\n" "\nArguments:\n" - "1. \"zcashaddress\" (string, required) The zcash address for transactions.\n" + "1. \"zcashaddress\" (string, required) The Zcash address for transactions.\n" "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n" "\nResult:\n" "amount (numeric) The total amount in " + CURRENCY_UNIT + " received at this address.\n" @@ -878,7 +878,7 @@ UniValue sendfrom(const UniValue& params, bool fHelp) if (fHelp || params.size() < 3 || params.size() > 6) throw runtime_error( "sendfrom \"fromaccount\" \"tozcashaddress\" amount ( minconf \"comment\" \"comment-to\" )\n" - "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a zcash address.\n" + "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a Zcash address.\n" "The amount is a real and is rounded to the nearest 0.00000001." + HelpRequiringPassphrase() + "\n" "\nArguments:\n" @@ -1063,15 +1063,15 @@ UniValue addmultisigaddress(const UniValue& params, bool fHelp) "\nArguments:\n" "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n" - "2. \"keysobject\" (string, required) A json array of zcash addresses or hex-encoded public keys\n" + "2. \"keysobject\" (string, required) A json array of Zcash addresses or hex-encoded public keys\n" " [\n" - " \"address\" (string) zcash address or hex-encoded public key\n" + " \"address\" (string) Zcash address or hex-encoded public key\n" " ...,\n" " ]\n" "3. \"account\" (string, optional) DEPRECATED. If provided, MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n" "\nResult:\n" - "\"zcashaddress\" (string) A zcash address associated with the keys.\n" + "\"zcashaddress\" (string) A Zcash address associated with the keys.\n" "\nExamples:\n" "\nAdd a multisig address from 2 addresses\n" @@ -1418,7 +1418,7 @@ UniValue listtransactions(const UniValue& params, bool fHelp) " {\n" " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. \n" " It will be \"\" for the default account.\n" - " \"address\":\"zcashaddress\", (string) The zcash address of the transaction. Not present for \n" + " \"address\":\"zcashaddress\", (string) The Zcash address of the transaction. Not present for \n" " move transactions (category = move).\n" " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n" " transaction between accounts, and not associated with an address,\n" @@ -1618,7 +1618,7 @@ UniValue listsinceblock(const UniValue& params, bool fHelp) "{\n" " \"transactions\": [\n" " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n" - " \"address\":\"zcashaddress\", (string) The zcash address of the transaction. Not present for move transactions (category = move).\n" + " \"address\":\"zcashaddress\", (string) The Zcash address of the transaction. Not present for move transactions (category = move).\n" " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n" " \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the 'move' category for moves \n" " outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n" @@ -1717,7 +1717,7 @@ UniValue gettransaction(const UniValue& params, bool fHelp) " \"details\" : [\n" " {\n" " \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n" - " \"address\" : \"zcashaddress\", (string) The zcash address involved in the transaction\n" + " \"address\" : \"zcashaddress\", (string) The Zcash address involved in the transaction\n" " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n" " \"amount\" : x.xxx (numeric) The amount in " + CURRENCY_UNIT + "\n" " \"vout\" : n, (numeric) the vout value\n" @@ -2326,9 +2326,9 @@ UniValue listunspent(const UniValue& params, bool fHelp) "\nArguments:\n" "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n" "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n" - "3. \"addresses\" (string) A json array of zcash addresses to filter\n" + "3. \"addresses\" (string) A json array of Zcash addresses to filter\n" " [\n" - " \"address\" (string) zcash address\n" + " \"address\" (string) Zcash address\n" " ,...\n" " ]\n" "\nResult\n" From c16528495c4c18dcd1fc5f1e0697b3f825435ed4 Mon Sep 17 00:00:00 2001 From: Jay Graber Date: Thu, 23 Mar 2017 15:29:56 -0700 Subject: [PATCH 013/177] s/zcash/Zcash --- src/init.cpp | 4 ---- src/rpcblockchain.cpp | 4 ++-- src/rpcmisc.cpp | 14 +++++++------- src/rpcnet.cpp | 2 +- src/rpcrawtransaction.cpp | 4 ++-- src/wallet/rpcwallet.cpp | 12 ++++++------ 6 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index add8bde5386..bb57f257d7a 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -419,10 +419,6 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-walletnotify=", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)")); strUsage += HelpMessageOpt("-zapwallettxes=", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") + " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)")); -<<<<<<< HEAD -======= - ->>>>>>> Removes out bitcoin mention in favor for zcash #endif #if ENABLE_ZMQ diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index bc3869db764..cbc7109ddb6 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -519,8 +519,8 @@ UniValue gettxout(const UniValue& params, bool fHelp) " \"hex\" : \"hex\", (string) \n" " \"reqSigs\" : n, (numeric) Number of required signatures\n" " \"type\" : \"pubkeyhash\", (string) The type, eg pubkeyhash\n" - " \"addresses\" : [ (array of string) array of zcash addresses\n" - " \"zcashaddress\" (string) zcash address\n" + " \"addresses\" : [ (array of string) array of Zcash addresses\n" + " \"zcashaddress\" (string) Zcash address\n" " ,...\n" " ]\n" " },\n" diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index ba5feb0b8bc..b2bc1aefeee 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -51,7 +51,7 @@ UniValue getinfo(const UniValue& params, bool fHelp) " \"version\": xxxxx, (numeric) the server version\n" " \"protocolversion\": xxxxx, (numeric) the protocol version\n" " \"walletversion\": xxxxx, (numeric) the wallet version\n" - " \"balance\": xxxxxxx, (numeric) the total zcash balance of the wallet\n" + " \"balance\": xxxxxxx, (numeric) the total Zcash balance of the wallet\n" " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n" " \"timeoffset\": xxxxx, (numeric) the time offset\n" " \"connections\": xxxxx, (numeric) the number of connections\n" @@ -153,13 +153,13 @@ UniValue validateaddress(const UniValue& params, bool fHelp) if (fHelp || params.size() != 1) throw runtime_error( "validateaddress \"zcashaddress\"\n" - "\nReturn information about the given zcash address.\n" + "\nReturn information about the given Zcash address.\n" "\nArguments:\n" - "1. \"zcashaddress\" (string, required) The zcash address to validate\n" + "1. \"zcashaddress\" (string, required) The Zcash address to validate\n" "\nResult:\n" "{\n" " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n" - " \"address\" : \"zcashaddress\", (string) The zcash address validated\n" + " \"address\" : \"zcashaddress\", (string) The Zcash address validated\n" " \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n" " \"ismine\" : true|false, (boolean) If the address is yours or not\n" " \"isscript\" : true|false, (boolean) If the key is a script\n" @@ -342,9 +342,9 @@ UniValue createmultisig(const UniValue& params, bool fHelp) "\nArguments:\n" "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n" - "2. \"keys\" (string, required) A json array of keys which are zcash addresses or hex-encoded public keys\n" + "2. \"keys\" (string, required) A json array of keys which are Zcash addresses or hex-encoded public keys\n" " [\n" - " \"key\" (string) zcash address or hex-encoded public key\n" + " \"key\" (string) Zcash address or hex-encoded public key\n" " ,...\n" " ]\n" @@ -382,7 +382,7 @@ UniValue verifymessage(const UniValue& params, bool fHelp) "verifymessage \"zcashaddress\" \"signature\" \"message\"\n" "\nVerify a signed message\n" "\nArguments:\n" - "1. \"zcashaddress\" (string, required) The zcash address to use for the signature.\n" + "1. \"zcashaddress\" (string, required) The Zcash address to use for the signature.\n" "2. \"signature\" (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n" "3. \"message\" (string, required) The message that was signed.\n" "\nResult:\n" diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 3370aae379b..dc46c786ec9 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -255,7 +255,7 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) " \"connected\" : true|false, (boolean) If connected\n" " \"addresses\" : [\n" " {\n" - " \"address\" : \"192.168.0.201:8233\", (string) The zcash server host and port\n" + " \"address\" : \"192.168.0.201:8233\", (string) The Zcash server host and port\n" " \"connected\" : \"outbound\" (string) connection, inbound or outbound\n" " }\n" " ,...\n" diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 4183a67ac4f..aa329f4e9d2 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -212,7 +212,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp) " \"reqSigs\" : n, (numeric) The required sigs\n" " \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n" " \"addresses\" : [ (json array of string)\n" - " \"zcashaddress\" (string) zcash address\n" + " \"zcashaddress\" (string) Zcash address\n" " ,...\n" " ]\n" " }\n" @@ -582,7 +582,7 @@ UniValue decodescript(const UniValue& params, bool fHelp) " \"type\":\"type\", (string) The output type\n" " \"reqSigs\": n, (numeric) The required signatures\n" " \"addresses\": [ (json array of string)\n" - " \"address\" (string) zcash address\n" + " \"address\" (string) Zcash address\n" " ,...\n" " ],\n" " \"p2sh\",\"address\" (string) script address\n" diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 5ce5470e8a0..385e71978a6 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -416,7 +416,7 @@ UniValue sendtoaddress(const UniValue& params, bool fHelp) " to which you're sending the transaction. This is not part of the \n" " transaction, just kept in your wallet.\n" "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n" - " The recipient will receive less zcash than you enter in the amount field.\n" + " The recipient will receive less Zcash than you enter in the amount field.\n" "\nResult:\n" "\"transactionid\" (string) The transaction id.\n" "\nExamples:\n" @@ -570,7 +570,7 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp) if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "getreceivedbyaddress \"zcashaddress\" ( minconf )\n" - "\nReturns the total amount received by the given zcashaddress in transactions with at least minconf confirmations.\n" + "\nReturns the total amount received by the given Zcash address in transactions with at least minconf confirmations.\n" "\nArguments:\n" "1. \"zcashaddress\" (string, required) The Zcash address for transactions.\n" "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n" @@ -956,7 +956,7 @@ UniValue sendmany(const UniValue& params, bool fHelp) "4. \"comment\" (string, optional) A comment\n" "5. subtractfeefromamount (string, optional) A json array with addresses.\n" " The fee will be equally deducted from the amount of each selected address.\n" - " Those recipients will receive less zcashs than you enter in their corresponding amount field.\n" + " Those recipients will receive less Zcash than you enter in their corresponding amount field.\n" " If no addresses are specified here, the sender pays the fee.\n" " [\n" " \"address\" (string) Subtract fee from this address\n" @@ -1877,7 +1877,7 @@ UniValue walletpassphrase(const UniValue& params, bool fHelp) throw runtime_error( "walletpassphrase \"passphrase\" timeout\n" "\nStores the wallet decryption key in memory for 'timeout' seconds.\n" - "This is needed prior to performing transactions related to private keys such as sending zcash\n" + "This is needed prior to performing transactions related to private keys such as sending Zcash\n" "\nArguments:\n" "1. \"passphrase\" (string, required) The wallet passphrase\n" "2. timeout (numeric, required) The time to keep the decryption key in seconds.\n" @@ -2042,7 +2042,7 @@ UniValue encryptwallet(const UniValue& params, bool fHelp) "\nExamples:\n" "\nEncrypt you wallet\n" + HelpExampleCli("encryptwallet", "\"my pass phrase\"") + - "\nNow set the passphrase to use the wallet, such as for signing or sending zcash\n" + "\nNow set the passphrase to use the wallet, such as for signing or sending Zcash\n" + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") + "\nNow we can so something like sign\n" + HelpExampleCli("signmessage", "\"zcashaddress\" \"test message\"") + @@ -2093,7 +2093,7 @@ UniValue lockunspent(const UniValue& params, bool fHelp) "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n" "\nUpdates list of temporarily unspendable outputs.\n" "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n" - "A locked transaction output will not be chosen by automatic coin selection, when spending zcash.\n" + "A locked transaction output will not be chosen by automatic coin selection, when spending Zcash.\n" "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n" "is always cleared (by virtue of process exit) when a node stops or fails.\n" "Also see the listunspent call\n" From 6de850120f440fa1dd913df91797578123cb8b49 Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 3 Oct 2017 17:48:00 -0700 Subject: [PATCH 014/177] Replace 'bitcoin address' with 'zcash address'. --- src/rpcrawtransaction.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index aa329f4e9d2..bd9b866c23a 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -417,7 +417,7 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) " ]\n" "2. \"addresses\" (string, required) a json object with addresses as keys and amounts as values\n" " {\n" - " \"address\": x.xxx (numeric, required) The key is the bitcoin address, the value is the " + CURRENCY_UNIT + " amount\n" + " \"address\": x.xxx (numeric, required) The key is the zcash address, the value is the " + CURRENCY_UNIT + " amount\n" " ,...\n" " }\n" @@ -459,7 +459,7 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) BOOST_FOREACH(const string& name_, addrList) { CBitcoinAddress address(name_); if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Zcash address: ")+name_); if (setAddress.count(address)) throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_); @@ -512,7 +512,7 @@ UniValue decoderawtransaction(const UniValue& params, bool fHelp) " \"reqSigs\" : n, (numeric) The required sigs\n" " \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n" " \"addresses\" : [ (json array of string)\n" - " \"t12tvKAXCxZjSmdNbao16dKXC8tRWfcF5oc\" (string) bitcoin address\n" + " \"t12tvKAXCxZjSmdNbao16dKXC8tRWfcF5oc\" (string) zcash address\n" " ,...\n" " ]\n" " }\n" From 13ca1e8011c8794d2b05861d3b0c9dc284965c1b Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 13 Jul 2017 14:23:33 -0500 Subject: [PATCH 015/177] [Test] MiniNode: Implement JSDescription parsing --- qa/rpc-tests/test_framework/mininode.py | 148 ++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py index c3963707363..7006e68e48f 100755 --- a/qa/rpc-tests/test_framework/mininode.py +++ b/qa/rpc-tests/test_framework/mininode.py @@ -307,6 +307,154 @@ def __repr__(self): % (self.nVersion, repr(self.vHave)) +G1_PREFIX_MASK = 0x02 +G2_PREFIX_MASK = 0x0a + +class ZCProof(object): + def __init__(self): + self.g_A = None + self.g_A_prime = None + self.g_B = None + self.g_B_prime = None + self.g_C = None + self.g_C_prime = None + self.g_K = None + self.g_H = None + + def deserialize(self, f): + def deser_g1(self, f): + leadingByte = struct.unpack(" Date: Thu, 13 Jul 2017 14:24:16 -0500 Subject: [PATCH 016/177] [Test] MiniNode: Implement v2 CTransaction parsing --- qa/rpc-tests/test_framework/mininode.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py index 7006e68e48f..7ebf685e26b 100755 --- a/qa/rpc-tests/test_framework/mininode.py +++ b/qa/rpc-tests/test_framework/mininode.py @@ -530,6 +530,9 @@ def __init__(self, tx=None): self.vin = [] self.vout = [] self.nLockTime = 0 + self.vjoinsplit = [] + self.joinSplitPubKey = None + self.joinSplitSig = None self.sha256 = None self.hash = None else: @@ -537,6 +540,9 @@ def __init__(self, tx=None): self.vin = copy.deepcopy(tx.vin) self.vout = copy.deepcopy(tx.vout) self.nLockTime = tx.nLockTime + self.vjoinsplit = copy.deepcopy(tx.vjoinsplit) + self.joinSplitPubKey = tx.joinSplitPubKey + self.joinSplitSig = tx.joinSplitSig self.sha256 = None self.hash = None @@ -545,6 +551,11 @@ def deserialize(self, f): self.vin = deser_vector(f, CTxIn) self.vout = deser_vector(f, CTxOut) self.nLockTime = struct.unpack("= 2: + self.vjoinsplit = deser_vector(f, JSDescription) + if len(self.vjoinsplit) > 0: + self.joinSplitPubKey = deser_uint256(f) + self.joinSplitSig = f.read(64) self.sha256 = None self.hash = None @@ -554,6 +565,11 @@ def serialize(self): r += ser_vector(self.vin) r += ser_vector(self.vout) r += struct.pack("= 2: + r += ser_vector(self.vjoinsplit) + if len(self.vjoinsplit) > 0: + r += ser_uint256(self.joinSplitPubKey) + r += self.joinSplitSig return r def rehash(self): @@ -573,8 +589,15 @@ def is_valid(self): return True def __repr__(self): - return "CTransaction(nVersion=%i vin=%s vout=%s nLockTime=%i)" \ + r = "CTransaction(nVersion=%i vin=%s vout=%s nLockTime=%i" \ % (self.nVersion, repr(self.vin), repr(self.vout), self.nLockTime) + if self.nVersion >= 2: + r += " vjoinsplit=%s" % repr(self.vjoinsplit) + if len(self.vjoinsplit) > 0: + r += " joinSplitPubKey=%064x joinSplitSig=%064x" \ + (self.joinSplitPubKey, self.joinSplitSig) + r += ")" + return r class CBlockHeader(object): From 31bc3d25818c60f0cb3b6e8a8ecdfa28d367fd58 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 13 Jul 2017 14:25:10 -0500 Subject: [PATCH 017/177] [Test] MiniNode: Implement Zcash block parsing --- qa/rpc-tests/test_framework/mininode.py | 59 +++++++++++++++++++++---- 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py index 7ebf685e26b..e35503bfb99 100755 --- a/qa/rpc-tests/test_framework/mininode.py +++ b/qa/rpc-tests/test_framework/mininode.py @@ -234,6 +234,36 @@ def ser_int_vector(l): return r +def deser_char_vector(f): + nit = struct.unpack(" Date: Thu, 13 Jul 2017 14:25:31 -0500 Subject: [PATCH 018/177] [Test] MiniNode: Update protocol version and network magics --- qa/rpc-tests/test_framework/mininode.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py index e35503bfb99..c418d3f6357 100755 --- a/qa/rpc-tests/test_framework/mininode.py +++ b/qa/rpc-tests/test_framework/mininode.py @@ -32,7 +32,7 @@ import copy BIP0031_VERSION = 60000 -MY_VERSION = 60001 # past bip-31 for ping/pong +MY_VERSION = 170002 # past bip-31 for ping/pong MY_SUBVERSION = "/python-mininode-tester:0.0.1/" MAX_INV_SZ = 50000 @@ -1294,9 +1294,9 @@ class NodeConn(asyncore.dispatcher): "mempool": msg_mempool } MAGIC_BYTES = { - "mainnet": "\xf9\xbe\xb4\xd9", # mainnet - "testnet3": "\x0b\x11\x09\x07", # testnet3 - "regtest": "\xfa\xbf\xb5\xda" # regtest + "mainnet": "\x24\xe9\x27\x64", # mainnet + "testnet3": "\xfa\x1a\xf9\xbf", # testnet3 + "regtest": "\xaa\xe8\x3f\x5f" # regtest } def __init__(self, dstaddr, dstport, rpc, callback, net="regtest"): From e68c3ec1887d340927ba573ef8dc625d1a4a7d9e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 13 Jul 2017 17:04:53 -0500 Subject: [PATCH 019/177] [Test] MiniNode: Use Zcash PoW Equihash solver code extracted from https://github.com/str4d/zcash-pow RPC tests now require pyblake2 to be installed --- qa/rpc-tests/test_framework/blocktools.py | 7 +- qa/rpc-tests/test_framework/equihash.py | 293 ++++++++++++++++++++++ qa/rpc-tests/test_framework/mininode.py | 37 ++- 3 files changed, 330 insertions(+), 7 deletions(-) create mode 100755 qa/rpc-tests/test_framework/equihash.py diff --git a/qa/rpc-tests/test_framework/blocktools.py b/qa/rpc-tests/test_framework/blocktools.py index 0f814725371..cffa109cf28 100644 --- a/qa/rpc-tests/test_framework/blocktools.py +++ b/qa/rpc-tests/test_framework/blocktools.py @@ -7,7 +7,7 @@ from mininode import CBlock, CTransaction, CTxIn, CTxOut, COutPoint, ser_string # Create a block (with regtest difficulty) -def create_block(hashprev, coinbase, nTime=None): +def create_block(hashprev, coinbase, nTime=None, nBits=None): block = CBlock() if nTime is None: import time @@ -15,7 +15,10 @@ def create_block(hashprev, coinbase, nTime=None): else: block.nTime = nTime block.hashPrevBlock = hashprev - block.nBits = 0x207fffff # Will break after a difficulty adjustment... + if nBits is None: + block.nBits = 0x200f0f0f # Will break after a difficulty adjustment... + else: + block.nBits = nBits block.vtx.append(coinbase) block.hashMerkleRoot = block.calc_merkle_root() block.calc_sha256() diff --git a/qa/rpc-tests/test_framework/equihash.py b/qa/rpc-tests/test_framework/equihash.py new file mode 100755 index 00000000000..e404519781a --- /dev/null +++ b/qa/rpc-tests/test_framework/equihash.py @@ -0,0 +1,293 @@ +from operator import itemgetter +import struct + +DEBUG = False +VERBOSE = False + + +word_size = 32 +word_mask = (1<= 8 and word_size >= 7+bit_len + bit_len_mask = (1<= bit_len: + acc_bits -= bit_len + for x in xrange(byte_pad, out_width): + out[j+x] = ( + # Big-endian + acc_value >> (acc_bits+(8*(out_width-x-1))) + ) & ( + # Apply bit_len_mask across byte boundaries + (bit_len_mask >> (8*(out_width-x-1))) & 0xFF + ) + j += out_width + + return out + +def compress_array(inp, out_len, bit_len, byte_pad=0): + assert bit_len >= 8 and word_size >= 7+bit_len + + in_width = (bit_len+7)/8 + byte_pad + assert out_len == bit_len*len(inp)/(8*in_width) + out = bytearray(out_len) + + bit_len_mask = (1 << bit_len) - 1 + + # The acc_bits least-significant bits of acc_value represent a bit sequence + # in big-endian order. + acc_bits = 0; + acc_value = 0; + + j = 0 + for i in xrange(out_len): + # When we have fewer than 8 bits left in the accumulator, read the next + # input element. + if acc_bits < 8: + acc_value = ((acc_value << bit_len) & word_mask) | inp[j] + for x in xrange(byte_pad, in_width): + acc_value = acc_value | ( + ( + # Apply bit_len_mask across byte boundaries + inp[j+x] & ((bit_len_mask >> (8*(in_width-x-1))) & 0xFF) + ) << (8*(in_width-x-1))); # Big-endian + j += in_width + acc_bits += bit_len + + acc_bits -= 8 + out[i] = (acc_value >> acc_bits) & 0xFF + + return out + +def get_indices_from_minimal(minimal, bit_len): + eh_index_size = 4 + assert (bit_len+7)/8 <= eh_index_size + len_indices = 8*eh_index_size*len(minimal)/bit_len + byte_pad = eh_index_size - (bit_len+7)/8 + expanded = expand_array(minimal, len_indices, bit_len, byte_pad) + return [struct.unpack('>I', expanded[i:i+4])[0] for i in range(0, len_indices, eh_index_size)] + +def get_minimal_from_indices(indices, bit_len): + eh_index_size = 4 + assert (bit_len+7)/8 <= eh_index_size + len_indices = len(indices)*eh_index_size + min_len = bit_len*len_indices/(8*eh_index_size) + byte_pad = eh_index_size - (bit_len+7)/8 + byte_indices = bytearray(''.join([struct.pack('>I', i) for i in indices])) + return compress_array(byte_indices, min_len, bit_len, byte_pad) + + +def hash_nonce(digest, nonce): + for i in range(8): + digest.update(struct.pack('> (32*i))) + +def hash_xi(digest, xi): + digest.update(struct.pack(' 0: + # 2b) Find next set of unordered pairs with collisions on first n/(k+1) bits + j = 1 + while j < len(X): + if not has_collision(X[-1][0], X[-1-j][0], i, collision_length): + break + j += 1 + + # 2c) Store tuples (X_i ^ X_j, (i, j)) on the table + for l in range(0, j-1): + for m in range(l+1, j): + # Check that there are no duplicate indices in tuples i and j + if distinct_indices(X[-1-l][1], X[-1-m][1]): + if X[-1-l][1][0] < X[-1-m][1][0]: + concat = X[-1-l][1] + X[-1-m][1] + else: + concat = X[-1-m][1] + X[-1-l][1] + Xc.append((xor(X[-1-l][0], X[-1-m][0]), concat)) + + # 2d) Drop this set + while j > 0: + X.pop(-1) + j -= 1 + # 2e) Replace previous list with new list + X = Xc + + # k+1) Find a collision on last 2n(k+1) bits + if DEBUG: + print 'Final round:' + print '- Sorting list' + X.sort(key=itemgetter(0)) + if DEBUG and VERBOSE: + for Xi in X[-32:]: + print '%s %s' % (print_hash(Xi[0]), Xi[1]) + if DEBUG: print '- Finding collisions' + solns = [] + while len(X) > 0: + j = 1 + while j < len(X): + if not (has_collision(X[-1][0], X[-1-j][0], k, collision_length) and + has_collision(X[-1][0], X[-1-j][0], k+1, collision_length)): + break + j += 1 + + for l in range(0, j-1): + for m in range(l+1, j): + res = xor(X[-1-l][0], X[-1-m][0]) + if count_zeroes(res) == 8*hash_length and distinct_indices(X[-1-l][1], X[-1-m][1]): + if DEBUG and VERBOSE: + print 'Found solution:' + print '- %s %s' % (print_hash(X[-1-l][0]), X[-1-l][1]) + print '- %s %s' % (print_hash(X[-1-m][0]), X[-1-m][1]) + if X[-1-l][1][0] < X[-1-m][1][0]: + solns.append(list(X[-1-l][1] + X[-1-m][1])) + else: + solns.append(list(X[-1-m][1] + X[-1-l][1])) + + # 2d) Drop this set + while j > 0: + X.pop(-1) + j -= 1 + return [get_minimal_from_indices(soln, collision_length+1) for soln in solns] + +def gbp_validate(digest, minimal, n, k): + validate_params(n, k) + collision_length = n/(k+1) + hash_length = (k+1)*((collision_length+7)//8) + indices_per_hash_output = 512/n + solution_width = (1 << k)*(collision_length+1)//8 + + if len(minimal) != solution_width: + print 'Invalid solution length: %d (expected %d)' % \ + (len(minimal), solution_width) + return False + + X = [] + for i in get_indices_from_minimal(minimal, collision_length+1): + r = i % indices_per_hash_output + # X_i = H(I||V||x_i) + curr_digest = digest.copy() + hash_xi(curr_digest, i/indices_per_hash_output) + tmp_hash = curr_digest.digest() + X.append(( + expand_array(bytearray(tmp_hash[r*n/8:(r+1)*n/8]), + hash_length, collision_length), + (i,) + )) + + for r in range(1, k+1): + Xc = [] + for i in range(0, len(X), 2): + if not has_collision(X[i][0], X[i+1][0], r, collision_length): + print 'Invalid solution: invalid collision length between StepRows' + return False + if X[i+1][1][0] < X[i][1][0]: + print 'Invalid solution: Index tree incorrectly ordered' + return False + if not distinct_indices(X[i][1], X[i+1][1]): + print 'Invalid solution: duplicate indices' + return False + Xc.append((xor(X[i][0], X[i+1][0]), X[i][1] + X[i+1][1])) + X = Xc + + if len(X) != 1: + print 'Invalid solution: incorrect length after end of rounds: %d' % len(X) + return False + + if count_zeroes(X[0][0]) != 8*hash_length: + print 'Invalid solution: incorrect number of zeroes: %d' % count_zeroes(X[0][0]) + return False + + return True + +def zcash_person(n, k): + return b'ZcashPoW' + struct.pack('= n): + raise ValueError('n must be larger than k') + if (((n/(k+1))+1) >= 32): + raise ValueError('Parameters must satisfy n/(k+1)+1 < 32') diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py index c418d3f6357..c74d3f93133 100755 --- a/qa/rpc-tests/test_framework/mininode.py +++ b/qa/rpc-tests/test_framework/mininode.py @@ -30,6 +30,14 @@ from threading import Thread import logging import copy +from pyblake2 import blake2b + +from .equihash import ( + gbp_basic, + gbp_validate, + hash_nonce, + zcash_person, +) BIP0031_VERSION = 60000 MY_VERSION = 170002 # past bip-31 for ping/pong @@ -736,7 +744,13 @@ def calc_merkle_root(self): hashes = newhashes return uint256_from_str(hashes[0]) - def is_valid(self): + def is_valid(self, n=48, k=5): + # H(I||... + digest = blake2b(digest_size=(512/n)*n/8, person=zcash_person(n, k)) + digest.update(super(CBlock, self).serialize()[:108]) + hash_nonce(digest, self.nNonce) + if not gbp_validate(self.nSolution, digest, n, k): + return False self.calc_sha256() target = uint256_from_compact(self.nBits) if self.sha256 > target: @@ -748,12 +762,25 @@ def is_valid(self): return False return True - def solve(self): - self.calc_sha256() + def solve(self, n=48, k=5): target = uint256_from_compact(self.nBits) - while self.sha256 > target: + # H(I||... + digest = blake2b(digest_size=(512/n)*n/8, person=zcash_person(n, k)) + digest.update(super(CBlock, self).serialize()[:108]) + self.nNonce = 0 + while True: + # H(I||V||... + curr_digest = digest.copy() + hash_nonce(curr_digest, self.nNonce) + # (x_1, x_2, ...) = A(I, V, n, k) + solns = gbp_basic(curr_digest, n, k) + for soln in solns: + assert(gbp_validate(curr_digest, soln, n, k)) + self.nSolution = soln + self.rehash() + if self.sha256 <= target: + return self.nNonce += 1 - self.rehash() def __repr__(self): return "CBlock(nVersion=%i hashPrevBlock=%064x hashMerkleRoot=%064x hashReserved=%064x nTime=%s nBits=%08x nNonce=%064x nSolution=%s vtx=%s)" \ From 643235859afb01fdc874f8e09ca1855b55fb8a97 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 4 Oct 2017 00:25:06 +0100 Subject: [PATCH 020/177] [Test] MiniNode: Fix coinbase creation CScriptNum is only used for heights > 16. --- qa/rpc-tests/test_framework/blocktools.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/qa/rpc-tests/test_framework/blocktools.py b/qa/rpc-tests/test_framework/blocktools.py index cffa109cf28..ca566e4bc2f 100644 --- a/qa/rpc-tests/test_framework/blocktools.py +++ b/qa/rpc-tests/test_framework/blocktools.py @@ -4,7 +4,8 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. # -from mininode import CBlock, CTransaction, CTxIn, CTxOut, COutPoint, ser_string +from mininode import CBlock, CTransaction, CTxIn, CTxOut, COutPoint +from script import CScript, OP_0 # Create a block (with regtest difficulty) def create_block(hashprev, coinbase, nTime=None, nBits=None): @@ -45,7 +46,7 @@ def create_coinbase(heightAdjust = 0): global counter coinbase = CTransaction() coinbase.vin.append(CTxIn(COutPoint(0, 0xffffffff), - ser_string(serialize_script_num(counter+heightAdjust)), 0xffffffff)) + CScript([counter+heightAdjust, OP_0]), 0xffffffff)) counter += 1 coinbaseoutput = CTxOut() coinbaseoutput.nValue = 50*100000000 From 7596a4922d8e1b43cdc03ddaabcad538375f3ab3 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 4 Oct 2017 00:28:40 +0100 Subject: [PATCH 021/177] [Test] MiniNode: Coerce OP_PUSHDATA bytearrays to bytes If a bytearray is passed in as part of an iterable, the CScript constructor fails because b''.join() cannot be used to join a bytearray to a bytes or str in Python 2. --- qa/rpc-tests/test_framework/script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/rpc-tests/test_framework/script.py b/qa/rpc-tests/test_framework/script.py index ab7f4ec7471..55a7f8e51ae 100644 --- a/qa/rpc-tests/test_framework/script.py +++ b/qa/rpc-tests/test_framework/script.py @@ -666,7 +666,7 @@ def __coerce_instance(cls, other): else: other = CScriptOp.encode_op_pushdata(bignum.bn2vch(other)) elif isinstance(other, (bytes, bytearray)): - other = CScriptOp.encode_op_pushdata(other) + other = bytes(CScriptOp.encode_op_pushdata(other)) return other def __add__(self, other): From c10c40779d9b73359ee61f85ec5f1bb88acac61d Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 4 Oct 2017 00:34:32 +0100 Subject: [PATCH 022/177] [Test] MiniNode: Implement Zcash coinbase --- qa/rpc-tests/test_framework/blocktools.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/qa/rpc-tests/test_framework/blocktools.py b/qa/rpc-tests/test_framework/blocktools.py index ca566e4bc2f..1fe2a5ddabb 100644 --- a/qa/rpc-tests/test_framework/blocktools.py +++ b/qa/rpc-tests/test_framework/blocktools.py @@ -5,7 +5,7 @@ # from mininode import CBlock, CTransaction, CTxIn, CTxOut, COutPoint -from script import CScript, OP_0 +from script import CScript, OP_0, OP_EQUAL, OP_HASH160 # Create a block (with regtest difficulty) def create_block(hashprev, coinbase, nTime=None, nBits=None): @@ -49,11 +49,21 @@ def create_coinbase(heightAdjust = 0): CScript([counter+heightAdjust, OP_0]), 0xffffffff)) counter += 1 coinbaseoutput = CTxOut() - coinbaseoutput.nValue = 50*100000000 + coinbaseoutput.nValue = int(12.5*100000000) halvings = int((counter+heightAdjust)/150) # regtest coinbaseoutput.nValue >>= halvings coinbaseoutput.scriptPubKey = "" coinbase.vout = [ coinbaseoutput ] + if halvings == 0: # regtest + froutput = CTxOut() + froutput.nValue = coinbaseoutput.nValue / 5 + # regtest + fraddr = bytearray([0x67, 0x08, 0xe6, 0x67, 0x0d, 0xb0, 0xb9, 0x50, + 0xda, 0xc6, 0x80, 0x31, 0x02, 0x5c, 0xc5, 0xb6, + 0x32, 0x13, 0xa4, 0x91]) + froutput.scriptPubKey = CScript([OP_HASH160, fraddr, OP_EQUAL]) + coinbaseoutput.nValue -= froutput.nValue + coinbase.vout = [ coinbaseoutput, froutput ] coinbase.calc_sha256() return coinbase From 5455ca0d0e9b39d6844133edfc01107031f2c594 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 4 Oct 2017 01:21:09 +0100 Subject: [PATCH 023/177] Fix BIP65 and BIP66 tests Blocks were being created that didn't satisfy the regtest consensus rules. --- qa/rpc-tests/bip65-cltv-p2p.py | 10 +++++++--- qa/rpc-tests/bipdersig-p2p.py | 11 +++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/qa/rpc-tests/bip65-cltv-p2p.py b/qa/rpc-tests/bip65-cltv-p2p.py index 8fef45afee5..cfd2df01eeb 100755 --- a/qa/rpc-tests/bip65-cltv-p2p.py +++ b/qa/rpc-tests/bip65-cltv-p2p.py @@ -12,7 +12,6 @@ from test_framework.script import CScript, OP_1NEGATE, OP_NOP2, OP_DROP from binascii import unhexlify import cStringIO -import time ''' @@ -64,9 +63,9 @@ def invalidate_transaction(self, tx): def get_tests(self): self.coinbase_blocks = self.nodes[0].generate(1) + self.nodes[0].generate(100) self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0) self.nodeaddress = self.nodes[0].getnewaddress() - self.block_time = time.time() + 1 '''Check that the rules are enforced.''' for valid in (True, False): @@ -77,7 +76,12 @@ def get_tests(self): self.invalidate_transaction(spendtx) spendtx.rehash() - block = create_block(self.tip, create_coinbase(1), self.block_time) + gbt = self.nodes[0].getblocktemplate() + self.block_time = gbt["mintime"] + 1 + self.block_bits = int("0x" + gbt["bits"], 0) + + block = create_block(self.tip, create_coinbase(101), + self.block_time, self.block_bits) block.nVersion = 4 block.vtx.append(spendtx) block.hashMerkleRoot = block.calc_merkle_root() diff --git a/qa/rpc-tests/bipdersig-p2p.py b/qa/rpc-tests/bipdersig-p2p.py index 523a694bf28..f254843f1f0 100755 --- a/qa/rpc-tests/bipdersig-p2p.py +++ b/qa/rpc-tests/bipdersig-p2p.py @@ -12,7 +12,6 @@ from test_framework.script import CScript from binascii import unhexlify import cStringIO -import time ''' @@ -71,9 +70,9 @@ def invalidate_transaction(self, tx): def get_tests(self): self.coinbase_blocks = self.nodes[0].generate(1) + self.nodes[0].generate(100) self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0) self.nodeaddress = self.nodes[0].getnewaddress() - self.block_time = time.time() + 1 '''Check that the rules are enforced.''' for valid in (True, False): @@ -84,13 +83,17 @@ def get_tests(self): self.invalidate_transaction(spendtx) spendtx.rehash() - block = create_block(self.tip, create_coinbase(1), self.block_time) + gbt = self.nodes[0].getblocktemplate() + self.block_time = gbt["mintime"] + 1 + self.block_bits = int("0x" + gbt["bits"], 0) + + block = create_block(self.tip, create_coinbase(101), + self.block_time, self.block_bits) block.nVersion = 4 block.vtx.append(spendtx) block.hashMerkleRoot = block.calc_merkle_root() block.rehash() block.solve() - self.block_time += 1 self.tip = block.sha256 yield TestInstance([[block, valid]]) From f8ef223ce381a9f59b1f4b085d360abad6cb9499 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 5 Oct 2017 15:13:28 +0100 Subject: [PATCH 024/177] Un-indent RPC test output in test runner The indentation caused the test stdout to be buffered and only printed at the end of the test, which makes it harder to diagnose hanging tests. --- qa/pull-tester/rpc-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index ed2bfca0ad1..5631f894f18 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -85,7 +85,7 @@ function runTestScript echo -e "=== Running testscript ${testName} ===" - if eval "$@" | sed 's/^/ /' + if eval "$@" then successCount=$(expr $successCount + 1) echo "--- Success: ${testName} ---" From b30900a54bdaed5a5fbe7d5ea1cc072a405b762d Mon Sep 17 00:00:00 2001 From: Jason Davies Date: Fri, 21 Jul 2017 09:18:09 +0100 Subject: [PATCH 025/177] Replace "bitcoin" with "Zcash". --- src/crypto/common.h | 2 +- src/httpserver.cpp | 4 ++-- src/net.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/crypto/common.h b/src/crypto/common.h index 5d5027adad7..ad4c6dd5e6d 100644 --- a/src/crypto/common.h +++ b/src/crypto/common.h @@ -16,7 +16,7 @@ #include "compat/endian.h" #if defined(NDEBUG) -# error "Bitcoin cannot be compiled without assertions." +# error "Zcash cannot be compiled without assertions." #endif uint16_t static inline ReadLE16(const unsigned char* ptr) diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 4215a0f2626..9c033e41519 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -267,7 +267,7 @@ static void http_request_cb(struct evhttp_request* req, void* arg) /** Event dispatcher thread */ static void ThreadHTTP(struct event_base* base, struct evhttp* http) { - RenameThread("bitcoin-http"); + RenameThread("zcash-http"); LogPrint("http", "Entering http event loop\n"); event_base_dispatch(base); // Event loop will be interrupted by InterruptHTTPServer() @@ -316,7 +316,7 @@ static bool HTTPBindAddresses(struct evhttp* http) /** Simple wrapper to set thread name and run work queue */ static void HTTPWorkQueueRun(WorkQueue* queue) { - RenameThread("bitcoin-httpworker"); + RenameThread("zcash-httpworker"); queue->Run(); } diff --git a/src/net.cpp b/src/net.cpp index 7a40d97d650..05f42770705 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1636,7 +1636,7 @@ bool BindListenPort(const CService &addrBind, string& strError, bool fWhiteliste { int nErr = WSAGetLastError(); if (nErr == WSAEADDRINUSE) - strError = strprintf(_("Unable to bind to %s on this computer. Bitcoin Core is probably already running."), addrBind.ToString()); + strError = strprintf(_("Unable to bind to %s on this computer. Zcash is probably already running."), addrBind.ToString()); else strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString(), NetworkErrorString(nErr)); LogPrintf("%s\n", strError); From aadf3aa15961fac06ca95f50f8034a20535ed002 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 6 Oct 2017 00:21:05 +0100 Subject: [PATCH 026/177] Replace full-test-suite.sh with a new test suite driver script This will be the canonical location for the entire Zcash merge test suite. --- qa/zcash/full-test-suite.sh | 47 -------------------- qa/zcash/full_test_suite.py | 87 +++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 47 deletions(-) delete mode 100755 qa/zcash/full-test-suite.sh create mode 100755 qa/zcash/full_test_suite.py diff --git a/qa/zcash/full-test-suite.sh b/qa/zcash/full-test-suite.sh deleted file mode 100755 index 7860b105a9f..00000000000 --- a/qa/zcash/full-test-suite.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash -# -# Execute all of the automated tests related to Zcash. -# - -set -eu - -SUITE_EXIT_STATUS=0 -REPOROOT="$(readlink -f "$(dirname "$0")"/../../)" - -function run_test_phase -{ - echo "===== BEGIN: $*" - set +e - eval "$@" - if [ $? -eq 0 ] - then - echo "===== PASSED: $*" - else - echo "===== FAILED: $*" - SUITE_EXIT_STATUS=1 - fi - set -e -} - -cd "${REPOROOT}" - -# Test phases: -run_test_phase "${REPOROOT}/qa/zcash/check-security-hardening.sh" -run_test_phase "${REPOROOT}/qa/zcash/ensure-no-dot-so-in-depends.py" - -# If make check fails, show test-suite.log as part of our run_test_phase -# output (and fail the phase with false): -run_test_phase make check '||' \ - '{' \ - echo '=== ./src/test-suite.log ===' ';' \ - cat './src/test-suite.log' ';' \ - false ';' \ - '}' - -exit $SUITE_EXIT_STATUS - - - - - - diff --git a/qa/zcash/full_test_suite.py b/qa/zcash/full_test_suite.py new file mode 100755 index 00000000000..f383d64e114 --- /dev/null +++ b/qa/zcash/full_test_suite.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python2 +# +# Execute all of the automated tests related to Zcash. +# + +import argparse +import os +import subprocess +import sys + +REPOROOT = os.path.dirname( + os.path.dirname( + os.path.dirname( + os.path.abspath(__file__) + ) + ) +) + +def repofile(filename): + return os.path.join(REPOROOT, filename) + + +# +# Tests +# + +STAGES = [ + 'btest', + 'gtest', + 'sec-hard', + 'no-dot-so', + 'secp256k1', + 'univalue', + 'rpc', +] + +STAGE_COMMANDS = { + 'btest': [repofile('src/test/test_bitcoin'), '-p'], + 'gtest': [repofile('src/zcash-gtest')], + 'sec-hard': [repofile('qa/zcash/check-security-hardening.sh')], + 'no-dot-so': [repofile('qa/zcash/ensure-no-dot-so-in-depends.py')], + 'secp256k1': ['make', '-C', repofile('src/secp256k1'), 'check'], + 'univalue': ['make', '-C', repofile('src/univalue'), 'check'], + 'rpc': [repofile('qa/pull-tester/rpc-tests.sh')], +} + + +# +# Test driver +# + +def run_stage(stage): + print('Running stage %s' % stage) + print('=' * (len(stage) + 14)) + print + + ret = subprocess.call(STAGE_COMMANDS[stage]) + + print + print('-' * (len(stage) + 15)) + print('Finished stage %s' % stage) + print + + return ret == 0 + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('stage', nargs='*', default=STAGES, + help='One of %s'%STAGES) + args = parser.parse_args() + + # Check validity of stages + for s in args.stage: + if s not in STAGES: + print("Invalid stage '%s' (choose from %s)" % (s, STAGES)) + sys.exit(1) + + # Run the stages + passed = True + for s in args.stage: + passed &= run_stage(s) + + if not passed: + sys.exit(1) + +if __name__ == '__main__': + main() From 105b2b6248a982ed6cab5d141cf2672d09442d5b Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 6 Oct 2017 00:39:05 +0100 Subject: [PATCH 027/177] Move ensure-no-dot-so-in-depends.py into full_test_suite.py --- qa/zcash/ensure-no-dot-so-in-depends.py | 41 ---------------------- qa/zcash/full_test_suite.py | 45 +++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 44 deletions(-) delete mode 100755 qa/zcash/ensure-no-dot-so-in-depends.py diff --git a/qa/zcash/ensure-no-dot-so-in-depends.py b/qa/zcash/ensure-no-dot-so-in-depends.py deleted file mode 100755 index beb4b9ec0f8..00000000000 --- a/qa/zcash/ensure-no-dot-so-in-depends.py +++ /dev/null @@ -1,41 +0,0 @@ -#! /usr/bin/env python2 - -import sys -import os - -def main(): - this_script = os.path.abspath(sys.argv[0]) - basedir = os.path.dirname(this_script) - arch_dir = os.path.join( - basedir, - '..', - '..', - 'depends', - 'x86_64-unknown-linux-gnu', - ) - - exit_code = 0 - - if os.path.isdir(arch_dir): - lib_dir = os.path.join(arch_dir, 'lib') - libraries = os.listdir(lib_dir) - - for lib in libraries: - if lib.find(".so") != -1: - print lib - exit_code = 1 - else: - exit_code = 2 - print "arch-specific build dir not present: {}".format(arch_dir) - print "Did you build the ./depends tree?" - print "Are you on a currently unsupported architecture?" - - if exit_code == 0: - print "PASS." - else: - print "FAIL." - - sys.exit(exit_code) - -if __name__ == '__main__': - main() diff --git a/qa/zcash/full_test_suite.py b/qa/zcash/full_test_suite.py index f383d64e114..d2eca6a4281 100755 --- a/qa/zcash/full_test_suite.py +++ b/qa/zcash/full_test_suite.py @@ -20,6 +20,41 @@ def repofile(filename): return os.path.join(REPOROOT, filename) +# +# Custom test runners +# + +def ensure_no_dot_so_in_depends(): + arch_dir = os.path.join( + REPOROOT, + 'depends', + 'x86_64-unknown-linux-gnu', + ) + + exit_code = 0 + + if os.path.isdir(arch_dir): + lib_dir = os.path.join(arch_dir, 'lib') + libraries = os.listdir(lib_dir) + + for lib in libraries: + if lib.find(".so") != -1: + print lib + exit_code = 1 + else: + exit_code = 2 + print "arch-specific build dir not present: {}".format(arch_dir) + print "Did you build the ./depends tree?" + print "Are you on a currently unsupported architecture?" + + if exit_code == 0: + print "PASS." + else: + print "FAIL." + + return exit_code == 0 + + # # Tests # @@ -38,7 +73,7 @@ def repofile(filename): 'btest': [repofile('src/test/test_bitcoin'), '-p'], 'gtest': [repofile('src/zcash-gtest')], 'sec-hard': [repofile('qa/zcash/check-security-hardening.sh')], - 'no-dot-so': [repofile('qa/zcash/ensure-no-dot-so-in-depends.py')], + 'no-dot-so': ensure_no_dot_so_in_depends, 'secp256k1': ['make', '-C', repofile('src/secp256k1'), 'check'], 'univalue': ['make', '-C', repofile('src/univalue'), 'check'], 'rpc': [repofile('qa/pull-tester/rpc-tests.sh')], @@ -54,14 +89,18 @@ def run_stage(stage): print('=' * (len(stage) + 14)) print - ret = subprocess.call(STAGE_COMMANDS[stage]) + cmd = STAGE_COMMANDS[stage] + if type(cmd) == type([]): + ret = subprocess.call(cmd) == 0 + else: + ret = cmd() print print('-' * (len(stage) + 15)) print('Finished stage %s' % stage) print - return ret == 0 + return ret def main(): parser = argparse.ArgumentParser() From c6af0aa45342a609c884f27446496b750f10a38f Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 6 Oct 2017 01:33:00 +0100 Subject: [PATCH 028/177] Move check-security-hardening.sh into full_test_suite.py --- qa/zcash/check-security-hardening.sh | 46 ---------------------- qa/zcash/full_test_suite.py | 58 +++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 47 deletions(-) delete mode 100755 qa/zcash/check-security-hardening.sh diff --git a/qa/zcash/check-security-hardening.sh b/qa/zcash/check-security-hardening.sh deleted file mode 100755 index 94a87fea33a..00000000000 --- a/qa/zcash/check-security-hardening.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -set -e - -REPOROOT="$(readlink -f "$(dirname "$0")"/../../)" - -function test_rpath_runpath { - if "${REPOROOT}/qa/zcash/checksec.sh" --file "$1" | grep -q "No RPATH.*No RUNPATH"; then - echo PASS: "$1" has no RPATH or RUNPATH. - return 0 - else - echo FAIL: "$1" has an RPATH or a RUNPATH. - "${REPOROOT}/qa/zcash/checksec.sh" --file "$1" - return 1 - fi -} - -function test_fortify_source { - if { "${REPOROOT}/qa/zcash/checksec.sh" --fortify-file "$1" | grep -q "FORTIFY_SOURCE support available.*Yes"; } && - { "${REPOROOT}/qa/zcash/checksec.sh" --fortify-file "$1" | grep -q "Binary compiled with FORTIFY_SOURCE support.*Yes"; }; then - echo PASS: "$1" has FORTIFY_SOURCE. - return 0 - else - echo FAIL: "$1" is missing FORTIFY_SOURCE. - return 1 - fi -} - -# PIE, RELRO, Canary, and NX are tested by make check-security. -make -C "$REPOROOT/src" check-security - -test_rpath_runpath "${REPOROOT}/src/zcashd" -test_rpath_runpath "${REPOROOT}/src/zcash-cli" -test_rpath_runpath "${REPOROOT}/src/zcash-gtest" -test_rpath_runpath "${REPOROOT}/src/zcash-tx" -test_rpath_runpath "${REPOROOT}/src/test/test_bitcoin" -test_rpath_runpath "${REPOROOT}/src/zcash/GenerateParams" - -# NOTE: checksec.sh does not reliably determine whether FORTIFY_SOURCE is -# enabled for the entire binary. See issue #915. -test_fortify_source "${REPOROOT}/src/zcashd" -test_fortify_source "${REPOROOT}/src/zcash-cli" -test_fortify_source "${REPOROOT}/src/zcash-gtest" -test_fortify_source "${REPOROOT}/src/zcash-tx" -test_fortify_source "${REPOROOT}/src/test/test_bitcoin" -test_fortify_source "${REPOROOT}/src/zcash/GenerateParams" diff --git a/qa/zcash/full_test_suite.py b/qa/zcash/full_test_suite.py index d2eca6a4281..6e890c49a1b 100755 --- a/qa/zcash/full_test_suite.py +++ b/qa/zcash/full_test_suite.py @@ -5,6 +5,7 @@ import argparse import os +import re import subprocess import sys @@ -24,6 +25,61 @@ def repofile(filename): # Custom test runners # +RE_RPATH_RUNPATH = re.compile('No RPATH.*No RUNPATH') +RE_FORTIFY_AVAILABLE = re.compile('FORTIFY_SOURCE support available.*Yes') +RE_FORTIFY_USED = re.compile('Binary compiled with FORTIFY_SOURCE support.*Yes') + +def test_rpath_runpath(filename): + output = subprocess.check_output( + [repofile('qa/zcash/checksec.sh'), '--file', repofile(filename)] + ) + if RE_RPATH_RUNPATH.search(output): + print('PASS: %s has no RPATH or RUNPATH.' % filename) + return True + else: + print('FAIL: %s has an RPATH or a RUNPATH.' % filename) + print(output) + return False + +def test_fortify_source(filename): + proc = subprocess.Popen( + [repofile('qa/zcash/checksec.sh'), '--fortify-file', repofile(filename)], + stdout=subprocess.PIPE, + ) + line1 = proc.stdout.readline() + line2 = proc.stdout.readline() + proc.terminate() + if RE_FORTIFY_AVAILABLE.search(line1) and RE_FORTIFY_USED.search(line2): + print('PASS: %s has FORTIFY_SOURCE.' % filename) + return True + else: + print('FAIL: %s is missing FORTIFY_SOURCE.' % filename) + return False + +def check_security_hardening(): + ret = True + + # PIE, RELRO, Canary, and NX are tested by make check-security. + ret &= subprocess.call(['make', '-C', repofile('src'), 'check-security']) == 0 + + ret &= test_rpath_runpath('src/zcashd') + ret &= test_rpath_runpath('src/zcash-cli') + ret &= test_rpath_runpath('src/zcash-gtest') + ret &= test_rpath_runpath('src/zcash-tx') + ret &= test_rpath_runpath('src/test/test_bitcoin') + ret &= test_rpath_runpath('src/zcash/GenerateParams') + + # NOTE: checksec.sh does not reliably determine whether FORTIFY_SOURCE + # is enabled for the entire binary. See issue #915. + ret &= test_fortify_source('src/zcashd') + ret &= test_fortify_source('src/zcash-cli') + ret &= test_fortify_source('src/zcash-gtest') + ret &= test_fortify_source('src/zcash-tx') + ret &= test_fortify_source('src/test/test_bitcoin') + ret &= test_fortify_source('src/zcash/GenerateParams') + + return ret + def ensure_no_dot_so_in_depends(): arch_dir = os.path.join( REPOROOT, @@ -72,7 +128,7 @@ def ensure_no_dot_so_in_depends(): STAGE_COMMANDS = { 'btest': [repofile('src/test/test_bitcoin'), '-p'], 'gtest': [repofile('src/zcash-gtest')], - 'sec-hard': [repofile('qa/zcash/check-security-hardening.sh')], + 'sec-hard': check_security_hardening, 'no-dot-so': ensure_no_dot_so_in_depends, 'secp256k1': ['make', '-C', repofile('src/secp256k1'), 'check'], 'univalue': ['make', '-C', repofile('src/univalue'), 'check'], From 94790c5d8f5710e775e3a217a9129059f8c930d8 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 9 Oct 2017 22:18:28 +0100 Subject: [PATCH 029/177] Add memory benchmark for validatelargetx --- qa/zcash/performance-measurements.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qa/zcash/performance-measurements.sh b/qa/zcash/performance-measurements.sh index 60f92dd1d28..4931d55190a 100755 --- a/qa/zcash/performance-measurements.sh +++ b/qa/zcash/performance-measurements.sh @@ -234,6 +234,9 @@ case "$1" in verifyequihash) zcash_rpc zcbenchmark verifyequihash 1 ;; + validatelargetx) + zcash_rpc zcbenchmark validatelargetx 1 + ;; trydecryptnotes) zcash_rpc zcbenchmark trydecryptnotes 1 "${@:3}" ;; From 054ae606455ddfded7af5a8d75151497dfa7d382 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 10 Oct 2017 15:58:35 +0100 Subject: [PATCH 030/177] Migrate libsnark test code to Google Test --- .../algebra/curves/tests/test_bilinearity.cpp | 22 ++--- .../src/algebra/curves/tests/test_groups.cpp | 76 ++++++++-------- .../src/algebra/fields/tests/test_bigint.cpp | 86 ++++++++----------- .../src/algebra/fields/tests/test_fields.cpp | 64 +++++++------- .../sha256/tests/test_sha256_gadget.cpp | 6 +- .../tests/test_merkle_tree_gadgets.cpp | 4 +- .../qap/tests/test_qap.cpp | 12 +-- .../tests/test_r1cs_ppzksnark.cpp | 6 +- 8 files changed, 140 insertions(+), 136 deletions(-) diff --git a/src/snark/src/algebra/curves/tests/test_bilinearity.cpp b/src/snark/src/algebra/curves/tests/test_bilinearity.cpp index 295745281a5..529bec33738 100644 --- a/src/snark/src/algebra/curves/tests/test_bilinearity.cpp +++ b/src/snark/src/algebra/curves/tests/test_bilinearity.cpp @@ -13,6 +13,8 @@ #include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" #include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#include + using namespace libsnark; template @@ -46,11 +48,11 @@ void pairing_test() ans1.print(); ans2.print(); ans3.print(); - assert(ans1 == ans2); - assert(ans2 == ans3); + EXPECT_EQ(ans1, ans2); + EXPECT_EQ(ans2, ans3); - assert(ans1 != GT_one); - assert((ans1^Fr::field_char()) == GT_one); + EXPECT_NE(ans1, GT_one); + EXPECT_EQ((ans1^Fr::field_char()), GT_one); printf("\n\n"); } @@ -70,7 +72,7 @@ void double_miller_loop_test() const Fqk ans_1 = ppT::miller_loop(prec_P1, prec_Q1); const Fqk ans_2 = ppT::miller_loop(prec_P2, prec_Q2); const Fqk ans_12 = ppT::double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); - assert(ans_1 * ans_2 == ans_12); + EXPECT_EQ(ans_1 * ans_2, ans_12); } template @@ -99,15 +101,15 @@ void affine_pairing_test() ans1.print(); ans2.print(); ans3.print(); - assert(ans1 == ans2); - assert(ans2 == ans3); + EXPECT_EQ(ans1, ans2); + EXPECT_EQ(ans2, ans3); - assert(ans1 != GT_one); - assert((ans1^Fr::field_char()) == GT_one); + EXPECT_NE(ans1, GT_one); + EXPECT_EQ((ans1^Fr::field_char()), GT_one); printf("\n\n"); } -int main(void) +TEST(algebra, bilinearity) { start_profiling(); edwards_pp::init_public_params(); diff --git a/src/snark/src/algebra/curves/tests/test_groups.cpp b/src/snark/src/algebra/curves/tests/test_groups.cpp index 725e490d7b4..087ee3d5255 100644 --- a/src/snark/src/algebra/curves/tests/test_groups.cpp +++ b/src/snark/src/algebra/curves/tests/test_groups.cpp @@ -14,6 +14,8 @@ #include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" #include +#include + using namespace libsnark; template @@ -25,31 +27,31 @@ void test_mixed_add() el = GroupT::zero(); el.to_special(); result = base.mixed_add(el); - assert(result == base + el); + EXPECT_EQ(result, base + el); base = GroupT::zero(); el = GroupT::random_element(); el.to_special(); result = base.mixed_add(el); - assert(result == base + el); + EXPECT_EQ(result, base + el); base = GroupT::random_element(); el = GroupT::zero(); el.to_special(); result = base.mixed_add(el); - assert(result == base + el); + EXPECT_EQ(result, base + el); base = GroupT::random_element(); el = GroupT::random_element(); el.to_special(); result = base.mixed_add(el); - assert(result == base + el); + EXPECT_EQ(result, base + el); base = GroupT::random_element(); el = base; el.to_special(); result = base.mixed_add(el); - assert(result == base.dbl()); + EXPECT_EQ(result, base.dbl()); } template @@ -60,53 +62,53 @@ void test_group() bigint<1> randsum = bigint<1>("121160274"); GroupT zero = GroupT::zero(); - assert(zero == zero); + EXPECT_EQ(zero, zero); GroupT one = GroupT::one(); - assert(one == one); + EXPECT_EQ(one, one); GroupT two = bigint<1>(2l) * GroupT::one(); - assert(two == two); + EXPECT_EQ(two, two); GroupT five = bigint<1>(5l) * GroupT::one(); GroupT three = bigint<1>(3l) * GroupT::one(); GroupT four = bigint<1>(4l) * GroupT::one(); - assert(two+five == three+four); + EXPECT_EQ(two+five, three+four); GroupT a = GroupT::random_element(); GroupT b = GroupT::random_element(); - assert(one != zero); - assert(a != zero); - assert(a != one); + EXPECT_NE(one, zero); + EXPECT_NE(a, zero); + EXPECT_NE(a, one); - assert(b != zero); - assert(b != one); + EXPECT_NE(b, zero); + EXPECT_NE(b, one); - assert(a.dbl() == a + a); - assert(b.dbl() == b + b); - assert(one.add(two) == three); - assert(two.add(one) == three); - assert(a + b == b + a); - assert(a - a == zero); - assert(a - b == a + (-b)); - assert(a - b == (-b) + a); + EXPECT_EQ(a.dbl(), a + a); + EXPECT_EQ(b.dbl(), b + b); + EXPECT_EQ(one.add(two), three); + EXPECT_EQ(two.add(one), three); + EXPECT_EQ(a + b, b + a); + EXPECT_EQ(a - a, zero); + EXPECT_EQ(a - b, a + (-b)); + EXPECT_EQ(a - b, (-b) + a); // handle special cases - assert(zero + (-a) == -a); - assert(zero - a == -a); - assert(a - zero == a); - assert(a + zero == a); - assert(zero + a == a); + EXPECT_EQ(zero + (-a), -a); + EXPECT_EQ(zero - a, -a); + EXPECT_EQ(a - zero, a); + EXPECT_EQ(a + zero, a); + EXPECT_EQ(zero + a, a); - assert((a + b).dbl() == (a + b) + (b + a)); - assert(bigint<1>("2") * (a + b) == (a + b) + (b + a)); + EXPECT_EQ((a + b).dbl(), (a + b) + (b + a)); + EXPECT_EQ(bigint<1>("2") * (a + b), (a + b) + (b + a)); - assert((rand1 * a) + (rand2 * a) == (randsum * a)); + EXPECT_EQ((rand1 * a) + (rand2 * a), (randsum * a)); - assert(GroupT::order() * a == zero); - assert(GroupT::order() * one == zero); - assert((GroupT::order() * a) - a != zero); - assert((GroupT::order() * one) - one != zero); + EXPECT_EQ(GroupT::order() * a, zero); + EXPECT_EQ(GroupT::order() * one, zero); + EXPECT_NE((GroupT::order() * a) - a, zero); + EXPECT_NE((GroupT::order() * one) - one, zero); test_mixed_add(); } @@ -115,7 +117,7 @@ template void test_mul_by_q() { GroupT a = GroupT::random_element(); - assert((GroupT::base_field_char()*a) == a.mul_by_q()); + EXPECT_EQ((GroupT::base_field_char()*a), a.mul_by_q()); } template @@ -129,13 +131,13 @@ void test_output() ss << g; GroupT gg; ss >> gg; - assert(g == gg); + EXPECT_EQ(g, gg); /* use a random point in next iteration */ g = GroupT::random_element(); } } -int main(void) +TEST(algebra, groups) { edwards_pp::init_public_params(); test_group >(); diff --git a/src/snark/src/algebra/fields/tests/test_bigint.cpp b/src/snark/src/algebra/fields/tests/test_bigint.cpp index b66aae0a3e4..d2da59e736a 100644 --- a/src/snark/src/algebra/fields/tests/test_bigint.cpp +++ b/src/snark/src/algebra/fields/tests/test_bigint.cpp @@ -7,9 +7,11 @@ #include "algebra/fields/bigint.hpp" +#include + using namespace libsnark; -void test_bigint() +TEST(algebra, bigint) { static_assert(ULONG_MAX == 0xFFFFFFFFFFFFFFFFul, "unsigned long not 64-bit"); static_assert(GMP_NUMB_BITS == 64, "GMP limb not 64-bit"); @@ -24,84 +26,72 @@ void test_bigint() bigint<1> b1 = bigint<1>(b1_decimal); bigint<2> b2 = bigint<2>(b2_decimal); - assert(b0.as_ulong() == 0ul); - assert(b0.is_zero()); - assert(b1.as_ulong() == 76749407ul); - assert(!(b1.is_zero())); - assert(b2.as_ulong() == 15747124762497195938ul); - assert(!(b2.is_zero())); - assert(b0 != b1); - assert(!(b0 == b1)); - - assert(b2.max_bits() == 128); - assert(b2.num_bits() == 99); + EXPECT_EQ(b0.as_ulong(), 0ul); + EXPECT_TRUE(b0.is_zero()); + EXPECT_EQ(b1.as_ulong(), 76749407ul); + EXPECT_FALSE(b1.is_zero()); + EXPECT_EQ(b2.as_ulong(), 15747124762497195938ul); + EXPECT_FALSE(b2.is_zero()); + EXPECT_NE(b0, b1); + EXPECT_FALSE(b0 == b1); + + EXPECT_EQ(b2.max_bits(), 128); + EXPECT_EQ(b2.num_bits(), 99); for (size_t i = 0; i < 128; i++) { - assert(b2.test_bit(i) == (b2_binary[127-i] == '1')); + EXPECT_EQ(b2.test_bit(i), (b2_binary[127-i] == '1')); } bigint<3> b3 = b2 * b1; - assert(b3 == bigint<3>(b3_decimal)); - assert(!(b3.is_zero())); + EXPECT_EQ(b3, bigint<3>(b3_decimal)); + EXPECT_FALSE(b3.is_zero()); bigint<3> b3a { b3 }; - assert(b3a == bigint<3>(b3_decimal)); - assert(b3a == b3); - assert(!(b3a.is_zero())); + EXPECT_EQ(b3a, bigint<3>(b3_decimal)); + EXPECT_EQ(b3a, b3); + EXPECT_FALSE(b3a.is_zero()); mpz_t m3; mpz_init(m3); b3.to_mpz(m3); bigint<3> b3b { m3 }; - assert(b3b == b3); + EXPECT_EQ(b3b, b3); bigint<2> quotient; bigint<2> remainder; bigint<3>::div_qr(quotient, remainder, b3, b2); - assert(quotient.num_bits() < GMP_NUMB_BITS); - assert(quotient.as_ulong() == b1.as_ulong()); + EXPECT_LT(quotient.num_bits(), GMP_NUMB_BITS); + EXPECT_EQ(quotient.as_ulong(), b1.as_ulong()); bigint<1> b1inc = bigint<1>("76749408"); bigint<1> b1a = quotient.shorten(b1inc, "test"); - assert(b1a == b1); - assert(remainder.is_zero()); + EXPECT_EQ(b1a, b1); + EXPECT_TRUE(remainder.is_zero()); remainder.limit(b2, "test"); - try { - (void)(quotient.shorten(b1, "test")); - assert(false); - } catch (std::domain_error) {} - try { - remainder.limit(remainder, "test"); - assert(false); - } catch (std::domain_error) {} + EXPECT_THROW((void)(quotient.shorten(b1, "test")), std::domain_error); + EXPECT_THROW(remainder.limit(remainder, "test"), std::domain_error); bigint<1> br = bigint<1>("42"); b3 += br; - assert(b3 != b3a); - assert(b3 > b3a); - assert(!(b3a > b3)); + EXPECT_NE(b3, b3a); + EXPECT_GT(b3, b3a); + EXPECT_FALSE(b3a > b3); bigint<3>::div_qr(quotient, remainder, b3, b2); - assert(quotient.num_bits() < GMP_NUMB_BITS); - assert(quotient.as_ulong() == b1.as_ulong()); - assert(remainder.num_bits() < GMP_NUMB_BITS); - assert(remainder.as_ulong() == 42); + EXPECT_LT(quotient.num_bits(), GMP_NUMB_BITS); + EXPECT_EQ(quotient.as_ulong(), b1.as_ulong()); + EXPECT_LT(remainder.num_bits(), GMP_NUMB_BITS); + EXPECT_EQ(remainder.as_ulong(), 42); b3a.clear(); - assert(b3a.is_zero()); - assert(b3a.num_bits() == 0); - assert(!(b3.is_zero())); + EXPECT_TRUE(b3a.is_zero()); + EXPECT_EQ(b3a.num_bits(), 0); + EXPECT_FALSE(b3.is_zero()); bigint<4> bx = bigint<4>().randomize(); bigint<4> by = bigint<4>().randomize(); - assert(!(bx == by)); + EXPECT_FALSE(bx == by); // TODO: test serialization } -int main(void) -{ - test_bigint(); - return 0; -} - diff --git a/src/snark/src/algebra/fields/tests/test_fields.cpp b/src/snark/src/algebra/fields/tests/test_fields.cpp index a05f601e690..f4fc3319af4 100644 --- a/src/snark/src/algebra/fields/tests/test_fields.cpp +++ b/src/snark/src/algebra/fields/tests/test_fields.cpp @@ -15,6 +15,8 @@ #include "algebra/fields/fp6_3over2.hpp" #include "algebra/fields/fp12_2over3over2.hpp" +#include + using namespace libsnark; template @@ -29,25 +31,25 @@ void test_field() FieldT a = FieldT::random_element(); FieldT a_ser; a_ser = reserialize(a); - assert(a_ser == a); + EXPECT_EQ(a_ser, a); FieldT b = FieldT::random_element(); FieldT c = FieldT::random_element(); FieldT d = FieldT::random_element(); - assert(a != zero); - assert(a != one); + EXPECT_NE(a, zero); + EXPECT_NE(a, one); - assert(a * a == a.squared()); - assert((a + b).squared() == a.squared() + a*b + b*a + b.squared()); - assert((a + b)*(c + d) == a*c + a*d + b*c + b*d); - assert(a - b == a + (-b)); - assert(a - b == (-b) + a); + EXPECT_EQ(a * a, a.squared()); + EXPECT_EQ((a + b).squared(), a.squared() + a*b + b*a + b.squared()); + EXPECT_EQ((a + b)*(c + d), a*c + a*d + b*c + b*d); + EXPECT_EQ(a - b, a + (-b)); + EXPECT_EQ(a - b, (-b) + a); - assert((a ^ rand1) * (a ^ rand2) == (a^randsum)); + EXPECT_EQ((a ^ rand1) * (a ^ rand2), (a^randsum)); - assert(a * a.inverse() == one); - assert((a + b) * c.inverse() == a * c.inverse() + (b.inverse() * c).inverse()); + EXPECT_EQ(a * a.inverse(), one); + EXPECT_EQ((a + b) * c.inverse(), a * c.inverse() + (b.inverse() * c).inverse()); } @@ -58,7 +60,7 @@ void test_sqrt() { FieldT a = FieldT::random_element(); FieldT asq = a.squared(); - assert(asq.sqrt() == a || asq.sqrt() == -a); + EXPECT_TRUE(asq.sqrt() == a || asq.sqrt() == -a); } } @@ -66,21 +68,21 @@ template void test_two_squarings() { FieldT a = FieldT::random_element(); - assert(a.squared() == a * a); - assert(a.squared() == a.squared_complex()); - assert(a.squared() == a.squared_karatsuba()); + EXPECT_EQ(a.squared(), a * a); + EXPECT_EQ(a.squared(), a.squared_complex()); + EXPECT_EQ(a.squared(), a.squared_karatsuba()); } template void test_Frobenius() { FieldT a = FieldT::random_element(); - assert(a.Frobenius_map(0) == a); + EXPECT_EQ(a.Frobenius_map(0), a); FieldT a_q = a ^ FieldT::base_field_char(); for (size_t power = 1; power < 10; ++power) { const FieldT a_qi = a.Frobenius_map(power); - assert(a_qi == a_q); + EXPECT_EQ(a_qi, a_q); a_q = a_q ^ FieldT::base_field_char(); } @@ -89,10 +91,10 @@ void test_Frobenius() template void test_unitary_inverse() { - assert(FieldT::extension_degree() % 2 == 0); + EXPECT_EQ(FieldT::extension_degree() % 2, 0); FieldT a = FieldT::random_element(); FieldT aqcubed_minus1 = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); - assert(aqcubed_minus1.inverse() == aqcubed_minus1.unitary_inverse()); + EXPECT_EQ(aqcubed_minus1.inverse(), aqcubed_minus1.unitary_inverse()); } template @@ -102,36 +104,36 @@ template<> void test_cyclotomic_squaring >() { typedef Fqk FieldT; - assert(FieldT::extension_degree() % 2 == 0); + EXPECT_EQ(FieldT::extension_degree() % 2, 0); FieldT a = FieldT::random_element(); FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); // beta = a^((q^(k/2)-1)*(q+1)) FieldT beta = a_unitary.Frobenius_map(1) * a_unitary; - assert(beta.cyclotomic_squared() == beta.squared()); + EXPECT_EQ(beta.cyclotomic_squared(), beta.squared()); } template<> void test_cyclotomic_squaring >() { typedef Fqk FieldT; - assert(FieldT::extension_degree() % 2 == 0); + EXPECT_EQ(FieldT::extension_degree() % 2, 0); FieldT a = FieldT::random_element(); FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); // beta = a^(q^(k/2)-1) FieldT beta = a_unitary; - assert(beta.cyclotomic_squared() == beta.squared()); + EXPECT_EQ(beta.cyclotomic_squared(), beta.squared()); } template<> void test_cyclotomic_squaring >() { typedef Fqk FieldT; - assert(FieldT::extension_degree() % 2 == 0); + EXPECT_EQ(FieldT::extension_degree() % 2, 0); FieldT a = FieldT::random_element(); FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); // beta = a^((q^(k/2)-1)*(q+1)) FieldT beta = a_unitary.Frobenius_map(1) * a_unitary; - assert(beta.cyclotomic_squared() == beta.squared()); + EXPECT_EQ(beta.cyclotomic_squared(), beta.squared()); } template @@ -197,16 +199,16 @@ void test_Fp4_tom_cook() c2 = - (FieldT(5)*(FieldT(4).inverse()))* v0 + (FieldT(2)*(FieldT(3).inverse()))*(v1 + v2) - FieldT(24).inverse()*(v3 + v4) + FieldT(4)*v6 + beta*v6; c3 = FieldT(12).inverse() * (FieldT(5)*v0 - FieldT(7)*v1) - FieldT(24).inverse()*(v2 - FieldT(7)*v3 + v4 + v5) + FieldT(15)*v6; - assert(res == correct_res); + EXPECT_EQ(res, correct_res); // {v0, v3, v4, v5} const FieldT u = (FieldT::one() - beta).inverse(); - assert(v0 == u * c0 + beta * u * c2 - beta * u * FieldT(2).inverse() * v1 - beta * u * FieldT(2).inverse() * v2 + beta * v6); - assert(v3 == - FieldT(15) * u * c0 - FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 - FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v1 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v2 + EXPECT_EQ(v0, u * c0 + beta * u * c2 - beta * u * FieldT(2).inverse() * v1 - beta * u * FieldT(2).inverse() * v2 + beta * v6); + EXPECT_EQ(v3, - FieldT(15) * u * c0 - FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 - FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v1 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v2 - FieldT(3) * (-FieldT(16) + beta) * v6); - assert(v4 == - FieldT(15) * u * c0 + FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 + FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v2 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v1 + EXPECT_EQ(v4, - FieldT(15) * u * c0 + FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 + FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v2 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v1 - FieldT(3) * (-FieldT(16) + beta) * v6); - assert(v5 == - FieldT(80) * u * c0 - FieldT(240) * u * c1 - FieldT(8) * (FieldT(9) + beta) * u * c2 - FieldT(24) * (FieldT(9) + beta) * u * c3 - FieldT(2) * (-FieldT(81) + beta) * u * v1 + (-FieldT(81) + beta) * u * v2 + EXPECT_EQ(v5, - FieldT(80) * u * c0 - FieldT(240) * u * c1 - FieldT(8) * (FieldT(9) + beta) * u * c2 - FieldT(24) * (FieldT(9) + beta) * u * c3 - FieldT(2) * (-FieldT(81) + beta) * u * v1 + (-FieldT(81) + beta) * u * v2 - FieldT(8) * (-FieldT(81) + beta) * v6); // c0 + beta c2 - (beta v1)/2 - (beta v2)/ 2 - (-1 + beta) beta v6, @@ -216,7 +218,7 @@ void test_Fp4_tom_cook() } } -int main(void) +TEST(algebra, fields) { edwards_pp::init_public_params(); test_all_fields(); diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp b/src/snark/src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp index 471928f6ab3..0bfaf3a125f 100644 --- a/src/snark/src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp +++ b/src/snark/src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp @@ -10,6 +10,8 @@ #include "common/profiling.hpp" #include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" +#include + using namespace libsnark; template @@ -35,10 +37,10 @@ void test_two_to_one() f.generate_r1cs_witness(); output.generate_r1cs_witness(hash_bv); - assert(pb.is_satisfied()); + EXPECT_TRUE(pb.is_satisfied()); } -int main(void) +TEST(gadgetlib1, sha256) { start_profiling(); default_ec_pp::init_public_params(); diff --git a/src/snark/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp b/src/snark/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp index 8d52c579b72..955a054407e 100644 --- a/src/snark/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp +++ b/src/snark/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp @@ -15,6 +15,8 @@ #include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp" #include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" +#include + using namespace libsnark; template @@ -28,7 +30,7 @@ void test_all_merkle_tree_gadgets() test_merkle_tree_check_update_gadget >(); } -int main(void) +TEST(gadgetlib1, merkle_tree) { start_profiling(); diff --git a/src/snark/src/relations/arithmetic_programs/qap/tests/test_qap.cpp b/src/snark/src/relations/arithmetic_programs/qap/tests/test_qap.cpp index d8aaddaa704..d776629262d 100644 --- a/src/snark/src/relations/arithmetic_programs/qap/tests/test_qap.cpp +++ b/src/snark/src/relations/arithmetic_programs/qap/tests/test_qap.cpp @@ -17,6 +17,8 @@ #include "reductions/r1cs_to_qap/r1cs_to_qap.hpp" #include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" +#include + using namespace libsnark; template @@ -28,7 +30,7 @@ void test_qap(const size_t qap_degree, const size_t num_inputs, const bool binar See the transformation from R1CS to QAP for why this is the case. So we need that qap_degree >= num_inputs + 1. */ - assert(num_inputs + 1 <= qap_degree); + ASSERT_LE(num_inputs + 1, qap_degree); enter_block("Call to test_qap"); const size_t num_constraints = qap_degree - num_inputs - 1; @@ -51,7 +53,7 @@ void test_qap(const size_t qap_degree, const size_t num_inputs, const bool binar leave_block("Generate constraint system and assignment"); enter_block("Check satisfiability of constraint system"); - assert(example.constraint_system.is_satisfied(example.primary_input, example.auxiliary_input)); + EXPECT_TRUE(example.constraint_system.is_satisfied(example.primary_input, example.auxiliary_input)); leave_block("Check satisfiability of constraint system"); const FieldT t = FieldT::random_element(), @@ -72,17 +74,17 @@ void test_qap(const size_t qap_degree, const size_t num_inputs, const bool binar leave_block("Compute QAP witness"); enter_block("Check satisfiability of QAP instance 1"); - assert(qap_inst_1.is_satisfied(qap_wit)); + EXPECT_TRUE(qap_inst_1.is_satisfied(qap_wit)); leave_block("Check satisfiability of QAP instance 1"); enter_block("Check satisfiability of QAP instance 2"); - assert(qap_inst_2.is_satisfied(qap_wit)); + EXPECT_TRUE(qap_inst_2.is_satisfied(qap_wit)); leave_block("Check satisfiability of QAP instance 2"); leave_block("Call to test_qap"); } -int main() +TEST(relations, qap) { start_profiling(); diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp b/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp index 6f8b575f207..36b5735490a 100644 --- a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp +++ b/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp @@ -17,6 +17,8 @@ #include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" #include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp" +#include + using namespace libsnark; template @@ -28,12 +30,12 @@ void test_r1cs_ppzksnark(size_t num_constraints, const bool test_serialization = true; r1cs_example > example = generate_r1cs_example_with_binary_input >(num_constraints, input_size); const bool bit = run_r1cs_ppzksnark(example, test_serialization); - assert(bit); + EXPECT_TRUE(bit); print_header("(leave) Test R1CS ppzkSNARK"); } -int main() +TEST(zk_proof_systems, r1cs_ppzksnark) { default_r1cs_ppzksnark_pp::init_public_params(); start_profiling(); From df3083fe4e90cd7f1d501f37c813cb37f2ff8687 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 11 Oct 2017 14:56:25 +0100 Subject: [PATCH 031/177] Remove test code corresponding to removed code --- .../algebra/curves/tests/test_bilinearity.cpp | 17 ------ .../src/algebra/curves/tests/test_groups.cpp | 24 -------- .../src/algebra/fields/tests/test_fields.cpp | 56 ------------------- .../merkle_tree_check_update_gadget.hpp | 1 - .../tests/test_merkle_tree_gadgets.cpp | 14 ----- .../qap/tests/test_qap.cpp | 18 ------ 6 files changed, 130 deletions(-) diff --git a/src/snark/src/algebra/curves/tests/test_bilinearity.cpp b/src/snark/src/algebra/curves/tests/test_bilinearity.cpp index 529bec33738..fe6593baeef 100644 --- a/src/snark/src/algebra/curves/tests/test_bilinearity.cpp +++ b/src/snark/src/algebra/curves/tests/test_bilinearity.cpp @@ -5,13 +5,10 @@ * @copyright MIT license (see LICENSE file) *****************************************************************************/ #include "common/profiling.hpp" -#include "algebra/curves/edwards/edwards_pp.hpp" #ifdef CURVE_BN128 #include "algebra/curves/bn128/bn128_pp.hpp" #endif #include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" -#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" -#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" #include @@ -112,20 +109,6 @@ void affine_pairing_test() TEST(algebra, bilinearity) { start_profiling(); - edwards_pp::init_public_params(); - pairing_test(); - double_miller_loop_test(); - - mnt6_pp::init_public_params(); - pairing_test(); - double_miller_loop_test(); - affine_pairing_test(); - - mnt4_pp::init_public_params(); - pairing_test(); - double_miller_loop_test(); - affine_pairing_test(); - alt_bn128_pp::init_public_params(); pairing_test(); double_miller_loop_test(); diff --git a/src/snark/src/algebra/curves/tests/test_groups.cpp b/src/snark/src/algebra/curves/tests/test_groups.cpp index 087ee3d5255..7bb7c31ccfa 100644 --- a/src/snark/src/algebra/curves/tests/test_groups.cpp +++ b/src/snark/src/algebra/curves/tests/test_groups.cpp @@ -5,9 +5,6 @@ * @copyright MIT license (see LICENSE file) *****************************************************************************/ #include "common/profiling.hpp" -#include "algebra/curves/edwards/edwards_pp.hpp" -#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" -#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" #ifdef CURVE_BN128 #include "algebra/curves/bn128/bn128_pp.hpp" #endif @@ -139,27 +136,6 @@ void test_output() TEST(algebra, groups) { - edwards_pp::init_public_params(); - test_group >(); - test_output >(); - test_group >(); - test_output >(); - test_mul_by_q >(); - - mnt4_pp::init_public_params(); - test_group >(); - test_output >(); - test_group >(); - test_output >(); - test_mul_by_q >(); - - mnt6_pp::init_public_params(); - test_group >(); - test_output >(); - test_group >(); - test_output >(); - test_mul_by_q >(); - alt_bn128_pp::init_public_params(); test_group >(); test_output >(); diff --git a/src/snark/src/algebra/fields/tests/test_fields.cpp b/src/snark/src/algebra/fields/tests/test_fields.cpp index f4fc3319af4..969800d8b58 100644 --- a/src/snark/src/algebra/fields/tests/test_fields.cpp +++ b/src/snark/src/algebra/fields/tests/test_fields.cpp @@ -5,9 +5,6 @@ * @copyright MIT license (see LICENSE file) *****************************************************************************/ #include "common/profiling.hpp" -#include "algebra/curves/edwards/edwards_pp.hpp" -#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" -#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" #ifdef CURVE_BN128 #include "algebra/curves/bn128/bn128_pp.hpp" #endif @@ -97,45 +94,6 @@ void test_unitary_inverse() EXPECT_EQ(aqcubed_minus1.inverse(), aqcubed_minus1.unitary_inverse()); } -template -void test_cyclotomic_squaring(); - -template<> -void test_cyclotomic_squaring >() -{ - typedef Fqk FieldT; - EXPECT_EQ(FieldT::extension_degree() % 2, 0); - FieldT a = FieldT::random_element(); - FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); - // beta = a^((q^(k/2)-1)*(q+1)) - FieldT beta = a_unitary.Frobenius_map(1) * a_unitary; - EXPECT_EQ(beta.cyclotomic_squared(), beta.squared()); -} - -template<> -void test_cyclotomic_squaring >() -{ - typedef Fqk FieldT; - EXPECT_EQ(FieldT::extension_degree() % 2, 0); - FieldT a = FieldT::random_element(); - FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); - // beta = a^(q^(k/2)-1) - FieldT beta = a_unitary; - EXPECT_EQ(beta.cyclotomic_squared(), beta.squared()); -} - -template<> -void test_cyclotomic_squaring >() -{ - typedef Fqk FieldT; - EXPECT_EQ(FieldT::extension_degree() % 2, 0); - FieldT a = FieldT::random_element(); - FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); - // beta = a^((q^(k/2)-1)*(q+1)) - FieldT beta = a_unitary.Frobenius_map(1) * a_unitary; - EXPECT_EQ(beta.cyclotomic_squared(), beta.squared()); -} - template void test_all_fields() { @@ -220,20 +178,6 @@ void test_Fp4_tom_cook() TEST(algebra, fields) { - edwards_pp::init_public_params(); - test_all_fields(); - test_cyclotomic_squaring >(); - - mnt4_pp::init_public_params(); - test_all_fields(); - test_Fp4_tom_cook(); - test_two_squarings >(); - test_cyclotomic_squaring >(); - - mnt6_pp::init_public_params(); - test_all_fields(); - test_cyclotomic_squaring >(); - alt_bn128_pp::init_public_params(); test_field(); test_Frobenius(); diff --git a/src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp b/src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp index 2d6840d6195..6ec0ca11ff6 100644 --- a/src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp +++ b/src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp @@ -19,7 +19,6 @@ #include "common/data_structures/merkle_tree.hpp" #include "gadgetlib1/gadget.hpp" -#include "gadgetlib1/gadgets/hashes/crh_gadget.hpp" #include "gadgetlib1/gadgets/hashes/hash_io.hpp" #include "gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp" #include "gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp" diff --git a/src/snark/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp b/src/snark/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp index 955a054407e..5f454687fd3 100644 --- a/src/snark/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp +++ b/src/snark/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp @@ -8,9 +8,6 @@ #ifdef CURVE_BN128 #include "algebra/curves/bn128/bn128_pp.hpp" #endif -#include "algebra/curves/edwards/edwards_pp.hpp" -#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" -#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" #include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp" #include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp" #include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" @@ -23,10 +20,8 @@ template void test_all_merkle_tree_gadgets() { typedef Fr FieldT; - test_merkle_tree_check_read_gadget >(); test_merkle_tree_check_read_gadget >(); - test_merkle_tree_check_update_gadget >(); test_merkle_tree_check_update_gadget >(); } @@ -38,13 +33,4 @@ TEST(gadgetlib1, merkle_tree) bn128_pp::init_public_params(); test_all_merkle_tree_gadgets(); #endif - - edwards_pp::init_public_params(); - test_all_merkle_tree_gadgets(); - - mnt4_pp::init_public_params(); - test_all_merkle_tree_gadgets(); - - mnt6_pp::init_public_params(); - test_all_merkle_tree_gadgets(); } diff --git a/src/snark/src/relations/arithmetic_programs/qap/tests/test_qap.cpp b/src/snark/src/relations/arithmetic_programs/qap/tests/test_qap.cpp index d776629262d..2cfa4fc92ce 100644 --- a/src/snark/src/relations/arithmetic_programs/qap/tests/test_qap.cpp +++ b/src/snark/src/relations/arithmetic_programs/qap/tests/test_qap.cpp @@ -10,7 +10,6 @@ #include #include -#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" #include "algebra/fields/field_utils.hpp" #include "common/profiling.hpp" #include "common/utils.hpp" @@ -88,30 +87,13 @@ TEST(relations, qap) { start_profiling(); - mnt6_pp::init_public_params(); - const size_t num_inputs = 10; - const size_t basic_domain_size = 1ul< >(basic_domain_size, num_inputs, true); - test_qap >(step_domain_size, num_inputs, true); - test_qap >(extended_domain_size, num_inputs, true); - test_qap >(extended_domain_size_special, num_inputs, true); - leave_block("Test QAP with binary input"); enter_block("Test QAP with field input"); - test_qap >(basic_domain_size, num_inputs, false); - test_qap >(step_domain_size, num_inputs, false); - test_qap >(extended_domain_size, num_inputs, false); - test_qap >(extended_domain_size_special, num_inputs, false); - leave_block("Test QAP with field input"); } From 4699d0eb36e2049f692ead9f44c5886ba87a007c Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 11 Oct 2017 15:18:01 +0100 Subject: [PATCH 032/177] Add alt_bn128 to QAP and Merkle tree gadget tests --- .../gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp | 4 ++++ .../src/relations/arithmetic_programs/qap/tests/test_qap.cpp | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/snark/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp b/src/snark/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp index 5f454687fd3..27b52f9ec29 100644 --- a/src/snark/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp +++ b/src/snark/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp @@ -5,6 +5,7 @@ * @copyright MIT license (see LICENSE file) *****************************************************************************/ +#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" #ifdef CURVE_BN128 #include "algebra/curves/bn128/bn128_pp.hpp" #endif @@ -29,6 +30,9 @@ TEST(gadgetlib1, merkle_tree) { start_profiling(); + alt_bn128_pp::init_public_params(); + test_all_merkle_tree_gadgets(); + #ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled bn128_pp::init_public_params(); test_all_merkle_tree_gadgets(); diff --git a/src/snark/src/relations/arithmetic_programs/qap/tests/test_qap.cpp b/src/snark/src/relations/arithmetic_programs/qap/tests/test_qap.cpp index 2cfa4fc92ce..e20f589c9dd 100644 --- a/src/snark/src/relations/arithmetic_programs/qap/tests/test_qap.cpp +++ b/src/snark/src/relations/arithmetic_programs/qap/tests/test_qap.cpp @@ -10,6 +10,7 @@ #include #include +#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" #include "algebra/fields/field_utils.hpp" #include "common/profiling.hpp" #include "common/utils.hpp" @@ -91,9 +92,13 @@ TEST(relations, qap) enter_block("Test QAP with binary input"); + test_qap >(1ul << 21, num_inputs, true); + leave_block("Test QAP with binary input"); enter_block("Test QAP with field input"); + test_qap >(1ul << 21, num_inputs, false); + leave_block("Test QAP with field input"); } From 638e742f3f32f8a65e8133f597d2813acad8ab93 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 11 Oct 2017 15:19:33 +0100 Subject: [PATCH 033/177] Update libsnark LDLIBS -lsodium is necessary as we altered libsnark to use libsodium's RNG. --- src/snark/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/snark/Makefile b/src/snark/Makefile index fe565a9060f..f069d1b0cfe 100644 --- a/src/snark/Makefile +++ b/src/snark/Makefile @@ -19,7 +19,7 @@ DEPINST = depinst CXXFLAGS += -I$(DEPINST)/include -Isrc LDFLAGS += -L$(DEPINST)/lib -Wl,-rpath,$(DEPINST)/lib -LDLIBS += -lgmpxx -lgmp -lboost_program_options +LDLIBS += -lgmpxx -lgmp -lboost_program_options-mt -lsodium # OpenSSL and its dependencies (needed explicitly for static builds): LDLIBS += -lcrypto -ldl -lz # List of .a files to include within libsnark.a and libsnark.so: From 19f6668c27d1838999b1be7dc280a6788d535884 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 11 Oct 2017 15:21:44 +0100 Subject: [PATCH 034/177] Add "make check" to libsnark that runs the Google Tests --- src/snark/Makefile | 46 ++++++++++++++++++++++++---------------- src/snark/src/gtests.cpp | 12 +++++++++++ 2 files changed, 40 insertions(+), 18 deletions(-) create mode 100644 src/snark/src/gtests.cpp diff --git a/src/snark/Makefile b/src/snark/Makefile index f069d1b0cfe..427f4f4ce98 100644 --- a/src/snark/Makefile +++ b/src/snark/Makefile @@ -70,20 +70,14 @@ endif # FIXME: most of these are broken due to removed code. DISABLED_EXECUTABLES = \ - src/algebra/curves/tests/test_bilinearity \ - src/algebra/curves/tests/test_groups \ - src/algebra/fields/tests/test_fields \ src/common/routing_algorithms/profiling/profile_routing_algorithms \ src/common/routing_algorithms/tests/test_routing_algorithms \ src/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram \ src/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget \ - src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget \ - src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets \ src/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets \ src/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget \ src/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget \ src/reductions/ram_to_r1cs/examples/demo_arithmetization \ - src/relations/arithmetic_programs/qap/tests/test_qap \ src/relations/arithmetic_programs/ssp/tests/test_ssp \ src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd \ src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd \ @@ -94,7 +88,6 @@ DISABLED_EXECUTABLES = \ src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark \ src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark \ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark \ - src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark \ src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark \ src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator \ src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover \ @@ -108,16 +101,26 @@ DISABLED_EXECUTABLES = \ src/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark \ src/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark -EXECUTABLES = \ - src/algebra/fields/tests/test_bigint +EXECUTABLES = -EXECUTABLES_WITH_GTEST = \ - src/gadgetlib2/examples/tutorial \ - src/gadgetlib2/tests/gadgetlib2_test +EXECUTABLES_WITH_GTEST = EXECUTABLES_WITH_SUPERCOP = \ src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark +GTEST_TESTS = src/gtests + +GTEST_SRCS = \ + src/algebra/curves/tests/test_bilinearity.cpp \ + src/algebra/curves/tests/test_groups.cpp \ + src/algebra/fields/tests/test_bigint.cpp \ + src/algebra/fields/tests/test_fields.cpp \ + src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp \ + src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp \ + src/relations/arithmetic_programs/qap/tests/test_qap.cpp \ + src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp \ + src/gtests.cpp + DOCS = README.html LIBSNARK_A = libsnark.a @@ -168,9 +171,10 @@ endif LIB_OBJS =$(patsubst %.cpp,%.o,$(LIB_SRCS)) EXEC_OBJS =$(patsubst %,%.o,$(EXECUTABLES) $(EXECUTABLES_WITH_GTEST) $(EXECUTABLES_WITH_SUPERCOP)) +GTEST_OBJS =$(patsubst %.cpp,%.o,$(GTEST_SRCS)) all: \ - $(if $(NO_GTEST),,$(EXECUTABLES_WITH_GTEST)) \ + $(if $(NO_GTEST),,$(EXECUTABLES_WITH_GTEST) $(GTEST_TESTS)) \ $(if $(NO_SUPERCOP),,$(EXECUTABLES_WITH_SUPERCOP)) \ $(EXECUTABLES) \ $(if $(NO_DOCS),,doc) @@ -183,9 +187,9 @@ $(DEPINST_EXISTS): touch $@ # In order to detect changes to #include dependencies. -MMD below generates a .d file for each .o file. Include the .d file. --include $(patsubst %.o,%.d, $(LIB_OBJS) $(EXEC_OBJS) ) +-include $(patsubst %.o,%.d, $(LIB_OBJS) $(GTEST_OBJS) $(EXEC_OBJS) ) -$(LIB_OBJS) $(EXEC_OBJS): %.o: %.cpp +$(LIB_OBJS) $(if $(NO_GTEST),,$(GTEST_OBJS)) $(EXEC_OBJS): %.o: %.cpp $(CXX) -o $@ $< -c -MMD $(CXXFLAGS) LIBGTEST_A = $(DEPINST)/lib/libgtest.a @@ -225,6 +229,9 @@ $(EXECUTABLES_WITH_GTEST): %: %.o $(LIBSNARK_A) $(if $(COMPILE_GTEST),$(LIBGTEST $(EXECUTABLES_WITH_SUPERCOP): %: %.o $(LIBSNARK_A) $(DEPINST_EXISTS) $(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(SUPERCOP_LDLIBS) $(LDLIBS) +$(GTEST_TESTS): %: $(GTEST_OBJS) $(LIBSNARK_A) $(if $(COMPILE_GTEST),$(LIBGTEST_A)) $(DEPINST_EXISTS) + $(CXX) -o $@ $(GTEST_OBJS) $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(GTEST_LDLIBS) $(LDLIBS) + ifeq ($(STATIC),1) LIB_FILE = $(LIBSNARK_A) @@ -258,16 +265,19 @@ ifneq ($(NO_COPY_DEPINST),1) endif endif +check: $(GTEST_TESTS) + $(GTEST_TESTS) + doxy: doxygen doxygen.conf # Clean generated files, except locally-compiled dependencies clean: $(RM) \ - $(LIB_OBJS) $(EXEC_OBJS) \ - $(EXECUTABLES) $(EXECUTABLES_WITH_GTEST) $(EXECUTABLES_WITH_SUPERCOP) \ + $(LIB_OBJS) $(GTEST_OBJS) $(EXEC_OBJS) \ + $(EXECUTABLES) $(EXECUTABLES_WITH_GTEST) $(EXECUTABLES_WITH_SUPERCOP) $(GTEST_TESTS) \ $(DOCS) \ - ${patsubst %.o,%.d,${LIB_OBJS} ${EXEC_OBJS}} \ + ${patsubst %.o,%.d,${LIB_OBJS} ${GTEST_OBJS} ${EXEC_OBJS}} \ libsnark.so $(LIBSNARK_A) \ $(RM) -fr doxygen/ \ $(RM) $(LIBGTEST_A) $(DEPINST)/lib/gtest-all.o diff --git a/src/snark/src/gtests.cpp b/src/snark/src/gtests.cpp new file mode 100644 index 00000000000..74c66bdada6 --- /dev/null +++ b/src/snark/src/gtests.cpp @@ -0,0 +1,12 @@ +#include + +#include "common/profiling.hpp" + +int main(int argc, char **argv) { + libsnark::inhibit_profiling_info = true; + libsnark::inhibit_profiling_counters = true; + + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + From 82e839e4ff52e78a208b762f158dfcec5a20b058 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 11 Oct 2017 15:22:24 +0100 Subject: [PATCH 035/177] Add "make libsnark-tests" that runs libsnark's "make check" --- src/Makefile.am | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index ab3c7bc4c55..3cbe026728e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -41,8 +41,14 @@ LIBZCASH=libzcash.a $(LIBSECP256K1): $(LIBSNARK) $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) +LIBSNARK_CXXFLAGS = -fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1 +LIBSNARK_CONFIG_FLAGS = CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT NO_COPY_DEPINST=1 + $(LIBSNARK): $(wildcard snark/src/*) - CXXFLAGS="-fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1" $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C snark/ install PREFIX=$(srcdir)/build DEPINST=$(prefix) CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT NO_COPY_DEPINST=1 OPTFLAGS="-O2 -march=x86-64" + $(AM_V_at) CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ install PREFIX=$(srcdir)/build DEPINST=$(prefix) $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" + +libsnark-tests: $(wildcard snark/src/*) + $(AM_V_at) CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ check PREFIX=$(srcdir)/build DEPINST=$(prefix) $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" $(LIBUNIVALUE): $(wildcard univalue/lib/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue/ From 8598c20d40e2b1f3fa466620457a2ae333e6c2a8 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 11 Oct 2017 15:31:42 +0100 Subject: [PATCH 036/177] Changes to get test_r1cs_ppzksnark passing --- .../r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc | 2 +- .../ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp | 3 ++- .../ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc b/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc index 9bc87586910..00af6fe25e3 100644 --- a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc +++ b/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc @@ -83,7 +83,7 @@ bool run_r1cs_ppzksnark(const r1cs_example > &example, } print_header("R1CS ppzkSNARK Prover"); - r1cs_ppzksnark_proof proof = r1cs_ppzksnark_prover(keypair.pk, example.primary_input, example.auxiliary_input); + r1cs_ppzksnark_proof proof = r1cs_ppzksnark_prover(keypair.pk, example.primary_input, example.auxiliary_input, example.constraint_system); printf("\n"); print_indent(); print_mem("after prover"); if (test_serialization) diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp b/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp index a068b09fde1..36f6c149996 100644 --- a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp +++ b/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp @@ -394,7 +394,8 @@ r1cs_ppzksnark_keypair r1cs_ppzksnark_generator( template r1cs_ppzksnark_proof r1cs_ppzksnark_prover(const r1cs_ppzksnark_proving_key &pk, const r1cs_ppzksnark_primary_input &primary_input, - const r1cs_ppzksnark_auxiliary_input &auxiliary_input); + const r1cs_ppzksnark_auxiliary_input &auxiliary_input, + const r1cs_ppzksnark_constraint_system &constraint_system); /* Below are four variants of verifier algorithm for the R1CS ppzkSNARK. diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp b/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp index 36b5735490a..6c6e51857f5 100644 --- a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp +++ b/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp @@ -11,7 +11,7 @@ #include #include -#include "common/default_types/r1cs_ppzksnark_pp.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" #include "common/profiling.hpp" #include "common/utils.hpp" #include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" @@ -29,6 +29,7 @@ void test_r1cs_ppzksnark(size_t num_constraints, const bool test_serialization = true; r1cs_example > example = generate_r1cs_example_with_binary_input >(num_constraints, input_size); + example.constraint_system.swap_AB_if_beneficial(); const bool bit = run_r1cs_ppzksnark(example, test_serialization); EXPECT_TRUE(bit); @@ -37,8 +38,7 @@ void test_r1cs_ppzksnark(size_t num_constraints, TEST(zk_proof_systems, r1cs_ppzksnark) { - default_r1cs_ppzksnark_pp::init_public_params(); start_profiling(); - test_r1cs_ppzksnark(1000, 100); + test_r1cs_ppzksnark(1000, 20); } From 147fffb7ec757612a0e32e3479f662415f67d87f Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Mon, 16 Oct 2017 08:39:59 -0700 Subject: [PATCH 037/177] Fix bug where performance-measurements.sh fails hards when given no args Better than "$1: unbound variable", we ran into this when testing this script in the Hush repo, so we are pushing this fix upstream. --- qa/zcash/performance-measurements.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/qa/zcash/performance-measurements.sh b/qa/zcash/performance-measurements.sh index 68de22892c4..fd7b30ffad5 100755 --- a/qa/zcash/performance-measurements.sh +++ b/qa/zcash/performance-measurements.sh @@ -154,6 +154,13 @@ EOF xzcat block-107134.tar.xz | tar x -C "$DATADIR/regtest" } + +if [ $# -lt 2 ] +then + echo "$0 : two arguments are required!" + exit 1 +fi + # Precomputation case "$1" in *) From 88fbdc48688f6d3f3bfaa5ae46a54e08e3571e83 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 16 Oct 2017 16:15:10 -0400 Subject: [PATCH 038/177] Add bitcoin-util-test.py to full_test_suite.py Not moved, because upstream makes improvements to this script, and the need to set environment variables makes it simpler to just use the given script. --- qa/zcash/full_test_suite.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/qa/zcash/full_test_suite.py b/qa/zcash/full_test_suite.py index 6e890c49a1b..ecdd3a39a59 100755 --- a/qa/zcash/full_test_suite.py +++ b/qa/zcash/full_test_suite.py @@ -110,6 +110,13 @@ def ensure_no_dot_so_in_depends(): return exit_code == 0 +def util_test(): + return subprocess.call( + [repofile('src/test/bitcoin-util-test.py')], + cwd=repofile('src'), + env={'PYTHONPATH': repofile('src/test'), 'srcdir': repofile('src')} + ) == 0 + # # Tests @@ -120,6 +127,7 @@ def ensure_no_dot_so_in_depends(): 'gtest', 'sec-hard', 'no-dot-so', + 'util-test', 'secp256k1', 'univalue', 'rpc', @@ -130,6 +138,7 @@ def ensure_no_dot_so_in_depends(): 'gtest': [repofile('src/zcash-gtest')], 'sec-hard': check_security_hardening, 'no-dot-so': ensure_no_dot_so_in_depends, + 'util-test': util_test, 'secp256k1': ['make', '-C', repofile('src/secp256k1'), 'check'], 'univalue': ['make', '-C', repofile('src/univalue'), 'check'], 'rpc': [repofile('qa/pull-tester/rpc-tests.sh')], From 6e98511cf1498d7fa445d95a74bd09a60ff95a30 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 16 Oct 2017 16:16:14 -0400 Subject: [PATCH 039/177] Add stdout notice if any stage fails --- qa/zcash/full_test_suite.py | 1 + 1 file changed, 1 insertion(+) diff --git a/qa/zcash/full_test_suite.py b/qa/zcash/full_test_suite.py index ecdd3a39a59..e01845635e2 100755 --- a/qa/zcash/full_test_suite.py +++ b/qa/zcash/full_test_suite.py @@ -185,6 +185,7 @@ def main(): passed &= run_stage(s) if not passed: + print("!!! One or more test stages failed !!!") sys.exit(1) if __name__ == '__main__': From e2283742db4f6a87cb981439152fa9633087c774 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 17 Oct 2017 19:03:41 -0700 Subject: [PATCH 040/177] Add libsnark to "make clean" --- src/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Makefile.am b/src/Makefile.am index 3cbe026728e..5bf09256124 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -545,6 +545,7 @@ EXTRA_DIST = leveldb clean-local: -$(MAKE) -C leveldb clean -$(MAKE) -C secp256k1 clean + -$(MAKE) -C snark clean rm -f leveldb/*/*.gcno leveldb/helpers/memenv/*.gcno -rm -f config.h From 99ca5e1a226304ea9f838123f96232b6f3f579ea Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 17 Oct 2017 19:04:02 -0700 Subject: [PATCH 041/177] Ensure that libsnark is built first, so its headers are available --- src/Makefile.am | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 5bf09256124..7cab29fda0b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -36,11 +36,15 @@ LIBSNARK=snark/build/lib/libsnark.a LIBUNIVALUE=univalue/libunivalue.la LIBZCASH=libzcash.a -# libsnark is added as a dependency here solely to ensure it is built early, so -# that its header files are collated for use in later build steps. -$(LIBSECP256K1): $(LIBSNARK) $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) +$(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) +# A phony target is included here to ensure libsnark is built first, so that its +# header files are collated for use in later build steps. +# See https://stackoverflow.com/a/10726725 +-include collate-libsnark +collate-libsnark: $(LIBSNARK) + LIBSNARK_CXXFLAGS = -fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1 LIBSNARK_CONFIG_FLAGS = CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT NO_COPY_DEPINST=1 @@ -103,7 +107,7 @@ LIBZCASH_H = \ zcash/util.h \ zcash/Zcash.h -.PHONY: FORCE check-symbols check-security +.PHONY: FORCE collate-libsnark check-symbols check-security # bitcoin core # BITCOIN_CORE_H = \ addrman.h \ From d43b32bbfe867988563c2b47359359272b87698a Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 17 Oct 2017 20:33:28 -0700 Subject: [PATCH 042/177] Remove OpenSSL libraries from libsnark LDLIBS Unnecessary in the Zcash libsnark fork. --- src/snark/Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/snark/Makefile b/src/snark/Makefile index 427f4f4ce98..cceffb98966 100644 --- a/src/snark/Makefile +++ b/src/snark/Makefile @@ -20,8 +20,6 @@ DEPINST = depinst CXXFLAGS += -I$(DEPINST)/include -Isrc LDFLAGS += -L$(DEPINST)/lib -Wl,-rpath,$(DEPINST)/lib LDLIBS += -lgmpxx -lgmp -lboost_program_options-mt -lsodium -# OpenSSL and its dependencies (needed explicitly for static builds): -LDLIBS += -lcrypto -ldl -lz # List of .a files to include within libsnark.a and libsnark.so: AR_LIBS = # List of library files to install: From 91dd425b4ab5f67b0107115fbe62531bb4846a08 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 18 Oct 2017 00:55:52 -0700 Subject: [PATCH 043/177] Add libsnark tests to full_test_suite.py --- qa/zcash/full_test_suite.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qa/zcash/full_test_suite.py b/qa/zcash/full_test_suite.py index e01845635e2..0bfc8a11918 100755 --- a/qa/zcash/full_test_suite.py +++ b/qa/zcash/full_test_suite.py @@ -129,6 +129,7 @@ def util_test(): 'no-dot-so', 'util-test', 'secp256k1', + 'libsnark', 'univalue', 'rpc', ] @@ -140,6 +141,7 @@ def util_test(): 'no-dot-so': ensure_no_dot_so_in_depends, 'util-test': util_test, 'secp256k1': ['make', '-C', repofile('src/secp256k1'), 'check'], + 'libsnark': ['make', '-C', repofile('src'), 'libsnark-tests'], 'univalue': ['make', '-C', repofile('src/univalue'), 'check'], 'rpc': [repofile('qa/pull-tester/rpc-tests.sh')], } From 692bf7a6df56da50f78efc6e77bbaafab0fcbc95 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 18 Oct 2017 00:56:32 -0700 Subject: [PATCH 044/177] Add --list-stages argument to full_test_suite.py --- qa/zcash/full_test_suite.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/qa/zcash/full_test_suite.py b/qa/zcash/full_test_suite.py index 0bfc8a11918..d8a07642064 100755 --- a/qa/zcash/full_test_suite.py +++ b/qa/zcash/full_test_suite.py @@ -171,10 +171,17 @@ def run_stage(stage): def main(): parser = argparse.ArgumentParser() + parser.add_argument('--list-stages', dest='list', action='store_true') parser.add_argument('stage', nargs='*', default=STAGES, help='One of %s'%STAGES) args = parser.parse_args() + # Check for list + if args.list: + for s in STAGES: + print(s) + sys.exit(0) + # Check validity of stages for s in args.stage: if s not in STAGES: From 1a9543d0646ebe20edccdb40dfdeabc5ae980b7c Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Fri, 7 Apr 2017 10:24:53 -0600 Subject: [PATCH 045/177] Remove crusty old "loadVerifyingKey"/"loadProvingKey" APIs and associated invariants. --- src/gtest/main.cpp | 7 +++ src/gtest/test_joinsplit.cpp | 52 +++++---------- src/gtest/utils.cpp | 4 -- src/init.cpp | 6 +- src/primitives/transaction.cpp | 3 - src/test/test_bitcoin.cpp | 28 ++++++--- src/test/test_bitcoin.h | 6 ++ src/test/transaction_tests.cpp | 20 +++--- src/wallet/rpcwallet.cpp | 6 -- src/zcash/CreateJoinSplit.cpp | 8 +-- src/zcash/GenerateParams.cpp | 8 +-- src/zcash/JoinSplit.cpp | 111 +++++++++------------------------ src/zcash/JoinSplit.hpp | 17 ++--- src/zcbenchmarks.cpp | 6 +- 14 files changed, 102 insertions(+), 180 deletions(-) diff --git a/src/gtest/main.cpp b/src/gtest/main.cpp index d1ffa628a2b..a0a2e0042ed 100644 --- a/src/gtest/main.cpp +++ b/src/gtest/main.cpp @@ -4,6 +4,8 @@ #include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp" #include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" +#include "zcash/JoinSplit.hpp" +#include "util.h" struct ECCryptoClosure { @@ -12,11 +14,16 @@ struct ECCryptoClosure ECCryptoClosure instance_of_eccryptoclosure; +ZCJoinSplit* params; + int main(int argc, char **argv) { assert(init_and_check_sodium() != -1); libsnark::default_r1cs_ppzksnark_pp::init_public_params(); libsnark::inhibit_profiling_info = true; libsnark::inhibit_profiling_counters = true; + boost::filesystem::path pk_path = ZC_GetParamsDir() / "sprout-proving.key"; + boost::filesystem::path vk_path = ZC_GetParamsDir() / "sprout-verifying.key"; + params = ZCJoinSplit::Prepared(vk_path.string(), pk_path.string()); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/src/gtest/test_joinsplit.cpp b/src/gtest/test_joinsplit.cpp index 17ac7ecb22f..986592e8995 100644 --- a/src/gtest/test_joinsplit.cpp +++ b/src/gtest/test_joinsplit.cpp @@ -5,6 +5,7 @@ #include #include "zcash/prf.h" +#include "util.h" #include "zcash/JoinSplit.hpp" #include "zcash/Note.hpp" @@ -13,6 +14,8 @@ using namespace libzcash; +extern ZCJoinSplit* params; + void test_full_api(ZCJoinSplit* js) { // Create verification context. @@ -219,8 +222,6 @@ void invokeAPIFailure( TEST(joinsplit, h_sig) { - auto js = ZCJoinSplit::Unopened(); - /* // by Taylor Hornby @@ -284,7 +285,7 @@ for test_input in TEST_VECTORS: }; BOOST_FOREACH(std::vector& v, tests) { - auto expected = js->h_sig( + auto expected = ZCJoinSplit::h_sig( uint256S(v[0]), {uint256S(v[1]), uint256S(v[2])}, uint256S(v[3]) @@ -292,8 +293,6 @@ for test_input in TEST_VECTORS: EXPECT_EQ(expected, uint256S(v[4])); } - - delete js; } void increment_note_witnesses( @@ -311,8 +310,6 @@ void increment_note_witnesses( TEST(joinsplit, full_api_test) { - auto js = ZCJoinSplit::Generate(); - { std::vector witnesses; ZCIncrementalMerkleTree tree; @@ -331,7 +328,7 @@ TEST(joinsplit, full_api_test) increment_note_witnesses(note5.cm(), witnesses, tree); // Should work - invokeAPI(js, + invokeAPI(params, { JSInput(), JSInput() @@ -345,7 +342,7 @@ TEST(joinsplit, full_api_test) tree.root()); // lhs > MAX_MONEY - invokeAPIFailure(js, + invokeAPIFailure(params, { JSInput(), JSInput() @@ -360,7 +357,7 @@ TEST(joinsplit, full_api_test) "nonsensical vpub_old value"); // rhs > MAX_MONEY - invokeAPIFailure(js, + invokeAPIFailure(params, { JSInput(), JSInput() @@ -375,7 +372,7 @@ TEST(joinsplit, full_api_test) "nonsensical vpub_new value"); // input witness for the wrong element - invokeAPIFailure(js, + invokeAPIFailure(params, { JSInput(witnesses[0], note1, sk), JSInput() @@ -391,7 +388,7 @@ TEST(joinsplit, full_api_test) // input witness doesn't match up with // real root - invokeAPIFailure(js, + invokeAPIFailure(params, { JSInput(witnesses[1], note1, sk), JSInput() @@ -406,7 +403,7 @@ TEST(joinsplit, full_api_test) "joinsplit not anchored to the correct root"); // input is in the tree now! this should work - invokeAPI(js, + invokeAPI(params, { JSInput(witnesses[1], note1, sk), JSInput() @@ -420,7 +417,7 @@ TEST(joinsplit, full_api_test) tree.root()); // Wrong secret key - invokeAPIFailure(js, + invokeAPIFailure(params, { JSInput(witnesses[1], note1, SpendingKey::random()), JSInput() @@ -435,7 +432,7 @@ TEST(joinsplit, full_api_test) "input note not authorized to spend with given key"); // Absurd input value - invokeAPIFailure(js, + invokeAPIFailure(params, { JSInput(witnesses[3], note3, sk), JSInput() @@ -450,7 +447,7 @@ TEST(joinsplit, full_api_test) "nonsensical input note value"); // Absurd total input value - invokeAPIFailure(js, + invokeAPIFailure(params, { JSInput(witnesses[4], note4, sk), JSInput(witnesses[5], note5, sk) @@ -465,7 +462,7 @@ TEST(joinsplit, full_api_test) "nonsensical left hand size of joinsplit balance"); // Absurd output value - invokeAPIFailure(js, + invokeAPIFailure(params, { JSInput(), JSInput() @@ -480,7 +477,7 @@ TEST(joinsplit, full_api_test) "nonsensical output value"); // Absurd total output value - invokeAPIFailure(js, + invokeAPIFailure(params, { JSInput(), JSInput() @@ -495,7 +492,7 @@ TEST(joinsplit, full_api_test) "nonsensical right hand side of joinsplit balance"); // Absurd total output value - invokeAPIFailure(js, + invokeAPIFailure(params, { JSInput(), JSInput() @@ -510,22 +507,7 @@ TEST(joinsplit, full_api_test) "invalid joinsplit balance"); } - test_full_api(js); - - js->saveProvingKey("./zcashTest.pk"); - js->saveVerifyingKey("./zcashTest.vk"); - - delete js; - - js = ZCJoinSplit::Unopened(); - - js->setProvingKeyPath("./zcashTest.pk"); - js->loadProvingKey(); - js->loadVerifyingKey("./zcashTest.vk"); - - test_full_api(js); - - delete js; + test_full_api(params); } TEST(joinsplit, note_plaintexts) diff --git a/src/gtest/utils.cpp b/src/gtest/utils.cpp index cf025162c33..527e613e2d7 100644 --- a/src/gtest/utils.cpp +++ b/src/gtest/utils.cpp @@ -1,7 +1,3 @@ -#include "zcash/JoinSplit.hpp" - -ZCJoinSplit* params = ZCJoinSplit::Unopened(); - int GenZero(int n) { return 0; diff --git a/src/init.cpp b/src/init.cpp index bb57f257d7a..0ed2e566537 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -688,18 +688,14 @@ static void ZC_LoadParams() return; } - pzcashParams = ZCJoinSplit::Unopened(); - LogPrintf("Loading verifying key from %s\n", vk_path.string().c_str()); gettimeofday(&tv_start, 0); - pzcashParams->loadVerifyingKey(vk_path.string()); + pzcashParams = ZCJoinSplit::Prepared(vk_path.string(), pk_path.string()); gettimeofday(&tv_end, 0); elapsed = float(tv_end.tv_sec-tv_start.tv_sec) + (tv_end.tv_usec-tv_start.tv_usec)/float(1000000); LogPrintf("Loaded verifying key in %fs seconds.\n", elapsed); - - pzcashParams->setProvingKeyPath(pk_path.string()); } bool AppInitServers(boost::thread_group& threadGroup) diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index f6236a2f81d..6aa7949b256 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -20,9 +20,6 @@ JSDescription::JSDescription(ZCJoinSplit& params, { boost::array notes; - if (computeProof) { - params.loadProvingKey(); - } proof = params.prove( inputs, outputs, diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 5c701c5ccc3..0a39f2944b2 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -30,20 +30,30 @@ ZCJoinSplit *pzcashParams; extern bool fPrintToConsole; extern void noui_connect(); +JoinSplitTestingSetup::JoinSplitTestingSetup() +{ + boost::filesystem::path pk_path = ZC_GetParamsDir() / "sprout-proving.key"; + boost::filesystem::path vk_path = ZC_GetParamsDir() / "sprout-verifying.key"; + pzcashParams = ZCJoinSplit::Prepared(vk_path.string(), pk_path.string()); +} + +JoinSplitTestingSetup::~JoinSplitTestingSetup() +{ + delete pzcashParams; +} + BasicTestingSetup::BasicTestingSetup() { - assert(init_and_check_sodium() != -1); - ECC_Start(); - pzcashParams = ZCJoinSplit::Unopened(); - SetupEnvironment(); - fPrintToDebugLog = false; // don't want to write to debug.log file - fCheckBlockIndex = true; - SelectParams(CBaseChainParams::MAIN); + assert(init_and_check_sodium() != -1); + ECC_Start(); + SetupEnvironment(); + fPrintToDebugLog = false; // don't want to write to debug.log file + fCheckBlockIndex = true; + SelectParams(CBaseChainParams::MAIN); } BasicTestingSetup::~BasicTestingSetup() { - ECC_Stop(); - delete pzcashParams; + ECC_Stop(); } TestingSetup::TestingSetup() diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index 205e5b5c46c..d30f19b226a 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -30,4 +30,10 @@ struct TestingSetup: public BasicTestingSetup { ~TestingSetup(); }; +// Setup w.r.t. zk-SNARK API +struct JoinSplitTestingSetup: public BasicTestingSetup { + JoinSplitTestingSetup(); + ~JoinSplitTestingSetup(); +}; + #endif diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 3fa691a94f0..6b207f643e3 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -6,6 +6,7 @@ #include "data/tx_valid.json.h" #include "test/test_bitcoin.h" +#include "init.h" #include "clientversion.h" #include "consensus/validation.h" #include "core_io.h" @@ -85,7 +86,7 @@ string FormatScriptFlags(unsigned int flags) return ret.substr(0, ret.size() - 1); } -BOOST_FIXTURE_TEST_SUITE(transaction_tests, BasicTestingSetup) +BOOST_FIXTURE_TEST_SUITE(transaction_tests, JoinSplitTestingSetup) BOOST_AUTO_TEST_CASE(tx_valid) { @@ -326,9 +327,6 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification) // Also, it's generally libzcash's job to ensure the // integrity of the scheme through its own tests. - // construct the r1cs keypair - auto p = ZCJoinSplit::Generate(); - // construct a merkle tree ZCIncrementalMerkleTree merkleTree; @@ -362,8 +360,8 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification) auto verifier = libzcash::ProofVerifier::Strict(); { - JSDescription jsdesc(*p, pubKeyHash, rt, inputs, outputs, 0, 0); - BOOST_CHECK(jsdesc.Verify(*p, verifier, pubKeyHash)); + JSDescription jsdesc(*pzcashParams, pubKeyHash, rt, inputs, outputs, 0, 0); + BOOST_CHECK(jsdesc.Verify(*pzcashParams, verifier, pubKeyHash)); CDataStream ss(SER_DISK, CLIENT_VERSION); ss << jsdesc; @@ -372,20 +370,20 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification) ss >> jsdesc_deserialized; BOOST_CHECK(jsdesc_deserialized == jsdesc); - BOOST_CHECK(jsdesc_deserialized.Verify(*p, verifier, pubKeyHash)); + BOOST_CHECK(jsdesc_deserialized.Verify(*pzcashParams, verifier, pubKeyHash)); } { // Ensure that the balance equation is working. - BOOST_CHECK_THROW(JSDescription(*p, pubKeyHash, rt, inputs, outputs, 10, 0), std::invalid_argument); - BOOST_CHECK_THROW(JSDescription(*p, pubKeyHash, rt, inputs, outputs, 0, 10), std::invalid_argument); + BOOST_CHECK_THROW(JSDescription(*pzcashParams, pubKeyHash, rt, inputs, outputs, 10, 0), std::invalid_argument); + BOOST_CHECK_THROW(JSDescription(*pzcashParams, pubKeyHash, rt, inputs, outputs, 0, 10), std::invalid_argument); } { // Ensure that it won't verify if the root is changed. - auto test = JSDescription(*p, pubKeyHash, rt, inputs, outputs, 0, 0); + auto test = JSDescription(*pzcashParams, pubKeyHash, rt, inputs, outputs, 0, 0); test.anchor = GetRandHash(); - BOOST_CHECK(!test.Verify(*p, verifier, pubKeyHash)); + BOOST_CHECK(!test.Verify(*pzcashParams, verifier, pubKeyHash)); } } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index bac5dc871b6..79b4f6de49e 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2543,12 +2543,6 @@ UniValue zc_benchmark(const UniValue& params, bool fHelp) std::vector sample_times; - if (benchmarktype == "createjoinsplit") { - /* Load the proving now key so that it doesn't happen as part of the - * first joinsplit. */ - pzcashParams->loadProvingKey(); - } - JSDescription samplejoinsplit; if (benchmarktype == "verifyjoinsplit") { diff --git a/src/zcash/CreateJoinSplit.cpp b/src/zcash/CreateJoinSplit.cpp index ea2d59c9eb1..7253e95685e 100644 --- a/src/zcash/CreateJoinSplit.cpp +++ b/src/zcash/CreateJoinSplit.cpp @@ -13,10 +13,8 @@ int main(int argc, char **argv) { libsnark::start_profiling(); - auto p = ZCJoinSplit::Unopened(); - p->loadVerifyingKey((ZC_GetParamsDir() / "sprout-verifying.key").string()); - p->setProvingKeyPath((ZC_GetParamsDir() / "sprout-proving.key").string()); - p->loadProvingKey(); + auto p = ZCJoinSplit::Prepared((ZC_GetParamsDir() / "sprout-verifying.key").string(), + (ZC_GetParamsDir() / "sprout-proving.key").string()); // construct a proof. @@ -32,4 +30,6 @@ int main(int argc, char **argv) 0, 0); } + + delete p; // not that it matters } diff --git a/src/zcash/GenerateParams.cpp b/src/zcash/GenerateParams.cpp index eadfe7b18ee..8ca2d781432 100644 --- a/src/zcash/GenerateParams.cpp +++ b/src/zcash/GenerateParams.cpp @@ -18,13 +18,7 @@ int main(int argc, char **argv) std::string vkFile = argv[2]; std::string r1csFile = argv[3]; - auto p = ZCJoinSplit::Generate(); - - p->saveProvingKey(pkFile); - p->saveVerifyingKey(vkFile); - p->saveR1CS(r1csFile); - - delete p; + ZCJoinSplit::Generate(r1csFile, vkFile, pkFile); return 0; } diff --git a/src/zcash/JoinSplit.cpp b/src/zcash/JoinSplit.cpp index 590700cd9ab..c7b468f89dc 100644 --- a/src/zcash/JoinSplit.cpp +++ b/src/zcash/JoinSplit.cpp @@ -28,7 +28,7 @@ CCriticalSection cs_ParamsIO; CCriticalSection cs_LoadKeys; template -void saveToFile(std::string path, T& obj) { +void saveToFile(const std::string path, T& obj) { LOCK(cs_ParamsIO); std::stringstream ss; @@ -42,7 +42,7 @@ void saveToFile(std::string path, T& obj) { } template -void loadFromFile(std::string path, boost::optional& objIn) { +void loadFromFile(const std::string path, T& objIn) { LOCK(cs_ParamsIO); std::stringstream ss; @@ -69,77 +69,33 @@ class JoinSplitCircuit : public JoinSplit { typedef default_r1cs_ppzksnark_pp ppzksnark_ppT; typedef Fr FieldT; - boost::optional> pk; - boost::optional> vk; - boost::optional> vk_precomp; - boost::optional pkPath; + r1cs_ppzksnark_verification_key vk; + r1cs_ppzksnark_processed_verification_key vk_precomp; + std::string pkPath; - JoinSplitCircuit() {} - ~JoinSplitCircuit() {} - - void setProvingKeyPath(std::string path) { - pkPath = path; - } - - void loadProvingKey() { - LOCK(cs_LoadKeys); - - if (!pk) { - if (!pkPath) { - throw std::runtime_error("proving key path unknown"); - } - loadFromFile(*pkPath, pk); - } - } - - void saveProvingKey(std::string path) { - if (pk) { - saveToFile(path, *pk); - } else { - throw std::runtime_error("cannot save proving key; key doesn't exist"); - } - } - void loadVerifyingKey(std::string path) { - LOCK(cs_LoadKeys); - - loadFromFile(path, vk); - - processVerifyingKey(); - } - void processVerifyingKey() { - vk_precomp = r1cs_ppzksnark_verifier_process_vk(*vk); - } - void saveVerifyingKey(std::string path) { - if (vk) { - saveToFile(path, *vk); - } else { - throw std::runtime_error("cannot save verifying key; key doesn't exist"); - } - } - void saveR1CS(std::string path) { - auto r1cs = generate_r1cs(); - - saveToFile(path, r1cs); + JoinSplitCircuit(const std::string vkPath, const std::string pkPath) : pkPath(pkPath) { + loadFromFile(vkPath, vk); + vk_precomp = r1cs_ppzksnark_verifier_process_vk(vk); } + ~JoinSplitCircuit() {} - r1cs_constraint_system generate_r1cs() { + static void generate(const std::string r1csPath, + const std::string vkPath, + const std::string pkPath) + { protoboard pb; joinsplit_gadget g(pb); g.generate_r1cs_constraints(); - return pb.get_constraint_system(); - } + auto r1cs = pb.get_constraint_system(); - void generate() { - LOCK(cs_LoadKeys); + saveToFile(r1csPath, r1cs); - const r1cs_constraint_system constraint_system = generate_r1cs(); - r1cs_ppzksnark_keypair keypair = r1cs_ppzksnark_generator(constraint_system); + r1cs_ppzksnark_keypair keypair = r1cs_ppzksnark_generator(r1cs); - pk = keypair.pk; - vk = keypair.vk; - processVerifyingKey(); + saveToFile(vkPath, keypair.vk); + saveToFile(pkPath, keypair.pk); } bool verify( @@ -154,10 +110,6 @@ class JoinSplitCircuit : public JoinSplit { uint64_t vpub_new, const uint256& rt ) { - if (!vk || !vk_precomp) { - throw std::runtime_error("JoinSplit verifying key not loaded"); - } - try { auto r1cs_proof = proof.to_libsnark_proof>(); @@ -174,8 +126,8 @@ class JoinSplitCircuit : public JoinSplit { ); return verifier.check( - *vk, - *vk_precomp, + vk, + vk_precomp, witness, r1cs_proof ); @@ -200,10 +152,6 @@ class JoinSplitCircuit : public JoinSplit { const uint256& rt, bool computeProof ) { - if (computeProof && !pk) { - throw std::runtime_error("JoinSplit proving key not loaded"); - } - if (vpub_old > MAX_MONEY) { throw std::invalid_argument("nonsensical vpub_old value"); } @@ -345,8 +293,11 @@ class JoinSplitCircuit : public JoinSplit { // estimate that it doesn't matter if we check every time. pb.constraint_system.swap_AB_if_beneficial(); + r1cs_ppzksnark_proving_key pk; + loadFromFile(pkPath, pk); + return ZCProof(r1cs_ppzksnark_prover( - *pk, + pk, primary_input, aux_input, pb.constraint_system @@ -355,20 +306,20 @@ class JoinSplitCircuit : public JoinSplit { }; template -JoinSplit* JoinSplit::Generate() +void JoinSplit::Generate(const std::string r1csPath, + const std::string vkPath, + const std::string pkPath) { initialize_curve_params(); - auto js = new JoinSplitCircuit(); - js->generate(); - - return js; + JoinSplitCircuit::generate(r1csPath, vkPath, pkPath); } template -JoinSplit* JoinSplit::Unopened() +JoinSplit* JoinSplit::Prepared(const std::string vkPath, + const std::string pkPath) { initialize_curve_params(); - return new JoinSplitCircuit(); + return new JoinSplitCircuit(vkPath, pkPath); } template diff --git a/src/zcash/JoinSplit.hpp b/src/zcash/JoinSplit.hpp index a8c08d21b02..2d9921ac818 100644 --- a/src/zcash/JoinSplit.hpp +++ b/src/zcash/JoinSplit.hpp @@ -48,22 +48,17 @@ class JoinSplit { public: virtual ~JoinSplit() {} - static JoinSplit* Generate(); - static JoinSplit* Unopened(); + static void Generate(const std::string r1csPath, + const std::string vkPath, + const std::string pkPath); + static JoinSplit* Prepared(const std::string vkPath, + const std::string pkPath); + static uint256 h_sig(const uint256& randomSeed, const boost::array& nullifiers, const uint256& pubKeyHash ); - // TODO: #789 - virtual void setProvingKeyPath(std::string) = 0; - virtual void loadProvingKey() = 0; - - virtual void saveProvingKey(std::string path) = 0; - virtual void loadVerifyingKey(std::string path) = 0; - virtual void saveVerifyingKey(std::string path) = 0; - virtual void saveR1CS(std::string path) = 0; - virtual ZCProof prove( const boost::array& inputs, const boost::array& outputs, diff --git a/src/zcbenchmarks.cpp b/src/zcbenchmarks.cpp index 1cb880ea106..bb51cdd6c51 100644 --- a/src/zcbenchmarks.cpp +++ b/src/zcbenchmarks.cpp @@ -97,11 +97,7 @@ double benchmark_parameter_loading() struct timeval tv_start; timer_start(tv_start); - auto newParams = ZCJoinSplit::Unopened(); - - newParams->loadVerifyingKey(vk_path.string()); - newParams->setProvingKeyPath(pk_path.string()); - newParams->loadProvingKey(); + auto newParams = ZCJoinSplit::Prepared(vk_path.string(), pk_path.string()); double ret = timer_stop(tv_start); From d3c8109b410e3538c6d85c13c01b8c7df8142980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Tue, 8 Aug 2017 13:30:04 +0100 Subject: [PATCH 046/177] Improve shutdown process Zcash: cherry-picked from commit 793667af1c31835e0eefcdd283930bb89cfeda8f --- src/httpserver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/httpserver.cpp b/src/httpserver.cpp index e2a6af6ad3e..a1f27fc0d43 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -479,6 +479,8 @@ void StopHTTPServer() } if (eventBase) { LogPrint("http", "Waiting for HTTP event thread to exit\n"); + // Exit the event loop as soon as there are no active events. + event_base_loopexit(eventBase, nullptr); // Give event loop a few seconds to exit (to send back last RPC responses), then break it // Before this was solved with event_base_loopexit, but that didn't work as expected in // at least libevent 2.0.21 and always introduced a delay. In libevent From a20b975a524c3a40c9c1b66e9b73fb14e32d189f Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Tue, 24 Oct 2017 14:50:26 -0700 Subject: [PATCH 047/177] Update performance-measurements.sh Fix error message, as per @daira --- qa/zcash/performance-measurements.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/zcash/performance-measurements.sh b/qa/zcash/performance-measurements.sh index fd7b30ffad5..76f41c0ab6c 100755 --- a/qa/zcash/performance-measurements.sh +++ b/qa/zcash/performance-measurements.sh @@ -157,7 +157,7 @@ EOF if [ $# -lt 2 ] then - echo "$0 : two arguments are required!" + echo "$0 : At least two arguments are required!" exit 1 fi From c2d3bafeaa19c7a4913adac3255ed780a50ffe11 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 26 Oct 2017 11:29:36 -0700 Subject: [PATCH 048/177] Closes #2639. z_shieldcoinbase is now supported, no longer experimental. This reverts commit 5023af7bd5fc8c147e6fd111b610bd8922e91131. --- qa/rpc-tests/wallet_shieldcoinbase.py | 4 ++-- src/init.cpp | 2 -- src/wallet/rpcwallet.cpp | 11 ----------- 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/qa/rpc-tests/wallet_shieldcoinbase.py b/qa/rpc-tests/wallet_shieldcoinbase.py index 599663390c3..d0e4bb122d9 100755 --- a/qa/rpc-tests/wallet_shieldcoinbase.py +++ b/qa/rpc-tests/wallet_shieldcoinbase.py @@ -18,11 +18,11 @@ def setup_chain(self): initialize_chain_clean(self.options.tmpdir, 4) def setup_network(self, split=False): - args = ['-regtestprotectcoinbase', '-debug=zrpcunsafe', '-experimentalfeatures', '-zshieldcoinbase'] + args = ['-regtestprotectcoinbase', '-debug=zrpcunsafe'] self.nodes = [] self.nodes.append(start_node(0, self.options.tmpdir, args)) self.nodes.append(start_node(1, self.options.tmpdir, args)) - args2 = ['-regtestprotectcoinbase', '-debug=zrpcunsafe', '-experimentalfeatures', '-zshieldcoinbase', "-mempooltxinputlimit=7"] + args2 = ['-regtestprotectcoinbase', '-debug=zrpcunsafe', "-mempooltxinputlimit=7"] self.nodes.append(start_node(2, self.options.tmpdir, args2)) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) diff --git a/src/init.cpp b/src/init.cpp index 6f87917a07e..59a59524d9c 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -790,8 +790,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (!fExperimentalMode) { if (mapArgs.count("-developerencryptwallet")) { return InitError(_("Wallet encryption requires -experimentalfeatures.")); - } else if (mapArgs.count("-zshieldcoinbase")) { - return InitError(_("RPC call z_shieldcoinbase requires -experimentalfeatures.")); } } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index bac5dc871b6..6738ec5d8f5 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3527,16 +3527,9 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp) if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - bool fEnableShieldCoinbase = fExperimentalMode && GetBoolArg("-zshieldcoinbase", false); - std::string strDisabledMsg = ""; - if (!fEnableShieldCoinbase) { - strDisabledMsg = "\nWARNING: z_shieldcoinbase is DISABLED but can be enabled as an experimental feature.\n"; - } - if (fHelp || params.size() < 2 || params.size() > 3) throw runtime_error( "z_shieldcoinbase \"fromaddress\" \"tozaddress\" ( fee )\n" - + strDisabledMsg + "\nShield transparent coinbase funds by sending to a shielded zaddr. This is an asynchronous operation and utxos" "\nselected for shielding will be locked. If there is an error, they are unlocked. The RPC call `listlockunspent`" "\ncan be used to return a list of locked utxos. The number of coinbase utxos selected for shielding is limited by" @@ -3558,10 +3551,6 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp) "}\n" ); - if (!fEnableShieldCoinbase) { - throw JSONRPCError(RPC_WALLET_ERROR, "Error: z_shieldcoinbase is disabled."); - } - LOCK2(cs_main, pwalletMain->cs_wallet); // Validate the from address From cf72e8e06eb009f91dac39c30bd1aef9d52785d6 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 30 Oct 2017 11:58:37 -0700 Subject: [PATCH 049/177] Closes #2263 fixing broken pipe error. --- qa/rpc-tests/wallet_protectcoinbase.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/qa/rpc-tests/wallet_protectcoinbase.py b/qa/rpc-tests/wallet_protectcoinbase.py index bebe8b9b5f7..e407f0914ef 100755 --- a/qa/rpc-tests/wallet_protectcoinbase.py +++ b/qa/rpc-tests/wallet_protectcoinbase.py @@ -11,6 +11,7 @@ import sys import time +import timeit from decimal import Decimal class WalletProtectCoinbaseTest (BitcoinTestFramework): @@ -244,9 +245,22 @@ def run_test (self): amount_per_recipient = Decimal('0.00000546') # dust threshold # Note that regtest chainparams does not require standard tx, so setting the amount to be # less than the dust threshold, e.g. 0.00000001 will not result in mempool rejection. + start_time = timeit.default_timer() for i in xrange(0,num_t_recipients): newtaddr = self.nodes[2].getnewaddress() recipients.append({"address":newtaddr, "amount":amount_per_recipient}) + elapsed = timeit.default_timer() - start_time + print("...invoked getnewaddress() {} times in {} seconds".format(num_t_recipients, elapsed)) + + # Issue #2263 Workaround START + # HTTP connection to node 0 may fall into a state, during the few minutes it takes to process + # loop above to create new addresses, that when z_sendmany is called with a large amount of + # rpc data in recipients, the connection fails with a 'broken pipe' error. Making a RPC call + # to node 0 before calling z_sendmany appears to fix this issue, perhaps putting the HTTP + # connection into a good state to handle a large amount of data in recipients. + self.nodes[0].getinfo() + # Issue #2263 Workaround END + myopid = self.nodes[0].z_sendmany(myzaddr, recipients) try: self.wait_and_assert_operationid_status(myopid) From 35e12d992acf15123dcfa16f2e5fba39bb87e4ce Mon Sep 17 00:00:00 2001 From: kozyilmaz Date: Tue, 31 Oct 2017 15:14:21 +0300 Subject: [PATCH 050/177] empty spaces in PATH variable cause build failure --- depends/funcs.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/depends/funcs.mk b/depends/funcs.mk index e1aeb026a1a..df305a74a86 100644 --- a/depends/funcs.mk +++ b/depends/funcs.mk @@ -129,9 +129,9 @@ $(1)_config_env+=$($(1)_config_env_$(host_arch)_$(host_os)) $($(1)_config_env_$( $(1)_config_env+=PKG_CONFIG_LIBDIR=$($($(1)_type)_prefix)/lib/pkgconfig $(1)_config_env+=PKG_CONFIG_PATH=$($($(1)_type)_prefix)/share/pkgconfig -$(1)_config_env+=PATH=$(build_prefix)/bin:$(PATH) -$(1)_build_env+=PATH=$(build_prefix)/bin:$(PATH) -$(1)_stage_env+=PATH=$(build_prefix)/bin:$(PATH) +$(1)_config_env+=PATH="$(build_prefix)/bin:$(PATH)" +$(1)_build_env+=PATH="$(build_prefix)/bin:$(PATH)" +$(1)_stage_env+=PATH="$(build_prefix)/bin:$(PATH)" $(1)_autoconf=./configure --host=$($($(1)_type)_host) --disable-dependency-tracking --prefix=$($($(1)_type)_prefix) $$($(1)_config_opts) CC="$$($(1)_cc)" CXX="$$($(1)_cxx)" ifneq ($($(1)_nm),) From abf4af12dfaf81dafe206e7ecf3b22b7dff9241a Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 25 Apr 2017 09:41:03 -0600 Subject: [PATCH 051/177] Refactor proof generation function. --- .../r1cs_ppzksnark/r1cs_ppzksnark.tcc | 134 ++++++++++++------ 1 file changed, 94 insertions(+), 40 deletions(-) diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc b/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc index aeb2bbb858f..69739593141 100644 --- a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc +++ b/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc @@ -431,6 +431,92 @@ r1cs_ppzksnark_keypair r1cs_ppzksnark_generator( return r1cs_ppzksnark_keypair(std::move(pk), std::move(vk)); } +template +knowledge_commitment r1cs_compute_proof_kc(const qap_witness > &qap_wit, + const knowledge_commitment_vector &kcv, + const Fr &zk_shift) +{ + knowledge_commitment returnval = kcv[0] + (zk_shift * kcv[qap_wit.num_variables()+1]); + +#ifdef DEBUG + assert(kcv.domain_size() == qap_wit.num_variables()+2); +#endif + +#ifdef MULTICORE + const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() +#else + const size_t chunks = 1; +#endif + + returnval = returnval + kc_multi_exp_with_mixed_addition >( + kcv, + 1, + 1 + qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin(), + qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, + true + ); + + return returnval; +} + + + +template +G1 r1cs_compute_proof_K(const qap_witness> &qap_wit, const G1_vector &K_query, const G1 &zk_shift) +{ +#ifdef DEBUG + assert(K_query.size() == qap_wit.num_variables()+4); +#endif + +#ifdef MULTICORE + const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() +#else + const size_t chunks = 1; +#endif + + G1 g_K = K_query[0] + zk_shift; + g_K = g_K + multi_exp_with_mixed_addition, Fr >( + K_query.begin()+1, + K_query.begin()+1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin(), + qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, + true + ); + + return g_K; +} + + +template +G1 r1cs_compute_proof_H(const qap_witness > &qap_wit, const G1_vector &H_query) +{ + G1 g_H = G1::zero(); + +#ifdef DEBUG + assert(H_query.size() == qap_wit.degree()+1); +#endif + +#ifdef MULTICORE + const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() +#else + const size_t chunks = 1; +#endif + + g_H = g_H + multi_exp, Fr >( + H_query.begin(), + H_query.begin()+qap_wit.degree()+1, + qap_wit.coefficients_for_H.begin(), + qap_wit.coefficients_for_H.begin()+qap_wit.degree()+1, + chunks, + true + ); + + return g_H; +} + template r1cs_ppzksnark_proof r1cs_ppzksnark_prover(const r1cs_ppzksnark_proving_key &pk, const r1cs_ppzksnark_primary_input &primary_input, @@ -457,67 +543,36 @@ r1cs_ppzksnark_proof r1cs_ppzksnark_prover(const r1cs_ppzksnark_proving_key assert(qap_inst.is_satisfied(qap_wit)); #endif - knowledge_commitment, G1 > g_A = pk.A_query[0] + qap_wit.d1*pk.A_query[qap_wit.num_variables()+1]; - knowledge_commitment, G1 > g_B = pk.B_query[0] + qap_wit.d2*pk.B_query[qap_wit.num_variables()+1]; - knowledge_commitment, G1 > g_C = pk.C_query[0] + qap_wit.d3*pk.C_query[qap_wit.num_variables()+1]; - - G1 g_H = G1::zero(); - G1 g_K = (pk.K_query[0] + - qap_wit.d1*pk.K_query[qap_wit.num_variables()+1] + - qap_wit.d2*pk.K_query[qap_wit.num_variables()+2] + - qap_wit.d3*pk.K_query[qap_wit.num_variables()+3]); - #ifdef DEBUG for (size_t i = 0; i < qap_wit.num_inputs() + 1; ++i) { assert(pk.A_query[i].g == G1::zero()); } - assert(pk.A_query.domain_size() == qap_wit.num_variables()+2); - assert(pk.B_query.domain_size() == qap_wit.num_variables()+2); - assert(pk.C_query.domain_size() == qap_wit.num_variables()+2); - assert(pk.H_query.size() == qap_wit.degree()+1); - assert(pk.K_query.size() == qap_wit.num_variables()+4); -#endif - -#ifdef MULTICORE - const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() -#else - const size_t chunks = 1; #endif enter_block("Compute the proof"); enter_block("Compute answer to A-query", false); - g_A = g_A + kc_multi_exp_with_mixed_addition, G1, Fr >(pk.A_query, - 1, 1+qap_wit.num_variables(), - qap_wit.coefficients_for_ABCs.begin(), qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), - chunks, true); + auto g_A = r1cs_compute_proof_kc, G1 >(qap_wit, pk.A_query, qap_wit.d1); leave_block("Compute answer to A-query", false); enter_block("Compute answer to B-query", false); - g_B = g_B + kc_multi_exp_with_mixed_addition, G1, Fr >(pk.B_query, - 1, 1+qap_wit.num_variables(), - qap_wit.coefficients_for_ABCs.begin(), qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), - chunks, true); + auto g_B = r1cs_compute_proof_kc, G1 >(qap_wit, pk.B_query, qap_wit.d2); leave_block("Compute answer to B-query", false); enter_block("Compute answer to C-query", false); - g_C = g_C + kc_multi_exp_with_mixed_addition, G1, Fr >(pk.C_query, - 1, 1+qap_wit.num_variables(), - qap_wit.coefficients_for_ABCs.begin(), qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), - chunks, true); + auto g_C = r1cs_compute_proof_kc, G1 >(qap_wit, pk.C_query, qap_wit.d3); leave_block("Compute answer to C-query", false); enter_block("Compute answer to H-query", false); - g_H = g_H + multi_exp, Fr >(pk.H_query.begin(), pk.H_query.begin()+qap_wit.degree()+1, - qap_wit.coefficients_for_H.begin(), qap_wit.coefficients_for_H.begin()+qap_wit.degree()+1, - chunks, true); + auto g_H = r1cs_compute_proof_H(qap_wit, pk.H_query); leave_block("Compute answer to H-query", false); enter_block("Compute answer to K-query", false); - g_K = g_K + multi_exp_with_mixed_addition, Fr >(pk.K_query.begin()+1, pk.K_query.begin()+1+qap_wit.num_variables(), - qap_wit.coefficients_for_ABCs.begin(), qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), - chunks, true); + G1 zk_shift = qap_wit.d1*pk.K_query[qap_wit.num_variables()+1] + + qap_wit.d2*pk.K_query[qap_wit.num_variables()+2] + + qap_wit.d3*pk.K_query[qap_wit.num_variables()+3]; + G1 g_K = r1cs_compute_proof_K(qap_wit, pk.K_query, zk_shift); leave_block("Compute answer to K-query", false); leave_block("Compute the proof"); @@ -525,7 +580,6 @@ r1cs_ppzksnark_proof r1cs_ppzksnark_prover(const r1cs_ppzksnark_proving_key leave_block("Call to r1cs_ppzksnark_prover"); r1cs_ppzksnark_proof proof = r1cs_ppzksnark_proof(std::move(g_A), std::move(g_B), std::move(g_C), std::move(g_H), std::move(g_K)); - //proof.print_size(); return proof; } From c8a7f74753300842f0211339633aee007b3d3349 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 25 Apr 2017 09:51:07 -0600 Subject: [PATCH 052/177] Add streaming prover. --- .../r1cs_ppzksnark/r1cs_ppzksnark.hpp | 6 ++ .../r1cs_ppzksnark/r1cs_ppzksnark.tcc | 70 +++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp b/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp index 36f6c149996..96bc36504b5 100644 --- a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp +++ b/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp @@ -397,6 +397,12 @@ r1cs_ppzksnark_proof r1cs_ppzksnark_prover(const r1cs_ppzksnark_proving_key const r1cs_ppzksnark_auxiliary_input &auxiliary_input, const r1cs_ppzksnark_constraint_system &constraint_system); +template +r1cs_ppzksnark_proof r1cs_ppzksnark_prover_streaming(std::ifstream &proving_key_file, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_auxiliary_input &auxiliary_input, + const r1cs_ppzksnark_constraint_system &constraint_system); + /* Below are four variants of verifier algorithm for the R1CS ppzkSNARK. diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc b/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc index 69739593141..84db9fc1a3b 100644 --- a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc +++ b/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc @@ -584,6 +584,76 @@ r1cs_ppzksnark_proof r1cs_ppzksnark_prover(const r1cs_ppzksnark_proving_key return proof; } +template +r1cs_ppzksnark_proof r1cs_ppzksnark_prover_streaming(std::ifstream &proving_key_file, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_auxiliary_input &auxiliary_input, + const r1cs_ppzksnark_constraint_system &constraint_system) +{ + enter_block("Call to r1cs_ppzksnark_prover_streaming"); + + const Fr d1 = Fr::random_element(), + d2 = Fr::random_element(), + d3 = Fr::random_element(); + + enter_block("Compute the polynomial H"); + const qap_witness > qap_wit = r1cs_to_qap_witness_map(constraint_system, primary_input, auxiliary_input, d1, d2, d3); + leave_block("Compute the polynomial H"); + + enter_block("Compute the proof"); + + r1cs_ppzksnark_proof proof; + + enter_block("Compute answer to A-query", false); + { + knowledge_commitment_vector, G1 > A_query; + proving_key_file >> A_query; + proof.g_A = r1cs_compute_proof_kc, G1 >(qap_wit, A_query, qap_wit.d1); + } + leave_block("Compute answer to A-query", false); + + enter_block("Compute answer to B-query", false); + { + knowledge_commitment_vector, G1 > B_query; + proving_key_file >> B_query; + proof.g_B = r1cs_compute_proof_kc, G1 >(qap_wit, B_query, qap_wit.d2); + } + leave_block("Compute answer to B-query", false); + + enter_block("Compute answer to C-query", false); + { + knowledge_commitment_vector, G1 > C_query; + proving_key_file >> C_query; + proof.g_C = r1cs_compute_proof_kc, G1 >(qap_wit, C_query, qap_wit.d3); + } + leave_block("Compute answer to C-query", false); + + enter_block("Compute answer to H-query", false); + { + G1_vector H_query; + proving_key_file >> H_query; + proof.g_H = r1cs_compute_proof_H(qap_wit, H_query); + } + leave_block("Compute answer to H-query", false); + + enter_block("Compute answer to K-query", false); + { + G1_vector K_query; + proving_key_file >> K_query; + G1 zk_shift = qap_wit.d1*K_query[qap_wit.num_variables()+1] + + qap_wit.d2*K_query[qap_wit.num_variables()+2] + + qap_wit.d3*K_query[qap_wit.num_variables()+3]; + proof.g_K = r1cs_compute_proof_K(qap_wit, K_query, zk_shift); + } + leave_block("Compute answer to K-query", false); + + leave_block("Compute the proof"); + + leave_block("Call to r1cs_ppzksnark_prover_streaming"); + + return proof; +} + template r1cs_ppzksnark_processed_verification_key r1cs_ppzksnark_verifier_process_vk(const r1cs_ppzksnark_verification_key &vk) { From 394f41853bfe51c980176fd93ab20e9330a785e5 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 25 Apr 2017 09:57:40 -0600 Subject: [PATCH 053/177] Integrate low memory prover. --- src/zcash/JoinSplit.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/zcash/JoinSplit.cpp b/src/zcash/JoinSplit.cpp index c7b468f89dc..409d3c89b39 100644 --- a/src/zcash/JoinSplit.cpp +++ b/src/zcash/JoinSplit.cpp @@ -293,11 +293,14 @@ class JoinSplitCircuit : public JoinSplit { // estimate that it doesn't matter if we check every time. pb.constraint_system.swap_AB_if_beneficial(); - r1cs_ppzksnark_proving_key pk; - loadFromFile(pkPath, pk); + std::ifstream fh(pkPath, std::ios::binary); - return ZCProof(r1cs_ppzksnark_prover( - pk, + if(!fh.is_open()) { + throw std::runtime_error((boost::format("could not load param file at %s") % pkPath).str()); + } + + return ZCProof(r1cs_ppzksnark_prover_streaming( + fh, primary_input, aux_input, pb.constraint_system From 4305a56221dbf97c0f8ef4870370995f70b5f1d7 Mon Sep 17 00:00:00 2001 From: Ariel Gabizon Date: Tue, 24 Oct 2017 13:27:59 +0300 Subject: [PATCH 054/177] boost::format -> tinyformat --- src/zcash/JoinSplit.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/zcash/JoinSplit.cpp b/src/zcash/JoinSplit.cpp index 409d3c89b39..d71dbd0eef0 100644 --- a/src/zcash/JoinSplit.cpp +++ b/src/zcash/JoinSplit.cpp @@ -14,7 +14,7 @@ #include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" #include "libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" #include "libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp" - +#include "tinyformat.h" #include "sync.h" #include "amount.h" @@ -49,7 +49,7 @@ void loadFromFile(const std::string path, T& objIn) { std::ifstream fh(path, std::ios::binary); if(!fh.is_open()) { - throw std::runtime_error((boost::format("could not load param file at %s") % path).str()); + throw std::runtime_error(strprintf("could not load param file at %s", path)); } ss << fh.rdbuf(); @@ -296,7 +296,7 @@ class JoinSplitCircuit : public JoinSplit { std::ifstream fh(pkPath, std::ios::binary); if(!fh.is_open()) { - throw std::runtime_error((boost::format("could not load param file at %s") % pkPath).str()); + throw std::runtime_error(strprintf("could not load param file at %s", pkPath)); } return ZCProof(r1cs_ppzksnark_prover_streaming( From 1051242926d6a972af6815c8ff79d05db6799c98 Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 31 Oct 2017 20:31:40 -0700 Subject: [PATCH 055/177] Closes #2576. Update link to security info on z.cash website. --- README.md | 4 ++-- src/util.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 769d08e7701..3d7501482d9 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,8 @@ blockchain has reached a significant size. Security Warnings ----------------- -See important security warnings in -[doc/security-warnings.md](doc/security-warnings.md). +See important security warnings on the +[Security Information page](https://z.cash/support/security/). **Zcash is experimental and a work-in-progress.** Use at your own risk. diff --git a/src/util.cpp b/src/util.cpp index 6ecb9af7c44..cc8632c6a87 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -892,7 +892,7 @@ std::string PrivacyInfo() { return "\n" + FormatParagraph(strprintf(_("In order to ensure you are adequately protecting your privacy when using Zcash, please see <%s>."), - "https://z.cash/support/security/index.html")) + "\n"; + "https://z.cash/support/security/")) + "\n"; } std::string LicenseInfo() From c5dabd2b66af89a7418658b82fbb12c2dcbf5257 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 1 Nov 2017 10:40:24 -0700 Subject: [PATCH 056/177] Closes #2639. Adds optional limit parameter with a default value of 50. The new parameter is to satisfy the principle of least astonishment by providing a sensible default for the maximum number of transparent inputs to shield. If users do not configure -mempooltxinputlimit it is possible for them to create transactions with hundreds of inputs which suffer from mining delay, due to the current state of the network where some miners have configured -mempooltxinputlimit as a way to deal with the problem of quadratic hashing. --- doc/payment-api.md | 2 +- qa/rpc-tests/wallet_shieldcoinbase.py | 40 +++++++++++++++++++++++++-- src/rpcclient.cpp | 1 + src/test/rpc_wallet_tests.cpp | 9 +++++- src/wallet/rpcwallet.cpp | 23 +++++++++++---- 5 files changed, 65 insertions(+), 10 deletions(-) diff --git a/doc/payment-api.md b/doc/payment-api.md index 803a0dc9780..1582255bb08 100644 --- a/doc/payment-api.md +++ b/doc/payment-api.md @@ -72,7 +72,7 @@ Command | Parameters | Description --- | --- | --- z_listreceivedbyaddress
| zaddr [minconf=1] | Return a list of amounts received by a zaddr belonging to the node’s wallet.

Optionally set the minimum number of confirmations which a received amount must have in order to be included in the result. Use 0 to count unconfirmed transactions.

Output:
[{
“txid”: “4a0f…”,
“amount”: 0.54,
“memo”:”F0FF…”,}, {...}, {...}
] z_sendmany
| fromaddress amounts [minconf=1] [fee=0.0001] | _This is an Asynchronous RPC call_

Send funds from an address to multiple outputs. The address can be either a taddr or a zaddr.

Amounts is a list containing key/value pairs corresponding to the addresses and amount to pay. Each output address can be in taddr or zaddr format.

When sending to a zaddr, you also have the option of attaching a memo in hexadecimal format.

**NOTE:**When sending coinbase funds to a zaddr, the node's wallet does not allow any change. Put another way, spending a partial amount of a coinbase utxo is not allowed. This is not a consensus rule but a local wallet rule due to the current implementation of z_sendmany. In future, this rule may be removed.

Example of Outputs parameter:
[{“address”:”t123…”, “amount”:0.005},
,{“address”:”z010…”,”amount”:0.03, “memo”:”f508af…”}]

Optionally set the minimum number of confirmations which a private or transparent transaction must have in order to be used as an input. When sending from a zaddr, minconf must be greater than zero.

Optionally set a transaction fee, which by default is 0.0001 ZEC.

Any transparent change will be sent to a new transparent address. Any private change will be sent back to the zaddr being used as the source of funds.

Returns an operationid. You use the operationid value with z_getoperationstatus and z_getoperationresult to obtain the result of sending funds, which if successful, will be a txid. -z_shieldcoinbase
| fromaddress toaddress [fee=0.0001] | _This is an Asynchronous RPC call_

Shield transparent coinbase funds by sending to a shielded z address. Utxos selected for shielding will be locked. If there is an error, they are unlocked. The RPC call `listlockunspent` can be used to return a list of locked utxos. The number of coinbase utxos selected for shielding is limited by both the -mempooltxinputlimit=xxx option and a consensus rule defining a maximum transaction size of 100000 bytes.

The from address is a taddr or "*" for all taddrs belonging to the wallet. The to address is a zaddr. The default fee is 0.0001.

Returns an object containing an operationid which can be used with z_getoperationstatus and z_getoperationresult, along with key-value pairs regarding how many utxos are being shielded in this trasaction and what remains to be shielded. +z_shieldcoinbase
| fromaddress toaddress [fee=0.0001] [limit=50] | _This is an Asynchronous RPC call_

Shield transparent coinbase funds by sending to a shielded z address. Utxos selected for shielding will be locked. If there is an error, they are unlocked. The RPC call `listlockunspent` can be used to return a list of locked utxos.

The number of coinbase utxos selected for shielding can be set with the limit parameter, which has a default value of 50. If the parameter is set to 0, the number of utxos selected is limited by the `-mempooltxinputlimit` option. Any limit is constrained by a consensus rule defining a maximum transaction size of 100000 bytes.

The from address is a taddr or "*" for all taddrs belonging to the wallet. The to address is a zaddr. The default fee is 0.0001.

Returns an object containing an operationid which can be used with z_getoperationstatus and z_getoperationresult, along with key-value pairs regarding how many utxos are being shielded in this trasaction and what remains to be shielded. ### Operations diff --git a/qa/rpc-tests/wallet_shieldcoinbase.py b/qa/rpc-tests/wallet_shieldcoinbase.py index d0e4bb122d9..d1698d94591 100755 --- a/qa/rpc-tests/wallet_shieldcoinbase.py +++ b/qa/rpc-tests/wallet_shieldcoinbase.py @@ -114,6 +114,20 @@ def run_test (self): errorString = e.error['message'] assert_equal("Insufficient coinbase funds" in errorString, True) + # Shielding will fail because limit parameter must be at least 0 + try: + self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('0.001'), -1) + except JSONRPCException,e: + errorString = e.error['message'] + assert_equal("Limit on maximum number of utxos cannot be negative" in errorString, True) + + # Shielding will fail because limit parameter is absurdly large + try: + self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('0.001'), 99999999999999) + except JSONRPCException,e: + errorString = e.error['message'] + assert_equal("JSON integer out of range" in errorString, True) + # Shield coinbase utxos from node 0 of value 40, standard fee of 0.00010000 result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr) self.wait_and_assert_operationid_status(0, result['opid']) @@ -151,14 +165,15 @@ def run_test (self): # Shielding the 800 utxos will occur over two transactions, since max tx size is 100,000 bytes. # We don't verify shieldingValue as utxos are not selected in any specific order, so value can change on each test run. - result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, 0) + # We set an unrealistically high limit parameter of 99999, to verify that max tx size will constrain the number of utxos. + result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, 0, 99999) assert_equal(result["shieldingUTXOs"], Decimal('662')) assert_equal(result["remainingUTXOs"], Decimal('138')) remainingValue = result["remainingValue"] opid1 = result['opid'] # Verify that utxos are locked (not available for selection) by queuing up another shielding operation - result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr) + result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, 0, 0) assert_equal(result["shieldingValue"], Decimal(remainingValue)) assert_equal(result["shieldingUTXOs"], Decimal('138')) assert_equal(result["remainingValue"], Decimal('0')) @@ -176,8 +191,9 @@ def run_test (self): self.sync_all() # Verify maximum number of utxos which node 2 can shield is limited by option -mempooltxinputlimit + # This option is used when the limit parameter is set to 0. mytaddr = self.nodes[2].getnewaddress() - result = self.nodes[2].z_shieldcoinbase(mytaddr, myzaddr, 0) + result = self.nodes[2].z_shieldcoinbase(mytaddr, myzaddr, Decimal('0.0001'), 0) assert_equal(result["shieldingUTXOs"], Decimal('7')) assert_equal(result["remainingUTXOs"], Decimal('13')) self.wait_and_assert_operationid_status(2, result['opid']) @@ -185,5 +201,23 @@ def run_test (self): self.nodes[1].generate(1) self.sync_all() + # Verify maximum number of utxos which node 0 can shield is set by default limit parameter of 50 + self.nodes[0].generate(200) + self.sync_all() + mytaddr = self.nodes[0].getnewaddress() + result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, Decimal('0.0001')) + assert_equal(result["shieldingUTXOs"], Decimal('50')) + assert_equal(result["remainingUTXOs"], Decimal('50')) + self.wait_and_assert_operationid_status(0, result['opid']) + + # Verify maximum number of utxos which node 0 can shield can be set by the limit parameter + result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, Decimal('0.0001'), 33) + assert_equal(result["shieldingUTXOs"], Decimal('33')) + assert_equal(result["remainingUTXOs"], Decimal('17')) + self.wait_and_assert_operationid_status(0, result['opid']) + sync_blocks(self.nodes) # don't sync on mempool as node 2 will reject thix tx due to its mempooltxinputlimit + self.nodes[1].generate(1) + self.sync_all() + if __name__ == '__main__': WalletShieldCoinbaseTest().main() diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 376b2b3d546..2c5bd122fe3 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -110,6 +110,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "z_sendmany", 2}, { "z_sendmany", 3}, { "z_shieldcoinbase", 2}, + { "z_shieldcoinbase", 3}, { "z_getoperationstatus", 0}, { "z_getoperationresult", 0}, { "z_importkey", 2 }, diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index 8233097decf..6017333b4c3 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -1251,7 +1251,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_parameters) BOOST_CHECK_THROW(CallRPC("z_shieldcoinbase"), runtime_error); BOOST_CHECK_THROW(CallRPC("z_shieldcoinbase toofewargs"), runtime_error); - BOOST_CHECK_THROW(CallRPC("z_shieldcoinbase too many args here"), runtime_error); + BOOST_CHECK_THROW(CallRPC("z_shieldcoinbase too many args shown here"), runtime_error); // bad from address BOOST_CHECK_THROW(CallRPC("z_shieldcoinbase " @@ -1279,6 +1279,13 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_parameters) "21000001" ), runtime_error); + // invalid limit, must be at least 0 + BOOST_CHECK_THROW(CallRPC("z_shieldcoinbase " + "tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ " + "tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB " + "100 -1" + ), runtime_error); + // Test constructor of AsyncRPCOperation_sendmany std::string testnetzaddr = "ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP"; std::string mainnetzaddr = "zcMuhvq8sEkHALuSU2i4NbNQxshSAYrpCExec45ZjtivYPbuiFPwk6WHy4SvsbeZ4siy1WheuRGjtaJmoD1J8bFqNXhsG6U"; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 6738ec5d8f5..843af53bd97 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3522,18 +3522,21 @@ When estimating the number of coinbase utxos we can shield in a single transacti */ #define CTXIN_SPEND_P2SH_SIZE 400 +#define SHIELD_COINBASE_DEFAULT_LIMIT 50 + UniValue z_shieldcoinbase(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - if (fHelp || params.size() < 2 || params.size() > 3) + if (fHelp || params.size() < 2 || params.size() > 4) throw runtime_error( - "z_shieldcoinbase \"fromaddress\" \"tozaddress\" ( fee )\n" + "z_shieldcoinbase \"fromaddress\" \"tozaddress\" ( fee ) ( limit )\n" "\nShield transparent coinbase funds by sending to a shielded zaddr. This is an asynchronous operation and utxos" "\nselected for shielding will be locked. If there is an error, they are unlocked. The RPC call `listlockunspent`" - "\ncan be used to return a list of locked utxos. The number of coinbase utxos selected for shielding is limited by" - "\nboth the -mempooltxinputlimit=xxx option and a consensus rule defining a maximum transaction size of " + "\ncan be used to return a list of locked utxos. The number of coinbase utxos selected for shielding can be limited" + "\nby the caller. If the limit parameter is set to zero, the -mempooltxinputlimit option will determine the number" + "\nof uxtos. Any limit is constrained by the consensus rule defining a maximum transaction size of " + strprintf("%d bytes.", MAX_TX_SIZE) + HelpRequiringPassphrase() + "\n" "\nArguments:\n" @@ -3541,6 +3544,8 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp) "2. \"toaddress\" (string, required) The address is a zaddr.\n" "3. fee (numeric, optional, default=" + strprintf("%s", FormatMoney(SHIELD_COINBASE_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n" + "4. limit (numeric, optional, default=" + + strprintf("%d", SHIELD_COINBASE_DEFAULT_LIMIT) + ") Limit on the maximum number of utxos to shield. Set to 0 to use node option -mempooltxinputlimit.\n" "\nResult:\n" "{\n" " \"operationid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n" @@ -3583,6 +3588,14 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp) } } + int nLimit = SHIELD_COINBASE_DEFAULT_LIMIT; + if (params.size() > 3) { + nLimit = params[3].get_int(); + if (nLimit < 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of utxos cannot be negative"); + } + } + // Prepare to get coinbase utxos std::vector inputs; CAmount shieldedValue = 0; @@ -3590,7 +3603,7 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp) size_t estimatedTxSize = 2000; // 1802 joinsplit description + tx overhead + wiggle room size_t utxoCounter = 0; bool maxedOutFlag = false; - size_t mempoolLimit = (size_t)GetArg("-mempooltxinputlimit", 0); + size_t mempoolLimit = (nLimit != 0) ? nLimit : (size_t)GetArg("-mempooltxinputlimit", 0); // Set of addresses to filter utxos by set setAddress = {}; From 337bca8125d89a0b9195a8787164e8b59435b5cf Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 3 Nov 2017 00:39:23 -0700 Subject: [PATCH 057/177] Fix an issue where qa test wallet_shieldcoinbase could hang. The mempool was not synced so a block could be generated and not clear out the mempool. This would then cause subsequent code which expected the mempool of all nodes to be empty to hang. --- qa/rpc-tests/wallet_shieldcoinbase.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/qa/rpc-tests/wallet_shieldcoinbase.py b/qa/rpc-tests/wallet_shieldcoinbase.py index d1698d94591..693326c8a63 100755 --- a/qa/rpc-tests/wallet_shieldcoinbase.py +++ b/qa/rpc-tests/wallet_shieldcoinbase.py @@ -6,7 +6,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, initialize_chain_clean, \ - start_node, connect_nodes_bi, sync_blocks + start_node, connect_nodes_bi, sync_blocks, sync_mempools import time from decimal import Decimal @@ -185,8 +185,10 @@ def run_test (self): self.wait_and_assert_operationid_status(0, opid2) # sync_all() invokes sync_mempool() but node 2's mempool limit will cause tx1 and tx2 to be rejected. - # So instead, we sync on blocks, and after a new block is generated, all nodes will have an empty mempool. - sync_blocks(self.nodes) + # So instead, we sync on blocks and mempool for node 0 and node 1, and after a new block is generated + # which mines tx1 and tx2, all nodes will have an empty mempool which can then be synced. + sync_blocks(self.nodes[:2]) + sync_mempools(self.nodes[:2]) self.nodes[1].generate(1) self.sync_all() @@ -215,7 +217,9 @@ def run_test (self): assert_equal(result["shieldingUTXOs"], Decimal('33')) assert_equal(result["remainingUTXOs"], Decimal('17')) self.wait_and_assert_operationid_status(0, result['opid']) - sync_blocks(self.nodes) # don't sync on mempool as node 2 will reject thix tx due to its mempooltxinputlimit + # Don't sync node 2 which rejects the tx due to its mempooltxinputlimit + sync_blocks(self.nodes[:2]) + sync_mempools(self.nodes[:2]) self.nodes[1].generate(1) self.sync_all() From bef1b5ce1b5f6aabfad3a52c9244aad800d1a171 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 5 Nov 2017 12:02:21 -0500 Subject: [PATCH 058/177] Fix NPE in rpc_wallet_tests --- src/test/rpc_wallet_tests.cpp | 4 ++-- src/test/test_bitcoin.h | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index 8233097decf..01e52920841 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -1175,7 +1175,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals) try { proxy.perform_joinsplit(info); } catch (const std::runtime_error & e) { - BOOST_CHECK( string(e.what()).find("JoinSplit verifying key not loaded")!= string::npos); + BOOST_CHECK( string(e.what()).find("error verifying joinsplit")!= string::npos); } } @@ -1365,7 +1365,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_internals) try { proxy.perform_joinsplit(info); } catch (const std::runtime_error & e) { - BOOST_CHECK( string(e.what()).find("JoinSplit verifying key not loaded")!= string::npos); + BOOST_CHECK( string(e.what()).find("error verifying joinsplit")!= string::npos); } } diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index d30f19b226a..d1c4263739b 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -17,11 +17,17 @@ struct BasicTestingSetup { ~BasicTestingSetup(); }; +// Setup w.r.t. zk-SNARK API +struct JoinSplitTestingSetup: public BasicTestingSetup { + JoinSplitTestingSetup(); + ~JoinSplitTestingSetup(); +}; + /** Testing setup that configures a complete environment. * Included are data directory, coins database, script check threads * and wallet (if enabled) setup. */ -struct TestingSetup: public BasicTestingSetup { +struct TestingSetup: public JoinSplitTestingSetup { CCoinsViewDB *pcoinsdbview; boost::filesystem::path pathTemp; boost::thread_group threadGroup; @@ -30,10 +36,4 @@ struct TestingSetup: public BasicTestingSetup { ~TestingSetup(); }; -// Setup w.r.t. zk-SNARK API -struct JoinSplitTestingSetup: public BasicTestingSetup { - JoinSplitTestingSetup(); - ~JoinSplitTestingSetup(); -}; - #endif From 45232b19619a9df52af318289accc6b8ad4930e5 Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 14 Nov 2017 13:29:05 -0800 Subject: [PATCH 059/177] Add payment disclosure as experimental feature. --- qa/pull-tester/rpc-tests.sh | 1 + qa/rpc-tests/paymentdisclosure.py | 233 ++++++++++++++ src/Makefile.am | 7 + src/Makefile.gtest.include | 1 + src/gtest/test_foundersreward.cpp | 2 + src/gtest/test_paymentdisclosure.cpp | 210 ++++++++++++ src/gtest/test_transaction.cpp | 4 +- src/init.cpp | 3 + src/paymentdisclosure.cpp | 63 ++++ src/paymentdisclosure.h | 145 +++++++++ src/paymentdisclosuredb.cpp | 93 ++++++ src/paymentdisclosuredb.h | 42 +++ src/primitives/transaction.cpp | 15 +- src/primitives/transaction.h | 4 +- src/rpcclient.cpp | 2 + src/rpcserver.cpp | 6 +- src/rpcserver.h | 2 + src/wallet/asyncrpcoperation_sendmany.cpp | 50 ++- src/wallet/asyncrpcoperation_sendmany.h | 5 + .../asyncrpcoperation_shieldcoinbase.cpp | 49 ++- src/wallet/asyncrpcoperation_shieldcoinbase.h | 7 + src/wallet/gtest/test_wallet_zkeys.cpp | 2 + src/wallet/rpcdisclosure.cpp | 299 ++++++++++++++++++ src/zcash/JoinSplit.cpp | 9 +- src/zcash/JoinSplit.hpp | 6 +- src/zcash/NoteEncryption.cpp | 48 +++ src/zcash/NoteEncryption.hpp | 30 ++ 27 files changed, 1324 insertions(+), 14 deletions(-) create mode 100755 qa/rpc-tests/paymentdisclosure.py create mode 100644 src/gtest/test_paymentdisclosure.cpp create mode 100644 src/paymentdisclosure.cpp create mode 100644 src/paymentdisclosure.h create mode 100644 src/paymentdisclosuredb.cpp create mode 100644 src/paymentdisclosuredb.h create mode 100644 src/wallet/rpcdisclosure.cpp diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index 5631f894f18..a09edaf0370 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -11,6 +11,7 @@ export BITCOIND=${REAL_BITCOIND} #Run the tests testScripts=( + 'paymentdisclosure.py' 'prioritisetransaction.py' 'wallet_treestate.py' 'wallet_protectcoinbase.py' diff --git a/qa/rpc-tests/paymentdisclosure.py b/qa/rpc-tests/paymentdisclosure.py new file mode 100755 index 00000000000..60d6f188f7a --- /dev/null +++ b/qa/rpc-tests/paymentdisclosure.py @@ -0,0 +1,233 @@ +#!/usr/bin/env python2 +# Copyright (c) 2017 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.authproxy import JSONRPCException +from test_framework.util import assert_equal, initialize_chain_clean, \ + start_node, connect_nodes_bi + +import time +from decimal import Decimal + +class PaymentDisclosureTest (BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4) + + def setup_network(self, split=False): + args = ['-debug=zrpcunsafe,paymentdisclosure', '-experimentalfeatures', '-paymentdisclosure', '-txindex=1'] + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, args)) + self.nodes.append(start_node(1, self.options.tmpdir, args)) + # node 2 does not enable payment disclosure + args2 = ['-debug=zrpcunsafe', '-experimentalfeatures', '-txindex=1'] + self.nodes.append(start_node(2, self.options.tmpdir, args2)) + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + self.is_network_split=False + self.sync_all() + + # Returns txid if operation was a success or None + def wait_and_assert_operationid_status(self, nodeid, myopid, in_status='success', in_errormsg=None): + print('waiting for async operation {}'.format(myopid)) + opids = [] + opids.append(myopid) + timeout = 300 + status = None + errormsg = None + txid = None + for x in xrange(1, timeout): + results = self.nodes[nodeid].z_getoperationresult(opids) + if len(results)==0: + time.sleep(1) + else: + status = results[0]["status"] + if status == "failed": + errormsg = results[0]['error']['message'] + elif status == "success": + txid = results[0]['result']['txid'] + break + print('...returned status: {}'.format(status)) + assert_equal(in_status, status) + if errormsg is not None: + assert(in_errormsg is not None) + assert(in_errormsg in errormsg) + print('...returned error: {}'.format(errormsg)) + return txid + + def run_test (self): + print "Mining blocks..." + + self.nodes[0].generate(4) + walletinfo = self.nodes[0].getwalletinfo() + assert_equal(walletinfo['immature_balance'], 40) + assert_equal(walletinfo['balance'], 0) + self.sync_all() + self.nodes[2].generate(3) + self.sync_all() + self.nodes[1].generate(101) + self.sync_all() + assert_equal(self.nodes[0].getbalance(), 40) + assert_equal(self.nodes[1].getbalance(), 10) + assert_equal(self.nodes[2].getbalance(), 30) + + mytaddr = self.nodes[0].getnewaddress() + myzaddr = self.nodes[0].z_getnewaddress() + + # Check that Node 2 has payment disclosure disabled. + try: + self.nodes[2].z_getpaymentdisclosure("invalidtxid", 0, 0) + assert(False) + except JSONRPCException as e: + errorString = e.error['message'] + assert("payment disclosure is disabled" in errorString) + + # Check that Node 0 returns an error for an unknown txid + try: + self.nodes[0].z_getpaymentdisclosure("invalidtxid", 0, 0) + assert(False) + except JSONRPCException as e: + errorString = e.error['message'] + assert("No information available about transaction" in errorString) + + # Shield coinbase utxos from node 0 of value 40, standard fee of 0.00010000 + recipients = [{"address":myzaddr, "amount":Decimal('40.0')-Decimal('0.0001')}] + myopid = self.nodes[0].z_sendmany(mytaddr, recipients) + txid = self.wait_and_assert_operationid_status(0, myopid) + + # Check the tx has joinsplits + assert( len(self.nodes[0].getrawtransaction("" + txid, 1)["vjoinsplit"]) > 0 ) + + # Sync mempools + self.sync_all() + + # Confirm that you can't create a payment disclosure for an unconfirmed tx + try: + self.nodes[0].z_getpaymentdisclosure(txid, 0, 0) + assert(False) + except JSONRPCException as e: + errorString = e.error['message'] + assert("Transaction has not been confirmed yet" in errorString) + + try: + self.nodes[1].z_getpaymentdisclosure(txid, 0, 0) + assert(False) + except JSONRPCException as e: + errorString = e.error['message'] + assert("Transaction has not been confirmed yet" in errorString) + + # Mine tx + self.nodes[0].generate(1) + self.sync_all() + + # Confirm that Node 1 cannot create a payment disclosure for a transaction which does not impact its wallet + try: + self.nodes[1].z_getpaymentdisclosure(txid, 0, 0) + assert(False) + except JSONRPCException as e: + errorString = e.error['message'] + assert("Transaction does not belong to the wallet" in errorString) + + # Check that an invalid joinsplit index is rejected + try: + self.nodes[0].z_getpaymentdisclosure(txid, 1, 0) + assert(False) + except JSONRPCException as e: + errorString = e.error['message'] + assert("Invalid js_index" in errorString) + + try: + self.nodes[0].z_getpaymentdisclosure(txid, -1, 0) + assert(False) + except JSONRPCException as e: + errorString = e.error['message'] + assert("Invalid js_index" in errorString) + + # Check that an invalid output index is rejected + try: + self.nodes[0].z_getpaymentdisclosure(txid, 0, 2) + assert(False) + except JSONRPCException as e: + errorString = e.error['message'] + assert("Invalid output_index" in errorString) + + try: + self.nodes[0].z_getpaymentdisclosure(txid, 0, -1) + assert(False) + except JSONRPCException as e: + errorString = e.error['message'] + assert("Invalid output_index" in errorString) + + # Ask Node 0 to create and validate a payment disclosure for output 0 + message = "Here is proof of my payment!" + pd = self.nodes[0].z_getpaymentdisclosure(txid, 0, 0, message) + result = self.nodes[0].z_validatepaymentdisclosure(pd) + assert(result["valid"]) + output_value_sum = Decimal(result["value"]) + + # Ask Node 1 to confirm the payment disclosure is valid + result = self.nodes[1].z_validatepaymentdisclosure(pd) + assert(result["valid"]) + assert_equal(result["message"], message) + assert_equal(result["value"], output_value_sum) + + # Check that total value of output index 0 and index 1 should equal shielding amount of 40 less standard fee. + pd = self.nodes[0].z_getpaymentdisclosure(txid, 0, 1) + result = self.nodes[0].z_validatepaymentdisclosure(pd) + output_value_sum += Decimal(result["value"]) + assert_equal(output_value_sum, Decimal('39.99990000')) + + # Create a z->z transaction, sending shielded funds from node 0 to node 1 + node1zaddr = self.nodes[1].z_getnewaddress() + recipients = [{"address":node1zaddr, "amount":Decimal('1')}] + myopid = self.nodes[0].z_sendmany(myzaddr, recipients) + txid = self.wait_and_assert_operationid_status(0, myopid) + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + # Confirm that Node 0 can create a valid payment disclosure + pd = self.nodes[0].z_getpaymentdisclosure(txid, 0, 0, "a message of your choice") + result = self.nodes[0].z_validatepaymentdisclosure(pd) + assert(result["valid"]) + + # Confirm that Node 1, even as recipient of shielded funds, cannot create a payment disclosure + # as the transaction was created by Node 0 and Node 1's payment disclosure database does not + # contain the necessary data to do so, where the data would only have been available on Node 0 + # when executing z_shieldcoinbase. + try: + self.nodes[1].z_getpaymentdisclosure(txid, 0, 0) + assert(False) + except JSONRPCException as e: + errorString = e.error['message'] + assert("Could not find payment disclosure info for the given joinsplit output" in errorString) + + # Payment disclosures cannot be created for transparent transactions. + txid = self.nodes[2].sendtoaddress(mytaddr, 1.0) + self.sync_all() + + # No matter the type of transaction, if it has not been confirmed, it is ignored. + try: + self.nodes[0].z_getpaymentdisclosure(txid, 0, 0) + assert(False) + except JSONRPCException as e: + errorString = e.error['message'] + assert("Transaction has not been confirmed yet" in errorString) + + self.nodes[0].generate(1) + self.sync_all() + + # Confirm that a payment disclosure can only be generated for a shielded transaction. + try: + self.nodes[0].z_getpaymentdisclosure(txid, 0, 0) + assert(False) + except JSONRPCException as e: + errorString = e.error['message'] + assert("Transaction is not a shielded transaction" in errorString) + +if __name__ == '__main__': + PaymentDisclosureTest().main() diff --git a/src/Makefile.am b/src/Makefile.am index 4a7554c07b0..5b80b724f13 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -160,6 +160,8 @@ BITCOIN_CORE_H = \ net.h \ netbase.h \ noui.h \ + paymentdisclosure.h \ + paymentdisclosuredb.h \ policy/fees.h \ pow.h \ primitives/block.h \ @@ -244,6 +246,8 @@ libbitcoin_server_a_SOURCES = \ miner.cpp \ net.cpp \ noui.cpp \ + paymentdisclosure.cpp \ + paymentdisclosuredb.cpp \ policy/fees.cpp \ pow.cpp \ rest.cpp \ @@ -293,6 +297,9 @@ libbitcoin_wallet_a_SOURCES = \ wallet/asyncrpcoperation_shieldcoinbase.cpp \ wallet/crypter.cpp \ wallet/db.cpp \ + paymentdisclosure.cpp \ + paymentdisclosuredb.cpp \ + wallet/rpcdisclosure.cpp \ wallet/rpcdump.cpp \ wallet/rpcwallet.cpp \ wallet/wallet.cpp \ diff --git a/src/Makefile.gtest.include b/src/Makefile.gtest.include index d92feaa20b1..02152f936f4 100644 --- a/src/Makefile.gtest.include +++ b/src/Makefile.gtest.include @@ -38,6 +38,7 @@ zcash_gtest_SOURCES += \ gtest/test_txid.cpp \ gtest/test_libzcash_utils.cpp \ gtest/test_proofs.cpp \ + gtest/test_paymentdisclosure.cpp \ gtest/test_checkblock.cpp if ENABLE_WALLET zcash_gtest_SOURCES += \ diff --git a/src/gtest/test_foundersreward.cpp b/src/gtest/test_foundersreward.cpp index 9016cde54c3..b5e8acc18d5 100644 --- a/src/gtest/test_foundersreward.cpp +++ b/src/gtest/test_foundersreward.cpp @@ -80,6 +80,8 @@ TEST(founders_reward_test, create_testnet_2of3multisig) { std::cout << s << std::endl; pWallet->Flush(true); + + ECC_Stop(); } #endif diff --git a/src/gtest/test_paymentdisclosure.cpp b/src/gtest/test_paymentdisclosure.cpp new file mode 100644 index 00000000000..e87c892975d --- /dev/null +++ b/src/gtest/test_paymentdisclosure.cpp @@ -0,0 +1,210 @@ +#include + +#include "main.h" +#include "utilmoneystr.h" +#include "chainparams.h" +#include "utilstrencodings.h" +#include "zcash/Address.hpp" +#include "wallet/wallet.h" +#include "amount.h" +#include +#include +#include +#include +#include +#include +#include "util.h" + +#include "paymentdisclosure.h" +#include "paymentdisclosuredb.h" + +#include "sodium.h" + +#include +#include +#include + +using namespace std; + +/* + To run tests: + ./zcash-gtest --gtest_filter="paymentdisclosure.*" + + Note: As an experimental feature, writing your own tests may require option flags to be set. + mapArgs["-experimentalfeatures"] = true; + mapArgs["-paymentdisclosure"] = true; +*/ + +#define NUM_TRIES 10000 + +#define DUMP_DATABASE_TO_STDOUT false + +static boost::uuids::random_generator uuidgen; + +static uint256 random_uint256() +{ + uint256 ret; + randombytes_buf(ret.begin(), 32); + return ret; +} + +// Subclass of PaymentDisclosureDB to add debugging methods +class PaymentDisclosureDBTest : public PaymentDisclosureDB { +public: + PaymentDisclosureDBTest(const boost::filesystem::path& dbPath) : PaymentDisclosureDB(dbPath) {} + + void DebugDumpAllStdout() { + ASSERT_NE(db, nullptr); + std::lock_guard guard(lock_); + + // Iterate over each item in the database and print them + leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions()); + + for (it->SeekToFirst(); it->Valid(); it->Next()) { + cout << it->key().ToString() << " : "; + // << it->value().ToString() << endl; + try { + std::string strValue = it->value().ToString(); + PaymentDisclosureInfo info; + CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION); + ssValue >> info; + cout << info.ToString() << std::endl; + } catch (const std::exception& e) { + cout << e.what() << std::endl; + } + } + + if (false == it->status().ok()) { + cerr << "An error was found iterating over the database" << endl; + cerr << it->status().ToString() << endl; + } + + delete it; + } +}; + + + +// This test creates random payment disclosure blobs and checks that they can be +// 1. inserted and retrieved from a database +// 2. serialized and deserialized without corruption +TEST(paymentdisclosure, mainnet) { + ECC_Start(); + SelectParams(CBaseChainParams::MAIN); + + boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + boost::filesystem::create_directories(pathTemp); + mapArgs["-datadir"] = pathTemp.string(); + + std::cout << "Test payment disclosure database created in folder: " << pathTemp.native() << std::endl; + + PaymentDisclosureDBTest mydb(pathTemp); + + for (int i=0; i vch(&buffer[0], &buffer[0] + 32); + uint256 joinSplitPrivKey = uint256(vch); + + // Create payment disclosure key and info data to store in test database + size_t js = random_uint256().GetCheapHash() % std::numeric_limits::max(); + uint8_t n = random_uint256().GetCheapHash() % std::numeric_limits::max(); + PaymentDisclosureKey key { random_uint256(), js, n}; + PaymentDisclosureInfo info; + info.esk = random_uint256(); + info.joinSplitPrivKey = joinSplitPrivKey; + info.zaddr = libzcash::SpendingKey::random().address(); + ASSERT_TRUE(mydb.Put(key, info)); + + // Retrieve info from test database into new local variable and test it matches + PaymentDisclosureInfo info2; + ASSERT_TRUE(mydb.Get(key, info2)); + ASSERT_EQ(info, info2); + + // Modify this local variable and confirm it no longer matches + info2.esk = random_uint256(); + info2.joinSplitPrivKey = random_uint256(); + info2.zaddr = libzcash::SpendingKey::random().address(); + ASSERT_NE(info, info2); + + // Using the payment info object, let's create a dummy payload + PaymentDisclosurePayload payload; + payload.version = PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL; + payload.esk = info.esk; + payload.txid = key.hash; + payload.js = key.js; + payload.n = key.n; + payload.message = "random-" + boost::uuids::to_string(uuidgen()); // random message + payload.zaddr = info.zaddr; + + // Serialize and hash the payload to generate a signature + uint256 dataToBeSigned = SerializeHash(payload, SER_GETHASH, 0); + + // Compute the payload signature + unsigned char payloadSig[64]; + if (!(crypto_sign_detached(&payloadSig[0], NULL, + dataToBeSigned.begin(), 32, + &buffer[0] // buffer containing both private and public key required + ) == 0)) + { + throw std::runtime_error("crypto_sign_detached failed"); + } + + // Sanity check + if (!(crypto_sign_verify_detached(&payloadSig[0], + dataToBeSigned.begin(), 32, + joinSplitPubKey.begin() + ) == 0)) + { + throw std::runtime_error("crypto_sign_verify_detached failed"); + } + + // Convert signature buffer to boost array + boost::array arrayPayloadSig; + memcpy(arrayPayloadSig.data(), &payloadSig[0], 64); + + // Payment disclosure blob to pass around + PaymentDisclosure pd = {payload, arrayPayloadSig}; + + // Test payment disclosure constructors + PaymentDisclosure pd2(payload, arrayPayloadSig); + ASSERT_EQ(pd, pd2); + PaymentDisclosure pd3(joinSplitPubKey, key, info, payload.message); + ASSERT_EQ(pd, pd3); + + // Verify serialization and deserialization works + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << pd; + std::string ssHexString = HexStr(ss.begin(), ss.end()); + + PaymentDisclosure pdTmp; + CDataStream ssTmp(ParseHex(ssHexString), SER_NETWORK, PROTOCOL_VERSION); + ssTmp >> pdTmp; + ASSERT_EQ(pd, pdTmp); + + CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); + ss2 << pdTmp; + std::string ss2HexString = HexStr(ss2.begin(), ss2.end()); + ASSERT_EQ(ssHexString, ss2HexString); + + // Verify marker + ASSERT_EQ(pd.payload.marker, PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES); + ASSERT_EQ(pdTmp.payload.marker, PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES); + ASSERT_EQ(0, ssHexString.find("706462ff")); // Little endian encoding of PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES value + + // Sanity check + PaymentDisclosure pdDummy; + ASSERT_NE(pd, pdDummy); + } + +#if DUMP_DATABASE_TO_STDOUT == true + mydb.DebugDumpAllStdout(); +#endif + + ECC_Stop(); +} diff --git a/src/gtest/test_transaction.cpp b/src/gtest/test_transaction.cpp index a339f7652a9..fb68fd35cb6 100644 --- a/src/gtest/test_transaction.cpp +++ b/src/gtest/test_transaction.cpp @@ -62,7 +62,7 @@ TEST(Transaction, JSDescriptionRandomized) { *params, pubKeyHash, rt, inputs, outputs, inputMap, outputMap, - 0, 0, false, GenZero); + 0, 0, false, nullptr, GenZero); boost::array expectedInputMap {1, 0}; boost::array expectedOutputMap {1, 0}; @@ -75,7 +75,7 @@ TEST(Transaction, JSDescriptionRandomized) { *params, pubKeyHash, rt, inputs, outputs, inputMap, outputMap, - 0, 0, false, GenMax); + 0, 0, false, nullptr, GenMax); boost::array expectedInputMap {0, 1}; boost::array expectedOutputMap {0, 1}; diff --git a/src/init.cpp b/src/init.cpp index 59a59524d9c..fe3a61f5a09 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -791,6 +791,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (mapArgs.count("-developerencryptwallet")) { return InitError(_("Wallet encryption requires -experimentalfeatures.")); } + else if (mapArgs.count("-paymentdisclosure")) { + return InitError(_("Payment disclosure requires -experimentalfeatures.")); + } } // Set this early so that parameter interactions go to console diff --git a/src/paymentdisclosure.cpp b/src/paymentdisclosure.cpp new file mode 100644 index 00000000000..a33b1c60403 --- /dev/null +++ b/src/paymentdisclosure.cpp @@ -0,0 +1,63 @@ +// Copyright (c) 2017 The Zcash developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "paymentdisclosure.h" +#include "util.h" + +std::string PaymentDisclosureInfo::ToString() const { + return strprintf("PaymentDisclosureInfo(version=%d, esk=%s, joinSplitPrivKey=, address=%s)", + version, esk.ToString(), CZCPaymentAddress(zaddr).ToString()); +} + +std::string PaymentDisclosure::ToString() const { + std::string s = HexStr(payloadSig.begin(), payloadSig.end()); + return strprintf("PaymentDisclosure(payload=%s, payloadSig=%s)", payload.ToString(), s); +} + +std::string PaymentDisclosurePayload::ToString() const { + return strprintf("PaymentDisclosurePayload(version=%d, esk=%s, txid=%s, js=%d, n=%d, address=%s, message=%s)", + version, esk.ToString(), txid.ToString(), js, n, CZCPaymentAddress(zaddr).ToString(), message); +} + +PaymentDisclosure::PaymentDisclosure(const uint256 &joinSplitPubKey, const PaymentDisclosureKey &key, const PaymentDisclosureInfo &info, const std::string &message) +{ + // Populate payload member variable + payload.version = info.version; // experimental = 0, production = 1 etc. + payload.esk = info.esk; + payload.txid = key.hash; + payload.js = key.js; + payload.n = key.n; + payload.zaddr = info.zaddr; + payload.message = message; + + // Serialize and hash the payload to generate a signature + uint256 dataToBeSigned = SerializeHash(payload, SER_GETHASH, 0); + + LogPrint("paymentdisclosure", "Payment Disclosure: signing raw payload = %s\n", dataToBeSigned.ToString()); + + // Prepare buffer to store ed25519 key pair in libsodium-compatible format + unsigned char bufferKeyPair[64]; + memcpy(&bufferKeyPair[0], info.joinSplitPrivKey.begin(), 32); + memcpy(&bufferKeyPair[32], joinSplitPubKey.begin(), 32); + + // Compute payload signature member variable + if (!(crypto_sign_detached(payloadSig.data(), NULL, + dataToBeSigned.begin(), 32, + &bufferKeyPair[0] + ) == 0)) + { + throw std::runtime_error("crypto_sign_detached failed"); + } + + // Sanity check + if (!(crypto_sign_verify_detached(payloadSig.data(), + dataToBeSigned.begin(), 32, + joinSplitPubKey.begin()) == 0)) + { + throw std::runtime_error("crypto_sign_verify_detached failed"); + } + + std::string sigString = HexStr(payloadSig.data(), payloadSig.data() + payloadSig.size()); + LogPrint("paymentdisclosure", "Payment Disclosure: signature = %s\n", sigString); +} diff --git a/src/paymentdisclosure.h b/src/paymentdisclosure.h new file mode 100644 index 00000000000..b4f56eb459a --- /dev/null +++ b/src/paymentdisclosure.h @@ -0,0 +1,145 @@ +// Copyright (c) 2017 The Zcash developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef ZCASH_PAYMENTDISCLOSURE_H +#define ZCASH_PAYMENTDISCLOSURE_H + +#include "uint256.h" +#include "clientversion.h" +#include "serialize.h" +#include "streams.h" +#include "version.h" + +// For JSOutPoint +#include "wallet/wallet.h" + +#include +#include + + +// Ensure that the two different protocol messages, payment disclosure blobs and transactions, +// which are signed with the same key, joinSplitPrivKey, have disjoint encodings such that an +// encoding from one context will be rejected in the other. We know that the set of valid +// transaction versions is currently ({1..INT32_MAX}) so we will use a negative value for +// payment disclosure of -10328976 which in hex is 0xFF626470. Serialization is in little endian +// format, so a payment disclosure hex string begins 706462FF, which in ISO-8859-1 is "pdbÿ". +#define PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES -10328976 + +#define PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL 0 + +typedef JSOutPoint PaymentDisclosureKey; + +struct PaymentDisclosureInfo { + uint8_t version; // 0 = experimental, 1 = first production version, etc. + uint256 esk; // zcash/NoteEncryption.cpp + uint256 joinSplitPrivKey; // primitives/transaction.h + // ed25519 - not tied to implementation e.g. libsodium, see ed25519 rfc + + libzcash::PaymentAddress zaddr; + + PaymentDisclosureInfo() : version(PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL) { + } + + PaymentDisclosureInfo(uint8_t v, uint256 esk, uint256 key, libzcash::PaymentAddress zaddr) : version(v), esk(esk), joinSplitPrivKey(key), zaddr(zaddr) { } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(version); + READWRITE(esk); + READWRITE(joinSplitPrivKey); + READWRITE(zaddr); + } + + std::string ToString() const; + + friend bool operator==(const PaymentDisclosureInfo& a, const PaymentDisclosureInfo& b) { + return (a.version == b.version && a.esk == b.esk && a.joinSplitPrivKey == b.joinSplitPrivKey && a.zaddr == b.zaddr); + } + + friend bool operator!=(const PaymentDisclosureInfo& a, const PaymentDisclosureInfo& b) { + return !(a == b); + } + +}; + + +struct PaymentDisclosurePayload { + int32_t marker = PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES; // to be disjoint from transaction encoding + uint8_t version; // 0 = experimental, 1 = first production version, etc. + uint256 esk; // zcash/NoteEncryption.cpp + uint256 txid; // primitives/transaction.h + size_t js; // Index into CTransaction.vjoinsplit + uint8_t n; // Index into JSDescription fields of length ZC_NUM_JS_OUTPUTS + libzcash::PaymentAddress zaddr; // zcash/Address.hpp + std::string message; // parameter to RPC call + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(marker); + READWRITE(version); + READWRITE(esk); + READWRITE(txid); + READWRITE(js); + READWRITE(n); + READWRITE(zaddr); + READWRITE(message); + } + + std::string ToString() const; + + friend bool operator==(const PaymentDisclosurePayload& a, const PaymentDisclosurePayload& b) { + return ( + a.version == b.version && + a.esk == b.esk && + a.txid == b.txid && + a.js == b.js && + a.n == b.n && + a.zaddr == b.zaddr && + a.message == b.message + ); + } + + friend bool operator!=(const PaymentDisclosurePayload& a, const PaymentDisclosurePayload& b) { + return !(a == b); + } +}; + +struct PaymentDisclosure { + PaymentDisclosurePayload payload; + boost::array payloadSig; + // We use boost array because serialize doesn't like char buffer, otherwise we could do: unsigned char payloadSig[64]; + + PaymentDisclosure() {}; + PaymentDisclosure(const PaymentDisclosurePayload payload, const boost::array sig) : payload(payload), payloadSig(sig) {}; + PaymentDisclosure(const uint256& joinSplitPubKey, const PaymentDisclosureKey& key, const PaymentDisclosureInfo& info, const std::string& message); + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(payload); + READWRITE(payloadSig); + } + + std::string ToString() const; + + friend bool operator==(const PaymentDisclosure& a, const PaymentDisclosure& b) { + return (a.payload == b.payload && a.payloadSig == b.payloadSig); + } + + friend bool operator!=(const PaymentDisclosure& a, const PaymentDisclosure& b) { + return !(a == b); + } +}; + + + +typedef std::pair PaymentDisclosureKeyInfo; + + +#endif // ZCASH_PAYMENTDISCLOSURE_H diff --git a/src/paymentdisclosuredb.cpp b/src/paymentdisclosuredb.cpp new file mode 100644 index 00000000000..ef32f28458b --- /dev/null +++ b/src/paymentdisclosuredb.cpp @@ -0,0 +1,93 @@ +// Copyright (c) 2017 The Zcash developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "paymentdisclosuredb.h" + +#include "util.h" +#include "leveldbwrapper.h" + +#include + +using namespace std; + +static boost::filesystem::path emptyPath; + +/** + * Static method to return the shared/default payment disclosure database. + */ +shared_ptr PaymentDisclosureDB::sharedInstance() { + // Thread-safe in C++11 and gcc 4.3 + static shared_ptr ptr = std::make_shared(); + return ptr; +} + +// C++11 delegated constructor +PaymentDisclosureDB::PaymentDisclosureDB() : PaymentDisclosureDB(emptyPath) { +} + +PaymentDisclosureDB::PaymentDisclosureDB(const boost::filesystem::path& dbPath) { + boost::filesystem::path path(dbPath); + if (path.empty()) { + path = GetDataDir() / "paymentdisclosure"; + LogPrintf("PaymentDisclosure: using default path for database: %s\n", path.string()); + } else { + LogPrintf("PaymentDisclosure: using custom path for database: %s\n", path.string()); + } + + TryCreateDirectory(path); + options.create_if_missing = true; + leveldb::Status status = leveldb::DB::Open(options, path.string(), &db); + HandleError(status); // throws exception + LogPrintf("PaymentDisclosure: Opened LevelDB successfully\n"); +} + +PaymentDisclosureDB::~PaymentDisclosureDB() { + if (db != nullptr) { + delete db; + } +} + +bool PaymentDisclosureDB::Put(const PaymentDisclosureKey& key, const PaymentDisclosureInfo& info) +{ + if (db == nullptr) { + return false; + } + + std::lock_guard guard(lock_); + + CDataStream ssValue(SER_DISK, CLIENT_VERSION); + ssValue.reserve(ssValue.GetSerializeSize(info)); + ssValue << info; + leveldb::Slice slice(&ssValue[0], ssValue.size()); + + leveldb::Status status = db->Put(writeOptions, key.ToString(), slice); + HandleError(status); + return true; +} + +bool PaymentDisclosureDB::Get(const PaymentDisclosureKey& key, PaymentDisclosureInfo& info) +{ + if (db == nullptr) { + return false; + } + + std::lock_guard guard(lock_); + + std::string strValue; + leveldb::Status status = db->Get(readOptions, key.ToString(), &strValue); + if (!status.ok()) { + if (status.IsNotFound()) + return false; + LogPrintf("PaymentDisclosure: LevelDB read failure: %s\n", status.ToString()); + HandleError(status); + } + + try { + CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION); + ssValue >> info; + } catch (const std::exception&) { + return false; + } + return true; +} diff --git a/src/paymentdisclosuredb.h b/src/paymentdisclosuredb.h new file mode 100644 index 00000000000..9352cac8f95 --- /dev/null +++ b/src/paymentdisclosuredb.h @@ -0,0 +1,42 @@ +// Copyright (c) 2017 The Zcash developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef ZCASH_PAYMENTDISCLOSUREDB_H +#define ZCASH_PAYMENTDISCLOSUREDB_H + +#include "paymentdisclosure.h" + +#include +#include +#include +#include +#include + +#include + +#include + + +class PaymentDisclosureDB +{ +protected: + leveldb::DB* db = nullptr; + leveldb::Options options; + leveldb::ReadOptions readOptions; + leveldb::WriteOptions writeOptions; + mutable std::mutex lock_; + +public: + static std::shared_ptr sharedInstance(); + + PaymentDisclosureDB(); + PaymentDisclosureDB(const boost::filesystem::path& dbPath); + ~PaymentDisclosureDB(); + + bool Put(const PaymentDisclosureKey& key, const PaymentDisclosureInfo& info); + bool Get(const PaymentDisclosureKey& key, PaymentDisclosureInfo& info); +}; + + +#endif // ZCASH_PAYMENTDISCLOSUREDB_H diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index f6236a2f81d..cdd2999679a 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -16,7 +16,9 @@ JSDescription::JSDescription(ZCJoinSplit& params, const boost::array& outputs, CAmount vpub_old, CAmount vpub_new, - bool computeProof) : vpub_old(vpub_old), vpub_new(vpub_new), anchor(anchor) + bool computeProof, + uint256 *esk // payment disclosure + ) : vpub_old(vpub_old), vpub_new(vpub_new), anchor(anchor) { boost::array notes; @@ -37,7 +39,8 @@ JSDescription::JSDescription(ZCJoinSplit& params, vpub_old, vpub_new, anchor, - computeProof + computeProof, + esk // payment disclosure ); } @@ -52,7 +55,9 @@ JSDescription JSDescription::Randomized( CAmount vpub_old, CAmount vpub_new, bool computeProof, - std::function gen) + uint256 *esk, // payment disclosure + std::function gen + ) { // Randomize the order of the inputs and outputs inputMap = {0, 1}; @@ -65,7 +70,9 @@ JSDescription JSDescription::Randomized( return JSDescription( params, pubKeyHash, anchor, inputs, outputs, - vpub_old, vpub_new, computeProof); + vpub_old, vpub_new, computeProof, + esk // payment disclosure + ); } bool JSDescription::Verify( diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 111237cb70c..f9723e3992e 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -77,7 +77,8 @@ class JSDescription const boost::array& outputs, CAmount vpub_old, CAmount vpub_new, - bool computeProof = true // Set to false in some tests + bool computeProof = true, // Set to false in some tests + uint256 *esk = nullptr // payment disclosure ); static JSDescription Randomized( @@ -91,6 +92,7 @@ class JSDescription CAmount vpub_old, CAmount vpub_new, bool computeProof = true, // Set to false in some tests + uint256 *esk = nullptr, // payment disclosure std::function gen = GetRandInt ); diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 2c5bd122fe3..c02c51991c0 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -114,6 +114,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "z_getoperationstatus", 0}, { "z_getoperationresult", 0}, { "z_importkey", 2 }, + { "z_getpaymentdisclosure", 1}, + { "z_getpaymentdisclosure", 2} }; class CRPCConvertTable diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 0bd8fb1b804..7a38809025a 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -396,7 +396,11 @@ static const CRPCCommand vRPCCommands[] = { "wallet", "z_exportkey", &z_exportkey, true }, { "wallet", "z_importkey", &z_importkey, true }, { "wallet", "z_exportwallet", &z_exportwallet, true }, - { "wallet", "z_importwallet", &z_importwallet, true } + { "wallet", "z_importwallet", &z_importwallet, true }, + + // TODO: rearrange into another category + { "disclosure", "z_getpaymentdisclosure", &z_getpaymentdisclosure, true }, + { "disclosure", "z_validatepaymentdisclosure", &z_validatepaymentdisclosure, true } #endif // ENABLE_WALLET }; diff --git a/src/rpcserver.h b/src/rpcserver.h index 4da5154263c..321568748f6 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -292,6 +292,8 @@ extern UniValue z_getoperationstatus(const UniValue& params, bool fHelp); // in extern UniValue z_getoperationresult(const UniValue& params, bool fHelp); // in rpcwallet.cpp extern UniValue z_listoperationids(const UniValue& params, bool fHelp); // in rpcwallet.cpp extern UniValue z_validateaddress(const UniValue& params, bool fHelp); // in rpcmisc.cpp +extern UniValue z_getpaymentdisclosure(const UniValue& params, bool fHelp); // in rpcdisclosure.cpp +extern UniValue z_validatepaymentdisclosure(const UniValue ¶ms, bool fHelp); // in rpcdisclosure.cpp bool StartRPC(); void InterruptRPC(); diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index b4e831d5761..539d5d7d660 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/src/wallet/asyncrpcoperation_sendmany.cpp @@ -28,6 +28,8 @@ #include #include +#include "paymentdisclosuredb.h" + using namespace libzcash; int find_output(UniValue obj, int n) { @@ -103,6 +105,10 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany( } else { LogPrint("zrpc", "%s: z_sendmany initialized\n", getId()); } + + + // Enable payment disclosure if requested + paymentDisclosureMode = fExperimentalMode && GetBoolArg("-paymentdisclosure", false); } AsyncRPCOperation_sendmany::~AsyncRPCOperation_sendmany() { @@ -169,6 +175,21 @@ void AsyncRPCOperation_sendmany::main() { s += strprintf(", error=%s)\n", getErrorMessage()); } LogPrintf("%s",s); + + // !!! Payment disclosure START + if (success && paymentDisclosureMode && paymentDisclosureData_.size()>0) { + uint256 txidhash = tx_.GetHash(); + std::shared_ptr db = PaymentDisclosureDB::sharedInstance(); + for (PaymentDisclosureKeyInfo p : paymentDisclosureData_) { + p.first.hash = txidhash; + if (!db->Put(p.first, p.second)) { + LogPrint("paymentdisclosure", "%s: Payment Disclosure: Error writing entry to database for key %s\n", getId(), p.first.ToString()); + } else { + LogPrint("paymentdisclosure", "%s: Payment Disclosure: Successfully added entry to database for key %s\n", getId(), p.first.ToString()); + } + } + } + // !!! Payment disclosure END } // Notes: @@ -945,6 +966,9 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit( {info.vjsout[0], info.vjsout[1]}; boost::array inputMap; boost::array outputMap; + + uint256 esk; // payment disclosure - secret + JSDescription jsdesc = JSDescription::Randomized( *pzcashParams, joinSplitPubKey_, @@ -955,8 +979,8 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit( outputMap, info.vpub_old, info.vpub_new, - !this->testmode); - + !this->testmode, + &esk); // parameter expects pointer to esk, so pass in address { auto verifier = libzcash::ProofVerifier::Strict(); if (!(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey_))) { @@ -1025,6 +1049,28 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit( arrOutputMap.push_back(outputMap[i]); } + + // !!! Payment disclosure START + unsigned char buffer[32] = {0}; + memcpy(&buffer[0], &joinSplitPrivKey_[0], 32); // private key in first half of 64 byte buffer + std::vector vch(&buffer[0], &buffer[0] + 32); + uint256 joinSplitPrivKey = uint256(vch); + size_t js_index = tx_.vjoinsplit.size() - 1; + uint256 placeholder; + for (int i = 0; i < ZC_NUM_JS_OUTPUTS; i++) { + uint8_t mapped_index = outputMap[i]; + // placeholder for txid will be filled in later when tx has been finalized and signed. + PaymentDisclosureKey pdKey = {placeholder, js_index, mapped_index}; + JSOutput output = outputs[mapped_index]; + libzcash::PaymentAddress zaddr = output.addr; // randomized output + PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr}; + paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo)); + + CZCPaymentAddress address(zaddr); + LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), address.ToString()); + } + // !!! Payment disclosure END + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("encryptednote1", encryptedNote1)); obj.push_back(Pair("encryptednote2", encryptedNote2)); diff --git a/src/wallet/asyncrpcoperation_sendmany.h b/src/wallet/asyncrpcoperation_sendmany.h index 6fac61160e8..69bdbe31536 100644 --- a/src/wallet/asyncrpcoperation_sendmany.h +++ b/src/wallet/asyncrpcoperation_sendmany.h @@ -12,6 +12,7 @@ #include "zcash/JoinSplit.hpp" #include "zcash/Address.hpp" #include "wallet.h" +#include "paymentdisclosure.h" #include #include @@ -65,6 +66,8 @@ class AsyncRPCOperation_sendmany : public AsyncRPCOperation { bool testmode = false; // Set to true to disable sending txs and generating proofs + bool paymentDisclosureMode = false; // Set to true to save esk for encrypted notes in payment disclosure database. + private: friend class TEST_FRIEND_AsyncRPCOperation_sendmany; // class for unit testing @@ -113,6 +116,8 @@ class AsyncRPCOperation_sendmany : public AsyncRPCOperation { void sign_send_raw_transaction(UniValue obj); // throws exception if there was an error + // payment disclosure! + std::vector paymentDisclosureData_; }; diff --git a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp index 20d659cc226..a845c6085f9 100644 --- a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp +++ b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp @@ -29,6 +29,9 @@ #include "asyncrpcoperation_shieldcoinbase.h" +#include "paymentdisclosure.h" +#include "paymentdisclosuredb.h" + using namespace libzcash; static int find_output(UniValue obj, int n) { @@ -80,6 +83,9 @@ AsyncRPCOperation_shieldcoinbase::AsyncRPCOperation_shieldcoinbase( // Lock UTXOs lock_utxos(); + + // Enable payment disclosure if requested + paymentDisclosureMode = fExperimentalMode && GetBoolArg("-paymentdisclosure", false); } AsyncRPCOperation_shieldcoinbase::~AsyncRPCOperation_shieldcoinbase() { @@ -150,6 +156,21 @@ void AsyncRPCOperation_shieldcoinbase::main() { LogPrintf("%s",s); unlock_utxos(); // clean up + + // !!! Payment disclosure START + if (success && paymentDisclosureMode && paymentDisclosureData_.size()>0) { + uint256 txidhash = tx_.GetHash(); + std::shared_ptr db = PaymentDisclosureDB::sharedInstance(); + for (PaymentDisclosureKeyInfo p : paymentDisclosureData_) { + p.first.hash = txidhash; + if (!db->Put(p.first, p.second)) { + LogPrint("paymentdisclosure", "%s: Payment Disclosure: Error writing entry to database for key %s\n", getId(), p.first.ToString()); + } else { + LogPrint("paymentdisclosure", "%s: Payment Disclosure: Successfully added entry to database for key %s\n", getId(), p.first.ToString()); + } + } + } + // !!! Payment disclosure END } @@ -319,6 +340,9 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf {info.vjsout[0], info.vjsout[1]}; boost::array inputMap; boost::array outputMap; + + uint256 esk; // payment disclosure - secret + JSDescription jsdesc = JSDescription::Randomized( *pzcashParams, joinSplitPubKey_, @@ -329,8 +353,8 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf outputMap, info.vpub_old, info.vpub_new, - !this->testmode); - + !this->testmode, + &esk); // parameter expects pointer to esk, so pass in address { auto verifier = libzcash::ProofVerifier::Strict(); if (!(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey_))) { @@ -399,6 +423,27 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf arrOutputMap.push_back(outputMap[i]); } + // !!! Payment disclosure START + unsigned char buffer[32] = {0}; + memcpy(&buffer[0], &joinSplitPrivKey_[0], 32); // private key in first half of 64 byte buffer + std::vector vch(&buffer[0], &buffer[0] + 32); + uint256 joinSplitPrivKey = uint256(vch); + size_t js_index = tx_.vjoinsplit.size() - 1; + uint256 placeholder; + for (int i = 0; i < ZC_NUM_JS_OUTPUTS; i++) { + uint8_t mapped_index = outputMap[i]; + // placeholder for txid will be filled in later when tx has been finalized and signed. + PaymentDisclosureKey pdKey = {placeholder, js_index, mapped_index}; + JSOutput output = outputs[mapped_index]; + libzcash::PaymentAddress zaddr = output.addr; // randomized output + PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr}; + paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo)); + + CZCPaymentAddress address(zaddr); + LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), address.ToString()); + } + // !!! Payment disclosure END + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("encryptednote1", encryptedNote1)); obj.push_back(Pair("encryptednote2", encryptedNote2)); diff --git a/src/wallet/asyncrpcoperation_shieldcoinbase.h b/src/wallet/asyncrpcoperation_shieldcoinbase.h index 981b2fbe912..379aa5bd7a9 100644 --- a/src/wallet/asyncrpcoperation_shieldcoinbase.h +++ b/src/wallet/asyncrpcoperation_shieldcoinbase.h @@ -18,6 +18,8 @@ #include +#include "paymentdisclosure.h" + // Default transaction fee if caller does not specify one. #define SHIELD_COINBASE_DEFAULT_MINERS_FEE 10000 @@ -55,6 +57,8 @@ class AsyncRPCOperation_shieldcoinbase : public AsyncRPCOperation { bool testmode = false; // Set to true to disable sending txs and generating proofs + bool paymentDisclosureMode = false; // Set to true to save esk for encrypted notes in payment disclosure database. + private: friend class TEST_FRIEND_AsyncRPCOperation_shieldcoinbase; // class for unit testing @@ -80,6 +84,9 @@ class AsyncRPCOperation_shieldcoinbase : public AsyncRPCOperation { void lock_utxos(); void unlock_utxos(); + + // payment disclosure! + std::vector paymentDisclosureData_; }; diff --git a/src/wallet/gtest/test_wallet_zkeys.cpp b/src/wallet/gtest/test_wallet_zkeys.cpp index c7912ae7a0f..554a4ee977b 100644 --- a/src/wallet/gtest/test_wallet_zkeys.cpp +++ b/src/wallet/gtest/test_wallet_zkeys.cpp @@ -214,5 +214,7 @@ TEST(wallet_zkeys_tests, write_cryptedzkey_direct_to_db) { wallet2.GetSpendingKey(paymentAddress2.Get(), keyOut); ASSERT_EQ(paymentAddress2.Get(), keyOut.address()); + + ECC_Stop(); } diff --git a/src/wallet/rpcdisclosure.cpp b/src/wallet/rpcdisclosure.cpp new file mode 100644 index 00000000000..c1c8cb87c55 --- /dev/null +++ b/src/wallet/rpcdisclosure.cpp @@ -0,0 +1,299 @@ +// Copyright (c) 2017 The Zcash developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "base58.h" +#include "rpcserver.h" +#include "init.h" +#include "main.h" +#include "script/script.h" +#include "script/standard.h" +#include "sync.h" +#include "util.h" +#include "utiltime.h" +#include "wallet.h" + +#include +#include + +#include +#include + +#include + +#include "paymentdisclosure.h" +#include "paymentdisclosuredb.h" + +#include "zcash/Note.hpp" +#include "zcash/NoteEncryption.hpp" + +using namespace std; +using namespace libzcash; + +// Function declaration for function implemented in wallet/rpcwallet.cpp +bool EnsureWalletIsAvailable(bool avoidException); + +/** + * RPC call to generate a payment disclosure + */ +UniValue z_getpaymentdisclosure(const UniValue& params, bool fHelp) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + auto fEnablePaymentDisclosure = fExperimentalMode && GetBoolArg("-paymentdisclosure", false); + string strPaymentDisclosureDisabledMsg = ""; + if (!fEnablePaymentDisclosure) { + strPaymentDisclosureDisabledMsg = "\nWARNING: Payment disclosure is currently DISABLED. This call always fails.\n"; + } + + if (fHelp || params.size() < 3 || params.size() > 4 ) + throw runtime_error( + "z_getpaymentdisclosure \"txid\" \"js_index\" \"output_index\" (\"message\") \n" + "\nGenerate a payment disclosure for a given joinsplit output.\n" + "\nEXPERIMENTAL FEATURE\n" + + strPaymentDisclosureDisabledMsg + + "\nArguments:\n" + "1. \"txid\" (string, required) \n" + "2. \"js_index\" (string, required) \n" + "3. \"output_index\" (string, required) \n" + "4. \"message\" (string, optional) \n" + "\nResult:\n" + "\"paymentblob\" (string) Hex string of payment blob\n" + "\nExamples:\n" + + HelpExampleCli("z_getpaymentdisclosure", "96f12882450429324d5f3b48630e3168220e49ab7b0f066e5c2935a6b88bb0f2 0 0 \"refund\"") + + HelpExampleRpc("z_getpaymentdisclosure", "\"96f12882450429324d5f3b48630e3168220e49ab7b0f066e5c2935a6b88bb0f2\", 0, 0, \"refund\"") + ); + + if (!fEnablePaymentDisclosure) { + throw JSONRPCError(RPC_WALLET_ERROR, "Error: payment disclosure is disabled."); + } + + LOCK2(cs_main, pwalletMain->cs_wallet); + + EnsureWalletIsUnlocked(); + + // Check wallet knows about txid + string txid = params[0].get_str(); + uint256 hash; + hash.SetHex(txid); + + CTransaction tx; + uint256 hashBlock; + + // Check txid has been seen + if (!GetTransaction(hash, tx, hashBlock, true)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); + } + + // Check tx has been confirmed + if (hashBlock.IsNull()) { + throw JSONRPCError(RPC_MISC_ERROR, "Transaction has not been confirmed yet"); + } + + // Check is mine + if (!pwalletMain->mapWallet.count(hash)) { + throw JSONRPCError(RPC_MISC_ERROR, "Transaction does not belong to the wallet"); + } + const CWalletTx& wtx = pwalletMain->mapWallet[hash]; + + // Check if shielded tx + if (wtx.vjoinsplit.empty()) { + throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not a shielded transaction"); + } + + // Check js_index + int js_index = params[1].get_int(); + if (js_index < 0 || js_index >= wtx.vjoinsplit.size()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid js_index"); + } + + // Check output_index + int output_index = params[2].get_int(); + if (output_index < 0 || output_index >= ZC_NUM_JS_OUTPUTS) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid output_index"); + } + + // Get message if it exists + string msg; + if (params.size() == 4) { + msg = params[3].get_str(); + } + + // Create PaymentDisclosureKey + PaymentDisclosureKey key = {hash, (size_t)js_index, (uint8_t)output_index }; + + // TODO: In future, perhaps init the DB in init.cpp + shared_ptr db = PaymentDisclosureDB::sharedInstance(); + PaymentDisclosureInfo info; + if (!db->Get(key, info)) { + throw JSONRPCError(RPC_DATABASE_ERROR, "Could not find payment disclosure info for the given joinsplit output"); + } + + PaymentDisclosure pd( wtx.joinSplitPubKey, key, info, msg ); + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << pd; + string strHex = HexStr(ss.begin(), ss.end()); + return strHex; +} + + + +/** + * RPC call to validate a payment disclosure data blob. + */ +UniValue z_validatepaymentdisclosure(const UniValue& params, bool fHelp) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + auto fEnablePaymentDisclosure = fExperimentalMode && GetBoolArg("-paymentdisclosure", false); + string strPaymentDisclosureDisabledMsg = ""; + if (!fEnablePaymentDisclosure) { + strPaymentDisclosureDisabledMsg = "\nWARNING: Payment disclosure is curretly DISABLED. This call always fails.\n"; + } + + if (fHelp || params.size() != 1) + throw runtime_error( + "z_validatepaymentdisclosure \"paymentdisclosure\"\n" + "\nValidates a payment disclosure.\n" + "\nEXPERIMENTAL FEATURE\n" + + strPaymentDisclosureDisabledMsg + + "\nArguments:\n" + "1. \"paymentdisclosure\" (string, required) Hex data string\n" + "\nExamples:\n" + + HelpExampleCli("z_validatepaymentdisclosure", "\"hexblob\"") + + HelpExampleRpc("z_validatepaymentdisclosure", "\"hexblob\"") + ); + + if (!fEnablePaymentDisclosure) { + throw JSONRPCError(RPC_WALLET_ERROR, "Error: payment disclosure is disabled."); + } + + LOCK2(cs_main, pwalletMain->cs_wallet); + + EnsureWalletIsUnlocked(); + + string hexInput = params[0].get_str(); + if (!IsHex(hexInput)) + { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected payment disclosure data in hexadecimal format."); + } + + // Unserialize the payment disclosure data into an object + PaymentDisclosure pd; + CDataStream ss(ParseHex(hexInput), SER_NETWORK, PROTOCOL_VERSION); + try { + ss >> pd; + // too much data is ignored, but if not enough data, exception of type ios_base::failure is thrown, + // CBaseDataStream::read(): end of data: iostream error + } catch (const std::exception &e) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, payment disclosure data is malformed."); + } + + if (pd.payload.marker != PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, payment disclosure marker not found."); + } + + if (pd.payload.version != PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Payment disclosure version is unsupported."); + } + + uint256 hash = pd.payload.txid; + CTransaction tx; + uint256 hashBlock; + // Check if we have seen the transaction + if (!GetTransaction(hash, tx, hashBlock, true)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); + } + + // Check if the transaction has been confirmed + if (hashBlock.IsNull()) { + throw JSONRPCError(RPC_MISC_ERROR, "Transaction has not been confirmed yet"); + } + + // Check if shielded tx + if (tx.vjoinsplit.empty()) { + throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not a shielded transaction"); + } + + UniValue errs(UniValue::VARR); + UniValue o(UniValue::VOBJ); + o.push_back(Pair("txid", pd.payload.txid.ToString())); + + // Check js_index + if (pd.payload.js >= tx.vjoinsplit.size()) { + errs.push_back("Payment disclosure refers to an invalid joinsplit index"); + } + o.push_back(Pair("jsIndex", pd.payload.js)); + + if (pd.payload.n < 0 || pd.payload.n >= ZC_NUM_JS_OUTPUTS) { + errs.push_back("Payment disclosure refers to an invalid output index"); + } + o.push_back(Pair("outputIndex", pd.payload.n)); + o.push_back(Pair("version", pd.payload.version)); + o.push_back(Pair("onetimePrivKey", pd.payload.esk.ToString())); + o.push_back(Pair("message", pd.payload.message)); + o.push_back(Pair("joinSplitPubKey", tx.joinSplitPubKey.ToString())); + + // Verify the payment disclosure was signed using the same key as the transaction i.e. the joinSplitPrivKey. + uint256 dataToBeSigned = SerializeHash(pd.payload, SER_GETHASH, 0); + bool sigVerified = (crypto_sign_verify_detached(pd.payloadSig.data(), + dataToBeSigned.begin(), 32, + tx.joinSplitPubKey.begin()) == 0); + o.push_back(Pair("signatureVerified", sigVerified)); + if (!sigVerified) { + errs.push_back("Payment disclosure signature does not match transaction signature"); + } + + // Check the payment address is valid + PaymentAddress zaddr = pd.payload.zaddr; + CZCPaymentAddress address; + if (!address.Set(zaddr)) { + errs.push_back("Payment disclosure refers to an invalid payment address"); + } else { + o.push_back(Pair("paymentAddress", address.ToString())); + + try { + // Decrypt the note to get value and memo field + JSDescription jsdesc = tx.vjoinsplit[pd.payload.js]; + uint256 h_sig = jsdesc.h_sig(*pzcashParams, tx.joinSplitPubKey); + + ZCPaymentDisclosureNoteDecryption decrypter; + + ZCNoteEncryption::Ciphertext ciphertext = jsdesc.ciphertexts[pd.payload.n]; + + uint256 pk_enc = zaddr.pk_enc; + auto plaintext = decrypter.decryptWithEsk(ciphertext, pk_enc, pd.payload.esk, h_sig, pd.payload.n); + + CDataStream ssPlain(SER_NETWORK, PROTOCOL_VERSION); + ssPlain << plaintext; + NotePlaintext npt; + ssPlain >> npt; + + string memoHexString = HexStr(npt.memo.data(), npt.memo.data() + npt.memo.size()); + o.push_back(Pair("memo", memoHexString)); + o.push_back(Pair("value", ValueFromAmount(npt.value))); + + // Check the blockchain commitment matches decrypted note commitment + uint256 cm_blockchain = jsdesc.commitments[pd.payload.n]; + Note note = npt.note(zaddr); + uint256 cm_decrypted = note.cm(); + bool cm_match = (cm_decrypted == cm_blockchain); + o.push_back(Pair("commitmentMatch", cm_match)); + if (!cm_match) { + errs.push_back("Commitment derived from payment disclosure does not match blockchain commitment"); + } + } catch (const std::exception &e) { + errs.push_back(string("Error while decrypting payment disclosure note: ") + string(e.what()) ); + } + } + + bool isValid = errs.empty(); + o.push_back(Pair("valid", isValid)); + if (!isValid) { + o.push_back(Pair("errors", errs)); + } + + return o; +} diff --git a/src/zcash/JoinSplit.cpp b/src/zcash/JoinSplit.cpp index 590700cd9ab..9a7fe69db93 100644 --- a/src/zcash/JoinSplit.cpp +++ b/src/zcash/JoinSplit.cpp @@ -198,7 +198,8 @@ class JoinSplitCircuit : public JoinSplit { uint64_t vpub_old, uint64_t vpub_new, const uint256& rt, - bool computeProof + bool computeProof, + uint256 *out_esk // Payment disclosure ) { if (computeProof && !pk) { throw std::runtime_error("JoinSplit proving key not loaded"); @@ -303,6 +304,12 @@ class JoinSplitCircuit : public JoinSplit { } out_ephemeralKey = encryptor.get_epk(); + + // !!! Payment disclosure START + if (out_esk != nullptr) { + *out_esk = encryptor.get_esk(); + } + // !!! Payment disclosure END } // Authenticate h_sig with each of the input diff --git a/src/zcash/JoinSplit.hpp b/src/zcash/JoinSplit.hpp index a8c08d21b02..c6c256129b7 100644 --- a/src/zcash/JoinSplit.hpp +++ b/src/zcash/JoinSplit.hpp @@ -78,7 +78,11 @@ class JoinSplit { uint64_t vpub_old, uint64_t vpub_new, const uint256& rt, - bool computeProof = true + bool computeProof = true, + // For paymentdisclosure, we need to retrieve the esk. + // Reference as non-const parameter with default value leads to compile error. + // So use pointer for simplicity. + uint256 *out_esk = nullptr ) = 0; virtual bool verify( diff --git a/src/zcash/NoteEncryption.cpp b/src/zcash/NoteEncryption.cpp index a5ea2da1515..9ae0ba5c342 100644 --- a/src/zcash/NoteEncryption.cpp +++ b/src/zcash/NoteEncryption.cpp @@ -135,6 +135,52 @@ typename NoteDecryption::Plaintext NoteDecryption::decrypt return plaintext; } +// +// Payment disclosure - decrypt with esk +// +template +typename PaymentDisclosureNoteDecryption::Plaintext PaymentDisclosureNoteDecryption::decryptWithEsk + (const PaymentDisclosureNoteDecryption::Ciphertext &ciphertext, + const uint256 &pk_enc, + const uint256 &esk, + const uint256 &hSig, + unsigned char nonce + ) const +{ + uint256 dhsecret; + + if (crypto_scalarmult(dhsecret.begin(), esk.begin(), pk_enc.begin()) != 0) { + throw std::logic_error("Could not create DH secret"); + } + + // Regenerate keypair + uint256 epk = NoteEncryption::generate_pubkey(esk); + + unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE]; + KDF(K, dhsecret, epk, pk_enc, hSig, nonce); + + // The nonce is zero because we never reuse keys + unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {}; + + PaymentDisclosureNoteDecryption::Plaintext plaintext; + + // Message length is always NOTEENCRYPTION_AUTH_BYTES less than + // the ciphertext length. + if (crypto_aead_chacha20poly1305_ietf_decrypt(plaintext.begin(), NULL, + NULL, + ciphertext.begin(), PaymentDisclosureNoteDecryption::CLEN, + NULL, + 0, + cipher_nonce, K) != 0) { + throw note_decryption_failed(); + } + + return plaintext; +} + + + + template uint256 NoteEncryption::generate_privkey(const uint252 &a_sk) { @@ -176,4 +222,6 @@ uint252 random_uint252() template class NoteEncryption; template class NoteDecryption; +template class PaymentDisclosureNoteDecryption; + } diff --git a/src/zcash/NoteEncryption.hpp b/src/zcash/NoteEncryption.hpp index 11346ebc145..321d7deadd7 100644 --- a/src/zcash/NoteEncryption.hpp +++ b/src/zcash/NoteEncryption.hpp @@ -31,6 +31,11 @@ class NoteEncryption { NoteEncryption(uint256 hSig); + // Gets the ephemeral secret key + uint256 get_esk() { + return esk; + } + // Gets the ephemeral public key uint256 get_epk() { return epk; @@ -87,9 +92,34 @@ class note_decryption_failed : public std::runtime_error { note_decryption_failed() : std::runtime_error("Could not decrypt message") { } }; + + +// Subclass PaymentDisclosureNoteDecryption provides a method to decrypt a note with esk. +template +class PaymentDisclosureNoteDecryption : public NoteDecryption { +protected: +public: + enum { CLEN=MLEN+NOTEENCRYPTION_AUTH_BYTES }; + typedef boost::array Ciphertext; + typedef boost::array Plaintext; + + PaymentDisclosureNoteDecryption() : NoteDecryption() {} + PaymentDisclosureNoteDecryption(uint256 sk_enc) : NoteDecryption(sk_enc) {} + + Plaintext decryptWithEsk( + const Ciphertext &ciphertext, + const uint256 &pk_enc, + const uint256 &esk, + const uint256 &hSig, + unsigned char nonce + ) const; +}; + } typedef libzcash::NoteEncryption ZCNoteEncryption; typedef libzcash::NoteDecryption ZCNoteDecryption; +typedef libzcash::PaymentDisclosureNoteDecryption ZCPaymentDisclosureNoteDecryption; + #endif /* ZC_NOTE_ENCRYPTION_H_ */ From c5b04132bd5f97b17d5f03d56ecaeeee45e976eb Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 14 Nov 2017 23:53:45 +0000 Subject: [PATCH 060/177] make-release.py: Versioning changes for 1.0.13-rc1. --- README.md | 2 +- configure.ac | 4 ++-- contrib/gitian-descriptors/gitian-linux.yml | 2 +- src/clientversion.h | 4 ++-- src/deprecation.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 3d7501482d9..88774bb0d53 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Zcash 1.0.12 +Zcash 1.0.13-rc1 ============= What is Zcash? diff --git a/configure.ac b/configure.ac index f032e18d1c4..8cafa452da4 100644 --- a/configure.ac +++ b/configure.ac @@ -2,8 +2,8 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) -define(_CLIENT_VERSION_REVISION, 12) -define(_CLIENT_VERSION_BUILD, 50) +define(_CLIENT_VERSION_REVISION, 13) +define(_CLIENT_VERSION_BUILD, 25) define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50))) define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1))) define(_CLIENT_VERSION_IS_RELEASE, true) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 74573b75713..d558f0b75f6 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,5 +1,5 @@ --- -name: "zcash-1.0.12" +name: "zcash-1.0.13-rc1" enable_cache: true distro: "debian" suites: diff --git a/src/clientversion.h b/src/clientversion.h index b7eab7ae55c..5ed4e142af6 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -17,8 +17,8 @@ //! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it #define CLIENT_VERSION_MAJOR 1 #define CLIENT_VERSION_MINOR 0 -#define CLIENT_VERSION_REVISION 12 -#define CLIENT_VERSION_BUILD 50 +#define CLIENT_VERSION_REVISION 13 +#define CLIENT_VERSION_BUILD 25 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true diff --git a/src/deprecation.h b/src/deprecation.h index 9d5111c1fac..3b0dc5a407c 100644 --- a/src/deprecation.h +++ b/src/deprecation.h @@ -8,7 +8,7 @@ // Deprecation policy: // * Shut down 18 weeks' worth of blocks after the estimated release block height. // * A warning is shown during the 2 weeks' worth of blocks prior to shut down. -static const int APPROX_RELEASE_HEIGHT = 192200; +static const int APPROX_RELEASE_HEIGHT = 219700; static const int WEEKS_UNTIL_DEPRECATION = 18; static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 24); From 563f13cd931fbcc1bea688869e6eb9d35cfd520c Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 15 Nov 2017 00:02:07 +0000 Subject: [PATCH 061/177] make-release.py: Updated manpages for 1.0.13-rc1. --- doc/man/zcash-cli.1 | 10 +++++----- doc/man/zcash-tx.1 | 8 ++++---- doc/man/zcashd.1 | 12 ++++++------ 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/doc/man/zcash-cli.1 b/doc/man/zcash-cli.1 index 582316d283b..184c07d07ad 100644 --- a/doc/man/zcash-cli.1 +++ b/doc/man/zcash-cli.1 @@ -1,12 +1,12 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH ZCASH-CLI "1" "September 2017" "zcash-cli v1.0.12" "User Commands" +.TH ZCASH-CLI "1" "November 2017" "zcash-cli v1.0.13-rc1" "User Commands" .SH NAME -zcash-cli \- manual page for zcash-cli v1.0.12 +zcash-cli \- manual page for zcash-cli v1.0.13-rc1 .SH DESCRIPTION -Zcash RPC client version v1.0.12 +Zcash RPC client version v1.0.13\-rc1 .PP In order to ensure you are adequately protecting your privacy when using Zcash, -please see . +please see . .SS "Usage:" .TP zcash\-cli [options] [params] @@ -68,7 +68,7 @@ Timeout in seconds during HTTP requests, or 0 for no timeout. (default: .SH COPYRIGHT In order to ensure you are adequately protecting your privacy when using Zcash, -please see . +please see . Copyright (C) 2009-2017 The Bitcoin Core Developers Copyright (C) 2015-2017 The Zcash Developers diff --git a/doc/man/zcash-tx.1 b/doc/man/zcash-tx.1 index 3a502969ae4..ecdfcc54dc7 100644 --- a/doc/man/zcash-tx.1 +++ b/doc/man/zcash-tx.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH ZCASH-TX "1" "September 2017" "zcash-tx v1.0.12" "User Commands" +.TH ZCASH-TX "1" "November 2017" "zcash-tx v1.0.13-rc1" "User Commands" .SH NAME -zcash-tx \- manual page for zcash-tx v1.0.12 +zcash-tx \- manual page for zcash-tx v1.0.13-rc1 .SH DESCRIPTION -Zcash zcash\-tx utility version v1.0.12 +Zcash zcash\-tx utility version v1.0.13\-rc1 .SS "Usage:" .TP zcash\-tx [options] [commands] @@ -86,7 +86,7 @@ Set register NAME to given JSON\-STRING .SH COPYRIGHT In order to ensure you are adequately protecting your privacy when using Zcash, -please see . +please see . Copyright (C) 2009-2017 The Bitcoin Core Developers Copyright (C) 2015-2017 The Zcash Developers diff --git a/doc/man/zcashd.1 b/doc/man/zcashd.1 index 70c6e57f132..73fb717606a 100644 --- a/doc/man/zcashd.1 +++ b/doc/man/zcashd.1 @@ -1,12 +1,12 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH ZCASHD "1" "September 2017" "zcashd v1.0.12" "User Commands" +.TH ZCASHD "1" "November 2017" "zcashd v1.0.13-rc1" "User Commands" .SH NAME -zcashd \- manual page for zcashd v1.0.12 +zcashd \- manual page for zcashd v1.0.13-rc1 .SH DESCRIPTION -Zcash Daemon version v1.0.12 +Zcash Daemon version v1.0.13\-rc1 .PP In order to ensure you are adequately protecting your privacy when using Zcash, -please see . +please see . .SS "Usage:" .TP zcashd [options] @@ -54,7 +54,7 @@ Specify data directory \fB\-disabledeprecation=\fR .IP Disable block\-height node deprecation and automatic shutdown (example: -\fB\-disabledeprecation\fR=\fI\,1\/\fR.0.12) +\fB\-disabledeprecation\fR=\fI\,1\/\fR.0.13\-rc1) .HP \fB\-exportdir=\fR .IP @@ -462,7 +462,7 @@ console, 600 otherwise) .SH COPYRIGHT In order to ensure you are adequately protecting your privacy when using Zcash, -please see . +please see . Copyright (C) 2009-2017 The Bitcoin Core Developers Copyright (C) 2015-2017 The Zcash Developers From cbd823ae5947b7f36e241284d99e97ce36dcdd6f Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 15 Nov 2017 00:02:21 +0000 Subject: [PATCH 062/177] make-release.py: Updated release notes and changelog for 1.0.13-rc1. --- contrib/debian/changelog | 6 ++ doc/authors.md | 21 +++-- doc/release-notes/release-notes-1.0.13-rc1.md | 87 +++++++++++++++++++ 3 files changed, 105 insertions(+), 9 deletions(-) create mode 100644 doc/release-notes/release-notes-1.0.13-rc1.md diff --git a/contrib/debian/changelog b/contrib/debian/changelog index 1316276144d..f5e93234b53 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,9 @@ +zcash (1.0.13~rc1) stable; urgency=medium + + * 1.0.13-rc1 release. + + -- Zcash Company Wed, 15 Nov 2017 00:02:21 +0000 + zcash (1.0.12) stable; urgency=medium * 1.0.12 release. diff --git a/doc/authors.md b/doc/authors.md index ce6dc0e9f64..b57e6e8ad3b 100644 --- a/doc/authors.md +++ b/doc/authors.md @@ -1,18 +1,18 @@ Zcash Contributors ================== -Jack Grigg (470) -Simon Liu (274) -Sean Bowe (188) +Jack Grigg (506) +Simon Liu (281) +Sean Bowe (193) Daira Hopwood (102) +Wladimir J. van der Laan (65) Taylor Hornby (65) -Wladimir J. van der Laan (61) Nathan Wilcox (56) -Jay Graber (49) +Jay Graber (50) Jonas Schnelli (48) Kevin Gallagher (38) Pieter Wuille (16) -Cory Fields (15) +Cory Fields (16) nomnombtc (9) Paige Peterson (9) fanquake (5) @@ -27,10 +27,11 @@ Karl-Johan Alm (4) Jeff Garzik (4) David Mercer (4) Daniel Cousens (4) +Ariel Gabizon (4) lpescher (3) kozyilmaz (3) Pavel Janík (3) -Ariel Gabizon (3) +João Barbosa (3) Alfie John (3) str4d (2) paveljanik (2) @@ -39,8 +40,8 @@ aniemerg (2) Scott (2) Robert C. Seacord (2) Luke Dashjr (2) -João Barbosa (2) Joe Turgeon (2) +Jason Davies (2) Jack Gavigan (2) ITH4Coinomia (2) Gavin Andresen (2) @@ -73,20 +74,22 @@ Leo Arias (1) Lars-Magnus Skog (1) Kevin Pan (1) Jorge Timón (1) +Jonathan "Duke" Leto (1) Jeffrey Walton (1) -Jason Davies (1) Ian Kelling (1) Gaurav Rana (1) Forrest Voight (1) Florian Schmaus (1) Ethan Heilman (1) Eran Tromer (1) +Duke Leto (1) Daniel Kraft (1) Christian von Roques (1) Chirag Davé (1) Casey Rodarmor (1) Cameron Boehmer (1) Bryan Stitt (1) +Bruno Arueira (1) Boris Hajduk (1) Bob McElrath (1) Bitcoin Error Log (1) diff --git a/doc/release-notes/release-notes-1.0.13-rc1.md b/doc/release-notes/release-notes-1.0.13-rc1.md new file mode 100644 index 00000000000..0f60564708d --- /dev/null +++ b/doc/release-notes/release-notes-1.0.13-rc1.md @@ -0,0 +1,87 @@ +Changelog +========= + +Ariel Gabizon (1): + boost::format -> tinyformat + +Bruno Arueira (1): + Removes out bitcoin mention in favor for zcash + +Cory Fields (1): + httpserver: explicitly detach worker threads + +Duke Leto (1): + Update performance-measurements.sh + +Jack Grigg (36): + Squashed 'src/snark/' content from commit 9ada3f8 + Add libsnark compile flag to not copy DEPINST to PREFIX + Add Ansible playbook for grind workers + Add connections in BIP65 and BIP66 tests to the test manager + Add benchmark for listunspent + [Test] MiniNode: Implement JSDescription parsing + [Test] MiniNode: Implement v2 CTransaction parsing + [Test] MiniNode: Implement Zcash block parsing + [Test] MiniNode: Update protocol version and network magics + [Test] MiniNode: Use Zcash PoW + [Test] MiniNode: Fix coinbase creation + [Test] MiniNode: Coerce OP_PUSHDATA bytearrays to bytes + [Test] MiniNode: Implement Zcash coinbase + Fix BIP65 and BIP66 tests + Un-indent RPC test output in test runner + Replace full-test-suite.sh with a new test suite driver script + Move ensure-no-dot-so-in-depends.py into full_test_suite.py + Move check-security-hardening.sh into full_test_suite.py + Add memory benchmark for validatelargetx + Migrate libsnark test code to Google Test + Remove test code corresponding to removed code + Add alt_bn128 to QAP and Merkle tree gadget tests + Update libsnark LDLIBS + Add "make check" to libsnark that runs the Google Tests + Add "make libsnark-tests" that runs libsnark's "make check" + Changes to get test_r1cs_ppzksnark passing + Add bitcoin-util-test.py to full_test_suite.py + Add stdout notice if any stage fails + Add libsnark to "make clean" + Ensure that libsnark is built first, so its headers are available + Remove OpenSSL libraries from libsnark LDLIBS + Add libsnark tests to full_test_suite.py + Add --list-stages argument to full_test_suite.py + Fix NPE in rpc_wallet_tests + make-release.py: Versioning changes for 1.0.13-rc1. + make-release.py: Updated manpages for 1.0.13-rc1. + +Jason Davies (1): + Replace "bitcoin" with "Zcash". + +Jay Graber (1): + s/zcash/Zcash + +Jonathan "Duke" Leto (1): + Fix bug where performance-measurements.sh fails hards when given no args + +João Barbosa (1): + Improve shutdown process + +Sean Bowe (5): + Remove libsnark from depends system and integrate it into build system. + Remove crusty old "loadVerifyingKey"/"loadProvingKey" APIs and associated invariants. + Refactor proof generation function. + Add streaming prover. + Integrate low memory prover. + +Simon Liu (7): + Replace 'bitcoin address' with 'zcash address'. + Closes #2639. z_shieldcoinbase is now supported, no longer experimental. + Closes #2263 fixing broken pipe error. + Closes #2576. Update link to security info on z.cash website. + Closes #2639. Adds optional limit parameter with a default value of 50. + Fix an issue where qa test wallet_shieldcoinbase could hang. + Add payment disclosure as experimental feature. + +Wladimir J. van der Laan (4): + Make HTTP server shutdown more graceful + http: Wait for worker threads to exit + http: Force-exit event loop after predefined time + http: speed up shutdown + From 66a9fd8b72103aa4ad907faf8c277f4c5b970f52 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 15 Nov 2017 00:37:02 +0000 Subject: [PATCH 063/177] Change auto-senescence cycle to 16 weeks Closes #2686 --- doc/release-notes/release-notes-1.0.13-rc1.md | 1 + src/deprecation.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/release-notes/release-notes-1.0.13-rc1.md b/doc/release-notes/release-notes-1.0.13-rc1.md index 0f60564708d..90e2306adf1 100644 --- a/doc/release-notes/release-notes-1.0.13-rc1.md +++ b/doc/release-notes/release-notes-1.0.13-rc1.md @@ -50,6 +50,7 @@ Jack Grigg (36): Fix NPE in rpc_wallet_tests make-release.py: Versioning changes for 1.0.13-rc1. make-release.py: Updated manpages for 1.0.13-rc1. + Change auto-senescence cycle to 16 weeks Jason Davies (1): Replace "bitcoin" with "Zcash". diff --git a/src/deprecation.h b/src/deprecation.h index 3b0dc5a407c..7ef71553941 100644 --- a/src/deprecation.h +++ b/src/deprecation.h @@ -6,10 +6,10 @@ #define ZCASH_DEPRECATION_H // Deprecation policy: -// * Shut down 18 weeks' worth of blocks after the estimated release block height. +// * Shut down 16 weeks' worth of blocks after the estimated release block height. // * A warning is shown during the 2 weeks' worth of blocks prior to shut down. static const int APPROX_RELEASE_HEIGHT = 219700; -static const int WEEKS_UNTIL_DEPRECATION = 18; +static const int WEEKS_UNTIL_DEPRECATION = 16; static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 24); // Number of blocks before deprecation to warn users From 83bef3fcbe13414b3b3d8a25bf3c2e65af9fea43 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 15 Nov 2017 10:14:19 +0000 Subject: [PATCH 064/177] Move libsnark from DIST_SUBDIRS into EXTRA_DIST --- src/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 5b80b724f13..e9f10232c50 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -DIST_SUBDIRS = secp256k1 snark univalue +DIST_SUBDIRS = secp256k1 univalue AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) @@ -553,7 +553,7 @@ CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a *.gcda *.gcno */*.gcno wal DISTCLEANFILES = obj/build.h -EXTRA_DIST = leveldb +EXTRA_DIST = leveldb snark clean-local: -$(MAKE) -C leveldb clean From 8f23c734e6484a9ee37e857c5225202a581d2123 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 15 Nov 2017 14:39:57 +0000 Subject: [PATCH 065/177] Pass correct dependencies path to libsnark from both Gitian and build.sh --- configure.ac | 10 +++++++++- src/Makefile.am | 4 ++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 8cafa452da4..8c30efcfe23 100644 --- a/configure.ac +++ b/configure.ac @@ -762,6 +762,14 @@ if test x$enable_rust != xno; then RUST_LIBS="-lrustzcash" fi +# Gitian uses a config.site that sets depends_prefix, and then sets --prefix=/ +# build.sh just uses --prefix +if test x$depends_prefix != x; then + LIBSNARK_DEPINST="$depends_prefix" +else + LIBSNARK_DEPINST="$prefix" +fi + LIBZCASH_LIBS="-lgmp -lgmpxx -lboost_system-mt -lcrypto -lsodium -fopenmp $RUST_LIBS" CXXFLAGS_TEMP="$CXXFLAGS" @@ -897,7 +905,7 @@ AC_SUBST(TESTDEFS) AC_SUBST(LEVELDB_TARGET_FLAGS) AC_SUBST(GMP_LIBS) AC_SUBST(GMPXX_LIBS) -AC_SUBST(LIBSNARK_LIBS) +AC_SUBST(LIBSNARK_DEPINST) AC_SUBST(LIBZCASH_LIBS) AC_SUBST(PROTON_LIBS) AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi src/test/buildenv.py]) diff --git a/src/Makefile.am b/src/Makefile.am index e9f10232c50..ea745a1f7d4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -49,10 +49,10 @@ LIBSNARK_CXXFLAGS = -fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1 LIBSNARK_CONFIG_FLAGS = CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT NO_COPY_DEPINST=1 $(LIBSNARK): $(wildcard snark/src/*) - $(AM_V_at) CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ install PREFIX=$(srcdir)/build DEPINST=$(prefix) $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" + $(AM_V_at) CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ install PREFIX=$(srcdir)/build DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" libsnark-tests: $(wildcard snark/src/*) - $(AM_V_at) CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ check PREFIX=$(srcdir)/build DEPINST=$(prefix) $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" + $(AM_V_at) CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ check PREFIX=$(srcdir)/build DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" $(LIBUNIVALUE): $(wildcard univalue/lib/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue/ From fee88353885147111bcca69c817a5339abd76109 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 15 Nov 2017 16:49:10 +0000 Subject: [PATCH 066/177] Mark libsnark includes as library includes --- src/gtest/main.cpp | 6 +++--- src/gtest/test_circuit.cpp | 9 +++++---- src/gtest/test_merkletree.cpp | 8 ++++---- src/gtest/test_proofs.cpp | 7 +++---- src/init.cpp | 2 +- src/zcash/CreateJoinSplit.cpp | 3 ++- src/zcash/JoinSplit.cpp | 8 ++++---- src/zcash/Proof.cpp | 8 ++++---- 8 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/gtest/main.cpp b/src/gtest/main.cpp index a0a2e0042ed..0b6e1ad0851 100644 --- a/src/gtest/main.cpp +++ b/src/gtest/main.cpp @@ -1,12 +1,12 @@ #include "gtest/gtest.h" #include "crypto/common.h" #include "pubkey.h" - -#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp" -#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" #include "zcash/JoinSplit.hpp" #include "util.h" +#include +#include + struct ECCryptoClosure { ECCVerifyHandle handle; diff --git a/src/gtest/test_circuit.cpp b/src/gtest/test_circuit.cpp index f8a0416a7cb..2cc9dbcbb9b 100644 --- a/src/gtest/test_circuit.cpp +++ b/src/gtest/test_circuit.cpp @@ -7,10 +7,11 @@ #include #include -#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp" -#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" -#include "libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" -#include "libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp" +#include +#include +#include +#include + #include "zcash/IncrementalMerkleTree.hpp" using namespace libsnark; diff --git a/src/gtest/test_merkletree.cpp b/src/gtest/test_merkletree.cpp index 6bac9ab3c19..d603b0aa651 100644 --- a/src/gtest/test_merkletree.cpp +++ b/src/gtest/test_merkletree.cpp @@ -19,10 +19,10 @@ #include "zcash/IncrementalMerkleTree.hpp" #include "zcash/util.h" -#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp" -#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" -#include "libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" -#include "libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp" +#include +#include +#include +#include #include diff --git a/src/gtest/test_proofs.cpp b/src/gtest/test_proofs.cpp index cf097d716a0..e33b1cc0c78 100644 --- a/src/gtest/test_proofs.cpp +++ b/src/gtest/test_proofs.cpp @@ -3,10 +3,9 @@ #include -#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp" -#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" -#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" -#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" +#include +#include +#include using namespace libzcash; diff --git a/src/init.cpp b/src/init.cpp index fe7f1700909..7df31ab1bbe 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -53,7 +53,7 @@ #include #include -#include "libsnark/common/profiling.hpp" +#include #if ENABLE_ZMQ #include "zmq/zmqnotificationinterface.h" diff --git a/src/zcash/CreateJoinSplit.cpp b/src/zcash/CreateJoinSplit.cpp index 7253e95685e..bcf9a218ec6 100644 --- a/src/zcash/CreateJoinSplit.cpp +++ b/src/zcash/CreateJoinSplit.cpp @@ -5,7 +5,8 @@ #include "../util.h" #include "primitives/transaction.h" #include "zcash/JoinSplit.hpp" -#include "libsnark/common/profiling.hpp" + +#include using namespace libzcash; diff --git a/src/zcash/JoinSplit.cpp b/src/zcash/JoinSplit.cpp index ab20592380f..2685569d35d 100644 --- a/src/zcash/JoinSplit.cpp +++ b/src/zcash/JoinSplit.cpp @@ -10,10 +10,10 @@ #include #include #include -#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp" -#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" -#include "libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" -#include "libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp" +#include +#include +#include +#include #include "tinyformat.h" #include "sync.h" #include "amount.h" diff --git a/src/zcash/Proof.cpp b/src/zcash/Proof.cpp index 1b2199407f9..e7264e68473 100644 --- a/src/zcash/Proof.cpp +++ b/src/zcash/Proof.cpp @@ -1,12 +1,12 @@ #include "Proof.hpp" +#include "crypto/common.h" + #include +#include +#include #include -#include "crypto/common.h" -#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp" -#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" - using namespace libsnark; typedef alt_bn128_pp curve_pp; From 051698a05c852793316810d3538fb4a84906d547 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 16 Nov 2017 22:37:38 +0000 Subject: [PATCH 067/177] Add the tar-pax option to automake This enables the tarball generated by "make dist" to contain file names longer than 99 characters. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 8c30efcfe23..8d18fb2a917 100644 --- a/configure.ac +++ b/configure.ac @@ -24,7 +24,7 @@ dnl faketime breaks configure and is only needed for make. Disable it here. unset FAKETIME dnl Automake init set-up and checks -AM_INIT_AUTOMAKE([no-define subdir-objects foreign]) +AM_INIT_AUTOMAKE([no-define subdir-objects foreign tar-pax]) dnl faketime messes with timestamps and causes configure to be re-run. dnl --disable-maintainer-mode can be used to bypass this. From ba1dbb3040cf678f9aee612fbfc23a336d5dbe6e Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 16 Nov 2017 22:29:37 -0800 Subject: [PATCH 068/177] RPC dumpwallet and z_exportwallet updated to no longer allow overwriting an existing file. --- qa/rpc-tests/walletbackup.py | 9 +++++++++ src/wallet/rpcdump.cpp | 8 ++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/qa/rpc-tests/walletbackup.py b/qa/rpc-tests/walletbackup.py index 37c1db9a568..78128ad49ab 100755 --- a/qa/rpc-tests/walletbackup.py +++ b/qa/rpc-tests/walletbackup.py @@ -34,6 +34,7 @@ """ from test_framework.test_framework import BitcoinTestFramework +from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, initialize_chain_clean, \ start_nodes, start_node, connect_nodes, stop_node, \ sync_blocks, sync_mempools @@ -141,6 +142,14 @@ def run_test(self): self.nodes[2].backupwallet("walletbak") self.nodes[2].dumpwallet("walletdump") + # Verify dumpwallet cannot overwrite an existing file + try: + self.nodes[2].dumpwallet("walletdump") + assert(False) + except JSONRPCException as e: + errorString = e.error['message'] + assert("Cannot overwrite existing file" in errorString) + logging.info("More transactions") for i in range(5): self.do_one_round() diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index fe5b83e8d4d..a02dfcb31fb 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -428,7 +428,7 @@ UniValue z_exportwallet(const UniValue& params, bool fHelp) if (fHelp || params.size() != 1) throw runtime_error( "z_exportwallet \"filename\"\n" - "\nExports all wallet keys, for taddr and zaddr, in a human-readable format.\n" + "\nExports all wallet keys, for taddr and zaddr, in a human-readable format. Overwriting an existing file is not permitted.\n" "\nArguments:\n" "1. \"filename\" (string, required) The filename, saved in folder set by zcashd -exportdir option\n" "\nResult:\n" @@ -449,7 +449,7 @@ UniValue dumpwallet(const UniValue& params, bool fHelp) if (fHelp || params.size() != 1) throw runtime_error( "dumpwallet \"filename\"\n" - "\nDumps taddr wallet keys in a human-readable format.\n" + "\nDumps taddr wallet keys in a human-readable format. Overwriting an existing file is not permitted.\n" "\nArguments:\n" "1. \"filename\" (string, required) The filename, saved in folder set by zcashd -exportdir option\n" "\nResult:\n" @@ -484,6 +484,10 @@ UniValue dumpwallet_impl(const UniValue& params, bool fHelp, bool fDumpZKeys) } boost::filesystem::path exportfilepath = exportdir / clean; + if (boost::filesystem::exists(exportfilepath)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot overwrite existing file " + exportfilepath.string()); + } + ofstream file; file.open(exportfilepath.string().c_str()); if (!file.is_open()) From e70c8d2ea31c0d55b46c411c28eb9a03c665b824 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 17 Nov 2017 17:49:28 +0000 Subject: [PATCH 069/177] make-release.py: Versioning changes for 1.0.13-rc2. --- README.md | 2 +- configure.ac | 2 +- contrib/gitian-descriptors/gitian-linux.yml | 2 +- src/clientversion.h | 2 +- src/deprecation.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 88774bb0d53..42e3f77f660 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Zcash 1.0.13-rc1 +Zcash 1.0.13-rc2 ============= What is Zcash? diff --git a/configure.ac b/configure.ac index 8d18fb2a917..ce3303da4d1 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 13) -define(_CLIENT_VERSION_BUILD, 25) +define(_CLIENT_VERSION_BUILD, 26) define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50))) define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1))) define(_CLIENT_VERSION_IS_RELEASE, true) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index d558f0b75f6..e78daa2688f 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,5 +1,5 @@ --- -name: "zcash-1.0.13-rc1" +name: "zcash-1.0.13-rc2" enable_cache: true distro: "debian" suites: diff --git a/src/clientversion.h b/src/clientversion.h index 5ed4e142af6..cd9919938e3 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -18,7 +18,7 @@ #define CLIENT_VERSION_MAJOR 1 #define CLIENT_VERSION_MINOR 0 #define CLIENT_VERSION_REVISION 13 -#define CLIENT_VERSION_BUILD 25 +#define CLIENT_VERSION_BUILD 26 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true diff --git a/src/deprecation.h b/src/deprecation.h index 7ef71553941..530de67b93e 100644 --- a/src/deprecation.h +++ b/src/deprecation.h @@ -8,7 +8,7 @@ // Deprecation policy: // * Shut down 16 weeks' worth of blocks after the estimated release block height. // * A warning is shown during the 2 weeks' worth of blocks prior to shut down. -static const int APPROX_RELEASE_HEIGHT = 219700; +static const int APPROX_RELEASE_HEIGHT = 221270; static const int WEEKS_UNTIL_DEPRECATION = 16; static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 24); From 562b55bec1a01b520064973ffa2ce65dfa89fcc0 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 17 Nov 2017 18:00:32 +0000 Subject: [PATCH 070/177] make-release.py: Updated manpages for 1.0.13-rc2. --- doc/man/zcash-cli.1 | 6 +++--- doc/man/zcash-tx.1 | 6 +++--- doc/man/zcashd.1 | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/man/zcash-cli.1 b/doc/man/zcash-cli.1 index 184c07d07ad..4d6081d3fbf 100644 --- a/doc/man/zcash-cli.1 +++ b/doc/man/zcash-cli.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH ZCASH-CLI "1" "November 2017" "zcash-cli v1.0.13-rc1" "User Commands" +.TH ZCASH-CLI "1" "November 2017" "zcash-cli v1.0.13-rc2" "User Commands" .SH NAME -zcash-cli \- manual page for zcash-cli v1.0.13-rc1 +zcash-cli \- manual page for zcash-cli v1.0.13-rc2 .SH DESCRIPTION -Zcash RPC client version v1.0.13\-rc1 +Zcash RPC client version v1.0.13\-rc2 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . diff --git a/doc/man/zcash-tx.1 b/doc/man/zcash-tx.1 index ecdfcc54dc7..4baa0cd599e 100644 --- a/doc/man/zcash-tx.1 +++ b/doc/man/zcash-tx.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH ZCASH-TX "1" "November 2017" "zcash-tx v1.0.13-rc1" "User Commands" +.TH ZCASH-TX "1" "November 2017" "zcash-tx v1.0.13-rc2" "User Commands" .SH NAME -zcash-tx \- manual page for zcash-tx v1.0.13-rc1 +zcash-tx \- manual page for zcash-tx v1.0.13-rc2 .SH DESCRIPTION -Zcash zcash\-tx utility version v1.0.13\-rc1 +Zcash zcash\-tx utility version v1.0.13\-rc2 .SS "Usage:" .TP zcash\-tx [options] [commands] diff --git a/doc/man/zcashd.1 b/doc/man/zcashd.1 index 73fb717606a..d39345c6872 100644 --- a/doc/man/zcashd.1 +++ b/doc/man/zcashd.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH ZCASHD "1" "November 2017" "zcashd v1.0.13-rc1" "User Commands" +.TH ZCASHD "1" "November 2017" "zcashd v1.0.13-rc2" "User Commands" .SH NAME -zcashd \- manual page for zcashd v1.0.13-rc1 +zcashd \- manual page for zcashd v1.0.13-rc2 .SH DESCRIPTION -Zcash Daemon version v1.0.13\-rc1 +Zcash Daemon version v1.0.13\-rc2 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . @@ -54,7 +54,7 @@ Specify data directory \fB\-disabledeprecation=\fR .IP Disable block\-height node deprecation and automatic shutdown (example: -\fB\-disabledeprecation\fR=\fI\,1\/\fR.0.13\-rc1) +\fB\-disabledeprecation\fR=\fI\,1\/\fR.0.13\-rc2) .HP \fB\-exportdir=\fR .IP From 48ea914cd0ab31de322223a36ea6c07b108655e6 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 17 Nov 2017 18:01:08 +0000 Subject: [PATCH 071/177] make-release.py: Updated release notes and changelog for 1.0.13-rc2. --- contrib/debian/changelog | 6 ++++++ doc/authors.md | 2 +- doc/release-notes/release-notes-1.0.13-rc2.md | 11 +++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 doc/release-notes/release-notes-1.0.13-rc2.md diff --git a/contrib/debian/changelog b/contrib/debian/changelog index f5e93234b53..835748fcb8d 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,9 @@ +zcash (1.0.13~rc2) stable; urgency=medium + + * 1.0.13-rc2 release. + + -- Zcash Company Fri, 17 Nov 2017 18:01:08 +0000 + zcash (1.0.13~rc1) stable; urgency=medium * 1.0.13-rc1 release. diff --git a/doc/authors.md b/doc/authors.md index b57e6e8ad3b..2dbe9f661ea 100644 --- a/doc/authors.md +++ b/doc/authors.md @@ -1,7 +1,7 @@ Zcash Contributors ================== -Jack Grigg (506) +Jack Grigg (512) Simon Liu (281) Sean Bowe (193) Daira Hopwood (102) diff --git a/doc/release-notes/release-notes-1.0.13-rc2.md b/doc/release-notes/release-notes-1.0.13-rc2.md new file mode 100644 index 00000000000..0b60ffc9afb --- /dev/null +++ b/doc/release-notes/release-notes-1.0.13-rc2.md @@ -0,0 +1,11 @@ +Changelog +========= + +Jack Grigg (6): + Move libsnark from DIST_SUBDIRS into EXTRA_DIST + Pass correct dependencies path to libsnark from both Gitian and build.sh + Mark libsnark includes as library includes + Add the tar-pax option to automake + make-release.py: Versioning changes for 1.0.13-rc2. + make-release.py: Updated manpages for 1.0.13-rc2. + From 337a99a219690057d1a4da4bb15a0ac6db2ffc53 Mon Sep 17 00:00:00 2001 From: Jay Graber Date: Mon, 13 Nov 2017 14:44:11 -0800 Subject: [PATCH 072/177] Add cli and rpc examples for z_sendmany --- src/rpcmisc.cpp | 3 ++- src/wallet/rpcwallet.cpp | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index b2bc1aefeee..96dbb756a33 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -224,7 +224,8 @@ UniValue z_validateaddress(const UniValue& params, bool fHelp) "}\n" "\nExamples:\n" - + HelpExampleCli("validateaddress", "\"zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL\"") + + HelpExampleCli("z_validateaddress", "\"zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL\"") + + HelpExampleRpc("z_validateaddress", "\"zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL\"") ); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 034147f42fc..b9240a800dc 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3053,6 +3053,9 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp) " \"amount\": xxxxx, (numeric) the amount of value in the note\n" " \"memo\": xxxxx, (string) hexademical string representation of memo field\n" "}\n" + "\nExamples:\n" + + HelpExampleCli("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"") + + HelpExampleRpc("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"") ); LOCK2(cs_main, pwalletMain->cs_wallet); @@ -3222,6 +3225,9 @@ UniValue z_getoperationresult(const UniValue& params, bool fHelp) "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n" "\nResult:\n" "\" [object, ...]\" (array) A list of JSON objects\n" + "\nExamples:\n" + + HelpExampleCli("z_getoperationresult", "'[\"operationid\", ... ]'") + + HelpExampleRpc("z_getoperationresult", "'[\"operationid\", ... ]'") ); // This call will remove finished operations @@ -3242,6 +3248,9 @@ UniValue z_getoperationstatus(const UniValue& params, bool fHelp) "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n" "\nResult:\n" "\" [object, ...]\" (array) A list of JSON objects\n" + "\nExamples:\n" + + HelpExampleCli("z_getoperationstatus", "'[\"operationid\", ... ]'") + + HelpExampleRpc("z_getoperationstatus", "'[\"operationid\", ... ]'") ); // This call is idempotent so we don't want to remove finished operations @@ -3342,6 +3351,9 @@ UniValue z_sendmany(const UniValue& params, bool fHelp) + strprintf("%s", FormatMoney(ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n" "\nResult:\n" "\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n" + "\nExamples:\n" + + HelpExampleCli("z_sendmany", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" '[{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]'") + + HelpExampleRpc("z_sendmany", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", [{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]") ); LOCK2(cs_main, pwalletMain->cs_wallet); @@ -3548,6 +3560,9 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp) " \"remainingUTXOs\": xxx (numeric) Number of coinbase utxos still available for shielding.\n" " \"remainingValue\": xxx (numeric) Value of coinbase utxos still available for shielding.\n" "}\n" + "\nExamples:\n" + + HelpExampleCli("z_shieldcoinbase", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"") + + HelpExampleRpc("z_shieldcoinbase", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"") ); LOCK2(cs_main, pwalletMain->cs_wallet); From 24902602f2f695a85dd364836b041ce5ec0a2565 Mon Sep 17 00:00:00 2001 From: syd Date: Sun, 19 Nov 2017 14:08:17 -0500 Subject: [PATCH 073/177] Upgrade googletest to 1.8.0 --- depends/packages/googlemock.mk | 20 -------------------- depends/packages/googletest.mk | 13 ++++++++----- depends/packages/packages.mk | 2 +- 3 files changed, 9 insertions(+), 26 deletions(-) delete mode 100644 depends/packages/googlemock.mk diff --git a/depends/packages/googlemock.mk b/depends/packages/googlemock.mk deleted file mode 100644 index 229dc358767..00000000000 --- a/depends/packages/googlemock.mk +++ /dev/null @@ -1,20 +0,0 @@ -# url=https://github.com/google/googlemock/archive/release-1.7.0.tar.gz - -package=googlemock -$(package)_version=1.7.0 -$(package)_dependencies=googletest - -$(package)_download_path=https://github.com/google/$(package)/archive/ -$(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_download_file=release-$($(package)_version).tar.gz -$(package)_sha256_hash=3f20b6acb37e5a98e8c4518165711e3e35d47deb6cdb5a4dd4566563b5efd232 - -define $(package)_build_cmds - $(MAKE) -C make GTEST_DIR='$(host_prefix)' CXXFLAGS='-fPIC' gmock-all.o -endef - - -define $(package)_stage_cmds - install -D ./make/gmock-all.o $($(package)_staging_dir)$(host_prefix)/lib/libgmock.a && \ - cp -a ./include $($(package)_staging_dir)$(host_prefix)/include -endef diff --git a/depends/packages/googletest.mk b/depends/packages/googletest.mk index 5133e64a104..94880efdbf5 100644 --- a/depends/packages/googletest.mk +++ b/depends/packages/googletest.mk @@ -1,15 +1,18 @@ package=googletest -$(package)_version=1.7.0 +$(package)_version=1.8.0 $(package)_download_path=https://github.com/google/$(package)/archive/ $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_download_file=release-$($(package)_version).tar.gz -$(package)_sha256_hash=f73a6546fdf9fce9ff93a5015e0333a8af3062a152a9ad6bcb772c96687016cc +$(package)_sha256_hash=58a6f4277ca2bc8565222b3bbd58a177609e9c488e8a72649359ba51450db7d8 define $(package)_build_cmds - $(MAKE) -C make CXXFLAGS=-fPIC gtest.a + $(MAKE) -C googlemock/make CXXFLAGS=-fPIC gmock.a && \ + $(MAKE) -C googletest/make CXXFLAGS=-fPIC gtest.a endef define $(package)_stage_cmds - install -D ./make/gtest.a $($(package)_staging_dir)$(host_prefix)/lib/libgtest.a && \ - cp -a ./include $($(package)_staging_dir)$(host_prefix)/include + install -D ./googlemock/make/gmock.a $($(package)_staging_dir)$(host_prefix)/lib/libgmock.a && \ + install -D ./googletest/make/gtest.a $($(package)_staging_dir)$(host_prefix)/lib/libgtest.a && \ + cp -a ./googlemock/include $($(package)_staging_dir)$(host_prefix)/ && \ + cp -a ./googletest/include $($(package)_staging_dir)$(host_prefix)/ endef diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index 0b7905e4ff0..296323c8cd3 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -1,7 +1,7 @@ rust_packages := rust librustzcash proton_packages := proton zcash_packages := libgmp libsodium -packages := boost openssl libevent zeromq $(zcash_packages) googletest googlemock +packages := boost openssl libevent zeromq $(zcash_packages) googletest native_packages := native_ccache wallet_packages=bdb From 2d342736dcfd002966512788a419e6dabe899c61 Mon Sep 17 00:00:00 2001 From: syd Date: Mon, 20 Nov 2017 00:48:12 -0500 Subject: [PATCH 074/177] Get the sec-hard tests to run correctly. This fixes the way arguments were passed to security-check, and also a typo in how BIND_NOW was being searched for in a list. Also fix how symbol-check is invoked although that script isn't currently used. --- contrib/devtools/security-check.py | 2 +- src/Makefile.am | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py index 301fea85c1f..84e7fceeace 100755 --- a/contrib/devtools/security-check.py +++ b/contrib/devtools/security-check.py @@ -94,7 +94,7 @@ def check_ELF_RELRO(executable): raise IOError('Error opening file') for line in stdout.split(b'\n'): tokens = line.split() - if len(tokens)>1 and tokens[1] == b'(BIND_NOW)' or (len(tokens)>2 and tokens[1] == b'(FLAGS)' and b'BIND_NOW' in tokens[2]): + if len(tokens)>1 and tokens[1] == b'(BIND_NOW)' or (len(tokens)>2 and tokens[1] == b'(FLAGS)' and b'BIND_NOW' in tokens[2:]): have_bindnow = True return have_gnu_relro and have_bindnow diff --git a/src/Makefile.am b/src/Makefile.am index ea745a1f7d4..1c741d05552 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -573,13 +573,13 @@ clean-local: check-symbols: $(bin_PROGRAMS) if GLIBC_BACK_COMPAT @echo "Checking glibc back compat of [$(bin_PROGRAMS)]..." - $(AM_V_at) READELF=$(READELF) CPPFILT=$(CPPFILT) $(top_srcdir)/contrib/devtools/symbol-check.py < $(bin_PROGRAMS) + $(AM_V_at) READELF=$(READELF) CPPFILT=$(CPPFILT) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS) endif check-security: $(bin_PROGRAMS) if HARDEN @echo "Checking binary security of [$(bin_PROGRAMS)]..." - $(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(top_srcdir)/contrib/devtools/security-check.py < $(bin_PROGRAMS) + $(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(top_srcdir)/contrib/devtools/security-check.py $(bin_PROGRAMS) endif %.pb.cc %.pb.h: %.proto From 0523d21d22aedf28842e7553a0f614cd9c7b5e24 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 20 Nov 2017 12:23:45 +0000 Subject: [PATCH 075/177] make-release.py: Versioning changes for 1.0.13. --- README.md | 2 +- configure.ac | 2 +- contrib/gitian-descriptors/gitian-linux.yml | 2 +- src/clientversion.h | 2 +- src/deprecation.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 42e3f77f660..2efce727afb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Zcash 1.0.13-rc2 +Zcash 1.0.13 ============= What is Zcash? diff --git a/configure.ac b/configure.ac index ce3303da4d1..3eca0a24de3 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 13) -define(_CLIENT_VERSION_BUILD, 26) +define(_CLIENT_VERSION_BUILD, 50) define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50))) define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1))) define(_CLIENT_VERSION_IS_RELEASE, true) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index e78daa2688f..3096a7f0ddf 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,5 +1,5 @@ --- -name: "zcash-1.0.13-rc2" +name: "zcash-1.0.13" enable_cache: true distro: "debian" suites: diff --git a/src/clientversion.h b/src/clientversion.h index cd9919938e3..f1081d55320 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -18,7 +18,7 @@ #define CLIENT_VERSION_MAJOR 1 #define CLIENT_VERSION_MINOR 0 #define CLIENT_VERSION_REVISION 13 -#define CLIENT_VERSION_BUILD 26 +#define CLIENT_VERSION_BUILD 50 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true diff --git a/src/deprecation.h b/src/deprecation.h index 530de67b93e..434a81f3668 100644 --- a/src/deprecation.h +++ b/src/deprecation.h @@ -8,7 +8,7 @@ // Deprecation policy: // * Shut down 16 weeks' worth of blocks after the estimated release block height. // * A warning is shown during the 2 weeks' worth of blocks prior to shut down. -static const int APPROX_RELEASE_HEIGHT = 221270; +static const int APPROX_RELEASE_HEIGHT = 222900; static const int WEEKS_UNTIL_DEPRECATION = 16; static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 24); From 404de74fc6203d9963cc4c833342ba10baebb597 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 20 Nov 2017 12:31:33 +0000 Subject: [PATCH 076/177] make-release.py: Updated manpages for 1.0.13. --- doc/man/zcash-cli.1 | 6 +++--- doc/man/zcash-tx.1 | 6 +++--- doc/man/zcashd.1 | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/man/zcash-cli.1 b/doc/man/zcash-cli.1 index 4d6081d3fbf..a77b67ffce8 100644 --- a/doc/man/zcash-cli.1 +++ b/doc/man/zcash-cli.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH ZCASH-CLI "1" "November 2017" "zcash-cli v1.0.13-rc2" "User Commands" +.TH ZCASH-CLI "1" "November 2017" "zcash-cli v1.0.13" "User Commands" .SH NAME -zcash-cli \- manual page for zcash-cli v1.0.13-rc2 +zcash-cli \- manual page for zcash-cli v1.0.13 .SH DESCRIPTION -Zcash RPC client version v1.0.13\-rc2 +Zcash RPC client version v1.0.13 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . diff --git a/doc/man/zcash-tx.1 b/doc/man/zcash-tx.1 index 4baa0cd599e..fb54abf116f 100644 --- a/doc/man/zcash-tx.1 +++ b/doc/man/zcash-tx.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH ZCASH-TX "1" "November 2017" "zcash-tx v1.0.13-rc2" "User Commands" +.TH ZCASH-TX "1" "November 2017" "zcash-tx v1.0.13" "User Commands" .SH NAME -zcash-tx \- manual page for zcash-tx v1.0.13-rc2 +zcash-tx \- manual page for zcash-tx v1.0.13 .SH DESCRIPTION -Zcash zcash\-tx utility version v1.0.13\-rc2 +Zcash zcash\-tx utility version v1.0.13 .SS "Usage:" .TP zcash\-tx [options] [commands] diff --git a/doc/man/zcashd.1 b/doc/man/zcashd.1 index d39345c6872..e6ea1b8dc55 100644 --- a/doc/man/zcashd.1 +++ b/doc/man/zcashd.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH ZCASHD "1" "November 2017" "zcashd v1.0.13-rc2" "User Commands" +.TH ZCASHD "1" "November 2017" "zcashd v1.0.13" "User Commands" .SH NAME -zcashd \- manual page for zcashd v1.0.13-rc2 +zcashd \- manual page for zcashd v1.0.13 .SH DESCRIPTION -Zcash Daemon version v1.0.13\-rc2 +Zcash Daemon version v1.0.13 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . @@ -54,7 +54,7 @@ Specify data directory \fB\-disabledeprecation=\fR .IP Disable block\-height node deprecation and automatic shutdown (example: -\fB\-disabledeprecation\fR=\fI\,1\/\fR.0.13\-rc2) +\fB\-disabledeprecation\fR=\fI\,1\/\fR.0.13) .HP \fB\-exportdir=\fR .IP From 4b9eb663bff9e2487ca22e48b06a1a7b88ef6f54 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 20 Nov 2017 12:31:53 +0000 Subject: [PATCH 077/177] make-release.py: Updated release notes and changelog for 1.0.13. --- contrib/debian/changelog | 6 ++++++ doc/authors.md | 2 +- doc/release-notes/release-notes-1.0.13.md | 7 +++++++ 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 doc/release-notes/release-notes-1.0.13.md diff --git a/contrib/debian/changelog b/contrib/debian/changelog index 835748fcb8d..71e8b0b589b 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,9 @@ +zcash (1.0.13) stable; urgency=medium + + * 1.0.13 release. + + -- Zcash Company Mon, 20 Nov 2017 12:31:53 +0000 + zcash (1.0.13~rc2) stable; urgency=medium * 1.0.13-rc2 release. diff --git a/doc/authors.md b/doc/authors.md index 2dbe9f661ea..7094aff8beb 100644 --- a/doc/authors.md +++ b/doc/authors.md @@ -1,7 +1,7 @@ Zcash Contributors ================== -Jack Grigg (512) +Jack Grigg (514) Simon Liu (281) Sean Bowe (193) Daira Hopwood (102) diff --git a/doc/release-notes/release-notes-1.0.13.md b/doc/release-notes/release-notes-1.0.13.md new file mode 100644 index 00000000000..d6552168798 --- /dev/null +++ b/doc/release-notes/release-notes-1.0.13.md @@ -0,0 +1,7 @@ +Changelog +========= + +Jack Grigg (2): + make-release.py: Versioning changes for 1.0.13. + make-release.py: Updated manpages for 1.0.13. + From f4f064bb1f87047139e701bf11de108de03884aa Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 17 Nov 2017 11:43:46 -0800 Subject: [PATCH 078/177] Add documentation for shielding coinbase utxos. --- doc/shield-coinbase.md | 101 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 doc/shield-coinbase.md diff --git a/doc/shield-coinbase.md b/doc/shield-coinbase.md new file mode 100644 index 00000000000..515ce95b7a7 --- /dev/null +++ b/doc/shield-coinbase.md @@ -0,0 +1,101 @@ +# Shielding Coinbase UTXOs + +**Summary** + +Use z_shieldcoinbase RPC call to shield coinbase UTXOs. + +**Who should read this document** + +Miners, Mining pools, Online wallets + +## Background + +The current Zcash protocol includes a consensus rule that coinbase rewards must be sent to a shielded address. + +## User Experience Challenges + +A user can use the z_sendmany RPC call to shield coinbase funds, but the call was not designed for sweeping up many utxos, and offered a suboptimal user experience. + +If customers send mining pool payouts to their online wallet, the service provider must sort through UTXOs to correctly determine the non-coinbase UTXO funds that can be withdrawn or transferred by customers to another transparent address. + +## Solution + +The z_shieldcoinbase call makes it easy to sweep up coinbase rewards from multiple coinbase utxos across multiple coinbase reward addresses. + + z_shieldcoinbase fromaddress toaddress (fee) (limit) + +Where the default fee is 0.0010000 ZEC and the default limit on the maximum number of UTXOs to shield is 50. + +## Examples + +Sweep up coinbase utxos from a transparent address you use for mining: + + zcash-cli z_shieldcoinbase tMyMiningAddress zMyPrivateAddress + +Sweep up coinbase utxos from multiple transparent addresses to a shielded address: + + zcash-cli z_shieldcoinbase "*" zMyPrivateAddress + +Sweep up with a fee of 1.23 ZEC: + + zcash-cli z_shieldcoinbase tMyMiningAddress zMyPrivateAddress 1.23 + +Sweep up with a fee of 0.1 ZEC and set limit on the maximum number of utxos to shield at 25: + + zcash-cli z_shieldcoinbase "*" zMyPrivateAddress 0.1 25 + +### Asynchronous Call + +The `z_shieldcoinbase` RPC call is an asynchronous call, so you can queue up multiple operations. + +When you invoke + + zcash-cli z_shieldcoinbase tMyMiningAddress zMyPrivateAddress + +JSON will be returned immediately, with the following data fields populated: + +- operationid: a temporary id to use with `z_getoperationstatus` and `z_getoperationresult` to get the status and result of the operation. +- shieldedUTXOs: number of coinbase utxos being shielded +- shieldedValue: value of coinbase utxos being shielded. +- remainingUTXOs: number of coinbase utxos still available for shielding. +- remainingValue: value of coinbase utxos still available for shielding + +### Locking UTXOs + +The `z_shieldcoinbase` call will lock any selected UTXOs. This prevents the selected UTXOs which are already queued up from being selected for any other send operation. If the `z_shieldcoinbase` call fails, any locked UTXOs are unlocked. + +You can use the RPC call `lockunspent` to see which UTXOs have been locked. You can also use this call to unlock any UTXOs in the event of an unexpected system failure which leaves UTXOs in a locked state. + +### Limits, Performance and Transaction Confirmation + +The number of coinbase utxos selected for shielding can be adjusted by setting the limit parameter. The default value is 50. + +If the limit parameter is set to zero, the zcashd `mempooltxinputlimit` option will be used instead, where the default value for `mempooltxinputlimit` is zero, which means no limit. + +Any limit is constrained by a hard limit due to the consensus rule defining a maximum transaction size of 100,000 bytes. + +In general, the more utxos that are selected, the longer it takes for the transaction to be verified. Due to the quadratic hashing problem, some miners use the `mempooltxinputlimit` option to reject transactions with a large number of UTXO inputs. + +Currently, as of November 2017, there is no commonly agreed upon limit, but as a rule of thumb (a form of emergent consensus) if a transaction has less than 100 UTXO inputs, the transaction will be mined promptly by the majority of mining pools, but if it has many more UTXO inputs, such as 500, it might take several days to be mined by a miner who has higher or no limits. + +### Anatomy of a z_shieldcoinbase transaction + +The transaction created is a shielded transaction. It consists of a single joinsplit, which consumes coinbase UTXOs as input, and deposits value at a shielded address, minus any fee. + +The number of coinbase UTXOs is determined by a user configured limit. + +If no limit is set (in the case when limit parameter and `mempooltxinputlimit` options are set to zero) the behaviour of z_shieldcoinbase is to consume as many utxos as possible, with `z_shieldcoinbase` constructing a transaction up to the size limit of 100,000 bytes. + +As a result, the maximum number of inputs that can be selected is: + +- P2PKH coinbase utxos ~ 662 +- 2-of-3 multisig P2SH coinbase utxos ~ 244. + +Here is an example of using `z_shieldcoinbase` on testnet to shield multi-sig coinbase utxos. + +- Block 141042 is almost ~2 MB in size (the maximum size for a block) and contains 1 coinbase reward transaction and 20 transactions, each indivually created by a call to z_shieldcoinbase. + - https://explorer.testnet.z.cash/block/0050552a78e97c89f666713c8448d49ad1d7263274422272696187dedf6c0d03 +- Drilling down into a transaction, you can see there is one joinsplit, with 244 inputs (vin) and 0 outputs (vout). + - https://explorer.testnet.z.cash/tx/cf4f3da2e434f68b6e361303403344e22a9ff9a8fda9abc180d9520d0ca6527d + + From 43f5d52123746e1da8166930ca898bcd04b4a103 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 20 Nov 2017 16:55:10 -0800 Subject: [PATCH 079/177] Add documentation for payment disclosure. --- doc/payment-disclosure.md | 107 ++++++++++++++++++++++++++++++++++++++ doc/shield-coinbase.md | 34 ++++++------ 2 files changed, 124 insertions(+), 17 deletions(-) create mode 100644 doc/payment-disclosure.md diff --git a/doc/payment-disclosure.md b/doc/payment-disclosure.md new file mode 100644 index 00000000000..d0aa68a963f --- /dev/null +++ b/doc/payment-disclosure.md @@ -0,0 +1,107 @@ +# Payment Disclosure (Experimental Feature) + +**Summary** + +Use RPC calls `z_getpaymentdisclosure` and `z_validatepaymentdisclosure` to reveal details of a shielded payment. + +**Who should read this document** + +Frequent users of shielded transactions, payment processors, exchanges, block explorer + +### Experimental Feature + +This is an experimental feature. Enable it by launching `zcashd` with flags: + + zcashd -experimentalfeatures -paymentdisclosure -debug=paymentdisclosure -txindex=1 + +These flags can also be set as options in `zcash.conf`. + +All nodes that generate or validate payment disclosures must run with `txindex=1` enabled. + +### Background + +Payment Disclosure is an implementation of the work-in-progress Payment Disclosure ZIP [1]. + +The ZIP describes a method of proving that a payment was sent to a shielded address. In the typical case, this means enabling a sender to present a proof that they transferred funds to a recipient's shielded address. + +[1] https://github.com/zcash/zips/pull/119 + +### Example Use Case + +Alice the customer sends 10 ZEC to Bob the merchant at the shielded address shown on their website. However, Bob is not sure if he received the funds. + +Alice's node is running with payment disclosure enabled, so Alice generates a payment disclosure and provides it to Bob, who verifies the payment was made. + +If Bob is a bad merchant, Alice can present the payment disclosure to a third party to validate that payment was indeed made. + +### Solution + +A payment disclosure can be generated for any output of a JoinSplit using the RPC call: + + z_getpaymentdisclosure txid js_index output_index (message) + +An optional message can be supplied. This could be used for a refund address or some other reference, as currently it is not common practice to (ahead of time) include a refund address in the memo field when making a payment. + +To validate a payment disclosure, the following RPC call can be used: + + z_validatepaymentdisclosure hexdata + +### Example + +Generate a payment disclosure for the first joinsplit, second output (index starts from zero): + + zcash-cli z_getpaymentdisclosure 79189528d611e811a1c7bb0358dd31343033d14b4c1e998d7c4799c40f8b652b 0 1 "Hello" + +This returns a payment disclosure in the form of a hex string: + + 706462ff000a3722aafa8190cdf9710bfad6da2af6d3a74262c1fc96ad47df814b0cd5641c2b658b0fc499477c8d991e4c4bd133303431dd5803bbc7a111e811d6289518790000000000000000017e861adb829d8cb1cbcf6330b8c2e25fb0d08041a67a857815a136f0227f8a5342bce5b3c0d894e2983000eb594702d3c1580817d0374e15078528e56bb6f80c0548656c6c6f59a7085395c9e706d82afe3157c54ad4ae5bf144fcc774a8d9c921c58471402019c156ec5641e2173c4fb6467df5f28530dc4636fa71f4d0e48fc5c560fac500 + +To validate the payment disclosure: + + zcash-cli z_validatepaymentdisclosure HEXDATA + +This returns data related to the payment and the payment disclosure: + + { + "txid": "79189528d611e811a1c7bb0358dd31343033d14b4c1e998d7c4799c40f8b652b", + "jsIndex": 0, + "outputIndex": 1, + "version": 0, + "onetimePrivKey": "1c64d50c4b81df47ad96fcc16242a7d3f62adad6fa0b71f9cd9081faaa22370a", + "message": "Hello", + "joinSplitPubKey": "d1c465d16166b602992479acfac18e87dc18065f6cefde6a002e70bc371b9faf", + "signatureVerified": true, + "paymentAddress": "ztaZJXy8iX8nrk2ytXKDBoTWqPkhQcj6E2ifARnD3wfkFwsxXs5SoX7NGmrjkzSiSKn8VtLHTJae48vX5NakvmDhtGNY5eb", + "memo": "f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": 12.49900000, + "commitmentMatch": true, + "valid": true + } + +The `signatureVerified` field confirms that the payment disclosure was generated and signed with the joinSplitPrivKey, which should only be known by the node generating and sending the transaction 7918...652b in question. + +### Where is the data stored? + +For all nodes, payment disclosure does not touch `wallet.dat` in any way. + +For nodes that only validate payment disclosures, no data is stored locally. + +For nodes that generate payment disclosures, a LevelDB database is created in the node's datadir. For most users, this would be in the folder: + + $HOME/.zcash/paymentdisclosure + +If you decide you don't want to use payment disclosure, it is safe to shut down your node and delete the database folder. + +### Security Properties + +Please consult the work-in-progress ZIP for details about the protocol, security properties and caveats. + +### Reminder + +Feedback is most welcome! + +This is an experimental feature so there are no guarantees that the protocol, database format, RPC interface etc. will remain the same in the future. + +### Notes + +Currently there is no user friendly way to help senders identify which joinsplit output index maps to a given payment they made. It is possible to construct this from `debug.log`. Ideas and feedback are most welcome on how to improve the user experience. diff --git a/doc/shield-coinbase.md b/doc/shield-coinbase.md index 515ce95b7a7..d3986fec75d 100644 --- a/doc/shield-coinbase.md +++ b/doc/shield-coinbase.md @@ -2,7 +2,7 @@ **Summary** -Use z_shieldcoinbase RPC call to shield coinbase UTXOs. +Use `z_shieldcoinbase` RPC call to shield coinbase UTXOs. **Who should read this document** @@ -14,25 +14,25 @@ The current Zcash protocol includes a consensus rule that coinbase rewards must ## User Experience Challenges -A user can use the z_sendmany RPC call to shield coinbase funds, but the call was not designed for sweeping up many utxos, and offered a suboptimal user experience. +A user can use the z_sendmany RPC call to shield coinbase funds, but the call was not designed for sweeping up many UTXOs, and offered a suboptimal user experience. If customers send mining pool payouts to their online wallet, the service provider must sort through UTXOs to correctly determine the non-coinbase UTXO funds that can be withdrawn or transferred by customers to another transparent address. ## Solution -The z_shieldcoinbase call makes it easy to sweep up coinbase rewards from multiple coinbase utxos across multiple coinbase reward addresses. +The z_shieldcoinbase call makes it easy to sweep up coinbase rewards from multiple coinbase UTXOs across multiple coinbase reward addresses. z_shieldcoinbase fromaddress toaddress (fee) (limit) -Where the default fee is 0.0010000 ZEC and the default limit on the maximum number of UTXOs to shield is 50. +The default fee is 0.0010000 ZEC and the default limit on the maximum number of UTXOs to shield is 50. ## Examples -Sweep up coinbase utxos from a transparent address you use for mining: +Sweep up coinbase UTXOs from a transparent address you use for mining: zcash-cli z_shieldcoinbase tMyMiningAddress zMyPrivateAddress -Sweep up coinbase utxos from multiple transparent addresses to a shielded address: +Sweep up coinbase UTXOs from multiple transparent addresses to a shielded address: zcash-cli z_shieldcoinbase "*" zMyPrivateAddress @@ -40,7 +40,7 @@ Sweep up with a fee of 1.23 ZEC: zcash-cli z_shieldcoinbase tMyMiningAddress zMyPrivateAddress 1.23 -Sweep up with a fee of 0.1 ZEC and set limit on the maximum number of utxos to shield at 25: +Sweep up with a fee of 0.1 ZEC and set limit on the maximum number of UTXOs to shield at 25: zcash-cli z_shieldcoinbase "*" zMyPrivateAddress 0.1 25 @@ -55,10 +55,10 @@ When you invoke JSON will be returned immediately, with the following data fields populated: - operationid: a temporary id to use with `z_getoperationstatus` and `z_getoperationresult` to get the status and result of the operation. -- shieldedUTXOs: number of coinbase utxos being shielded -- shieldedValue: value of coinbase utxos being shielded. -- remainingUTXOs: number of coinbase utxos still available for shielding. -- remainingValue: value of coinbase utxos still available for shielding +- shieldedUTXOs: number of coinbase UTXOs being shielded +- shieldedValue: value of coinbase UTXOs being shielded. +- remainingUTXOs: number of coinbase UTXOs still available for shielding. +- remainingValue: value of coinbase UTXOs still available for shielding ### Locking UTXOs @@ -68,13 +68,13 @@ You can use the RPC call `lockunspent` to see which UTXOs have been locked. You ### Limits, Performance and Transaction Confirmation -The number of coinbase utxos selected for shielding can be adjusted by setting the limit parameter. The default value is 50. +The number of coinbase UTXOs selected for shielding can be adjusted by setting the limit parameter. The default value is 50. If the limit parameter is set to zero, the zcashd `mempooltxinputlimit` option will be used instead, where the default value for `mempooltxinputlimit` is zero, which means no limit. Any limit is constrained by a hard limit due to the consensus rule defining a maximum transaction size of 100,000 bytes. -In general, the more utxos that are selected, the longer it takes for the transaction to be verified. Due to the quadratic hashing problem, some miners use the `mempooltxinputlimit` option to reject transactions with a large number of UTXO inputs. +In general, the more UTXOs that are selected, the longer it takes for the transaction to be verified. Due to the quadratic hashing problem, some miners use the `mempooltxinputlimit` option to reject transactions with a large number of UTXO inputs. Currently, as of November 2017, there is no commonly agreed upon limit, but as a rule of thumb (a form of emergent consensus) if a transaction has less than 100 UTXO inputs, the transaction will be mined promptly by the majority of mining pools, but if it has many more UTXO inputs, such as 500, it might take several days to be mined by a miner who has higher or no limits. @@ -84,14 +84,14 @@ The transaction created is a shielded transaction. It consists of a single join The number of coinbase UTXOs is determined by a user configured limit. -If no limit is set (in the case when limit parameter and `mempooltxinputlimit` options are set to zero) the behaviour of z_shieldcoinbase is to consume as many utxos as possible, with `z_shieldcoinbase` constructing a transaction up to the size limit of 100,000 bytes. +If no limit is set (in the case when limit parameter and `mempooltxinputlimit` options are set to zero) the behaviour of z_shieldcoinbase is to consume as many UTXOs as possible, with `z_shieldcoinbase` constructing a transaction up to the size limit of 100,000 bytes. As a result, the maximum number of inputs that can be selected is: -- P2PKH coinbase utxos ~ 662 -- 2-of-3 multisig P2SH coinbase utxos ~ 244. +- P2PKH coinbase UTXOs ~ 662 +- 2-of-3 multisig P2SH coinbase UTXOs ~ 244. -Here is an example of using `z_shieldcoinbase` on testnet to shield multi-sig coinbase utxos. +Here is an example of using `z_shieldcoinbase` on testnet to shield multi-sig coinbase UTXOs. - Block 141042 is almost ~2 MB in size (the maximum size for a block) and contains 1 coinbase reward transaction and 20 transactions, each indivually created by a call to z_shieldcoinbase. - https://explorer.testnet.z.cash/block/0050552a78e97c89f666713c8448d49ad1d7263274422272696187dedf6c0d03 From 159aa37fc0139d298e5f54fc332fc500825dc5f9 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 22 Nov 2017 00:02:52 -0800 Subject: [PATCH 080/177] Closes #2759. Fixes broken pipe error with QA test wallet.py. --- qa/rpc-tests/wallet.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index 9b91c803d2f..12dfac0e419 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -271,6 +271,16 @@ def run_test (self): for i in xrange(0,num_t_recipients): newtaddr = self.nodes[2].getnewaddress() recipients.append({"address":newtaddr, "amount":amount_per_recipient}) + + # Issue #2759 Workaround START + # HTTP connection to node 0 may fall into a state, during the few minutes it takes to process + # loop above to create new addresses, that when z_sendmany is called with a large amount of + # rpc data in recipients, the connection fails with a 'broken pipe' error. Making a RPC call + # to node 0 before calling z_sendmany appears to fix this issue, perhaps putting the HTTP + # connection into a good state to handle a large amount of data in recipients. + self.nodes[0].getinfo() + # Issue #2759 Workaround END + try: self.nodes[0].z_sendmany(myzaddr, recipients) except JSONRPCException,e: @@ -288,6 +298,11 @@ def run_test (self): for i in xrange(0,num_z_recipients): newzaddr = self.nodes[2].z_getnewaddress() recipients.append({"address":newzaddr, "amount":amount_per_recipient}) + + # Issue #2759 Workaround START + self.nodes[0].getinfo() + # Issue #2759 Workaround END + try: self.nodes[0].z_sendmany(myzaddr, recipients) except JSONRPCException,e: From 0c177bc585ca96029a606249c6bd09e6e6f8c6c2 Mon Sep 17 00:00:00 2001 From: syd Date: Wed, 22 Nov 2017 23:16:51 -0500 Subject: [PATCH 081/177] Update libsodium from 1.0.11 to 1.0.15 --- depends/packages/libsodium.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/depends/packages/libsodium.mk b/depends/packages/libsodium.mk index d7717bbfc7d..8135e83d6ff 100644 --- a/depends/packages/libsodium.mk +++ b/depends/packages/libsodium.mk @@ -1,8 +1,8 @@ package=libsodium -$(package)_version=1.0.11 +$(package)_version=1.0.15 $(package)_download_path=https://download.libsodium.org/libsodium/releases/ -$(package)_file_name=libsodium-1.0.11.tar.gz -$(package)_sha256_hash=a14549db3c49f6ae2170cbbf4664bd48ace50681045e8dbea7c8d9fb96f9c765 +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=fb6a9e879a2f674592e4328c5d9f79f082405ee4bb05cb6e679b90afe9e178f4 $(package)_dependencies= $(package)_config_opts= From c72a4732cc16a33790ea1d071ed5635803af9f6a Mon Sep 17 00:00:00 2001 From: syd Date: Thu, 23 Nov 2017 00:05:21 -0500 Subject: [PATCH 082/177] Remove Boost conditional compilation. Boost is currently at version 106200 in the depends subsystem so it is safe to remove code the refers to earlier versions. This closes #2445 --- src/scheduler.cpp | 16 +--------------- src/util.cpp | 4 ---- src/wallet/walletdb.cpp | 4 ---- 3 files changed, 1 insertion(+), 23 deletions(-) diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 184ddc28abb..8729f2a5a51 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -20,13 +20,6 @@ CScheduler::~CScheduler() } -#if BOOST_VERSION < 105000 -static boost::system_time toPosixTime(const boost::chrono::system_clock::time_point& t) -{ - return boost::posix_time::from_time_t(boost::chrono::system_clock::to_time_t(t)); -} -#endif - void CScheduler::serviceQueue() { boost::unique_lock lock(newTaskMutex); @@ -45,20 +38,13 @@ void CScheduler::serviceQueue() // Wait until either there is a new task, or until // the time of the first item on the queue: -// wait_until needs boost 1.50 or later; older versions have timed_wait: -#if BOOST_VERSION < 105000 - while (!shouldStop() && !taskQueue.empty() && - newTaskScheduled.timed_wait(lock, toPosixTime(taskQueue.begin()->first))) { - // Keep waiting until timeout - } -#else // Some boost versions have a conflicting overload of wait_until that returns void. // Explicitly use a template here to avoid hitting that overload. while (!shouldStop() && !taskQueue.empty() && newTaskScheduled.wait_until<>(lock, taskQueue.begin()->first) != boost::cv_status::timeout) { // Keep waiting until timeout } -#endif + // If there are multiple threads, the queue can empty while we're waiting (another // thread may service the task we were waiting on). if (shouldStop() || taskQueue.empty()) diff --git a/src/util.cpp b/src/util.cpp index cc8632c6a87..19c400631d5 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -911,10 +911,6 @@ std::string LicenseInfo() int GetNumCores() { -#if BOOST_VERSION >= 105600 return boost::thread::physical_concurrency(); -#else // Must fall back to hardware_concurrency, which unfortunately counts virtual cores - return boost::thread::hardware_concurrency(); -#endif } diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index ec6c55ee30e..f252243369c 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -968,11 +968,7 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) pathDest /= wallet.strWalletFile; try { -#if BOOST_VERSION >= 104000 boost::filesystem::copy_file(pathSrc, pathDest, boost::filesystem::copy_option::overwrite_if_exists); -#else - boost::filesystem::copy_file(pathSrc, pathDest); -#endif LogPrintf("copied wallet.dat to %s\n", pathDest.string()); return true; } catch (const boost::filesystem::filesystem_error& e) { From 6df5f51b7ca545c16d000f68bc7dedca6ca9daa7 Mon Sep 17 00:00:00 2001 From: syd Date: Thu, 23 Nov 2017 11:58:25 -0500 Subject: [PATCH 083/177] Update to address @daira comments wrt fixing configure.ac Since we're enforcing Boost >= 1.62, we no longer need HAVE_WORKING_BOOST_SLEEP_FOR. --- configure.ac | 76 +----------------------------------- src/test/scheduler_tests.cpp | 7 ---- src/utiltime.cpp | 13 ------ 3 files changed, 2 insertions(+), 94 deletions(-) diff --git a/configure.ac b/configure.ac index 3eca0a24de3..b61acf468d5 100644 --- a/configure.ac +++ b/configure.ac @@ -554,33 +554,14 @@ fi if test x$use_boost = xyes; then dnl Check for boost libs -AX_BOOST_BASE +dnl We need Boost >= 1.62 to fix a potential security bug (https://github.com/zcash/zcash/issues/1241) +AX_BOOST_BASE([1.62]) AX_BOOST_SYSTEM AX_BOOST_FILESYSTEM AX_BOOST_PROGRAM_OPTIONS AX_BOOST_THREAD AX_BOOST_CHRONO - -if test x$use_reduce_exports = xyes; then - AC_MSG_CHECKING([for working boost reduced exports]) - TEMP_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$BOOST_CPPFLAGS $CPPFLAGS" - AC_PREPROC_IFELSE([AC_LANG_PROGRAM([[ - @%:@include - ]], [[ - #if BOOST_VERSION >= 104900 - // Everything is okay - #else - # error Boost version is too old - #endif - ]])],[ - AC_MSG_RESULT(yes) - ],[ - AC_MSG_ERROR([boost versions < 1.49 are known to be broken with reduced exports. Use --disable-reduce-exports.]) - ]) - CPPFLAGS="$TEMP_CPPFLAGS" -fi fi if test x$use_reduce_exports = xyes; then @@ -621,60 +602,7 @@ if test x$use_tests = xyes; then fi if test x$use_boost = xyes; then - BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB $BOOST_PROGRAM_OPTIONS_LIB $BOOST_THREAD_LIB $BOOST_CHRONO_LIB" - -dnl Boost >= 1.50 uses sleep_for rather than the now-deprecated sleep, however -dnl it was broken from 1.50 to 1.52 when backed by nanosleep. Use sleep_for if -dnl a working version is available, else fall back to sleep. sleep was removed -dnl after 1.56. -dnl If neither is available, abort. -TEMP_LIBS="$LIBS" -LIBS="$BOOST_LIBS $LIBS" -TEMP_CPPFLAGS="$CPPFLAGS" -CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" -AC_LINK_IFELSE([AC_LANG_PROGRAM([[ - #include - #include - ]],[[ - #if BOOST_VERSION >= 105000 && (!defined(BOOST_HAS_NANOSLEEP) || BOOST_VERSION >= 105200) - boost::this_thread::sleep_for(boost::chrono::milliseconds(0)); - #else - choke me - #endif - ]])], - [boost_sleep=yes; - AC_DEFINE(HAVE_WORKING_BOOST_SLEEP_FOR, 1, [Define this symbol if boost sleep_for works])], - [boost_sleep=no]) -LIBS="$TEMP_LIBS" -CPPFLAGS="$TEMP_CPPFLAGS" - -if test x$boost_sleep != xyes; then -TEMP_LIBS="$LIBS" -LIBS="$BOOST_LIBS $LIBS" -TEMP_CPPFLAGS="$CPPFLAGS" -CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" -AC_LINK_IFELSE([AC_LANG_PROGRAM([[ - #include - #include - #include - ]],[[ - #if BOOST_VERSION <= 105600 - boost::this_thread::sleep(boost::posix_time::milliseconds(0)); - #else - choke me - #endif - ]])], - [boost_sleep=yes; AC_DEFINE(HAVE_WORKING_BOOST_SLEEP, 1, [Define this symbol if boost sleep works])], - [boost_sleep=no]) -LIBS="$TEMP_LIBS" -CPPFLAGS="$TEMP_CPPFLAGS" -fi - -if test x$boost_sleep != xyes; then - AC_MSG_ERROR(No working boost sleep implementation found.) -fi - fi if test x$use_pkgconfig = xyes; then diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp index cb1a427db00..d6c93ef3bca 100644 --- a/src/test/scheduler_tests.cpp +++ b/src/test/scheduler_tests.cpp @@ -30,14 +30,7 @@ static void microTask(CScheduler& s, boost::mutex& mutex, int& counter, int delt static void MicroSleep(uint64_t n) { -#if defined(HAVE_WORKING_BOOST_SLEEP_FOR) boost::this_thread::sleep_for(boost::chrono::microseconds(n)); -#elif defined(HAVE_WORKING_BOOST_SLEEP) - boost::this_thread::sleep(boost::posix_time::microseconds(n)); -#else - //should never get here - #error missing boost sleep implementation -#endif } BOOST_AUTO_TEST_CASE(manythreads) diff --git a/src/utiltime.cpp b/src/utiltime.cpp index a7cdeb114b3..f1a408a31d4 100644 --- a/src/utiltime.cpp +++ b/src/utiltime.cpp @@ -43,20 +43,7 @@ int64_t GetTimeMicros() void MilliSleep(int64_t n) { - -/** - * Boost's sleep_for was uninterruptable when backed by nanosleep from 1.50 - * until fixed in 1.52. Use the deprecated sleep method for the broken case. - * See: https://svn.boost.org/trac/boost/ticket/7238 - */ -#if defined(HAVE_WORKING_BOOST_SLEEP_FOR) boost::this_thread::sleep_for(boost::chrono::milliseconds(n)); -#elif defined(HAVE_WORKING_BOOST_SLEEP) - boost::this_thread::sleep(boost::posix_time::milliseconds(n)); -#else -//should never get here -#error missing boost sleep implementation -#endif } std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime) From dffc025d38bb12b655bfde53de6dd237840c7d8e Mon Sep 17 00:00:00 2001 From: syd Date: Thu, 23 Nov 2017 12:20:50 -0500 Subject: [PATCH 084/177] Get rid of consensus.fPowAllowMinDifficultyBlocks. This closes #1380 --- src/chainparams.cpp | 2 -- src/consensus/params.h | 1 - src/miner.cpp | 9 --------- 3 files changed, 12 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 16c5e9d24a7..034eee6b2b3 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -49,7 +49,6 @@ class CMainParams : public CChainParams { consensus.nPowMaxAdjustDown = 32; // 32% adjustment down consensus.nPowMaxAdjustUp = 16; // 16% adjustment up consensus.nPowTargetSpacing = 2.5 * 60; - consensus.fPowAllowMinDifficultyBlocks = false; /** * The message start string should be awesome! ⓩ❤ */ @@ -211,7 +210,6 @@ class CTestNetParams : public CMainParams { consensus.nMajorityWindow = 400; consensus.powLimit = uint256S("07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow); - consensus.fPowAllowMinDifficultyBlocks = true; pchMessageStart[0] = 0xfa; pchMessageStart[1] = 0x1a; pchMessageStart[2] = 0xf9; diff --git a/src/consensus/params.h b/src/consensus/params.h index d3e6462b8e3..c74e66d5fa4 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -41,7 +41,6 @@ struct Params { int nMajorityWindow; /** Proof of work parameters */ uint256 powLimit; - bool fPowAllowMinDifficultyBlocks; int64_t nPowAveragingWindow; int64_t nPowMaxAdjustDown; int64_t nPowMaxAdjustUp; diff --git a/src/miner.cpp b/src/miner.cpp index 3434a0d7c79..327228f3f6e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -100,10 +100,6 @@ class TxPriorityCompare void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev) { pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); - - // Updating time can change work required on testnet: - if (consensusParams.fPowAllowMinDifficultyBlocks) - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams); } CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) @@ -714,11 +710,6 @@ void static BitcoinMiner() // Update nNonce and nTime pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1); UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); - if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks) - { - // Changing pblock->nTime can change work required on testnet: - hashTarget.SetCompact(pblock->nBits); - } } } } From 7c591c6d2f6466f1adda6f85122098db327ad32e Mon Sep 17 00:00:00 2001 From: syd Date: Sat, 25 Nov 2017 10:58:37 -0500 Subject: [PATCH 085/177] Don't compile libgtest.a when building libsnark. Previously libsnark would try to build libgtest if /usr/src/gtest exists on the build machine. This caused issues because the version of libgtest in /usr/src isn't necessarily the same as the one that the rest of zcash's gtests were built with. --- src/Makefile.am | 2 +- src/snark/Makefile | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index ea745a1f7d4..48b60911a99 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -46,7 +46,7 @@ $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) collate-libsnark: $(LIBSNARK) LIBSNARK_CXXFLAGS = -fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1 -LIBSNARK_CONFIG_FLAGS = CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT NO_COPY_DEPINST=1 +LIBSNARK_CONFIG_FLAGS = CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT NO_COPY_DEPINST=1 NO_COMPILE_LIBGTEST=1 $(LIBSNARK): $(wildcard snark/src/*) $(AM_V_at) CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ install PREFIX=$(srcdir)/build DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" diff --git a/src/snark/Makefile b/src/snark/Makefile index cceffb98966..32b8609f202 100644 --- a/src/snark/Makefile +++ b/src/snark/Makefile @@ -27,13 +27,13 @@ INSTALL_LIBS = $(LIB_FILE) # Sentinel file to check existence of this directory (since directories don't work as a Make dependency): DEPINST_EXISTS = $(DEPINST)/.exists - -COMPILE_GTEST := ifneq ($(NO_GTEST),1) - GTESTDIR=/usr/src/gtest -# Compile GTest from sourcecode if we can (e.g., Ubuntu). Otherwise use precompiled one (e.g., Fedora). -# See https://code.google.com/p/googletest/wiki/FAQ#Why_is_it_not_recommended_to_install_a_pre-compiled_copy_of_Goog . - COMPILE_GTEST :=$(shell test -d $(GTESTDIR) && echo -n 1) + # Compile GTest from sourcecode if we can (e.g., Ubuntu). Otherwise use precompiled one (e.g., Fedora). + # See https://github.com/google/googletest/blob/master/googletest/docs/FAQ.md#why-is-it-not-recommended-to-install-a-pre-compiled-copy-of-google-test-for-example-into-usrlocal + ifneq ($(NO_COMPILE_LIBGTEST),1) + GTESTDIR=/usr/src/gtest + COMPILE_LIBGTEST = $(shell test -d $(GTESTDIR) && echo -n 1) + endif GTEST_LDLIBS += -lgtest -lpthread endif @@ -221,13 +221,13 @@ src/gadgetlib2/tests/gadgetlib2_test: \ $(EXECUTABLES): %: %.o $(LIBSNARK_A) $(DEPINST_EXISTS) $(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(LDLIBS) -$(EXECUTABLES_WITH_GTEST): %: %.o $(LIBSNARK_A) $(if $(COMPILE_GTEST),$(LIBGTEST_A)) $(DEPINST_EXISTS) +$(EXECUTABLES_WITH_GTEST): %: %.o $(LIBSNARK_A) $(if $(COMPILE_LIBGTEST),$(LIBGTEST_A)) $(DEPINST_EXISTS) $(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(GTEST_LDLIBS) $(LDLIBS) $(EXECUTABLES_WITH_SUPERCOP): %: %.o $(LIBSNARK_A) $(DEPINST_EXISTS) $(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(SUPERCOP_LDLIBS) $(LDLIBS) -$(GTEST_TESTS): %: $(GTEST_OBJS) $(LIBSNARK_A) $(if $(COMPILE_GTEST),$(LIBGTEST_A)) $(DEPINST_EXISTS) +$(GTEST_TESTS): %: $(GTEST_OBJS) $(LIBSNARK_A) $(if $(COMPILE_LIBGTEST),$(LIBGTEST_A)) $(DEPINST_EXISTS) $(CXX) -o $@ $(GTEST_OBJS) $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(GTEST_LDLIBS) $(LDLIBS) From a10c2f46a59229461c9c8c3c8257a986d68d05dd Mon Sep 17 00:00:00 2001 From: syd Date: Sat, 25 Nov 2017 11:05:01 -0500 Subject: [PATCH 086/177] Add gtests to .gitignore --- src/snark/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/src/snark/.gitignore b/src/snark/.gitignore index f6fb450a271..bb48e1abade 100644 --- a/src/snark/.gitignore +++ b/src/snark/.gitignore @@ -6,6 +6,7 @@ depinst/ depsrc/ README.html doxygen/ +src/gtests src/gadgetlib2/examples/tutorial src/gadgetlib2/tests/gadgetlib2_test From 5163fd9d07d4eec886e02d8169a07d4d80d9a2f0 Mon Sep 17 00:00:00 2001 From: syd Date: Sat, 25 Nov 2017 15:08:01 -0500 Subject: [PATCH 087/177] Get rid of fp3 from libsnark, it is not used. This is for #1544 --- src/snark/src/algebra/fields/fp3.hpp | 122 ------------- src/snark/src/algebra/fields/fp3.tcc | 259 --------------------------- 2 files changed, 381 deletions(-) delete mode 100644 src/snark/src/algebra/fields/fp3.hpp delete mode 100644 src/snark/src/algebra/fields/fp3.tcc diff --git a/src/snark/src/algebra/fields/fp3.hpp b/src/snark/src/algebra/fields/fp3.hpp deleted file mode 100644 index 53b178a276d..00000000000 --- a/src/snark/src/algebra/fields/fp3.hpp +++ /dev/null @@ -1,122 +0,0 @@ -/** @file - ***************************************************************************** - Declaration of arithmetic in the finite field F[p^3]. - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef FP3_HPP_ -#define FP3_HPP_ -#include "algebra/fields/fp.hpp" -#include - -namespace libsnark { - -template& modulus> -class Fp3_model; - -template& modulus> -std::ostream& operator<<(std::ostream &, const Fp3_model &); - -template& modulus> -std::istream& operator>>(std::istream &, Fp3_model &); - -/** - * Arithmetic in the field F[p^3]. - * - * Let p := modulus. This interface provides arithmetic for the extension field - * Fp3 = Fp[U]/(U^3-non_residue), where non_residue is in Fp. - * - * ASSUMPTION: p = 1 (mod 6) - */ -template& modulus> -class Fp3_model { -public: - typedef Fp_model my_Fp; - - static bigint<3*n> euler; // (modulus^3-1)/2 - static size_t s; // modulus^3 = 2^s * t + 1 - static bigint<3*n> t; // with t odd - static bigint<3*n> t_minus_1_over_2; // (t-1)/2 - static my_Fp non_residue; // X^6-non_residue irreducible over Fp; used for constructing Fp3 = Fp[X] / (X^3 - non_residue) - static Fp3_model nqr; // a quadratic nonresidue in Fp3 - static Fp3_model nqr_to_t; // nqr^t - static my_Fp Frobenius_coeffs_c1[3]; // non_residue^((modulus^i-1)/3) for i=0,1,2 - static my_Fp Frobenius_coeffs_c2[3]; // non_residue^((2*modulus^i-2)/3) for i=0,1,2 - - my_Fp c0, c1, c2; - Fp3_model() {}; - Fp3_model(const my_Fp& c0, const my_Fp& c1, const my_Fp& c2) : c0(c0), c1(c1), c2(c2) {}; - - void clear() { c0.clear(); c1.clear(); c2.clear(); } - void print() const { printf("c0/c1/c2:\n"); c0.print(); c1.print(); c2.print(); } - - static Fp3_model zero(); - static Fp3_model one(); - static Fp3_model random_element(); - - bool is_zero() const { return c0.is_zero() && c1.is_zero() && c2.is_zero(); } - bool operator==(const Fp3_model &other) const; - bool operator!=(const Fp3_model &other) const; - - Fp3_model operator+(const Fp3_model &other) const; - Fp3_model operator-(const Fp3_model &other) const; - Fp3_model operator*(const Fp3_model &other) const; - Fp3_model operator-() const; - Fp3_model squared() const; - Fp3_model inverse() const; - Fp3_model Frobenius_map(unsigned long power) const; - Fp3_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate) - - template - Fp3_model operator^(const bigint &other) const; - - static size_t size_in_bits() { return 3*my_Fp::size_in_bits(); } - static bigint base_field_char() { return modulus; } - - friend std::ostream& operator<< (std::ostream &out, const Fp3_model &el); - friend std::istream& operator>> (std::istream &in, Fp3_model &el); -}; - -template& modulus> -std::ostream& operator<<(std::ostream& out, const std::vector > &v); - -template& modulus> -std::istream& operator>>(std::istream& in, std::vector > &v); - -template& modulus> -Fp3_model operator*(const Fp_model &lhs, const Fp3_model &rhs); - -template& modulus> -bigint<3*n> Fp3_model::euler; - -template& modulus> -size_t Fp3_model::s; - -template& modulus> -bigint<3*n> Fp3_model::t; - -template& modulus> -bigint<3*n> Fp3_model::t_minus_1_over_2; - -template& modulus> -Fp_model Fp3_model::non_residue; - -template& modulus> -Fp3_model Fp3_model::nqr; - -template& modulus> -Fp3_model Fp3_model::nqr_to_t; - -template& modulus> -Fp_model Fp3_model::Frobenius_coeffs_c1[3]; - -template& modulus> -Fp_model Fp3_model::Frobenius_coeffs_c2[3]; - -} // libsnark -#include "algebra/fields/fp3.tcc" - -#endif // FP3_HPP_ diff --git a/src/snark/src/algebra/fields/fp3.tcc b/src/snark/src/algebra/fields/fp3.tcc deleted file mode 100644 index 590a2a98729..00000000000 --- a/src/snark/src/algebra/fields/fp3.tcc +++ /dev/null @@ -1,259 +0,0 @@ -/** @file - ***************************************************************************** - Implementation of arithmetic in the finite field F[p^3]. - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef FP3_TCC_ -#define FP3_TCC_ - -#include "algebra/fields/field_utils.hpp" - -namespace libsnark { - -template& modulus> -Fp3_model Fp3_model::zero() -{ - return Fp3_model(my_Fp::zero(), my_Fp::zero(), my_Fp::zero()); -} - -template& modulus> -Fp3_model Fp3_model::one() -{ - return Fp3_model(my_Fp::one(), my_Fp::zero(), my_Fp::zero()); -} - -template& modulus> -Fp3_model Fp3_model::random_element() -{ - Fp3_model r; - r.c0 = my_Fp::random_element(); - r.c1 = my_Fp::random_element(); - r.c2 = my_Fp::random_element(); - - return r; -} - -template& modulus> -bool Fp3_model::operator==(const Fp3_model &other) const -{ - return (this->c0 == other.c0 && this->c1 == other.c1 && this->c2 == other.c2); -} - -template& modulus> -bool Fp3_model::operator!=(const Fp3_model &other) const -{ - return !(operator==(other)); -} - -template& modulus> -Fp3_model Fp3_model::operator+(const Fp3_model &other) const -{ - return Fp3_model(this->c0 + other.c0, - this->c1 + other.c1, - this->c2 + other.c2); -} - -template& modulus> -Fp3_model Fp3_model::operator-(const Fp3_model &other) const -{ - return Fp3_model(this->c0 - other.c0, - this->c1 - other.c1, - this->c2 - other.c2); -} - -template& modulus> -Fp3_model operator*(const Fp_model &lhs, const Fp3_model &rhs) -{ - return Fp3_model(lhs*rhs.c0, - lhs*rhs.c1, - lhs*rhs.c2); -} - -template& modulus> -Fp3_model Fp3_model::operator*(const Fp3_model &other) const -{ - /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (Karatsuba) */ - const my_Fp - &A = other.c0, &B = other.c1, &C = other.c2, - &a = this->c0, &b = this->c1, &c = this->c2; - const my_Fp aA = a*A; - const my_Fp bB = b*B; - const my_Fp cC = c*C; - - return Fp3_model(aA + non_residue*((b+c)*(B+C)-bB-cC), - (a+b)*(A+B)-aA-bB+non_residue*cC, - (a+c)*(A+C)-aA+bB-cC); -} - -template& modulus> -Fp3_model Fp3_model::operator-() const -{ - return Fp3_model(-this->c0, - -this->c1, - -this->c2); -} - -template& modulus> -Fp3_model Fp3_model::squared() const -{ - /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (CH-SQR2) */ - const my_Fp - &a = this->c0, &b = this->c1, &c = this->c2; - const my_Fp s0 = a.squared(); - const my_Fp ab = a*b; - const my_Fp s1 = ab + ab; - const my_Fp s2 = (a - b + c).squared(); - const my_Fp bc = b*c; - const my_Fp s3 = bc + bc; - const my_Fp s4 = c.squared(); - - return Fp3_model(s0 + non_residue * s3, - s1 + non_residue * s4, - s1 + s2 + s3 - s0 - s4); -} - -template& modulus> -Fp3_model Fp3_model::inverse() const -{ - const my_Fp - &a = this->c0, &b = this->c1, &c = this->c2; - - /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 17 */ - const my_Fp t0 = a.squared(); - const my_Fp t1 = b.squared(); - const my_Fp t2 = c.squared(); - const my_Fp t3 = a*b; - const my_Fp t4 = a*c; - const my_Fp t5 = b*c; - const my_Fp c0 = t0 - non_residue * t5; - const my_Fp c1 = non_residue * t2 - t3; - const my_Fp c2 = t1 - t4; // typo in paper referenced above. should be "-" as per Scott, but is "*" - const my_Fp t6 = (a * c0 + non_residue * (c * c1 + b * c2)).inverse(); - return Fp3_model(t6 * c0, t6 * c1, t6 * c2); -} - -template& modulus> -Fp3_model Fp3_model::Frobenius_map(unsigned long power) const -{ - return Fp3_model(c0, - Frobenius_coeffs_c1[power % 3] * c1, - Frobenius_coeffs_c2[power % 3] * c2); -} - -template& modulus> -Fp3_model Fp3_model::sqrt() const -{ - Fp3_model one = Fp3_model::one(); - - size_t v = Fp3_model::s; - Fp3_model z = Fp3_model::nqr_to_t; - Fp3_model w = (*this)^Fp3_model::t_minus_1_over_2; - Fp3_model x = (*this) * w; - Fp3_model b = x * w; // b = (*this)^t - -#if DEBUG - // check if square with euler's criterion - Fp3_model check = b; - for (size_t i = 0; i < v-1; ++i) - { - check = check.squared(); - } - if (check != one) - { - assert(0); - } -#endif - - // compute square root with Tonelli--Shanks - // (does not terminate if not a square!) - - while (b != one) - { - size_t m = 0; - Fp3_model b2m = b; - while (b2m != one) - { - /* invariant: b2m = b^(2^m) after entering this loop */ - b2m = b2m.squared(); - m += 1; - } - - int j = v-m-1; - w = z; - while (j > 0) - { - w = w.squared(); - --j; - } // w = z^2^(v-m-1) - - z = w.squared(); - b = b * z; - x = x * w; - v = m; - } - - return x; -} - -template& modulus> -template -Fp3_model Fp3_model::operator^(const bigint &pow) const -{ - return power >(*this, pow); -} - -template& modulus> -std::ostream& operator<<(std::ostream &out, const Fp3_model &el) -{ - out << el.c0 << OUTPUT_SEPARATOR << el.c1 << OUTPUT_SEPARATOR << el.c2; - return out; -} - -template& modulus> -std::istream& operator>>(std::istream &in, Fp3_model &el) -{ - in >> el.c0 >> el.c1 >> el.c2; - return in; -} - -template& modulus> -std::ostream& operator<<(std::ostream& out, const std::vector > &v) -{ - out << v.size() << "\n"; - for (const Fp3_model& t : v) - { - out << t << OUTPUT_NEWLINE; - } - - return out; -} - -template& modulus> -std::istream& operator>>(std::istream& in, std::vector > &v) -{ - v.clear(); - - size_t s; - in >> s; - - char b; - in.read(&b, 1); - - v.reserve(s); - - for (size_t i = 0; i < s; ++i) - { - Fp3_model el; - in >> el; - v.emplace_back(el); - } - - return in; -} - -} // libsnark -#endif // FP3_TCC_ From d52dcf5d0ce3c16a79c7f49fef72d17c9df38a8f Mon Sep 17 00:00:00 2001 From: syd Date: Mon, 27 Nov 2017 11:08:34 -0500 Subject: [PATCH 088/177] InitGoogleMock instead of InitGoogleTest per CR --- src/gtest/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gtest/main.cpp b/src/gtest/main.cpp index 0b6e1ad0851..d2ae0b23d69 100644 --- a/src/gtest/main.cpp +++ b/src/gtest/main.cpp @@ -1,4 +1,4 @@ -#include "gtest/gtest.h" +#include "gmock/gmock.h" #include "crypto/common.h" #include "pubkey.h" #include "zcash/JoinSplit.hpp" @@ -25,6 +25,6 @@ int main(int argc, char **argv) { boost::filesystem::path vk_path = ZC_GetParamsDir() / "sprout-verifying.key"; params = ZCJoinSplit::Prepared(vk_path.string(), pk_path.string()); - testing::InitGoogleTest(&argc, argv); + testing::InitGoogleMock(&argc, argv); return RUN_ALL_TESTS(); } From 9eb8089e984a4cc83bd93011c84281f49687bc86 Mon Sep 17 00:00:00 2001 From: Jay Graber Date: Mon, 27 Nov 2017 20:06:36 -0800 Subject: [PATCH 089/177] Fix cli help result for z_shieldcoinbase --- src/wallet/rpcwallet.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index b9240a800dc..60d48fb41ef 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3554,11 +3554,11 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp) + strprintf("%d", SHIELD_COINBASE_DEFAULT_LIMIT) + ") Limit on the maximum number of utxos to shield. Set to 0 to use node option -mempooltxinputlimit.\n" "\nResult:\n" "{\n" - " \"operationid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n" - " \"shieldedUTXOs\": xxx (numeric) Number of coinbase utxos being shielded.\n" - " \"shieldedValue\": xxx (numeric) Value of coinbase utxos being shielded.\n" " \"remainingUTXOs\": xxx (numeric) Number of coinbase utxos still available for shielding.\n" " \"remainingValue\": xxx (numeric) Value of coinbase utxos still available for shielding.\n" + " \"shieldingUTXOs\": xxx (numeric) Number of coinbase utxos being shielded.\n" + " \"shieldingValue\": xxx (numeric) Value of coinbase utxos being shielded.\n" + " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n" "}\n" "\nExamples:\n" + HelpExampleCli("z_shieldcoinbase", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"") From cde23ac085af43a3d28eb7b146f861041fe7ec12 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 28 Nov 2017 16:42:12 +0000 Subject: [PATCH 090/177] Squashed 'src/secp256k1/' changes from 84973d3..6ad5cdb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 6ad5cdb Merge #479: Get rid of reserved _t in type names d1dc9df Get rid of reserved _t in type names 0b70241 Merge #474: Fix header guards using reserved identifiers ab1f89f Merge #478: Fixed multiple typos 8c7ea22 Fixed multiple typos abe2d3e Fix header guards using reserved identifiers f532bdc Merge #459: Add pubkey prefix constants to include/secp256k1.h cac7c55 Merge #470: Fix wnaf_const documentation 768514b Fix wnaf_const documentation with respect to return value and number of words set b8c26a3 Merge #458: Fix typo in API documentation 817fb20 Merge #440: Fix typos 12230f9 Merge #468: Remove redundant conditional expression 2e1ccdc Remove redundant conditional expression bc61b91 add pubkey prefix constants to include/secp256k1.h b0452e6 Fix typo in API documentation 4c0f32e Fix typo: "Agressive" → "Aggressive" 73aca83 Fix typo: "exectured" → "executed" git-subtree-dir: src/secp256k1 git-subtree-split: 6ad5cdb42a1a8257289a0423d644dcbdeab0f83c --- contrib/lax_der_parsing.h | 10 ++--- contrib/lax_der_privatekey_parsing.h | 10 ++--- include/secp256k1.h | 23 +++++++---- include/secp256k1_ecdh.h | 16 +++---- include/secp256k1_recovery.h | 16 +++---- sage/group_prover.sage | 4 +- src/asm/field_10x26_arm.s | 4 +- src/basic-config.h | 9 ++-- src/bench.h | 6 +-- src/bench_ecdh.c | 8 ++-- src/bench_internal.c | 62 ++++++++++++++-------------- src/bench_recover.c | 8 ++-- src/bench_sign.c | 12 +++--- src/ecdsa.h | 6 +-- src/ecdsa_impl.h | 8 ++-- src/eckey.h | 6 +-- src/eckey_impl.h | 17 ++++---- src/ecmult.h | 6 +-- src/ecmult_const.h | 6 +-- src/ecmult_const_impl.h | 13 +++--- src/ecmult_gen.h | 6 +-- src/ecmult_gen_impl.h | 8 ++-- src/ecmult_impl.h | 6 +-- src/field.h | 6 +-- src/field_10x26.h | 7 ++-- src/field_10x26_impl.h | 6 +-- src/field_5x52.h | 6 +-- src/field_5x52_asm_impl.h | 6 +-- src/field_5x52_impl.h | 6 +-- src/field_5x52_int128_impl.h | 6 +-- src/field_impl.h | 6 +-- src/group.h | 6 +-- src/group_impl.h | 6 +-- src/hash.h | 32 +++++++------- src/hash_impl.h | 32 +++++++------- src/modules/ecdh/main_impl.h | 8 ++-- src/modules/ecdh/tests_impl.h | 8 ++-- src/modules/recovery/main_impl.h | 6 +-- src/modules/recovery/tests_impl.h | 6 +-- src/num.h | 6 +-- src/num_gmp.h | 6 +-- src/num_gmp_impl.h | 6 +-- src/num_impl.h | 6 +-- src/scalar.h | 6 +-- src/scalar_4x64.h | 6 +-- src/scalar_4x64_impl.h | 6 +-- src/scalar_8x32.h | 6 +-- src/scalar_8x32_impl.h | 6 +-- src/scalar_impl.h | 6 +-- src/scalar_low.h | 6 +-- src/scalar_low_impl.h | 6 +-- src/secp256k1.c | 2 +- src/testrand.h | 6 +-- src/testrand_impl.h | 8 ++-- src/tests.c | 6 +-- src/util.h | 6 +-- 56 files changed, 266 insertions(+), 257 deletions(-) diff --git a/contrib/lax_der_parsing.h b/contrib/lax_der_parsing.h index 6d27871a7cc..7eaf63bf6a0 100644 --- a/contrib/lax_der_parsing.h +++ b/contrib/lax_der_parsing.h @@ -48,14 +48,14 @@ * 8.3.1. */ -#ifndef _SECP256K1_CONTRIB_LAX_DER_PARSING_H_ -#define _SECP256K1_CONTRIB_LAX_DER_PARSING_H_ +#ifndef SECP256K1_CONTRIB_LAX_DER_PARSING_H +#define SECP256K1_CONTRIB_LAX_DER_PARSING_H #include -# ifdef __cplusplus +#ifdef __cplusplus extern "C" { -# endif +#endif /** Parse a signature in "lax DER" format * @@ -88,4 +88,4 @@ int ecdsa_signature_parse_der_lax( } #endif -#endif +#endif /* SECP256K1_CONTRIB_LAX_DER_PARSING_H */ diff --git a/contrib/lax_der_privatekey_parsing.h b/contrib/lax_der_privatekey_parsing.h index 2fd088f8abf..fece261fb9e 100644 --- a/contrib/lax_der_privatekey_parsing.h +++ b/contrib/lax_der_privatekey_parsing.h @@ -25,14 +25,14 @@ * library are sufficient. */ -#ifndef _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_ -#define _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_ +#ifndef SECP256K1_CONTRIB_BER_PRIVATEKEY_H +#define SECP256K1_CONTRIB_BER_PRIVATEKEY_H #include -# ifdef __cplusplus +#ifdef __cplusplus extern "C" { -# endif +#endif /** Export a private key in DER format. * @@ -87,4 +87,4 @@ SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der( } #endif -#endif +#endif /* SECP256K1_CONTRIB_BER_PRIVATEKEY_H */ diff --git a/include/secp256k1.h b/include/secp256k1.h index fc4c5cefbb3..3e9c098d19f 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -1,9 +1,9 @@ -#ifndef _SECP256K1_ -# define _SECP256K1_ +#ifndef SECP256K1_H +#define SECP256K1_H -# ifdef __cplusplus +#ifdef __cplusplus extern "C" { -# endif +#endif #include @@ -61,7 +61,7 @@ typedef struct { * however guaranteed to be 64 bytes in size, and can be safely copied/moved. * If you need to convert to a format suitable for storage, transmission, or * comparison, use the secp256k1_ecdsa_signature_serialize_* and - * secp256k1_ecdsa_signature_serialize_* functions. + * secp256k1_ecdsa_signature_parse_* functions. */ typedef struct { unsigned char data[64]; @@ -159,6 +159,13 @@ typedef int (*secp256k1_nonce_function)( #define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION) #define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION) +/** Prefix byte used to tag various encoded curvepoints for specific purposes */ +#define SECP256K1_TAG_PUBKEY_EVEN 0x02 +#define SECP256K1_TAG_PUBKEY_ODD 0x03 +#define SECP256K1_TAG_PUBKEY_UNCOMPRESSED 0x04 +#define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06 +#define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07 + /** Create a secp256k1 context object. * * Returns: a newly created context object. @@ -607,8 +614,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine( size_t n ) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -# ifdef __cplusplus +#ifdef __cplusplus } -# endif - #endif + +#endif /* SECP256K1_H */ diff --git a/include/secp256k1_ecdh.h b/include/secp256k1_ecdh.h index 4b84d7a9634..88492dc1a40 100644 --- a/include/secp256k1_ecdh.h +++ b/include/secp256k1_ecdh.h @@ -1,11 +1,11 @@ -#ifndef _SECP256K1_ECDH_ -# define _SECP256K1_ECDH_ +#ifndef SECP256K1_ECDH_H +#define SECP256K1_ECDH_H -# include "secp256k1.h" +#include "secp256k1.h" -# ifdef __cplusplus +#ifdef __cplusplus extern "C" { -# endif +#endif /** Compute an EC Diffie-Hellman secret in constant time * Returns: 1: exponentiation was successful @@ -24,8 +24,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh( const unsigned char *privkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); -# ifdef __cplusplus +#ifdef __cplusplus } -# endif - #endif + +#endif /* SECP256K1_ECDH_H */ diff --git a/include/secp256k1_recovery.h b/include/secp256k1_recovery.h index 05537972532..cf6c5ed7f5e 100644 --- a/include/secp256k1_recovery.h +++ b/include/secp256k1_recovery.h @@ -1,11 +1,11 @@ -#ifndef _SECP256K1_RECOVERY_ -# define _SECP256K1_RECOVERY_ +#ifndef SECP256K1_RECOVERY_H +#define SECP256K1_RECOVERY_H -# include "secp256k1.h" +#include "secp256k1.h" -# ifdef __cplusplus +#ifdef __cplusplus extern "C" { -# endif +#endif /** Opaque data structured that holds a parsed ECDSA signature, * supporting pubkey recovery. @@ -103,8 +103,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover( const unsigned char *msg32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); -# ifdef __cplusplus +#ifdef __cplusplus } -# endif - #endif + +#endif /* SECP256K1_RECOVERY_H */ diff --git a/sage/group_prover.sage b/sage/group_prover.sage index ab580c5b23b..8521f079993 100644 --- a/sage/group_prover.sage +++ b/sage/group_prover.sage @@ -3,7 +3,7 @@ # to independently set assumptions on input or intermediary variables. # # The general approach is: -# * A constraint is a tuple of two sets of of symbolic expressions: +# * A constraint is a tuple of two sets of symbolic expressions: # the first of which are required to evaluate to zero, the second of which # are required to evaluate to nonzero. # - A constraint is said to be conflicting if any of its nonzero expressions @@ -17,7 +17,7 @@ # - A constraint describing the requirements of the law, called "require" # * Implementations are transliterated into functions that operate as well on # algebraic input points, and are called once per combination of branches -# exectured. Each execution returns: +# executed. Each execution returns: # - A constraint describing the assumptions this implementation requires # (such as Z1=1), called "assumeFormula" # - A constraint describing the assumptions this specific branch requires, diff --git a/src/asm/field_10x26_arm.s b/src/asm/field_10x26_arm.s index 5df561f2fc9..5a9cc3ffcfd 100644 --- a/src/asm/field_10x26_arm.s +++ b/src/asm/field_10x26_arm.s @@ -11,7 +11,7 @@ Note: - To avoid unnecessary loads and make use of available registers, two 'passes' have every time been interleaved, with the odd passes accumulating c' and d' - which will be added to c and d respectively in the the even passes + which will be added to c and d respectively in the even passes */ @@ -23,7 +23,7 @@ Note: .eabi_attribute 10, 0 @ Tag_FP_arch = none .eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte .eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP - .eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Agressive Speed + .eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Aggressive Speed .eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6 .text diff --git a/src/basic-config.h b/src/basic-config.h index c4c16eb7ca7..fc588061ca4 100644 --- a/src/basic-config.h +++ b/src/basic-config.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_BASIC_CONFIG_ -#define _SECP256K1_BASIC_CONFIG_ +#ifndef SECP256K1_BASIC_CONFIG_H +#define SECP256K1_BASIC_CONFIG_H #ifdef USE_BASIC_CONFIG @@ -28,5 +28,6 @@ #define USE_FIELD_10X26 1 #define USE_SCALAR_8X32 1 -#endif // USE_BASIC_CONFIG -#endif // _SECP256K1_BASIC_CONFIG_ +#endif /* USE_BASIC_CONFIG */ + +#endif /* SECP256K1_BASIC_CONFIG_H */ diff --git a/src/bench.h b/src/bench.h index d67f08a4267..d5ebe01301b 100644 --- a/src/bench.h +++ b/src/bench.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_BENCH_H_ -#define _SECP256K1_BENCH_H_ +#ifndef SECP256K1_BENCH_H +#define SECP256K1_BENCH_H #include #include @@ -63,4 +63,4 @@ void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), v printf("us\n"); } -#endif +#endif /* SECP256K1_BENCH_H */ diff --git a/src/bench_ecdh.c b/src/bench_ecdh.c index cde5e2dbb4e..2de5126d634 100644 --- a/src/bench_ecdh.c +++ b/src/bench_ecdh.c @@ -15,11 +15,11 @@ typedef struct { secp256k1_context *ctx; secp256k1_pubkey point; unsigned char scalar[32]; -} bench_ecdh_t; +} bench_ecdh; static void bench_ecdh_setup(void* arg) { int i; - bench_ecdh_t *data = (bench_ecdh_t*)arg; + bench_ecdh *data = (bench_ecdh*)arg; const unsigned char point[] = { 0x03, 0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06, @@ -39,7 +39,7 @@ static void bench_ecdh_setup(void* arg) { static void bench_ecdh(void* arg) { int i; unsigned char res[32]; - bench_ecdh_t *data = (bench_ecdh_t*)arg; + bench_ecdh *data = (bench_ecdh*)arg; for (i = 0; i < 20000; i++) { CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar) == 1); @@ -47,7 +47,7 @@ static void bench_ecdh(void* arg) { } int main(void) { - bench_ecdh_t data; + bench_ecdh data; run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, 20000); return 0; diff --git a/src/bench_internal.c b/src/bench_internal.c index 0809f77bda1..9b30c50d0be 100644 --- a/src/bench_internal.c +++ b/src/bench_internal.c @@ -25,10 +25,10 @@ typedef struct { secp256k1_gej gej_x, gej_y; unsigned char data[64]; int wnaf[256]; -} bench_inv_t; +} bench_inv; void bench_setup(void* arg) { - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; static const unsigned char init_x[32] = { 0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13, @@ -58,7 +58,7 @@ void bench_setup(void* arg) { void bench_scalar_add(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 2000000; i++) { secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); @@ -67,7 +67,7 @@ void bench_scalar_add(void* arg) { void bench_scalar_negate(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 2000000; i++) { secp256k1_scalar_negate(&data->scalar_x, &data->scalar_x); @@ -76,7 +76,7 @@ void bench_scalar_negate(void* arg) { void bench_scalar_sqr(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 200000; i++) { secp256k1_scalar_sqr(&data->scalar_x, &data->scalar_x); @@ -85,7 +85,7 @@ void bench_scalar_sqr(void* arg) { void bench_scalar_mul(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 200000; i++) { secp256k1_scalar_mul(&data->scalar_x, &data->scalar_x, &data->scalar_y); @@ -95,7 +95,7 @@ void bench_scalar_mul(void* arg) { #ifdef USE_ENDOMORPHISM void bench_scalar_split(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 20000; i++) { secp256k1_scalar l, r; @@ -107,7 +107,7 @@ void bench_scalar_split(void* arg) { void bench_scalar_inverse(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 2000; i++) { secp256k1_scalar_inverse(&data->scalar_x, &data->scalar_x); @@ -117,7 +117,7 @@ void bench_scalar_inverse(void* arg) { void bench_scalar_inverse_var(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 2000; i++) { secp256k1_scalar_inverse_var(&data->scalar_x, &data->scalar_x); @@ -127,7 +127,7 @@ void bench_scalar_inverse_var(void* arg) { void bench_field_normalize(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 2000000; i++) { secp256k1_fe_normalize(&data->fe_x); @@ -136,7 +136,7 @@ void bench_field_normalize(void* arg) { void bench_field_normalize_weak(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 2000000; i++) { secp256k1_fe_normalize_weak(&data->fe_x); @@ -145,7 +145,7 @@ void bench_field_normalize_weak(void* arg) { void bench_field_mul(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 200000; i++) { secp256k1_fe_mul(&data->fe_x, &data->fe_x, &data->fe_y); @@ -154,7 +154,7 @@ void bench_field_mul(void* arg) { void bench_field_sqr(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 200000; i++) { secp256k1_fe_sqr(&data->fe_x, &data->fe_x); @@ -163,7 +163,7 @@ void bench_field_sqr(void* arg) { void bench_field_inverse(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 20000; i++) { secp256k1_fe_inv(&data->fe_x, &data->fe_x); @@ -173,7 +173,7 @@ void bench_field_inverse(void* arg) { void bench_field_inverse_var(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 20000; i++) { secp256k1_fe_inv_var(&data->fe_x, &data->fe_x); @@ -183,7 +183,7 @@ void bench_field_inverse_var(void* arg) { void bench_field_sqrt(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 20000; i++) { secp256k1_fe_sqrt(&data->fe_x, &data->fe_x); @@ -193,7 +193,7 @@ void bench_field_sqrt(void* arg) { void bench_group_double_var(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 200000; i++) { secp256k1_gej_double_var(&data->gej_x, &data->gej_x, NULL); @@ -202,7 +202,7 @@ void bench_group_double_var(void* arg) { void bench_group_add_var(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 200000; i++) { secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y, NULL); @@ -211,7 +211,7 @@ void bench_group_add_var(void* arg) { void bench_group_add_affine(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 200000; i++) { secp256k1_gej_add_ge(&data->gej_x, &data->gej_x, &data->ge_y); @@ -220,7 +220,7 @@ void bench_group_add_affine(void* arg) { void bench_group_add_affine_var(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 200000; i++) { secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y, NULL); @@ -229,7 +229,7 @@ void bench_group_add_affine_var(void* arg) { void bench_group_jacobi_var(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 20000; i++) { secp256k1_gej_has_quad_y_var(&data->gej_x); @@ -238,7 +238,7 @@ void bench_group_jacobi_var(void* arg) { void bench_ecmult_wnaf(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 20000; i++) { secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar_x, WINDOW_A); @@ -248,7 +248,7 @@ void bench_ecmult_wnaf(void* arg) { void bench_wnaf_const(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 20000; i++) { secp256k1_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A); @@ -259,8 +259,8 @@ void bench_wnaf_const(void* arg) { void bench_sha256(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; - secp256k1_sha256_t sha; + bench_inv *data = (bench_inv*)arg; + secp256k1_sha256 sha; for (i = 0; i < 20000; i++) { secp256k1_sha256_initialize(&sha); @@ -271,8 +271,8 @@ void bench_sha256(void* arg) { void bench_hmac_sha256(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; - secp256k1_hmac_sha256_t hmac; + bench_inv *data = (bench_inv*)arg; + secp256k1_hmac_sha256 hmac; for (i = 0; i < 20000; i++) { secp256k1_hmac_sha256_initialize(&hmac, data->data, 32); @@ -283,8 +283,8 @@ void bench_hmac_sha256(void* arg) { void bench_rfc6979_hmac_sha256(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; - secp256k1_rfc6979_hmac_sha256_t rng; + bench_inv *data = (bench_inv*)arg; + secp256k1_rfc6979_hmac_sha256 rng; for (i = 0; i < 20000; i++) { secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64); @@ -311,7 +311,7 @@ void bench_context_sign(void* arg) { #ifndef USE_NUM_NONE void bench_num_jacobi(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; secp256k1_num nx, norder; secp256k1_scalar_get_num(&nx, &data->scalar_x); @@ -340,7 +340,7 @@ int have_flag(int argc, char** argv, char *flag) { } int main(int argc, char **argv) { - bench_inv_t data; + bench_inv data; if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, 2000000); if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, 2000000); if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, 200000); diff --git a/src/bench_recover.c b/src/bench_recover.c index 6489378cc64..506fc1880e6 100644 --- a/src/bench_recover.c +++ b/src/bench_recover.c @@ -13,11 +13,11 @@ typedef struct { secp256k1_context *ctx; unsigned char msg[32]; unsigned char sig[64]; -} bench_recover_t; +} bench_recover; void bench_recover(void* arg) { int i; - bench_recover_t *data = (bench_recover_t*)arg; + bench_recover *data = (bench_recover*)arg; secp256k1_pubkey pubkey; unsigned char pubkeyc[33]; @@ -38,7 +38,7 @@ void bench_recover(void* arg) { void bench_recover_setup(void* arg) { int i; - bench_recover_t *data = (bench_recover_t*)arg; + bench_recover *data = (bench_recover*)arg; for (i = 0; i < 32; i++) { data->msg[i] = 1 + i; @@ -49,7 +49,7 @@ void bench_recover_setup(void* arg) { } int main(void) { - bench_recover_t data; + bench_recover data; data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); diff --git a/src/bench_sign.c b/src/bench_sign.c index ed7224d757e..544b43963c8 100644 --- a/src/bench_sign.c +++ b/src/bench_sign.c @@ -12,11 +12,11 @@ typedef struct { secp256k1_context* ctx; unsigned char msg[32]; unsigned char key[32]; -} bench_sign_t; +} bench_sign; static void bench_sign_setup(void* arg) { int i; - bench_sign_t *data = (bench_sign_t*)arg; + bench_sign *data = (bench_sign*)arg; for (i = 0; i < 32; i++) { data->msg[i] = i + 1; @@ -26,9 +26,9 @@ static void bench_sign_setup(void* arg) { } } -static void bench_sign(void* arg) { +static void bench_sign_run(void* arg) { int i; - bench_sign_t *data = (bench_sign_t*)arg; + bench_sign *data = (bench_sign*)arg; unsigned char sig[74]; for (i = 0; i < 20000; i++) { @@ -45,11 +45,11 @@ static void bench_sign(void* arg) { } int main(void) { - bench_sign_t data; + bench_sign data; data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); - run_benchmark("ecdsa_sign", bench_sign, bench_sign_setup, NULL, &data, 10, 20000); + run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, 20000); secp256k1_context_destroy(data.ctx); return 0; diff --git a/src/ecdsa.h b/src/ecdsa.h index 54ae101b924..80590c7cc86 100644 --- a/src/ecdsa.h +++ b/src/ecdsa.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECDSA_ -#define _SECP256K1_ECDSA_ +#ifndef SECP256K1_ECDSA_H +#define SECP256K1_ECDSA_H #include @@ -18,4 +18,4 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar* r, const secp256k1_scalar* s, const secp256k1_ge *pubkey, const secp256k1_scalar *message); static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid); -#endif +#endif /* SECP256K1_ECDSA_H */ diff --git a/src/ecdsa_impl.h b/src/ecdsa_impl.h index 453bb118806..c3400042d83 100644 --- a/src/ecdsa_impl.h +++ b/src/ecdsa_impl.h @@ -5,8 +5,8 @@ **********************************************************************/ -#ifndef _SECP256K1_ECDSA_IMPL_H_ -#define _SECP256K1_ECDSA_IMPL_H_ +#ifndef SECP256K1_ECDSA_IMPL_H +#define SECP256K1_ECDSA_IMPL_H #include "scalar.h" #include "field.h" @@ -81,8 +81,6 @@ static int secp256k1_der_read_len(const unsigned char **sigp, const unsigned cha return -1; } while (lenleft > 0) { - if ((ret >> ((sizeof(size_t) - 1) * 8)) != 0) { - } ret = (ret << 8) | **sigp; if (ret + lenleft > (size_t)(sigend - *sigp)) { /* Result exceeds the length of the passed array. */ @@ -312,4 +310,4 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec return 1; } -#endif +#endif /* SECP256K1_ECDSA_IMPL_H */ diff --git a/src/eckey.h b/src/eckey.h index 42739a3bea7..b621f1e6c39 100644 --- a/src/eckey.h +++ b/src/eckey.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECKEY_ -#define _SECP256K1_ECKEY_ +#ifndef SECP256K1_ECKEY_H +#define SECP256K1_ECKEY_H #include @@ -22,4 +22,4 @@ static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak); static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak); -#endif +#endif /* SECP256K1_ECKEY_H */ diff --git a/src/eckey_impl.h b/src/eckey_impl.h index ce38071ac2e..1ab9a68ec04 100644 --- a/src/eckey_impl.h +++ b/src/eckey_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECKEY_IMPL_H_ -#define _SECP256K1_ECKEY_IMPL_H_ +#ifndef SECP256K1_ECKEY_IMPL_H +#define SECP256K1_ECKEY_IMPL_H #include "eckey.h" @@ -15,16 +15,17 @@ #include "ecmult_gen.h" static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) { - if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) { + if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) { secp256k1_fe x; - return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == 0x03); + return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD); } else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) { secp256k1_fe x, y; if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) { return 0; } secp256k1_ge_set_xy(elem, &x, &y); - if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07)) { + if ((pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD) && + secp256k1_fe_is_odd(&y) != (pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) { return 0; } return secp256k1_ge_is_valid_var(elem); @@ -42,10 +43,10 @@ static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *p secp256k1_fe_get_b32(&pub[1], &elem->x); if (compressed) { *size = 33; - pub[0] = 0x02 | (secp256k1_fe_is_odd(&elem->y) ? 0x01 : 0x00); + pub[0] = secp256k1_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN; } else { *size = 65; - pub[0] = 0x04; + pub[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED; secp256k1_fe_get_b32(&pub[33], &elem->y); } return 1; @@ -96,4 +97,4 @@ static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, return 1; } -#endif +#endif /* SECP256K1_ECKEY_IMPL_H */ diff --git a/src/ecmult.h b/src/ecmult.h index 20484134f52..6d44aba60b5 100644 --- a/src/ecmult.h +++ b/src/ecmult.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECMULT_ -#define _SECP256K1_ECMULT_ +#ifndef SECP256K1_ECMULT_H +#define SECP256K1_ECMULT_H #include "num.h" #include "group.h" @@ -28,4 +28,4 @@ static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx /** Double multiply: R = na*A + ng*G */ static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng); -#endif +#endif /* SECP256K1_ECMULT_H */ diff --git a/src/ecmult_const.h b/src/ecmult_const.h index 2b0097655c1..72bf7d7582f 100644 --- a/src/ecmult_const.h +++ b/src/ecmult_const.h @@ -4,12 +4,12 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECMULT_CONST_ -#define _SECP256K1_ECMULT_CONST_ +#ifndef SECP256K1_ECMULT_CONST_H +#define SECP256K1_ECMULT_CONST_H #include "scalar.h" #include "group.h" static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q); -#endif +#endif /* SECP256K1_ECMULT_CONST_H */ diff --git a/src/ecmult_const_impl.h b/src/ecmult_const_impl.h index 0db314c48e0..7d7a172b7b3 100644 --- a/src/ecmult_const_impl.h +++ b/src/ecmult_const_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECMULT_CONST_IMPL_ -#define _SECP256K1_ECMULT_CONST_IMPL_ +#ifndef SECP256K1_ECMULT_CONST_IMPL_H +#define SECP256K1_ECMULT_CONST_IMPL_H #include "scalar.h" #include "group.h" @@ -42,11 +42,12 @@ } while(0) -/** Convert a number to WNAF notation. The number becomes represented by sum(2^{wi} * wnaf[i], i=0..return_val) - * with the following guarantees: +/** Convert a number to WNAF notation. + * The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val. + * It has the following guarantees: * - each wnaf[i] an odd integer between -(1 << w) and (1 << w) * - each wnaf[i] is nonzero - * - the number of words set is returned; this is always (WNAF_BITS + w - 1) / w + * - the number of words set is always WNAF_SIZE(w) + 1 * * Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar * Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.) @@ -236,4 +237,4 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons } } -#endif +#endif /* SECP256K1_ECMULT_CONST_IMPL_H */ diff --git a/src/ecmult_gen.h b/src/ecmult_gen.h index eb2cc9ead6e..7564b7015f0 100644 --- a/src/ecmult_gen.h +++ b/src/ecmult_gen.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECMULT_GEN_ -#define _SECP256K1_ECMULT_GEN_ +#ifndef SECP256K1_ECMULT_GEN_H +#define SECP256K1_ECMULT_GEN_H #include "scalar.h" #include "group.h" @@ -40,4 +40,4 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp25 static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32); -#endif +#endif /* SECP256K1_ECMULT_GEN_H */ diff --git a/src/ecmult_gen_impl.h b/src/ecmult_gen_impl.h index 35f25460773..714f02e94c9 100644 --- a/src/ecmult_gen_impl.h +++ b/src/ecmult_gen_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECMULT_GEN_IMPL_H_ -#define _SECP256K1_ECMULT_GEN_IMPL_H_ +#ifndef SECP256K1_ECMULT_GEN_IMPL_H +#define SECP256K1_ECMULT_GEN_IMPL_H #include "scalar.h" #include "group.h" @@ -161,7 +161,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const secp256k1_gej gb; secp256k1_fe s; unsigned char nonce32[32]; - secp256k1_rfc6979_hmac_sha256_t rng; + secp256k1_rfc6979_hmac_sha256 rng; int retry; unsigned char keydata[64] = {0}; if (seed32 == NULL) { @@ -207,4 +207,4 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const secp256k1_gej_clear(&gb); } -#endif +#endif /* SECP256K1_ECMULT_GEN_IMPL_H */ diff --git a/src/ecmult_impl.h b/src/ecmult_impl.h index 4e40104ad43..93d3794cb43 100644 --- a/src/ecmult_impl.h +++ b/src/ecmult_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECMULT_IMPL_H_ -#define _SECP256K1_ECMULT_IMPL_H_ +#ifndef SECP256K1_ECMULT_IMPL_H +#define SECP256K1_ECMULT_IMPL_H #include @@ -403,4 +403,4 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej } } -#endif +#endif /* SECP256K1_ECMULT_IMPL_H */ diff --git a/src/field.h b/src/field.h index bbb1ee866cc..bb6692ad578 100644 --- a/src/field.h +++ b/src/field.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_ -#define _SECP256K1_FIELD_ +#ifndef SECP256K1_FIELD_H +#define SECP256K1_FIELD_H /** Field element module. * @@ -129,4 +129,4 @@ static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_f /** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); -#endif +#endif /* SECP256K1_FIELD_H */ diff --git a/src/field_10x26.h b/src/field_10x26.h index 61ee1e09656..727c5267fbb 100644 --- a/src/field_10x26.h +++ b/src/field_10x26.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_REPR_ -#define _SECP256K1_FIELD_REPR_ +#ifndef SECP256K1_FIELD_REPR_H +#define SECP256K1_FIELD_REPR_H #include @@ -44,4 +44,5 @@ typedef struct { #define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }} #define SECP256K1_FE_STORAGE_CONST_GET(d) d.n[7], d.n[6], d.n[5], d.n[4],d.n[3], d.n[2], d.n[1], d.n[0] -#endif + +#endif /* SECP256K1_FIELD_REPR_H */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 234c13a6442..94f8132fc8e 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_REPR_IMPL_H_ -#define _SECP256K1_FIELD_REPR_IMPL_H_ +#ifndef SECP256K1_FIELD_REPR_IMPL_H +#define SECP256K1_FIELD_REPR_IMPL_H #include "util.h" #include "num.h" @@ -1158,4 +1158,4 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const se #endif } -#endif +#endif /* SECP256K1_FIELD_REPR_IMPL_H */ diff --git a/src/field_5x52.h b/src/field_5x52.h index 8e69a560dcc..bccd8feb4dd 100644 --- a/src/field_5x52.h +++ b/src/field_5x52.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_REPR_ -#define _SECP256K1_FIELD_REPR_ +#ifndef SECP256K1_FIELD_REPR_H +#define SECP256K1_FIELD_REPR_H #include @@ -44,4 +44,4 @@ typedef struct { (d6) | (((uint64_t)(d7)) << 32) \ }} -#endif +#endif /* SECP256K1_FIELD_REPR_H */ diff --git a/src/field_5x52_asm_impl.h b/src/field_5x52_asm_impl.h index 98cc004bf04..1fc3171f6b0 100644 --- a/src/field_5x52_asm_impl.h +++ b/src/field_5x52_asm_impl.h @@ -11,8 +11,8 @@ * - December 2014, Pieter Wuille: converted from YASM to GCC inline assembly */ -#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_ -#define _SECP256K1_FIELD_INNER5X52_IMPL_H_ +#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H +#define SECP256K1_FIELD_INNER5X52_IMPL_H SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { /** @@ -499,4 +499,4 @@ __asm__ __volatile__( ); } -#endif +#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */ diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 8e8b286baff..957c61b0145 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_REPR_IMPL_H_ -#define _SECP256K1_FIELD_REPR_IMPL_H_ +#ifndef SECP256K1_FIELD_REPR_IMPL_H +#define SECP256K1_FIELD_REPR_IMPL_H #if defined HAVE_CONFIG_H #include "libsecp256k1-config.h" @@ -493,4 +493,4 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const se #endif } -#endif +#endif /* SECP256K1_FIELD_REPR_IMPL_H */ diff --git a/src/field_5x52_int128_impl.h b/src/field_5x52_int128_impl.h index 0bf22bdd3ec..95a0d1791c0 100644 --- a/src/field_5x52_int128_impl.h +++ b/src/field_5x52_int128_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_ -#define _SECP256K1_FIELD_INNER5X52_IMPL_H_ +#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H +#define SECP256K1_FIELD_INNER5X52_IMPL_H #include @@ -274,4 +274,4 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ } -#endif +#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */ diff --git a/src/field_impl.h b/src/field_impl.h index 5127b279bc7..20428648af3 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_IMPL_H_ -#define _SECP256K1_FIELD_IMPL_H_ +#ifndef SECP256K1_FIELD_IMPL_H +#define SECP256K1_FIELD_IMPL_H #if defined HAVE_CONFIG_H #include "libsecp256k1-config.h" @@ -312,4 +312,4 @@ static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) { #endif } -#endif +#endif /* SECP256K1_FIELD_IMPL_H */ diff --git a/src/group.h b/src/group.h index 4957b248fe6..ea1302deb82 100644 --- a/src/group.h +++ b/src/group.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_GROUP_ -#define _SECP256K1_GROUP_ +#ifndef SECP256K1_GROUP_H +#define SECP256K1_GROUP_H #include "num.h" #include "field.h" @@ -141,4 +141,4 @@ static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_g /** Rescale a jacobian point by b which must be non-zero. Constant-time. */ static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b); -#endif +#endif /* SECP256K1_GROUP_H */ diff --git a/src/group_impl.h b/src/group_impl.h index 7d723532ff3..b31b6c12efe 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_GROUP_IMPL_H_ -#define _SECP256K1_GROUP_IMPL_H_ +#ifndef SECP256K1_GROUP_IMPL_H +#define SECP256K1_GROUP_IMPL_H #include "num.h" #include "field.h" @@ -697,4 +697,4 @@ static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) { return secp256k1_fe_is_quad_var(&yz); } -#endif +#endif /* SECP256K1_GROUP_IMPL_H */ diff --git a/src/hash.h b/src/hash.h index fca98cab9f8..de26e4b89f8 100644 --- a/src/hash.h +++ b/src/hash.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_HASH_ -#define _SECP256K1_HASH_ +#ifndef SECP256K1_HASH_H +#define SECP256K1_HASH_H #include #include @@ -14,28 +14,28 @@ typedef struct { uint32_t s[8]; uint32_t buf[16]; /* In big endian */ size_t bytes; -} secp256k1_sha256_t; +} secp256k1_sha256; -static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash); -static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t size); -static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32); +static void secp256k1_sha256_initialize(secp256k1_sha256 *hash); +static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t size); +static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32); typedef struct { - secp256k1_sha256_t inner, outer; -} secp256k1_hmac_sha256_t; + secp256k1_sha256 inner, outer; +} secp256k1_hmac_sha256; -static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t size); -static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size); -static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32); +static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t size); +static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size); +static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32); typedef struct { unsigned char v[32]; unsigned char k[32]; int retry; -} secp256k1_rfc6979_hmac_sha256_t; +} secp256k1_rfc6979_hmac_sha256; -static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen); -static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen); -static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng); +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen); +static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen); +static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng); -#endif +#endif /* SECP256K1_HASH_H */ diff --git a/src/hash_impl.h b/src/hash_impl.h index b47e65f830a..c06db9e3382 100644 --- a/src/hash_impl.h +++ b/src/hash_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_HASH_IMPL_H_ -#define _SECP256K1_HASH_IMPL_H_ +#ifndef SECP256K1_HASH_IMPL_H +#define SECP256K1_HASH_IMPL_H #include "hash.h" @@ -33,7 +33,7 @@ #define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) #endif -static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash) { +static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) { hash->s[0] = 0x6a09e667ul; hash->s[1] = 0xbb67ae85ul; hash->s[2] = 0x3c6ef372ul; @@ -128,7 +128,7 @@ static void secp256k1_sha256_transform(uint32_t* s, const uint32_t* chunk) { s[7] += h; } -static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t len) { +static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t len) { size_t bufsize = hash->bytes & 0x3F; hash->bytes += len; while (bufsize + len >= 64) { @@ -145,7 +145,7 @@ static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char } } -static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32) { +static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32) { static const unsigned char pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint32_t sizedesc[2]; uint32_t out[8]; @@ -161,14 +161,14 @@ static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *o memcpy(out32, (const unsigned char*)out, 32); } -static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t keylen) { +static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) { int n; unsigned char rkey[64]; if (keylen <= 64) { memcpy(rkey, key, keylen); memset(rkey + keylen, 0, 64 - keylen); } else { - secp256k1_sha256_t sha256; + secp256k1_sha256 sha256; secp256k1_sha256_initialize(&sha256); secp256k1_sha256_write(&sha256, key, keylen); secp256k1_sha256_finalize(&sha256, rkey); @@ -189,11 +189,11 @@ static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, cons memset(rkey, 0, 64); } -static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size) { +static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size) { secp256k1_sha256_write(&hash->inner, data, size); } -static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32) { +static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32) { unsigned char temp[32]; secp256k1_sha256_finalize(&hash->inner, temp); secp256k1_sha256_write(&hash->outer, temp, 32); @@ -202,8 +202,8 @@ static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsign } -static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen) { - secp256k1_hmac_sha256_t hmac; +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) { + secp256k1_hmac_sha256 hmac; static const unsigned char zero[1] = {0x00}; static const unsigned char one[1] = {0x01}; @@ -232,11 +232,11 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2 rng->retry = 0; } -static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen) { +static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen) { /* RFC6979 3.2.h. */ static const unsigned char zero[1] = {0x00}; if (rng->retry) { - secp256k1_hmac_sha256_t hmac; + secp256k1_hmac_sha256 hmac; secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); secp256k1_hmac_sha256_write(&hmac, zero, 1); @@ -247,7 +247,7 @@ static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 } while (outlen > 0) { - secp256k1_hmac_sha256_t hmac; + secp256k1_hmac_sha256 hmac; int now = outlen; secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); @@ -263,7 +263,7 @@ static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 rng->retry = 1; } -static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng) { +static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng) { memset(rng->k, 0, 32); memset(rng->v, 0, 32); rng->retry = 0; @@ -278,4 +278,4 @@ static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 #undef Maj #undef Ch -#endif +#endif /* SECP256K1_HASH_IMPL_H */ diff --git a/src/modules/ecdh/main_impl.h b/src/modules/ecdh/main_impl.h index 9e30fb73dd7..bd8739eeb1f 100644 --- a/src/modules/ecdh/main_impl.h +++ b/src/modules/ecdh/main_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_MODULE_ECDH_MAIN_ -#define _SECP256K1_MODULE_ECDH_MAIN_ +#ifndef SECP256K1_MODULE_ECDH_MAIN_H +#define SECP256K1_MODULE_ECDH_MAIN_H #include "include/secp256k1_ecdh.h" #include "ecmult_const_impl.h" @@ -28,7 +28,7 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const se } else { unsigned char x[32]; unsigned char y[1]; - secp256k1_sha256_t sha; + secp256k1_sha256 sha; secp256k1_ecmult_const(&res, &pt, &s); secp256k1_ge_set_gej(&pt, &res); @@ -51,4 +51,4 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const se return ret; } -#endif +#endif /* SECP256K1_MODULE_ECDH_MAIN_H */ diff --git a/src/modules/ecdh/tests_impl.h b/src/modules/ecdh/tests_impl.h index 85a5d0a9a69..0c53f8ee08b 100644 --- a/src/modules/ecdh/tests_impl.h +++ b/src/modules/ecdh/tests_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_MODULE_ECDH_TESTS_ -#define _SECP256K1_MODULE_ECDH_TESTS_ +#ifndef SECP256K1_MODULE_ECDH_TESTS_H +#define SECP256K1_MODULE_ECDH_TESTS_H void test_ecdh_api(void) { /* Setup context that just counts errors */ @@ -44,7 +44,7 @@ void test_ecdh_generator_basepoint(void) { s_one[31] = 1; /* Check against pubkey creation when the basepoint is the generator */ for (i = 0; i < 100; ++i) { - secp256k1_sha256_t sha; + secp256k1_sha256 sha; unsigned char s_b32[32]; unsigned char output_ecdh[32]; unsigned char output_ser[32]; @@ -102,4 +102,4 @@ void run_ecdh_tests(void) { test_bad_scalar(); } -#endif +#endif /* SECP256K1_MODULE_ECDH_TESTS_H */ diff --git a/src/modules/recovery/main_impl.h b/src/modules/recovery/main_impl.h index c6fbe239813..2f6691c5a13 100755 --- a/src/modules/recovery/main_impl.h +++ b/src/modules/recovery/main_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_MODULE_RECOVERY_MAIN_ -#define _SECP256K1_MODULE_RECOVERY_MAIN_ +#ifndef SECP256K1_MODULE_RECOVERY_MAIN_H +#define SECP256K1_MODULE_RECOVERY_MAIN_H #include "include/secp256k1_recovery.h" @@ -190,4 +190,4 @@ int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubk } } -#endif +#endif /* SECP256K1_MODULE_RECOVERY_MAIN_H */ diff --git a/src/modules/recovery/tests_impl.h b/src/modules/recovery/tests_impl.h index 765c7dd81e9..5c9bbe86101 100644 --- a/src/modules/recovery/tests_impl.h +++ b/src/modules/recovery/tests_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_MODULE_RECOVERY_TESTS_ -#define _SECP256K1_MODULE_RECOVERY_TESTS_ +#ifndef SECP256K1_MODULE_RECOVERY_TESTS_H +#define SECP256K1_MODULE_RECOVERY_TESTS_H static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { (void) msg32; @@ -390,4 +390,4 @@ void run_recovery_tests(void) { test_ecdsa_recovery_edge_cases(); } -#endif +#endif /* SECP256K1_MODULE_RECOVERY_TESTS_H */ diff --git a/src/num.h b/src/num.h index 7bb9c5be8cf..49f2dd791d5 100644 --- a/src/num.h +++ b/src/num.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_NUM_ -#define _SECP256K1_NUM_ +#ifndef SECP256K1_NUM_H +#define SECP256K1_NUM_H #ifndef USE_NUM_NONE @@ -71,4 +71,4 @@ static void secp256k1_num_negate(secp256k1_num *r); #endif -#endif +#endif /* SECP256K1_NUM_H */ diff --git a/src/num_gmp.h b/src/num_gmp.h index 7dd813088af..3619844bd51 100644 --- a/src/num_gmp.h +++ b/src/num_gmp.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_NUM_REPR_ -#define _SECP256K1_NUM_REPR_ +#ifndef SECP256K1_NUM_REPR_H +#define SECP256K1_NUM_REPR_H #include @@ -17,4 +17,4 @@ typedef struct { int limbs; } secp256k1_num; -#endif +#endif /* SECP256K1_NUM_REPR_H */ diff --git a/src/num_gmp_impl.h b/src/num_gmp_impl.h index 3a46495eeac..0ae2a8ba0ec 100644 --- a/src/num_gmp_impl.h +++ b/src/num_gmp_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_NUM_REPR_IMPL_H_ -#define _SECP256K1_NUM_REPR_IMPL_H_ +#ifndef SECP256K1_NUM_REPR_IMPL_H +#define SECP256K1_NUM_REPR_IMPL_H #include #include @@ -285,4 +285,4 @@ static void secp256k1_num_negate(secp256k1_num *r) { r->neg ^= 1; } -#endif +#endif /* SECP256K1_NUM_REPR_IMPL_H */ diff --git a/src/num_impl.h b/src/num_impl.h index 0b0e3a072a1..c45193b033d 100644 --- a/src/num_impl.h +++ b/src/num_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_NUM_IMPL_H_ -#define _SECP256K1_NUM_IMPL_H_ +#ifndef SECP256K1_NUM_IMPL_H +#define SECP256K1_NUM_IMPL_H #if defined HAVE_CONFIG_H #include "libsecp256k1-config.h" @@ -21,4 +21,4 @@ #error "Please select num implementation" #endif -#endif +#endif /* SECP256K1_NUM_IMPL_H */ diff --git a/src/scalar.h b/src/scalar.h index 27e9d8375e8..59304cb66e9 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_SCALAR_ -#define _SECP256K1_SCALAR_ +#ifndef SECP256K1_SCALAR_H +#define SECP256K1_SCALAR_H #include "num.h" @@ -103,4 +103,4 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar /** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */ static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift); -#endif +#endif /* SECP256K1_SCALAR_H */ diff --git a/src/scalar_4x64.h b/src/scalar_4x64.h index cff406038fb..19c7495d1c8 100644 --- a/src/scalar_4x64.h +++ b/src/scalar_4x64.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_SCALAR_REPR_ -#define _SECP256K1_SCALAR_REPR_ +#ifndef SECP256K1_SCALAR_REPR_H +#define SECP256K1_SCALAR_REPR_H #include @@ -16,4 +16,4 @@ typedef struct { #define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{((uint64_t)(d1)) << 32 | (d0), ((uint64_t)(d3)) << 32 | (d2), ((uint64_t)(d5)) << 32 | (d4), ((uint64_t)(d7)) << 32 | (d6)}} -#endif +#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/src/scalar_4x64_impl.h b/src/scalar_4x64_impl.h index 56e7bd82afd..db1ebf94bee 100644 --- a/src/scalar_4x64_impl.h +++ b/src/scalar_4x64_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_ -#define _SECP256K1_SCALAR_REPR_IMPL_H_ +#ifndef SECP256K1_SCALAR_REPR_IMPL_H +#define SECP256K1_SCALAR_REPR_IMPL_H /* Limbs of the secp256k1 order. */ #define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL) @@ -946,4 +946,4 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1); } -#endif +#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/scalar_8x32.h b/src/scalar_8x32.h index 1319664f654..2c9a348e247 100644 --- a/src/scalar_8x32.h +++ b/src/scalar_8x32.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_SCALAR_REPR_ -#define _SECP256K1_SCALAR_REPR_ +#ifndef SECP256K1_SCALAR_REPR_H +#define SECP256K1_SCALAR_REPR_H #include @@ -16,4 +16,4 @@ typedef struct { #define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}} -#endif +#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/src/scalar_8x32_impl.h b/src/scalar_8x32_impl.h index aae4f35c085..4f9ed61feae 100644 --- a/src/scalar_8x32_impl.h +++ b/src/scalar_8x32_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_ -#define _SECP256K1_SCALAR_REPR_IMPL_H_ +#ifndef SECP256K1_SCALAR_REPR_IMPL_H +#define SECP256K1_SCALAR_REPR_IMPL_H /* Limbs of the secp256k1 order. */ #define SECP256K1_N_0 ((uint32_t)0xD0364141UL) @@ -718,4 +718,4 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1); } -#endif +#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/scalar_impl.h b/src/scalar_impl.h index 2690d86558a..fa790570ff8 100644 --- a/src/scalar_impl.h +++ b/src/scalar_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_SCALAR_IMPL_H_ -#define _SECP256K1_SCALAR_IMPL_H_ +#ifndef SECP256K1_SCALAR_IMPL_H +#define SECP256K1_SCALAR_IMPL_H #include "group.h" #include "scalar.h" @@ -330,4 +330,4 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar #endif #endif -#endif +#endif /* SECP256K1_SCALAR_IMPL_H */ diff --git a/src/scalar_low.h b/src/scalar_low.h index 5574c44c7ae..5836febc5b7 100644 --- a/src/scalar_low.h +++ b/src/scalar_low.h @@ -4,12 +4,12 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_SCALAR_REPR_ -#define _SECP256K1_SCALAR_REPR_ +#ifndef SECP256K1_SCALAR_REPR_H +#define SECP256K1_SCALAR_REPR_H #include /** A scalar modulo the group order of the secp256k1 curve. */ typedef uint32_t secp256k1_scalar; -#endif +#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/src/scalar_low_impl.h b/src/scalar_low_impl.h index 4f94441f492..c80e70c5a2a 100644 --- a/src/scalar_low_impl.h +++ b/src/scalar_low_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_ -#define _SECP256K1_SCALAR_REPR_IMPL_H_ +#ifndef SECP256K1_SCALAR_REPR_IMPL_H +#define SECP256K1_SCALAR_REPR_IMPL_H #include "scalar.h" @@ -111,4 +111,4 @@ SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const return *a == *b; } -#endif +#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/secp256k1.c b/src/secp256k1.c index 4f8c01655bd..cecb1550be7 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -310,7 +310,7 @@ int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_s static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { unsigned char keydata[112]; int keylen = 64; - secp256k1_rfc6979_hmac_sha256_t rng; + secp256k1_rfc6979_hmac_sha256 rng; unsigned int i; /* We feed a byte array to the PRNG as input, consisting of: * - the private key (32 bytes) and message (32 bytes), see RFC 6979 3.2d. diff --git a/src/testrand.h b/src/testrand.h index f8efa93c7c3..f1f9be077e3 100644 --- a/src/testrand.h +++ b/src/testrand.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_TESTRAND_H_ -#define _SECP256K1_TESTRAND_H_ +#ifndef SECP256K1_TESTRAND_H +#define SECP256K1_TESTRAND_H #if defined HAVE_CONFIG_H #include "libsecp256k1-config.h" @@ -35,4 +35,4 @@ static void secp256k1_rand256_test(unsigned char *b32); /** Generate pseudorandom bytes with long sequences of zero and one bits. */ static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len); -#endif +#endif /* SECP256K1_TESTRAND_H */ diff --git a/src/testrand_impl.h b/src/testrand_impl.h index 15c7b9f12df..30a91e52961 100644 --- a/src/testrand_impl.h +++ b/src/testrand_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_TESTRAND_IMPL_H_ -#define _SECP256K1_TESTRAND_IMPL_H_ +#ifndef SECP256K1_TESTRAND_IMPL_H +#define SECP256K1_TESTRAND_IMPL_H #include #include @@ -13,7 +13,7 @@ #include "testrand.h" #include "hash.h" -static secp256k1_rfc6979_hmac_sha256_t secp256k1_test_rng; +static secp256k1_rfc6979_hmac_sha256 secp256k1_test_rng; static uint32_t secp256k1_test_rng_precomputed[8]; static int secp256k1_test_rng_precomputed_used = 8; static uint64_t secp256k1_test_rng_integer; @@ -107,4 +107,4 @@ static void secp256k1_rand256_test(unsigned char *b32) { secp256k1_rand_bytes_test(b32, 32); } -#endif +#endif /* SECP256K1_TESTRAND_IMPL_H */ diff --git a/src/tests.c b/src/tests.c index 3d9bd5ebb48..f307b99d5af 100644 --- a/src/tests.c +++ b/src/tests.c @@ -270,7 +270,7 @@ void run_sha256_tests(void) { int i; for (i = 0; i < 8; i++) { unsigned char out[32]; - secp256k1_sha256_t hasher; + secp256k1_sha256 hasher; secp256k1_sha256_initialize(&hasher); secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); secp256k1_sha256_finalize(&hasher, out); @@ -313,7 +313,7 @@ void run_hmac_sha256_tests(void) { }; int i; for (i = 0; i < 6; i++) { - secp256k1_hmac_sha256_t hasher; + secp256k1_hmac_sha256 hasher; unsigned char out[32]; secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); @@ -345,7 +345,7 @@ void run_rfc6979_hmac_sha256_tests(void) { {0x75, 0x97, 0x88, 0x7c, 0xbd, 0x76, 0x32, 0x1f, 0x32, 0xe3, 0x04, 0x40, 0x67, 0x9a, 0x22, 0xcf, 0x7f, 0x8d, 0x9d, 0x2e, 0xac, 0x39, 0x0e, 0x58, 0x1f, 0xea, 0x09, 0x1c, 0xe2, 0x02, 0xba, 0x94} }; - secp256k1_rfc6979_hmac_sha256_t rng; + secp256k1_rfc6979_hmac_sha256 rng; unsigned char out[32]; int i; diff --git a/src/util.h b/src/util.h index 4092a86c917..b0441d8e305 100644 --- a/src/util.h +++ b/src/util.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_UTIL_H_ -#define _SECP256K1_UTIL_H_ +#ifndef SECP256K1_UTIL_H +#define SECP256K1_UTIL_H #if defined HAVE_CONFIG_H #include "libsecp256k1-config.h" @@ -110,4 +110,4 @@ static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_ SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t; #endif -#endif +#endif /* SECP256K1_UTIL_H */ From 4e4aa5b6ec5ba34de77c837362b589003e007a00 Mon Sep 17 00:00:00 2001 From: syd Date: Thu, 23 Nov 2017 14:20:20 -0500 Subject: [PATCH 091/177] Get rid of underscore prefixes for include guards. This is because they may conflict with reserved names. Also took this opportunity to make the guards in the zcash subdir a bit more uniform by having them all conform to ZC_<...>_H_ This closes #1272 --- src/univalue/include/univalue.h | 6 +++--- src/zcash/Address.hpp | 6 +++--- src/zcash/IncrementalMerkleTree.hpp | 7 +++---- src/zcash/JoinSplit.hpp | 6 +++--- src/zcash/Note.hpp | 6 +++--- src/zcash/Proof.hpp | 6 +++--- src/zcash/Zcash.h | 6 +++--- src/zcash/prf.h | 6 +++--- src/zcash/util.h | 6 +++--- 9 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h index 07314bc5c8b..dfc84f92111 100644 --- a/src/univalue/include/univalue.h +++ b/src/univalue/include/univalue.h @@ -3,8 +3,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef __UNIVALUE_H__ -#define __UNIVALUE_H__ +#ifndef UNIVALUE_H__ +#define UNIVALUE_H__ #include @@ -293,4 +293,4 @@ extern const UniValue NullUniValue; const UniValue& find_value( const UniValue& obj, const std::string& name); -#endif // __UNIVALUE_H__ +#endif // UNIVALUE_H__ diff --git a/src/zcash/Address.hpp b/src/zcash/Address.hpp index efae2af223b..9bf22663d3a 100644 --- a/src/zcash/Address.hpp +++ b/src/zcash/Address.hpp @@ -1,5 +1,5 @@ -#ifndef _ZCADDRESS_H_ -#define _ZCADDRESS_H_ +#ifndef ZC_ADDRESS_H_ +#define ZC_ADDRESS_H_ #include "uint256.h" #include "uint252.h" @@ -58,4 +58,4 @@ class SpendingKey : public uint252 { } -#endif // _ZCADDRESS_H_ +#endif // ZC_ADDRESS_H_ diff --git a/src/zcash/IncrementalMerkleTree.hpp b/src/zcash/IncrementalMerkleTree.hpp index 67b356318f7..151a395c18d 100644 --- a/src/zcash/IncrementalMerkleTree.hpp +++ b/src/zcash/IncrementalMerkleTree.hpp @@ -1,5 +1,5 @@ -#ifndef ZCINCREMENTALMERKLETREE_H_ -#define ZCINCREMENTALMERKLETREE_H_ +#ifndef ZC_INCREMENTALMERKLETREE_H_ +#define ZC_INCREMENTALMERKLETREE_H_ #include #include @@ -202,5 +202,4 @@ typedef libzcash::IncrementalMerkleTree ZCIncrementalWitness; typedef libzcash::IncrementalWitness ZCTestingIncrementalWitness; -#endif /* ZCINCREMENTALMERKLETREE_H_ */ - +#endif /* ZC_INCREMENTALMERKLETREE_H_ */ diff --git a/src/zcash/JoinSplit.hpp b/src/zcash/JoinSplit.hpp index b7ed454fda3..6a2d4e1f2ff 100644 --- a/src/zcash/JoinSplit.hpp +++ b/src/zcash/JoinSplit.hpp @@ -1,5 +1,5 @@ -#ifndef _ZCJOINSPLIT_H_ -#define _ZCJOINSPLIT_H_ +#ifndef ZC_JOINSPLIT_H_ +#define ZC_JOINSPLIT_H_ #include "Zcash.h" #include "Proof.hpp" @@ -102,4 +102,4 @@ class JoinSplit { typedef libzcash::JoinSplit ZCJoinSplit; -#endif // _ZCJOINSPLIT_H_ +#endif // ZC_JOINSPLIT_H_ diff --git a/src/zcash/Note.hpp b/src/zcash/Note.hpp index 460e68f9d81..faacd2720d3 100644 --- a/src/zcash/Note.hpp +++ b/src/zcash/Note.hpp @@ -1,5 +1,5 @@ -#ifndef _ZCNOTE_H_ -#define _ZCNOTE_H_ +#ifndef ZC_NOTE_H_ +#define ZC_NOTE_H_ #include "uint256.h" #include "Zcash.h" @@ -68,4 +68,4 @@ class NotePlaintext { } -#endif // _ZCNOTE_H_ \ No newline at end of file +#endif // ZC_NOTE_H_ diff --git a/src/zcash/Proof.hpp b/src/zcash/Proof.hpp index 3b6b5e568b6..5f05aa2c530 100644 --- a/src/zcash/Proof.hpp +++ b/src/zcash/Proof.hpp @@ -1,5 +1,5 @@ -#ifndef _ZCPROOF_H_ -#define _ZCPROOF_H_ +#ifndef ZC_PROOF_H_ +#define ZC_PROOF_H_ #include "serialize.h" #include "uint256.h" @@ -274,4 +274,4 @@ class ProofVerifier { } -#endif // _ZCPROOF_H_ +#endif // ZC_PROOF_H_ diff --git a/src/zcash/Zcash.h b/src/zcash/Zcash.h index c2dfe548b48..9e668447543 100644 --- a/src/zcash/Zcash.h +++ b/src/zcash/Zcash.h @@ -1,5 +1,5 @@ -#ifndef _ZCCONSTANTS_H_ -#define _ZCCONSTANTS_H_ +#ifndef ZC_ZCASH_H_ +#define ZC_ZCASH_H_ #define ZC_NUM_JS_INPUTS 2 #define ZC_NUM_JS_OUTPUTS 2 @@ -14,4 +14,4 @@ #define ZC_NOTEPLAINTEXT_SIZE (ZC_NOTEPLAINTEXT_LEADING + ZC_V_SIZE + ZC_RHO_SIZE + ZC_R_SIZE + ZC_MEMO_SIZE) -#endif // _ZCCONSTANTS_H_ +#endif // ZC_ZCASH_H_ diff --git a/src/zcash/prf.h b/src/zcash/prf.h index c6cb45384d4..dec934f4a70 100644 --- a/src/zcash/prf.h +++ b/src/zcash/prf.h @@ -3,8 +3,8 @@ Zcash uses SHA256Compress as a PRF for various components within the zkSNARK circuit. */ -#ifndef _PRF_H_ -#define _PRF_H_ +#ifndef ZC_PRF_H_ +#define ZC_PRF_H_ #include "uint256.h" #include "uint252.h" @@ -15,4 +15,4 @@ uint256 PRF_nf(const uint252& a_sk, const uint256& rho); uint256 PRF_pk(const uint252& a_sk, size_t i0, const uint256& h_sig); uint256 PRF_rho(const uint252& phi, size_t i0, const uint256& h_sig); -#endif // _PRF_H_ +#endif // ZC_PRF_H_ diff --git a/src/zcash/util.h b/src/zcash/util.h index bbfeac1c38f..10886e3ca68 100644 --- a/src/zcash/util.h +++ b/src/zcash/util.h @@ -1,5 +1,5 @@ -#ifndef __ZCASH_UTIL_H -#define __ZCASH_UTIL_H +#ifndef ZC_UTIL_H_ +#define ZC_UTIL_H_ #include #include @@ -8,4 +8,4 @@ std::vector convertIntToVectorLE(const uint64_t val_int); std::vector convertBytesVectorToVector(const std::vector& bytes); uint64_t convertVectorToInt(const std::vector& v); -#endif // __ZCASH_UTIL_H +#endif // ZC_UTIL_H_ From e619c219441191d6d2c47a5f89463fd83e66809d Mon Sep 17 00:00:00 2001 From: syd Date: Thu, 23 Nov 2017 16:00:05 -0500 Subject: [PATCH 092/177] Rename bash completion files so that they refer to zcash and not bitcoin. This closes #2167 --- ...sh-completion => zcash-cli.bash-completion} | 16 ++++++++-------- ...ash-completion => zcash-tx.bash-completion} | 18 +++++++++--------- ....bash-completion => zcashd.bash-completion} | 6 +++--- zcutil/build-debian-package.sh | 4 ++-- 4 files changed, 22 insertions(+), 22 deletions(-) rename contrib/{bitcoin-cli.bash-completion => zcash-cli.bash-completion} (92%) rename contrib/{bitcoin-tx.bash-completion => zcash-tx.bash-completion} (74%) rename contrib/{bitcoind.bash-completion => zcashd.bash-completion} (91%) diff --git a/contrib/bitcoin-cli.bash-completion b/contrib/zcash-cli.bash-completion similarity index 92% rename from contrib/bitcoin-cli.bash-completion rename to contrib/zcash-cli.bash-completion index f2a44d2328a..79b57a06395 100644 --- a/contrib/bitcoin-cli.bash-completion +++ b/contrib/zcash-cli.bash-completion @@ -1,9 +1,9 @@ -# bash programmable completion for bitcoin-cli(1) +# bash programmable completion for zcash-cli(1) # Copyright (c) 2012-2016 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -# call $bitcoin-cli for RPC +# call $zcash-cli for RPC _zcash_rpc() { # determine already specified args necessary for RPC local rpcargs=() @@ -14,7 +14,7 @@ _zcash_rpc() { ;; esac done - $bitcoin_cli "${rpcargs[@]}" "$@" + $zcash_cli "${rpcargs[@]}" "$@" } # Add wallet accounts to COMPREPLY @@ -28,11 +28,11 @@ _zcash_accounts() { _zcash_cli() { local cur prev words=() cword - local bitcoin_cli + local zcash_cli - # save and use original argument to invoke bitcoin-cli for -help, help and RPC - # as bitcoin-cli might not be in $PATH - bitcoin_cli="$1" + # save and use original argument to invoke zcash-cli for -help, help and RPC + # as zcash-cli might not be in $PATH + zcash_cli="$1" COMPREPLY=() _get_comp_words_by_ref -n = cur prev words cword @@ -127,7 +127,7 @@ _zcash_cli() { # only parse -help if senseful if [[ -z "$cur" || "$cur" =~ ^- ]]; then - helpopts=$($bitcoin_cli -help 2>&1 | awk '$1 ~ /^-/ { sub(/=.*/, "="); print $1 }' ) + helpopts=$($zcash_cli -help 2>&1 | awk '$1 ~ /^-/ { sub(/=.*/, "="); print $1 }' ) fi # only parse help if senseful diff --git a/contrib/bitcoin-tx.bash-completion b/contrib/zcash-tx.bash-completion similarity index 74% rename from contrib/bitcoin-tx.bash-completion rename to contrib/zcash-tx.bash-completion index 0206eba7489..e808f93cb95 100644 --- a/contrib/bitcoin-tx.bash-completion +++ b/contrib/zcash-tx.bash-completion @@ -1,15 +1,15 @@ -# bash programmable completion for bitcoin-tx(1) +# bash programmable completion for zcash-tx(1) # Copyright (c) 2016 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -_bitcoin_tx() { +_zcash_tx() { local cur prev words=() cword - local bitcoin_tx + local zcash_tx - # save and use original argument to invoke bitcoin-tx for -help + # save and use original argument to invoke zcash-tx for -help # it might not be in $PATH - bitcoin_tx="$1" + zcash_tx="$1" COMPREPLY=() _get_comp_words_by_ref -n =: cur prev words cword @@ -27,15 +27,15 @@ _bitcoin_tx() { if [[ "$cword" == 1 || ( "$prev" != "-create" && "$prev" == -* ) ]]; then # only options (or an uncompletable hex-string) allowed - # parse bitcoin-tx -help for options + # parse zcash-tx -help for options local helpopts - helpopts=$($bitcoin_tx -help | sed -e '/^ -/ p' -e d ) + helpopts=$($zcash_tx -help | sed -e '/^ -/ p' -e d ) COMPREPLY=( $( compgen -W "$helpopts" -- "$cur" ) ) else # only commands are allowed # parse -help for commands local helpcmds - helpcmds=$($bitcoin_tx -help | sed -e '1,/Commands:/d' -e 's/=.*/=/' -e '/^ [a-z]/ p' -e d ) + helpcmds=$($zcash_tx -help | sed -e '1,/Commands:/d' -e 's/=.*/=/' -e '/^ [a-z]/ p' -e d ) COMPREPLY=( $( compgen -W "$helpcmds" -- "$cur" ) ) fi @@ -46,7 +46,7 @@ _bitcoin_tx() { return 0 } && -complete -F _bitcoin_tx zcash-tx +complete -F _zcash_tx zcash-tx # Local variables: # mode: shell-script diff --git a/contrib/bitcoind.bash-completion b/contrib/zcashd.bash-completion similarity index 91% rename from contrib/bitcoind.bash-completion rename to contrib/zcashd.bash-completion index 104365024f9..3a2f091bdcd 100644 --- a/contrib/bitcoind.bash-completion +++ b/contrib/zcashd.bash-completion @@ -6,11 +6,11 @@ _zcashd() { local cur prev words=() cword - local bitcoind + local zcashd # save and use original argument to invoke zcashd for -help # it might not be in $PATH - bitcoind="$1" + zcashd="$1" COMPREPLY=() _get_comp_words_by_ref -n = cur prev words cword @@ -34,7 +34,7 @@ _zcashd() { # only parse -help if senseful if [[ -z "$cur" || "$cur" =~ ^- ]]; then local helpopts - helpopts=$($bitcoind -help 2>&1 | awk '$1 ~ /^-/ { sub(/=.*/, "="); print $1 }' ) + helpopts=$($zcashd -help 2>&1 | awk '$1 ~ /^-/ { sub(/=.*/, "="); print $1 }' ) COMPREPLY=( $( compgen -W "$helpopts" -- "$cur" ) ) fi diff --git a/zcutil/build-debian-package.sh b/zcutil/build-debian-package.sh index 694b7492901..8705300831d 100755 --- a/zcutil/build-debian-package.sh +++ b/zcutil/build-debian-package.sh @@ -51,8 +51,8 @@ cp $SRC_DOC/man/zcashd.1 $DEB_MAN cp $SRC_DOC/man/zcash-cli.1 $DEB_MAN cp $SRC_DOC/man/zcash-fetch-params.1 $DEB_MAN # Copy bash completion files -cp $SRC_PATH/contrib/bitcoind.bash-completion $DEB_CMP/zcashd -cp $SRC_PATH/contrib/bitcoin-cli.bash-completion $DEB_CMP/zcash-cli +cp $SRC_PATH/contrib/zcashd.bash-completion $DEB_CMP/zcashd +cp $SRC_PATH/contrib/zcash-cli.bash-completion $DEB_CMP/zcash-cli # Gzip files gzip --best -n $DEB_DOC/changelog gzip --best -n $DEB_DOC/changelog.Debian From 7fa05b29b6cd06a5914a16234f7c8315255b09fc Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 29 Oct 2017 13:10:09 +1300 Subject: [PATCH 093/177] Use g-prefixed coreutils commands if they are available If they are present on the system, it means that the non-prefixed ones are not necessarily the versions we want, while the prefixed ones are highly likely to be the ones from GNU Coreutils. --- zcutil/build.sh | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/zcutil/build.sh b/zcutil/build.sh index 5e6b318f51e..570ad3abb8c 100755 --- a/zcutil/build.sh +++ b/zcutil/build.sh @@ -2,6 +2,21 @@ set -eu -o pipefail +function cmd_pref() { + if type -p "$2" > /dev/null; then + eval "$1=$2" + else + eval "$1=$3" + fi +} + +# If a g-prefixed version of the command exists, use it preferentially. +function gprefix() { + cmd_pref "$1" "g$2" "$2" +} + +gprefix READLINK readlink + # Allow user overrides to $MAKE. Typical usage for users who need it: # MAKE=gmake ./zcutil/build.sh -j$(nproc) if [[ -z "${MAKE-}" ]]; then @@ -58,7 +73,7 @@ EOF fi set -x -cd "$(dirname "$(readlink -f "$0")")/.." +cd "$(dirname "$("$READLINK" -f "$0")")/.." # If --enable-lcov is the first argument, enable lcov coverage support: LCOV_ARG='' From e4cd34126063beb5dfa7b01909f8ea8b204e1d86 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 30 Oct 2017 01:22:55 +1300 Subject: [PATCH 094/177] Replace hard-coded defaults for HOST and BUILD with config.guess --- zcutil/build.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zcutil/build.sh b/zcutil/build.sh index 570ad3abb8c..f665088ac8a 100755 --- a/zcutil/build.sh +++ b/zcutil/build.sh @@ -16,6 +16,7 @@ function gprefix() { } gprefix READLINK readlink +cd "$(dirname "$("$READLINK" -f "$0")")/.." # Allow user overrides to $MAKE. Typical usage for users who need it: # MAKE=gmake ./zcutil/build.sh -j$(nproc) @@ -26,10 +27,10 @@ fi # Allow overrides to $BUILD and $HOST for porters. Most users will not need it. # BUILD=i686-pc-linux-gnu ./zcutil/build.sh if [[ -z "${BUILD-}" ]]; then - BUILD=x86_64-unknown-linux-gnu + BUILD="$(./depends/config.guess)" fi if [[ -z "${HOST-}" ]]; then - HOST=x86_64-unknown-linux-gnu + HOST="$BUILD" fi # Allow override to $CC and $CXX for porters. Most users will not need it. @@ -73,7 +74,6 @@ EOF fi set -x -cd "$(dirname "$("$READLINK" -f "$0")")/.." # If --enable-lcov is the first argument, enable lcov coverage support: LCOV_ARG='' From 124e9389af07a19f3dc63147706be318c3ba8d84 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Mon, 30 Nov 2015 13:23:00 +0100 Subject: [PATCH 095/177] Fix url in .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b2cc7b02b99..aba6702a556 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ # - A travis bug causes caches to trample eachother when using the same # compiler key (which we don't use anyway). This is worked around for now by # replacing the "compilers" with a build name prefixed by the no-op ":" -# command. See: https://github.com/travis-ci/casher/issues/6 +# command. See: https://github.com/travis-ci/travis-ci/issues/4393 os: linux language: cpp From 4165af1b739a15bad046ab037acbb1eb6bcf14cb Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 5 Jan 2016 16:10:13 -0500 Subject: [PATCH 096/177] c++11: don't throw from the reverselock destructor noexcept is default for destructors as of c++11. By throwing in reverselock's destructor if it's lock has been tampered with, the likely result is std::terminate being called. Indeed that happened before this change. Once reverselock has taken another lock (its ctor didn't throw), it makes no sense to try to grab or lock the parent lock. That is be broken/undefined behavior depending on the parent lock's implementation, but it shouldn't cause the reverselock to fail to re-lock when destroyed. To avoid those problems, simply swap the parent lock's contents with a dummy for the duration of the lock. That will ensure that any undefined behavior is caught at the call-site rather than the reverse lock's destruction. Barring a failed mutex unlock which would be indicative of a larger problem, the destructor should now never throw. --- src/reverselock.h | 7 +++++-- src/test/reverselock_tests.cpp | 16 ++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/reverselock.h b/src/reverselock.h index db5c626c958..fac1ccb7931 100644 --- a/src/reverselock.h +++ b/src/reverselock.h @@ -15,10 +15,12 @@ class reverse_lock explicit reverse_lock(Lock& lock) : lock(lock) { lock.unlock(); + lock.swap(templock); } - ~reverse_lock() noexcept(false) { - lock.lock(); + ~reverse_lock() { + templock.lock(); + templock.swap(lock); } private: @@ -26,6 +28,7 @@ class reverse_lock reverse_lock& operator=(reverse_lock const&); Lock& lock; + Lock templock; }; #endif // BITCOIN_REVERSELOCK_H diff --git a/src/test/reverselock_tests.cpp b/src/test/reverselock_tests.cpp index e7e627ae0f2..8bdff97000f 100644 --- a/src/test/reverselock_tests.cpp +++ b/src/test/reverselock_tests.cpp @@ -42,22 +42,18 @@ BOOST_AUTO_TEST_CASE(reverselock_errors) BOOST_CHECK(failed); BOOST_CHECK(!lock.owns_lock()); - // Make sure trying to lock a lock after it has been reverse locked fails - failed = false; - bool locked = false; + // Locking the original lock after it has been taken by a reverse lock + // makes no sense. Ensure that the original lock no longer owns the lock + // after giving it to a reverse one. lock.lock(); BOOST_CHECK(lock.owns_lock()); - - try { + { reverse_lock > rlock(lock); - lock.lock(); - locked = true; - } catch(...) { - failed = true; + BOOST_CHECK(!lock.owns_lock()); } - BOOST_CHECK(locked && failed); + BOOST_CHECK(failed); BOOST_CHECK(lock.owns_lock()); } From 4bfe8a744bd8b23b770b1562e8188c9b18859f3b Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 5 Jan 2016 16:25:42 -0500 Subject: [PATCH 097/177] c++11: CAccountingEntry must be defined before use in a list c++11ism. This fixes builds against libc++. --- src/wallet/wallet.h | 164 +++++++++++++++++++++----------------------- 1 file changed, 80 insertions(+), 84 deletions(-) diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index e73d05cc988..2b481d87a8c 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -60,7 +60,6 @@ static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000; // unless there is some exceptional network disruption. static const unsigned int WITNESS_CACHE_SIZE = COINBASE_MATURITY; -class CAccountingEntry; class CBlockIndex; class CCoinControl; class COutput; @@ -570,6 +569,86 @@ class CWalletKey } }; +/** + * Internal transfers. + * Database key is acentry. + */ +class CAccountingEntry +{ +public: + std::string strAccount; + CAmount nCreditDebit; + int64_t nTime; + std::string strOtherAccount; + std::string strComment; + mapValue_t mapValue; + int64_t nOrderPos; //! position in ordered transaction list + uint64_t nEntryNo; + + CAccountingEntry() + { + SetNull(); + } + + void SetNull() + { + nCreditDebit = 0; + nTime = 0; + strAccount.clear(); + strOtherAccount.clear(); + strComment.clear(); + nOrderPos = -1; + nEntryNo = 0; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + if (!(nType & SER_GETHASH)) + READWRITE(nVersion); + //! Note: strAccount is serialized as part of the key, not here. + READWRITE(nCreditDebit); + READWRITE(nTime); + READWRITE(LIMITED_STRING(strOtherAccount, 65536)); + + if (!ser_action.ForRead()) + { + WriteOrderPos(nOrderPos, mapValue); + + if (!(mapValue.empty() && _ssExtra.empty())) + { + CDataStream ss(nType, nVersion); + ss.insert(ss.begin(), '\0'); + ss << mapValue; + ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end()); + strComment.append(ss.str()); + } + } + + READWRITE(LIMITED_STRING(strComment, 65536)); + + size_t nSepPos = strComment.find("\0", 0, 1); + if (ser_action.ForRead()) + { + mapValue.clear(); + if (std::string::npos != nSepPos) + { + CDataStream ss(std::vector(strComment.begin() + nSepPos + 1, strComment.end()), nType, nVersion); + ss >> mapValue; + _ssExtra = std::vector(ss.begin(), ss.end()); + } + ReadOrderPos(nOrderPos, mapValue); + } + if (std::string::npos != nSepPos) + strComment.erase(nSepPos); + + mapValue.erase("n"); + } + +private: + std::vector _ssExtra; +}; /** @@ -1094,87 +1173,4 @@ class CAccount } }; - - -/** - * Internal transfers. - * Database key is acentry. - */ -class CAccountingEntry -{ -public: - std::string strAccount; - CAmount nCreditDebit; - int64_t nTime; - std::string strOtherAccount; - std::string strComment; - mapValue_t mapValue; - int64_t nOrderPos; //! position in ordered transaction list - uint64_t nEntryNo; - - CAccountingEntry() - { - SetNull(); - } - - void SetNull() - { - nCreditDebit = 0; - nTime = 0; - strAccount.clear(); - strOtherAccount.clear(); - strComment.clear(); - nOrderPos = -1; - nEntryNo = 0; - } - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - if (!(nType & SER_GETHASH)) - READWRITE(nVersion); - //! Note: strAccount is serialized as part of the key, not here. - READWRITE(nCreditDebit); - READWRITE(nTime); - READWRITE(LIMITED_STRING(strOtherAccount, 65536)); - - if (!ser_action.ForRead()) - { - WriteOrderPos(nOrderPos, mapValue); - - if (!(mapValue.empty() && _ssExtra.empty())) - { - CDataStream ss(nType, nVersion); - ss.insert(ss.begin(), '\0'); - ss << mapValue; - ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end()); - strComment.append(ss.str()); - } - } - - READWRITE(LIMITED_STRING(strComment, 65536)); - - size_t nSepPos = strComment.find("\0", 0, 1); - if (ser_action.ForRead()) - { - mapValue.clear(); - if (std::string::npos != nSepPos) - { - CDataStream ss(std::vector(strComment.begin() + nSepPos + 1, strComment.end()), nType, nVersion); - ss >> mapValue; - _ssExtra = std::vector(ss.begin(), ss.end()); - } - ReadOrderPos(nOrderPos, mapValue); - } - if (std::string::npos != nSepPos) - strComment.erase(nSepPos); - - mapValue.erase("n"); - } - -private: - std::vector _ssExtra; -}; - #endif // BITCOIN_WALLET_WALLET_H From 1f623c64b6dd636895ebebb726c8aaab3ebeafc3 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 5 Jan 2016 16:27:42 -0500 Subject: [PATCH 098/177] c++11: fix libbdb build against libc++ in c++11 mode atomic_init clashes with --- depends/packages/bdb.mk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk index df5df6bdead..d0e9949f163 100644 --- a/depends/packages/bdb.mk +++ b/depends/packages/bdb.mk @@ -11,6 +11,11 @@ $(package)_config_opts_mingw32=--enable-mingw $(package)_config_opts_linux=--with-pic endef +define $(package)_preprocess_cmds + sed -i.old 's/__atomic_compare_exchange\\(/__atomic_compare_exchange_db(/' src/dbinc/atomic.h && \ + sed -i.old 's/atomic_init/atomic_init_db/' src/dbinc/atomic.h src/mp/mp_region.c src/mp/mp_mvcc.c src/mp/mp_fget.c src/mutex/mut_method.c src/mutex/mut_tas.c +endef + define $(package)_config_cmds ../dist/$($(package)_autoconf) endef From bd03cfebec5d0e00747cf53dd678211e867a0a44 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 9 Feb 2016 03:29:23 +0000 Subject: [PATCH 099/177] depends: Use curl for fetching on Linux Currently Travis's wget fails fetching qrencode: Fetching qrencode... ERROR: no certificate subject alternative name matches requested host name `fukuchi.org'. To connect to fukuchi.org insecurely, use `--no-check-certificate'. OpenSSL: error:14077438:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert internal error Unable to establish SSL connection. make: *** [/home/travis/build/luke-jr/bitcoin/depends/sources/download-stamps/.stamp_fetched-qrencode-qrencode-3.4.4.tar.bz2.hash] Error 4 --- depends/builders/linux.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/builders/linux.mk b/depends/builders/linux.mk index 98d0e9de348..75055e77e93 100644 --- a/depends/builders/linux.mk +++ b/depends/builders/linux.mk @@ -1,2 +1,2 @@ build_linux_SHA256SUM = sha256sum -build_linux_DOWNLOAD = wget --timeout=$(DOWNLOAD_CONNECT_TIMEOUT) --tries=$(DOWNLOAD_RETRIES) -nv -O +build_linux_DOWNLOAD = curl --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -L -o From bdd12c9b3c48f05cf1c85dcc0f127a7b795d3fcf Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 9 Feb 2016 05:53:39 +0000 Subject: [PATCH 100/177] Travis: Use curl rather than wget for Mac SDK --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index aba6702a556..acf7f44aecf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,7 +51,7 @@ install: before_script: - unset CC; unset CXX - mkdir -p depends/SDKs depends/sdk-sources - - if [ -n "$OSX_SDK" -a ! -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then wget $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -O depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi + - if [ -n "$OSX_SDK" -a ! -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then curl $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -o depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - if [ -n "$OSX_SDK" -a -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then tar -C depends/SDKs -xf depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS script: From a8982ac97d9af178c9cd7b577e19ce99949d009b Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 9 Feb 2016 22:15:25 +0000 Subject: [PATCH 101/177] Bugfix: depends/Travis: Use --location (follow redirects) and --fail [on HTTP error response] with curl --- .travis.yml | 2 +- depends/builders/darwin.mk | 2 +- depends/builders/linux.mk | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index acf7f44aecf..07bfba32ea1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,7 +51,7 @@ install: before_script: - unset CC; unset CXX - mkdir -p depends/SDKs depends/sdk-sources - - if [ -n "$OSX_SDK" -a ! -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then curl $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -o depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi + - if [ -n "$OSX_SDK" -a ! -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then curl --location --fail $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -o depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - if [ -n "$OSX_SDK" -a -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then tar -C depends/SDKs -xf depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS script: diff --git a/depends/builders/darwin.mk b/depends/builders/darwin.mk index b366460e64b..cedbddc5784 100644 --- a/depends/builders/darwin.mk +++ b/depends/builders/darwin.mk @@ -7,7 +7,7 @@ build_darwin_OTOOL: = $(shell xcrun -f otool) build_darwin_NM: = $(shell xcrun -f nm) build_darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool) build_darwin_SHA256SUM = shasum -a 256 -build_darwin_DOWNLOAD = curl --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -L -o +build_darwin_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -L -o #darwin host on darwin builder. overrides darwin host preferences. darwin_CC=$(shell xcrun -f clang) -mmacosx-version-min=$(OSX_MIN_VERSION) diff --git a/depends/builders/linux.mk b/depends/builders/linux.mk index 75055e77e93..d6a304e4b4b 100644 --- a/depends/builders/linux.mk +++ b/depends/builders/linux.mk @@ -1,2 +1,2 @@ build_linux_SHA256SUM = sha256sum -build_linux_DOWNLOAD = curl --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -L -o +build_linux_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -L -o From 7ab7005fbc042b8160a6007a5eec20c1479b1b93 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 9 Feb 2016 22:17:09 +0000 Subject: [PATCH 102/177] Travis: Use Blue Box VMs for IPv6 loopback support --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.travis.yml b/.travis.yml index 07bfba32ea1..ecb31ef0f05 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,12 @@ # compiler key (which we don't use anyway). This is worked around for now by # replacing the "compilers" with a build name prefixed by the no-op ":" # command. See: https://github.com/travis-ci/travis-ci/issues/4393 +# - sudo/dist/group are set so as to get Blue Box VMs, necessary for [loopback] +# IPv6 support + +sudo: required +dist: precise +group: legacy os: linux language: cpp From b0a7ddb0b1a1bbb1064faada00fc7c4d39b0847b Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Fri, 26 Feb 2016 09:59:39 +0100 Subject: [PATCH 103/177] [depends] builders: No need to set -L and --location for curl --- depends/builders/darwin.mk | 2 +- depends/builders/linux.mk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/builders/darwin.mk b/depends/builders/darwin.mk index cedbddc5784..200d6ed22a2 100644 --- a/depends/builders/darwin.mk +++ b/depends/builders/darwin.mk @@ -7,7 +7,7 @@ build_darwin_OTOOL: = $(shell xcrun -f otool) build_darwin_NM: = $(shell xcrun -f nm) build_darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool) build_darwin_SHA256SUM = shasum -a 256 -build_darwin_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -L -o +build_darwin_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o #darwin host on darwin builder. overrides darwin host preferences. darwin_CC=$(shell xcrun -f clang) -mmacosx-version-min=$(OSX_MIN_VERSION) diff --git a/depends/builders/linux.mk b/depends/builders/linux.mk index d6a304e4b4b..b03f4240104 100644 --- a/depends/builders/linux.mk +++ b/depends/builders/linux.mk @@ -1,2 +1,2 @@ build_linux_SHA256SUM = sha256sum -build_linux_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -L -o +build_linux_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o From b08a1f7836563c005927b06d521eec85f3cc9605 Mon Sep 17 00:00:00 2001 From: fanquake Date: Sat, 19 Mar 2016 15:24:00 +0800 Subject: [PATCH 104/177] [build-aux] Update Boost & check macros to latest serials --- build-aux/m4/ax_boost_base.m4 | 20 +- build-aux/m4/ax_boost_program_options.m4 | 7 +- build-aux/m4/ax_boost_system.m4 | 5 +- build-aux/m4/ax_check_compile_flag.m4 | 12 +- build-aux/m4/ax_check_link_flag.m4 | 13 +- build-aux/m4/ax_check_preproc_flag.m4 | 12 +- build-aux/m4/ax_gcc_func_attribute.m4 | 8 +- build-aux/m4/ax_pthread.m4 | 537 +++++++++++++++-------- 8 files changed, 395 insertions(+), 219 deletions(-) diff --git a/build-aux/m4/ax_boost_base.m4 b/build-aux/m4/ax_boost_base.m4 index 3f24d5ddc61..45d948933d1 100644 --- a/build-aux/m4/ax_boost_base.m4 +++ b/build-aux/m4/ax_boost_base.m4 @@ -33,7 +33,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 23 +#serial 26 AC_DEFUN([AX_BOOST_BASE], [ @@ -95,8 +95,8 @@ if test "x$want_boost" = "xyes"; then x86_64) libsubdirs="lib64 libx32 lib lib64" ;; - ppc64|s390x|sparc64|aarch64) - libsubdirs="lib64 lib lib64" + ppc64|s390x|sparc64|aarch64|ppc64le) + libsubdirs="lib64 lib lib64 ppc64le" ;; esac @@ -170,7 +170,7 @@ if test "x$want_boost" = "xyes"; then AC_MSG_RESULT(yes) succeeded=yes found_system=yes - ],[: + ],[ ]) AC_LANG_POP([C++]) @@ -179,6 +179,10 @@ if test "x$want_boost" = "xyes"; then dnl if we found no boost with system layout we search for boost libraries dnl built and installed without the --layout=system option or for a staged(not installed) version if test "x$succeeded" != "xyes"; then + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + BOOST_CPPFLAGS= + BOOST_LDFLAGS= _version=0 if test "$ac_boost_path" != ""; then if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then @@ -191,6 +195,12 @@ if test "x$want_boost" = "xyes"; then VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE" done + dnl if nothing found search for layout used in Windows distributions + if test -z "$BOOST_CPPFLAGS"; then + if test -d "$ac_boost_path/boost" && test -r "$ac_boost_path/boost"; then + BOOST_CPPFLAGS="-I$ac_boost_path" + fi + fi fi else if test "$cross_compiling" != yes; then @@ -253,7 +263,7 @@ if test "x$want_boost" = "xyes"; then AC_MSG_RESULT(yes) succeeded=yes found_system=yes - ],[: + ],[ ]) AC_LANG_POP([C++]) fi diff --git a/build-aux/m4/ax_boost_program_options.m4 b/build-aux/m4/ax_boost_program_options.m4 index f591441854f..2bdb5937162 100644 --- a/build-aux/m4/ax_boost_program_options.m4 +++ b/build-aux/m4/ax_boost_program_options.m4 @@ -29,7 +29,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 22 +#serial 24 AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS], [ @@ -63,9 +63,9 @@ AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS], AC_CACHE_CHECK([whether the Boost::Program_Options library is available], ax_cv_boost_program_options, [AC_LANG_PUSH(C++) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], - [[boost::program_options::options_description generic("Generic options"); + [[boost::program_options::error err("Error message"); return 0;]])], ax_cv_boost_program_options=yes, ax_cv_boost_program_options=no) AC_LANG_POP([C++]) @@ -74,7 +74,6 @@ AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS], AC_DEFINE(HAVE_BOOST_PROGRAM_OPTIONS,,[define if the Boost::PROGRAM_OPTIONS library is available]) BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` if test "x$ax_boost_user_program_options_lib" = "x"; then - ax_lib= for libextension in `ls $BOOSTLIBDIR/libboost_program_options*.so* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.so.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.dylib* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.dylib.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.a.*$;\1;'` ; do ax_lib=${libextension} AC_CHECK_LIB($ax_lib, exit, diff --git a/build-aux/m4/ax_boost_system.m4 b/build-aux/m4/ax_boost_system.m4 index 9c78280fcae..1c05450cbe1 100644 --- a/build-aux/m4/ax_boost_system.m4 +++ b/build-aux/m4/ax_boost_system.m4 @@ -31,7 +31,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 17 +#serial 18 AC_DEFUN([AX_BOOST_SYSTEM], [ @@ -68,9 +68,10 @@ AC_DEFUN([AX_BOOST_SYSTEM], ax_cv_boost_system, [AC_LANG_PUSH([C++]) CXXFLAGS_SAVE=$CXXFLAGS + CXXFLAGS= AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], - [[boost::system::system_category]])], + [[boost::system::error_category *a = 0;]])], ax_cv_boost_system=yes, ax_cv_boost_system=no) CXXFLAGS=$CXXFLAGS_SAVE AC_LANG_POP([C++]) diff --git a/build-aux/m4/ax_check_compile_flag.m4 b/build-aux/m4/ax_check_compile_flag.m4 index c3a8d695a1b..ca3639715e7 100644 --- a/build-aux/m4/ax_check_compile_flag.m4 +++ b/build-aux/m4/ax_check_compile_flag.m4 @@ -4,7 +4,7 @@ # # SYNOPSIS # -# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # @@ -19,6 +19,8 @@ # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # @@ -53,19 +55,19 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 2 +#serial 4 AC_DEFUN([AX_CHECK_COMPILE_FLAG], -[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) -AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], +AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl diff --git a/build-aux/m4/ax_check_link_flag.m4 b/build-aux/m4/ax_check_link_flag.m4 index e2d0d363e4c..eb01a6ce135 100644 --- a/build-aux/m4/ax_check_link_flag.m4 +++ b/build-aux/m4/ax_check_link_flag.m4 @@ -4,7 +4,7 @@ # # SYNOPSIS # -# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) +# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # @@ -19,6 +19,8 @@ # EXTRA-FLAGS FLAG". This can for example be used to force the linker to # issue an error when a bad flag is given. # +# INPUT gives an alternative input source to AC_LINK_IFELSE. +# # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. # @@ -53,18 +55,19 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 2 +#serial 4 AC_DEFUN([AX_CHECK_LINK_FLAG], -[AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ ax_check_save_flags=$LDFLAGS LDFLAGS="$LDFLAGS $4 $1" - AC_LINK_IFELSE([AC_LANG_PROGRAM()], + AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) LDFLAGS=$ax_check_save_flags]) -AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], +AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl diff --git a/build-aux/m4/ax_check_preproc_flag.m4 b/build-aux/m4/ax_check_preproc_flag.m4 index b1cfef6b86d..ca1d5ee2b6d 100644 --- a/build-aux/m4/ax_check_preproc_flag.m4 +++ b/build-aux/m4/ax_check_preproc_flag.m4 @@ -4,7 +4,7 @@ # # SYNOPSIS # -# AX_CHECK_PREPROC_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) +# AX_CHECK_PREPROC_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # @@ -19,6 +19,8 @@ # "CPPFLAGS EXTRA-FLAGS FLAG". This can for example be used to force the # preprocessor to issue an error when a bad flag is given. # +# INPUT gives an alternative input source to AC_PREPROC_IFELSE. +# # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{COMPILE,LINK}_FLAG. # @@ -53,19 +55,19 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 2 +#serial 4 AC_DEFUN([AX_CHECK_PREPROC_FLAG], -[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]cppflags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG preprocessor accepts $1], CACHEVAR, [ ax_check_save_flags=$CPPFLAGS CPPFLAGS="$CPPFLAGS $4 $1" - AC_PREPROC_IFELSE([AC_LANG_PROGRAM()], + AC_PREPROC_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) CPPFLAGS=$ax_check_save_flags]) -AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], +AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl diff --git a/build-aux/m4/ax_gcc_func_attribute.m4 b/build-aux/m4/ax_gcc_func_attribute.m4 index 275ca63a2c2..c788ca9bd43 100644 --- a/build-aux/m4/ax_gcc_func_attribute.m4 +++ b/build-aux/m4/ax_gcc_func_attribute.m4 @@ -31,6 +31,7 @@ # cold # const # constructor +# constructor_priority for constructor attribute with priority # deprecated # destructor # dllexport @@ -73,7 +74,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 2 +#serial 3 AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [ AS_VAR_PUSHDEF([ac_var], [ax_cv_have_func_attribute_$1]) @@ -103,6 +104,9 @@ AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [ [const], [ int foo( void ) __attribute__(($1)); ], + [constructor_priority], [ + int foo( void ) __attribute__((__constructor__(65535/2))); + ], [constructor], [ int foo( void ) __attribute__(($1)); ], @@ -180,6 +184,8 @@ AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [ [visibility], [ int foo_def( void ) __attribute__(($1("default"))); int foo_hid( void ) __attribute__(($1("hidden"))); + int foo_int( void ) __attribute__(($1("internal"))); + int foo_pro( void ) __attribute__(($1("protected"))); ], [warning], [ int foo( void ) __attribute__(($1(""))); diff --git a/build-aux/m4/ax_pthread.m4 b/build-aux/m4/ax_pthread.m4 index d383ad5c6d6..d218d1af738 100644 --- a/build-aux/m4/ax_pthread.m4 +++ b/build-aux/m4/ax_pthread.m4 @@ -19,10 +19,10 @@ # is necessary on AIX to use the special cc_r compiler alias.) # # NOTE: You are assumed to not only compile your program with these flags, -# but also link it with them as well. e.g. you should link with +# but also to link with them as well. For example, you might link with # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # -# If you are only building threads programs, you may wish to use these +# If you are only building threaded programs, you may wish to use these # variables in your default LIBS, CFLAGS, and CC: # # LIBS="$PTHREAD_LIBS $LIBS" @@ -30,8 +30,8 @@ # CC="$PTHREAD_CC" # # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant -# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name -# (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to +# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the # PTHREAD_PRIO_INHERIT symbol is defined when compiling with @@ -82,35 +82,40 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 21 +#serial 22 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AC_PROG_SED]) AC_LANG_PUSH([C]) ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h -# requires special compiler flags (e.g. on True64 or Sequent). +# requires special compiler flags (e.g. on Tru64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: -if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) - AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes]) - AC_MSG_RESULT([$ax_pthread_ok]) - if test x"$ax_pthread_ok" = xno; then - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" - fi - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" +if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then + ax_pthread_save_CC="$CC" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) + AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) + AC_MSG_RESULT([$ax_pthread_ok]) + if test "x$ax_pthread_ok" = "xno"; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + CC="$ax_pthread_save_CC" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" fi # We must check for the threads library under a number of different @@ -123,7 +128,7 @@ fi # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. -ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" +ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: @@ -132,186 +137,334 @@ ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mt # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) -# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) -# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) -# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) -# -pthreads: Solaris/gcc -# -mthreads: Mingw32/gcc, Lynx/gcc +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 +# (Note: HP C rejects this with "bad form for `-t' option") +# -pthreads: Solaris/gcc (Note: HP C also rejects) # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it -# doesn't hurt to check since this sometimes defines pthreads too; -# also defines -D_REENTRANT) -# ... -mt is also the pthreads flag for HP/aCC +# doesn't hurt to check since this sometimes defines pthreads and +# -D_REENTRANT too), HP C (must be checked before -lpthread, which +# is present but should not be used directly; and before -mthreads, +# because the compiler interprets this as "-mt" + "-hreads") +# -mthreads: Mingw32/gcc, Lynx/gcc # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) -case ${host_os} in - solaris*) +case $host_os in + + freebsd*) + + # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) + # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) + + ax_pthread_flags="-kthread lthread $ax_pthread_flags" + ;; + + hpux*) + + # From the cc(1) man page: "[-mt] Sets various -D flags to enable + # multi-threading and also sets -lpthread." + + ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" + ;; + + openedition*) - # On Solaris (at least, for some versions), libc contains stubbed - # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (We need to link with -pthreads/-mt/ - # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather - # a function called by this macro, so we could check for that, but - # who knows whether they'll stub that too in a future libc.) So, - # we'll just look for -pthreads and -lpthread first: + # IBM z/OS requires a feature-test macro to be defined in order to + # enable POSIX threads at all, so give the user a hint if this is + # not set. (We don't define these ourselves, as they can affect + # other portions of the system API in unpredictable ways.) - ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" - ;; + AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], + [ +# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) + AX_PTHREAD_ZOS_MISSING +# endif + ], + [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) + ;; - darwin*) - ax_pthread_flags="-pthread $ax_pthread_flags" - ;; + solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (N.B.: The stubs are missing + # pthread_cleanup_push, or rather a function called by this macro, + # so we could check for that, but who knows whether they'll stub + # that too in a future libc.) So we'll check first for the + # standard Solaris way of linking pthreads (-mt -lpthread). + + ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags" + ;; esac -# Clang doesn't consider unrecognized options an error unless we specify -# -Werror. We throw in some extra Clang-specific options to ensure that -# this doesn't happen for GCC, which also accepts -Werror. - -AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags]) -save_CFLAGS="$CFLAGS" -ax_pthread_extra_flags="-Werror" -CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument" -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])], - [AC_MSG_RESULT([yes])], - [ax_pthread_extra_flags= - AC_MSG_RESULT([no])]) -CFLAGS="$save_CFLAGS" - -if test x"$ax_pthread_ok" = xno; then -for flag in $ax_pthread_flags; do - - case $flag in - none) - AC_MSG_CHECKING([whether pthreads work without any flags]) - ;; - - -*) - AC_MSG_CHECKING([whether pthreads work with $flag]) - PTHREAD_CFLAGS="$flag" - ;; - - pthread-config) - AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) - if test x"$ax_pthread_config" = xno; then continue; fi - PTHREAD_CFLAGS="`pthread-config --cflags`" - PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" - ;; - - *) - AC_MSG_CHECKING([for the pthreads library -l$flag]) - PTHREAD_LIBS="-l$flag" - ;; - esac - - save_LIBS="$LIBS" - save_CFLAGS="$CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags" - - # Check for various functions. We must include pthread.h, - # since some functions may be macros. (On the Sequent, we - # need a special flag -Kthread to make this header compile.) - # We check for pthread_join because it is in -lpthread on IRIX - # while pthread_create is in libc. We check for pthread_attr_init - # due to DEC craziness with -lpthreads. We check for - # pthread_cleanup_push because it is one of the few pthread - # functions on Solaris that doesn't have a non-functional libc stub. - # We try pthread_create on general principles. - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include - static void routine(void *a) { a = 0; } - static void *start_routine(void *a) { return a; }], - [pthread_t th; pthread_attr_t attr; - pthread_create(&th, 0, start_routine, 0); - pthread_join(th, 0); - pthread_attr_init(&attr); - pthread_cleanup_push(routine, 0); - pthread_cleanup_pop(0) /* ; */])], - [ax_pthread_ok=yes], - []) - - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" - - AC_MSG_RESULT([$ax_pthread_ok]) - if test "x$ax_pthread_ok" = xyes; then - break; - fi - - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" +# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) + +AS_IF([test "x$GCC" = "xyes"], + [ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"]) + +# The presence of a feature test macro requesting re-entrant function +# definitions is, on some systems, a strong hint that pthreads support is +# correctly enabled + +case $host_os in + darwin* | hpux* | linux* | osf* | solaris*) + ax_pthread_check_macro="_REENTRANT" + ;; + + aix* | freebsd*) + ax_pthread_check_macro="_THREAD_SAFE" + ;; + + *) + ax_pthread_check_macro="--" + ;; +esac +AS_IF([test "x$ax_pthread_check_macro" = "x--"], + [ax_pthread_check_cond=0], + [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"]) + +# Are we compiling with Clang? + +AC_CACHE_CHECK([whether $CC is Clang], + [ax_cv_PTHREAD_CLANG], + [ax_cv_PTHREAD_CLANG=no + # Note that Autoconf sets GCC=yes for Clang as well as GCC + if test "x$GCC" = "xyes"; then + AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], + [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ +# if defined(__clang__) && defined(__llvm__) + AX_PTHREAD_CC_IS_CLANG +# endif + ], + [ax_cv_PTHREAD_CLANG=yes]) + fi + ]) +ax_pthread_clang="$ax_cv_PTHREAD_CLANG" + +ax_pthread_clang_warning=no + +# Clang needs special handling, because older versions handle the -pthread +# option in a rather... idiosyncratic way + +if test "x$ax_pthread_clang" = "xyes"; then + + # Clang takes -pthread; it has never supported any other flag + + # (Note 1: This will need to be revisited if a system that Clang + # supports has POSIX threads in a separate library. This tends not + # to be the way of modern systems, but it's conceivable.) + + # (Note 2: On some systems, notably Darwin, -pthread is not needed + # to get POSIX threads support; the API is always present and + # active. We could reasonably leave PTHREAD_CFLAGS empty. But + # -pthread does define _REENTRANT, and while the Darwin headers + # ignore this macro, third-party headers might not.) + + PTHREAD_CFLAGS="-pthread" + PTHREAD_LIBS= + + ax_pthread_ok=yes + + # However, older versions of Clang make a point of warning the user + # that, in an invocation where only linking and no compilation is + # taking place, the -pthread option has no effect ("argument unused + # during compilation"). They expect -pthread to be passed in only + # when source code is being compiled. + # + # Problem is, this is at odds with the way Automake and most other + # C build frameworks function, which is that the same flags used in + # compilation (CFLAGS) are also used in linking. Many systems + # supported by AX_PTHREAD require exactly this for POSIX threads + # support, and in fact it is often not straightforward to specify a + # flag that is used only in the compilation phase and not in + # linking. Such a scenario is extremely rare in practice. + # + # Even though use of the -pthread flag in linking would only print + # a warning, this can be a nuisance for well-run software projects + # that build with -Werror. So if the active version of Clang has + # this misfeature, we search for an option to squash it. + + AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown + # Create an alternate version of $ac_link that compiles and + # links in two steps (.c -> .o, .o -> exe) instead of one + # (.c -> exe), because the warning occurs only in the second + # step + ax_pthread_save_ac_link="$ac_link" + ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' + ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"` + ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" + ax_pthread_save_CFLAGS="$CFLAGS" + for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do + AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) + CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" + ac_link="$ax_pthread_save_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [ac_link="$ax_pthread_2step_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [break]) + ]) + done + ac_link="$ax_pthread_save_ac_link" + CFLAGS="$ax_pthread_save_CFLAGS" + AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" + ]) + + case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in + no | unknown) ;; + *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; + esac + +fi # $ax_pthread_clang = yes + +if test "x$ax_pthread_ok" = "xno"; then +for ax_pthread_try_flag in $ax_pthread_flags; do + + case $ax_pthread_try_flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -mt,pthread) + AC_MSG_CHECKING([whether pthreads work with -mt -lpthread]) + PTHREAD_CFLAGS="-mt" + PTHREAD_LIBS="-lpthread" + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) + PTHREAD_CFLAGS="$ax_pthread_try_flag" + ;; + + pthread-config) + AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) + AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) + PTHREAD_LIBS="-l$ax_pthread_try_flag" + ;; + esac + + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include +# if $ax_pthread_check_cond +# error "$ax_pthread_check_macro must be defined" +# endif + static void routine(void *a) { a = 0; } + static void *start_routine(void *a) { return a; }], + [pthread_t th; pthread_attr_t attr; + pthread_create(&th, 0, start_routine, 0); + pthread_join(th, 0); + pthread_attr_init(&attr); + pthread_cleanup_push(routine, 0); + pthread_cleanup_pop(0) /* ; */])], + [ax_pthread_ok=yes], + []) + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + AC_MSG_RESULT([$ax_pthread_ok]) + AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" done fi # Various other checks: -if test "x$ax_pthread_ok" = xyes; then - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - - # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. - AC_MSG_CHECKING([for joinable pthread attribute]) - attr_name=unknown - for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], - [int attr = $attr; return attr /* ; */])], - [attr_name=$attr; break], - []) - done - AC_MSG_RESULT([$attr_name]) - if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then - AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name], - [Define to necessary symbol if this constant - uses a non-standard name on your system.]) - fi - - AC_MSG_CHECKING([if more special flags are required for pthreads]) - flag=no - case ${host_os} in - aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; - osf* | hpux*) flag="-D_REENTRANT";; - solaris*) - if test "$GCC" = "yes"; then - flag="-D_REENTRANT" - else - # TODO: What about Clang on Solaris? - flag="-mt -D_REENTRANT" - fi - ;; - esac - AC_MSG_RESULT([$flag]) - if test "x$flag" != xno; then - PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" - fi - - AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], - [ax_cv_PTHREAD_PRIO_INHERIT], [ - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], - [[int i = PTHREAD_PRIO_INHERIT;]])], - [ax_cv_PTHREAD_PRIO_INHERIT=yes], - [ax_cv_PTHREAD_PRIO_INHERIT=no]) - ]) - AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], - [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])]) - - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" - - # More AIX lossage: compile with *_r variant - if test "x$GCC" != xyes; then - case $host_os in - aix*) - AS_CASE(["x/$CC"], - [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], - [#handle absolute path differently from PATH based program lookup - AS_CASE(["x$CC"], - [x/*], - [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], - [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) - ;; - esac - fi +if test "x$ax_pthread_ok" = "xyes"; then + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + AC_CACHE_CHECK([for joinable pthread attribute], + [ax_cv_PTHREAD_JOINABLE_ATTR], + [ax_cv_PTHREAD_JOINABLE_ATTR=unknown + for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], + [int attr = $ax_pthread_attr; return attr /* ; */])], + [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], + []) + done + ]) + AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ + test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ + test "x$ax_pthread_joinable_attr_defined" != "xyes"], + [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], + [$ax_cv_PTHREAD_JOINABLE_ATTR], + [Define to necessary symbol if this constant + uses a non-standard name on your system.]) + ax_pthread_joinable_attr_defined=yes + ]) + + AC_CACHE_CHECK([whether more special flags are required for pthreads], + [ax_cv_PTHREAD_SPECIAL_FLAGS], + [ax_cv_PTHREAD_SPECIAL_FLAGS=no + case $host_os in + solaris*) + ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" + ;; + esac + ]) + AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ + test "x$ax_pthread_special_flags_added" != "xyes"], + [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" + ax_pthread_special_flags_added=yes]) + + AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], + [ax_cv_PTHREAD_PRIO_INHERIT], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[int i = PTHREAD_PRIO_INHERIT;]])], + [ax_cv_PTHREAD_PRIO_INHERIT=yes], + [ax_cv_PTHREAD_PRIO_INHERIT=no]) + ]) + AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ + test "x$ax_pthread_prio_inherit_defined" != "xyes"], + [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) + ax_pthread_prio_inherit_defined=yes + ]) + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + # More AIX lossage: compile with *_r variant + if test "x$GCC" != "xyes"; then + case $host_os in + aix*) + AS_CASE(["x/$CC"], + [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], + [#handle absolute path differently from PATH based program lookup + AS_CASE(["x$CC"], + [x/*], + [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], + [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) + ;; + esac + fi fi test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" @@ -321,12 +474,12 @@ AC_SUBST([PTHREAD_CFLAGS]) AC_SUBST([PTHREAD_CC]) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test x"$ax_pthread_ok" = xyes; then - ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) - : +if test "x$ax_pthread_ok" = "xyes"; then + ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) + : else - ax_pthread_ok=no - $2 + ax_pthread_ok=no + $2 fi AC_LANG_POP ])dnl AX_PTHREAD From 4ba172369df69a8818cd805d037c6b334aabc4d1 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 3 Dec 2015 14:44:57 +0100 Subject: [PATCH 105/177] build: Enable C++11 build, require C++11 compiler Implements #6211. --- build-aux/m4/ax_cxx_compile_stdcxx.m4 | 558 ++++++++++++++++++++++++++ configure.ac | 2 + 2 files changed, 560 insertions(+) create mode 100644 build-aux/m4/ax_cxx_compile_stdcxx.m4 diff --git a/build-aux/m4/ax_cxx_compile_stdcxx.m4 b/build-aux/m4/ax_cxx_compile_stdcxx.m4 new file mode 100644 index 00000000000..079e17d2a62 --- /dev/null +++ b/build-aux/m4/ax_cxx_compile_stdcxx.m4 @@ -0,0 +1,558 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the specified +# version of the C++ standard. If necessary, add switches to CXXFLAGS to +# enable support. VERSION may be '11' (for the C++11 standard) or '14' +# (for the C++14 standard). +# +# The second argument, if specified, indicates whether you insist on an +# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. +# -std=c++11). If neither is specified, you get whatever works, with +# preference for an extended mode. +# +# The third argument, if specified 'mandatory' or if left unspecified, +# indicates that baseline support for the specified C++ standard is +# required and that the macro should error out if no mode with that +# support is found. If specified 'optional', then configuration proceeds +# regardless, after defining HAVE_CXX${VERSION} if and only if a +# supporting mode is found. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov +# Copyright (c) 2015 Paul Norman +# Copyright (c) 2015 Moritz Klammler +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 1 + +dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro +dnl (serial version number 13). + +AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl + m4_if([$1], [11], [], + [$1], [14], [], + [$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])], + [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$2], [], [], + [$2], [ext], [], + [$2], [noext], [], + [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], + [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], + [$3], [optional], [ax_cxx_compile_cxx$1_required=false], + [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) + AC_LANG_PUSH([C++])dnl + ac_success=no + AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, + ax_cv_cxx_compile_cxx$1, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [ax_cv_cxx_compile_cxx$1=yes], + [ax_cv_cxx_compile_cxx$1=no])]) + if test x$ax_cv_cxx_compile_cxx$1 = xyes; then + ac_success=yes + fi + + m4_if([$2], [noext], [], [dnl + if test x$ac_success = xno; then + for switch in -std=gnu++$1 -std=gnu++0x; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXXFLAGS="$ac_save_CXXFLAGS"]) + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi]) + + m4_if([$2], [ext], [], [dnl + if test x$ac_success = xno; then + dnl HP's aCC needs +std=c++11 according to: + dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf + dnl Cray's crayCC needs "-h std=c++11" + for switch in -std=c++$1 -std=c++0x +std=c++$1 "-h std=c++$1"; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXXFLAGS="$ac_save_CXXFLAGS"]) + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi]) + AC_LANG_POP([C++]) + if test x$ax_cxx_compile_cxx$1_required = xtrue; then + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) + fi + else + if test x$ac_success = xno; then + HAVE_CXX$1=0 + AC_MSG_NOTICE([No compiler with C++$1 support was found]) + else + HAVE_CXX$1=1 + AC_DEFINE(HAVE_CXX$1,1, + [define if the compiler supports basic C++$1 syntax]) + fi + + AC_SUBST(HAVE_CXX$1) + fi +]) + + +dnl Test body for checking C++11 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 +) + + +dnl Test body for checking C++14 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 +) + + +dnl Tests for new features in C++11 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201103L + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual void f() {} + }; + + struct Derived : public Base + { + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + +]]) + + +dnl Tests for new features in C++14 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ + +// If the compiler admits that it is not ready for C++14, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201402L + +#error "This is not a C++14 compiler" + +#else + +namespace cxx14 +{ + + namespace test_polymorphic_lambdas + { + + int + test() + { + const auto lambda = [](auto&&... args){ + const auto istiny = [](auto x){ + return (sizeof(x) == 1UL) ? 1 : 0; + }; + const int aretiny[] = { istiny(args)... }; + return aretiny[0]; + }; + return lambda(1, 1L, 1.0f, '1'); + } + + } + + namespace test_binary_literals + { + + constexpr auto ivii = 0b0000000000101010; + static_assert(ivii == 42, "wrong value"); + + } + + namespace test_generalized_constexpr + { + + template < typename CharT > + constexpr unsigned long + strlen_c(const CharT *const s) noexcept + { + auto length = 0UL; + for (auto p = s; *p; ++p) + ++length; + return length; + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("x") == 1UL, ""); + static_assert(strlen_c("test") == 4UL, ""); + static_assert(strlen_c("another\0test") == 7UL, ""); + + } + + namespace test_lambda_init_capture + { + + int + test() + { + auto x = 0; + const auto lambda1 = [a = x](int b){ return a + b; }; + const auto lambda2 = [a = lambda1(x)](){ return a; }; + return lambda2(); + } + + } + + namespace test_digit_seperators + { + + constexpr auto ten_million = 100'000'000; + static_assert(ten_million == 100000000, ""); + + } + + namespace test_return_type_deduction + { + + auto f(int& x) { return x; } + decltype(auto) g(int& x) { return x; } + + template < typename T1, typename T2 > + struct is_same + { + static constexpr auto value = false; + }; + + template < typename T > + struct is_same + { + static constexpr auto value = true; + }; + + int + test() + { + auto x = 0; + static_assert(is_same::value, ""); + static_assert(is_same::value, ""); + return x; + } + + } + +} // namespace cxx14 + +#endif // __cplusplus >= 201402L + +]]) diff --git a/configure.ac b/configure.ac index b61acf468d5..18e97b88e56 100644 --- a/configure.ac +++ b/configure.ac @@ -54,6 +54,8 @@ case $host in lt_cv_deplibs_check_method="pass_all" ;; esac +dnl Require C++11 compiler (no GNU extensions) +AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory]) dnl Libtool init checks. LT_INIT([pic-only]) From 038a858d2ffc4949a8ff548d48777dd34c4a4c73 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 21 Apr 2016 16:23:40 -0400 Subject: [PATCH 106/177] depends: use c++11 --- depends/hosts/darwin.mk | 2 +- depends/packages/bdb.mk | 1 + depends/packages/boost.mk | 2 +- depends/packages/zeromq.mk | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk index 2958dc50cc8..dbe6d00795e 100644 --- a/depends/hosts/darwin.mk +++ b/depends/hosts/darwin.mk @@ -3,7 +3,7 @@ OSX_SDK_VERSION=10.9 OSX_SDK=$(SDK_PATH)/MacOSX$(OSX_SDK_VERSION).sdk LD64_VERSION=241.9 darwin_CC=clang -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) -darwin_CXX=clang++ -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) +darwin_CXX=clang++ -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) -stdlib=libc++ darwin_CFLAGS=-pipe darwin_CXXFLAGS=$(darwin_CFLAGS) diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk index d0e9949f163..1134e94d012 100644 --- a/depends/packages/bdb.mk +++ b/depends/packages/bdb.mk @@ -9,6 +9,7 @@ define $(package)_set_vars $(package)_config_opts=--disable-shared --enable-cxx --disable-replication $(package)_config_opts_mingw32=--enable-mingw $(package)_config_opts_linux=--with-pic +$(package)_cxxflags=-std=c++11 endef define $(package)_preprocess_cmds diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index 7303821bedf..0c545c4d596 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -21,7 +21,7 @@ $(package)_archiver_$(host_os)=$($(package)_ar) $(package)_toolset_darwin=darwin $(package)_archiver_darwin=$($(package)_libtool) $(package)_config_libraries=chrono,filesystem,program_options,system,thread,test -$(package)_cxxflags=-fvisibility=hidden +$(package)_cxxflags=-std=c++11 -fvisibility=hidden $(package)_cxxflags_linux=-fPIC endef diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index 4b335c54cdc..3cca06dae08 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -7,6 +7,7 @@ $(package)_sha256_hash=27d1e82a099228ee85a7ddb2260f40830212402c605a4a10b5e5498a7 define $(package)_set_vars $(package)_config_opts=--without-documentation --disable-shared --disable-curve $(package)_config_opts_linux=--with-pic + $(package)_cxxflags=-std=c++11 endef define $(package)_config_cmds From a65be830411e164acdad3ad6c3cbc81379d86f43 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 28 Apr 2016 10:18:06 +0200 Subject: [PATCH 107/177] build: update ax_cxx_compile_stdcxx to serial 4 --- build-aux/m4/ax_cxx_compile_stdcxx.m4 | 48 +++++++++++++++------------ 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/build-aux/m4/ax_cxx_compile_stdcxx.m4 b/build-aux/m4/ax_cxx_compile_stdcxx.m4 index 079e17d2a62..2c18e49c56c 100644 --- a/build-aux/m4/ax_cxx_compile_stdcxx.m4 +++ b/build-aux/m4/ax_cxx_compile_stdcxx.m4 @@ -9,9 +9,9 @@ # DESCRIPTION # # Check for baseline language coverage in the compiler for the specified -# version of the C++ standard. If necessary, add switches to CXXFLAGS to -# enable support. VERSION may be '11' (for the C++11 standard) or '14' -# (for the C++14 standard). +# version of the C++ standard. If necessary, add switches to CXX and +# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) +# or '14' (for the C++14 standard). # # The second argument, if specified, indicates whether you insist on an # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. @@ -39,7 +39,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 1 +#serial 4 dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro dnl (serial version number 13). @@ -74,14 +74,17 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, $cachevar, - [ac_save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS $switch" + [ac_save_CXX="$CXX" + CXX="$CXX $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], [eval $cachevar=yes], [eval $cachevar=no]) - CXXFLAGS="$ac_save_CXXFLAGS"]) + CXX="$ac_save_CXX"]) if eval test x\$$cachevar = xyes; then - CXXFLAGS="$CXXFLAGS $switch" + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi ac_success=yes break fi @@ -97,14 +100,17 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, $cachevar, - [ac_save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS $switch" + [ac_save_CXX="$CXX" + CXX="$CXX $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], [eval $cachevar=yes], [eval $cachevar=no]) - CXXFLAGS="$ac_save_CXXFLAGS"]) + CXX="$ac_save_CXX"]) if eval test x\$$cachevar = xyes; then - CXXFLAGS="$CXXFLAGS $switch" + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi ac_success=yes break fi @@ -115,18 +121,16 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl if test x$ac_success = xno; then AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) fi + fi + if test x$ac_success = xno; then + HAVE_CXX$1=0 + AC_MSG_NOTICE([No compiler with C++$1 support was found]) else - if test x$ac_success = xno; then - HAVE_CXX$1=0 - AC_MSG_NOTICE([No compiler with C++$1 support was found]) - else - HAVE_CXX$1=1 - AC_DEFINE(HAVE_CXX$1,1, - [define if the compiler supports basic C++$1 syntax]) - fi - - AC_SUBST(HAVE_CXX$1) + HAVE_CXX$1=1 + AC_DEFINE(HAVE_CXX$1,1, + [define if the compiler supports basic C++$1 syntax]) fi + AC_SUBST(HAVE_CXX$1) ]) From 377092a15248020eb6cf9fb9da8ad885029a5551 Mon Sep 17 00:00:00 2001 From: fanquake Date: Wed, 4 May 2016 19:03:59 +0800 Subject: [PATCH 108/177] [depends] Add -stdlib=libc++ to darwin CXX flags --- depends/builders/darwin.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/builders/darwin.mk b/depends/builders/darwin.mk index 200d6ed22a2..27f550ab036 100644 --- a/depends/builders/darwin.mk +++ b/depends/builders/darwin.mk @@ -11,7 +11,7 @@ build_darwin_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONN #darwin host on darwin builder. overrides darwin host preferences. darwin_CC=$(shell xcrun -f clang) -mmacosx-version-min=$(OSX_MIN_VERSION) -darwin_CXX:=$(shell xcrun -f clang++) -mmacosx-version-min=$(OSX_MIN_VERSION) +darwin_CXX:=$(shell xcrun -f clang++) -mmacosx-version-min=$(OSX_MIN_VERSION) -stdlib=libc++ darwin_AR:=$(shell xcrun -f ar) darwin_RANLIB:=$(shell xcrun -f ranlib) darwin_STRIP:=$(shell xcrun -f strip) From 68ce87eddce21b7ada3533b817437ea7e56a4170 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 9 Jun 2016 12:30:38 -0400 Subject: [PATCH 109/177] depends: bump OSX toolchain clang: 3.7.1 cctools: 877.8 ld64: 253.9 --- depends/hosts/darwin.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk index dbe6d00795e..985649619ff 100644 --- a/depends/hosts/darwin.mk +++ b/depends/hosts/darwin.mk @@ -1,7 +1,7 @@ OSX_MIN_VERSION=10.7 -OSX_SDK_VERSION=10.9 +OSX_SDK_VERSION=10.11 OSX_SDK=$(SDK_PATH)/MacOSX$(OSX_SDK_VERSION).sdk -LD64_VERSION=241.9 +LD64_VERSION=253.9 darwin_CC=clang -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) darwin_CXX=clang++ -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) -stdlib=libc++ From e2e7ca30543bb1f35fa1d1ce17d28af21563464c Mon Sep 17 00:00:00 2001 From: fanquake Date: Wed, 9 Nov 2016 18:55:04 +0800 Subject: [PATCH 110/177] [depends] Set OSX_MIN_VERSION to 10.8 --- depends/hosts/darwin.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk index 985649619ff..4e58bec74e3 100644 --- a/depends/hosts/darwin.mk +++ b/depends/hosts/darwin.mk @@ -1,4 +1,4 @@ -OSX_MIN_VERSION=10.7 +OSX_MIN_VERSION=10.8 OSX_SDK_VERSION=10.11 OSX_SDK=$(SDK_PATH)/MacOSX$(OSX_SDK_VERSION).sdk LD64_VERSION=253.9 From c16188cc6d0d6f77992d3132991c3ebcfd4c1613 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 29 Oct 2017 16:30:09 +1300 Subject: [PATCH 111/177] Remove manual -std=c++11 flag This is handled by autoconf now. --- configure.ac | 3 --- 1 file changed, 3 deletions(-) diff --git a/configure.ac b/configure.ac index 18e97b88e56..9fcaafae6f0 100644 --- a/configure.ac +++ b/configure.ac @@ -40,9 +40,6 @@ else CXXFLAGS_overridden=no fi -# Zcash requries C++11 compatibility; set it early: -CXXFLAGS="-std=c++11 $CXXFLAGS" - AC_PROG_CXX m4_ifdef([AC_PROG_OBJCXX],[AC_PROG_OBJCXX]) From 9635679cbafb82d86b08e87fb2c63dd002d4a096 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 29 Oct 2017 14:24:27 +1300 Subject: [PATCH 112/177] Replace "install -D" with "mkdir -p && install" --- depends/packages/googletest.mk | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/depends/packages/googletest.mk b/depends/packages/googletest.mk index 94880efdbf5..b10ce89ebf2 100644 --- a/depends/packages/googletest.mk +++ b/depends/packages/googletest.mk @@ -11,8 +11,9 @@ define $(package)_build_cmds endef define $(package)_stage_cmds - install -D ./googlemock/make/gmock.a $($(package)_staging_dir)$(host_prefix)/lib/libgmock.a && \ - install -D ./googletest/make/gtest.a $($(package)_staging_dir)$(host_prefix)/lib/libgtest.a && \ + mkdir -p $($(package)_staging_dir)$(host_prefix)/lib && \ + install ./googlemock/make/gmock.a $($(package)_staging_dir)$(host_prefix)/lib/libgmock.a && \ + install ./googletest/make/gtest.a $($(package)_staging_dir)$(host_prefix)/lib/libgtest.a && \ cp -a ./googlemock/include $($(package)_staging_dir)$(host_prefix)/ && \ cp -a ./googletest/include $($(package)_staging_dir)$(host_prefix)/ endef From daad2c273657233735a100e5011fcc2fd1a88b75 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 29 Oct 2017 21:21:18 +1300 Subject: [PATCH 113/177] Check if OpenMP is available before using it --- build-aux/m4/ax_openmp.m4 | 123 ++++++++++++++++++++++++++++++++++++++ configure.ac | 11 +++- src/Makefile.am | 5 +- 3 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 build-aux/m4/ax_openmp.m4 diff --git a/build-aux/m4/ax_openmp.m4 b/build-aux/m4/ax_openmp.m4 new file mode 100644 index 00000000000..866e1d66451 --- /dev/null +++ b/build-aux/m4/ax_openmp.m4 @@ -0,0 +1,123 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_openmp.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_OPENMP([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +# +# DESCRIPTION +# +# This macro tries to find out how to compile programs that use OpenMP a +# standard API and set of compiler directives for parallel programming +# (see http://www-unix.mcs/) +# +# On success, it sets the OPENMP_CFLAGS/OPENMP_CXXFLAGS/OPENMP_F77FLAGS +# output variable to the flag (e.g. -omp) used both to compile *and* link +# OpenMP programs in the current language. +# +# NOTE: You are assumed to not only compile your program with these flags, +# but also link it with them as well. +# +# If you want to compile everything with OpenMP, you should set: +# +# CFLAGS="$CFLAGS $OPENMP_CFLAGS" +# #OR# CXXFLAGS="$CXXFLAGS $OPENMP_CXXFLAGS" +# #OR# FFLAGS="$FFLAGS $OPENMP_FFLAGS" +# +# (depending on the selected language). +# +# The user can override the default choice by setting the corresponding +# environment variable (e.g. OPENMP_CFLAGS). +# +# ACTION-IF-FOUND is a list of shell commands to run if an OpenMP flag is +# found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it is +# not found. If ACTION-IF-FOUND is not specified, the default action will +# define HAVE_OPENMP. +# +# LICENSE +# +# Copyright (c) 2008 Steven G. Johnson +# Copyright (c) 2015 John W. Peterson +# Copyright (c) 2016 Nick R. Papior +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 13 + +AC_DEFUN([AX_OPENMP], [ +AC_PREREQ([2.69]) dnl for _AC_LANG_PREFIX + +AC_CACHE_CHECK([for OpenMP flag of _AC_LANG compiler], ax_cv_[]_AC_LANG_ABBREV[]_openmp, [save[]_AC_LANG_PREFIX[]FLAGS=$[]_AC_LANG_PREFIX[]FLAGS +ax_cv_[]_AC_LANG_ABBREV[]_openmp=unknown +# Flags to try: -fopenmp (gcc), -mp (SGI & PGI), +# -qopenmp (icc>=15), -openmp (icc), +# -xopenmp (Sun), -omp (Tru64), +# -qsmp=omp (AIX), +# none +ax_openmp_flags="-fopenmp -openmp -qopenmp -mp -xopenmp -omp -qsmp=omp none" +if test "x$OPENMP_[]_AC_LANG_PREFIX[]FLAGS" != x; then + ax_openmp_flags="$OPENMP_[]_AC_LANG_PREFIX[]FLAGS $ax_openmp_flags" +fi +for ax_openmp_flag in $ax_openmp_flags; do + case $ax_openmp_flag in + none) []_AC_LANG_PREFIX[]FLAGS=$save[]_AC_LANG_PREFIX[] ;; + *) []_AC_LANG_PREFIX[]FLAGS="$save[]_AC_LANG_PREFIX[]FLAGS $ax_openmp_flag" ;; + esac + AC_LINK_IFELSE([AC_LANG_SOURCE([[ +@%:@include + +static void +parallel_fill(int * data, int n) +{ + int i; +@%:@pragma omp parallel for + for (i = 0; i < n; ++i) + data[i] = i; +} + +int +main() +{ + int arr[100000]; + omp_set_num_threads(2); + parallel_fill(arr, 100000); + return 0; +} +]])],[ax_cv_[]_AC_LANG_ABBREV[]_openmp=$ax_openmp_flag; break],[]) +done +[]_AC_LANG_PREFIX[]FLAGS=$save[]_AC_LANG_PREFIX[]FLAGS +]) +if test "x$ax_cv_[]_AC_LANG_ABBREV[]_openmp" = "xunknown"; then + m4_default([$2],:) +else + if test "x$ax_cv_[]_AC_LANG_ABBREV[]_openmp" != "xnone"; then + OPENMP_[]_AC_LANG_PREFIX[]FLAGS=$ax_cv_[]_AC_LANG_ABBREV[]_openmp + fi + m4_default([$1], [AC_DEFINE(HAVE_OPENMP,1,[Define if OpenMP is enabled])]) +fi +])dnl AX_OPENMP diff --git a/configure.ac b/configure.ac index 9fcaafae6f0..75a7aeba8ec 100644 --- a/configure.ac +++ b/configure.ac @@ -689,6 +689,15 @@ if test x$enable_rust != xno; then RUST_LIBS="-lrustzcash" fi +dnl Check for OpenMP support +AX_OPENMP( + [AC_DEFINE(HAVE_OPENMP, 1, [Define if OpenMP is enabled]) + AM_CONDITIONAL([HAVE_OPENMP], [true]) + CXXFLAGS="$CXXFLAGS $OPENMP_CXXFLAGS"], + [AC_MSG_WARN([OpenMP not supported, disabling multithreading]) + AC_DEFINE(HAVE_OPENMP, 0, [Define if OpenMP is enabled]) + AM_CONDITIONAL([HAVE_OPENMP], [false])]) + # Gitian uses a config.site that sets depends_prefix, and then sets --prefix=/ # build.sh just uses --prefix if test x$depends_prefix != x; then @@ -697,7 +706,7 @@ else LIBSNARK_DEPINST="$prefix" fi -LIBZCASH_LIBS="-lgmp -lgmpxx -lboost_system-mt -lcrypto -lsodium -fopenmp $RUST_LIBS" +LIBZCASH_LIBS="-lgmp -lgmpxx -lboost_system-mt -lcrypto -lsodium $RUST_LIBS" CXXFLAGS_TEMP="$CXXFLAGS" LIBS_TEMP="$LIBS" diff --git a/src/Makefile.am b/src/Makefile.am index 71b89b96d41..797fdcfe990 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -46,7 +46,10 @@ $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) collate-libsnark: $(LIBSNARK) LIBSNARK_CXXFLAGS = -fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1 -LIBSNARK_CONFIG_FLAGS = CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT NO_COPY_DEPINST=1 NO_COMPILE_LIBGTEST=1 +LIBSNARK_CONFIG_FLAGS = CURVE=ALT_BN128 NO_PROCPS=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT NO_COPY_DEPINST=1 NO_COMPILE_LIBGTEST=1 +if HAVE_OPENMP +LIBSNARK_CONFIG_FLAGS += MULTICORE=1 +endif $(LIBSNARK): $(wildcard snark/src/*) $(AM_V_at) CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ install PREFIX=$(srcdir)/build DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" From d3096198c87de283d0ee1f8ce2ab10657fd7991d Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 29 Oct 2017 22:34:08 +1300 Subject: [PATCH 114/177] [libsnark] Use POSIX-compliant ar arguments --- src/snark/Makefile | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/snark/Makefile b/src/snark/Makefile index 32b8609f202..1583facf786 100644 --- a/src/snark/Makefile +++ b/src/snark/Makefile @@ -198,13 +198,8 @@ $(LIBGTEST_A): $(GTESTDIR)/src/gtest-all.cc $(DEPINST_EXISTS) # libsnark.a will contains all of our relevant object files, and we also mash in the .a files of relevant dependencies built by ./prepare-depends.sh $(LIBSNARK_A): $(LIB_OBJS) $(AR_LIBS) - ( \ - echo "create $(LIBSNARK_A)"; \ - echo "addmod $(LIB_OBJS)"; \ - if [ -n "$(AR_LIBS)" ]; then for AR_LIB in $(AR_LIBS); do echo addlib $$AR_LIB; done; fi; \ - echo "save"; \ - echo "end"; \ - ) | $(AR) -M + $(AR) q $(LIBSNARK_A) $(LIB_OBJS) + if [ -n "$(AR_LIBS)" ]; then mkdir -p tmp-ar; cd tmp-ar; for AR_LIB in $(AR_LIBS); do $(AR) x $$AR_LIB; done; $(AR) qc $(LIBSNARK_A) tmp-ar/*; cd ..; rm -r tmp-ar; fi; $(AR) s $(LIBSNARK_A) libsnark.so: $(LIBSNARK_A) $(DEPINST_EXISTS) From c6b39fbbd62e5f9ea58f6934a38c64a0cbfbb608 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 29 Oct 2017 22:41:43 +1300 Subject: [PATCH 115/177] Include endian-ness compatibility layer in Equihash implementation --- src/crypto/equihash.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/crypto/equihash.cpp b/src/crypto/equihash.cpp index d22244aa988..d983898611d 100644 --- a/src/crypto/equihash.cpp +++ b/src/crypto/equihash.cpp @@ -16,6 +16,7 @@ #include "config/bitcoin-config.h" #endif +#include "compat/endian.h" #include "crypto/equihash.h" #include "util.h" From 8fbf5350ba0d9592f40da577ecc9e3f9b6ff8541 Mon Sep 17 00:00:00 2001 From: backendmaster <34057530+backendmaster@users.noreply.github.com> Date: Thu, 30 Nov 2017 06:10:18 +0200 Subject: [PATCH 116/177] Windows Wallet From c459de2f0331f1bfaab812a4555018095dc0e0a4 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Mon, 9 Nov 2015 20:50:25 -0500 Subject: [PATCH 117/177] build: Split hardening/fPIE options out This allows for fPIE to be used selectively. --- configure.ac | 18 +++++++++++------ src/Makefile.am | 41 ++++++++++++++++++++++++++------------- src/Makefile.test.include | 3 ++- 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/configure.ac b/configure.ac index 75a7aeba8ec..4fc9c6ce175 100644 --- a/configure.ac +++ b/configure.ac @@ -323,6 +323,7 @@ case $host in AX_CHECK_LINK_FLAG([[-Wl,-headerpad_max_install_names]], [LDFLAGS="$LDFLAGS -Wl,-headerpad_max_install_names"]) CPPFLAGS="$CPPFLAGS -DMAC_OSX" + OBJCXXFLAGS="$CXXFLAGS" ;; *linux*) TARGET_OS=linux @@ -423,6 +424,11 @@ else AC_SEARCH_LIBS([clock_gettime],[rt]) fi +if test x$TARGET_OS != xwindows; then + # All windows code is PIC, forcing it on just adds useless compile warnings + AX_CHECK_COMPILE_FLAG([-fPIC],[PIC_FLAGS="-fPIC"]) +fi + if test x$use_hardening != xno; then AX_CHECK_COMPILE_FLAG([-Wformat],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -Wformat"],[AC_MSG_ERROR(Cannot enable -Wformat)]) AX_CHECK_COMPILE_FLAG([-Wformat-security],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -Wformat-security"],[AC_MSG_ERROR(Cannot enable -Wformat-security)],[-Wformat]) @@ -441,7 +447,7 @@ if test x$use_hardening != xno; then if test x$TARGET_OS != xwindows; then # All windows code is PIC, forcing it on just adds useless compile warnings - AX_CHECK_COMPILE_FLAG([-fPIE],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fPIE"],[AC_MSG_ERROR(Cannot enable -fPIE)]) + AX_CHECK_COMPILE_FLAG([-fPIE],[PIE_FLAGS="-fPIE"],[AC_MSG_ERROR(Cannot enable -fPIE)]) AX_CHECK_LINK_FLAG([[-pie]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -pie"],[AC_MSG_ERROR(Cannot enable -pie)]) else # These are only available on Windows. @@ -454,11 +460,6 @@ if test x$use_hardening != xno; then AC_CHECK_LIB([ssp], [main],, AC_MSG_ERROR(lib missing)) ;; esac - - CXXFLAGS="$CXXFLAGS $HARDENED_CXXFLAGS" - CPPFLAGS="$CPPFLAGS $HARDENED_CPPFLAGS" - LDFLAGS="$LDFLAGS $HARDENED_LDFLAGS" - OBJCXXFLAGS="$CXXFLAGS" fi dnl this flag screws up non-darwin gcc even when the check fails. special-case it. @@ -835,6 +836,11 @@ AC_SUBST(CLIENT_VERSION_IS_RELEASE, _CLIENT_VERSION_IS_RELEASE) AC_SUBST(COPYRIGHT_YEAR, _COPYRIGHT_YEAR) AC_SUBST(RELDFLAGS) +AC_SUBST(HARDENED_CXXFLAGS) +AC_SUBST(HARDENED_CPPFLAGS) +AC_SUBST(HARDENED_LDFLAGS) +AC_SUBST(PIC_FLAGS) +AC_SUBST(PIE_FLAGS) AC_SUBST(LIBTOOL_APP_LDFLAGS) AC_SUBST(BOOST_LIBS) AC_SUBST(TESTDEFS) diff --git a/src/Makefile.am b/src/Makefile.am index 797fdcfe990..d9f2adbda07 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,8 @@ DIST_SUBDIRS = secp256k1 univalue -AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) +AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) +AM_CXXFLAGS = $(HARDENED_CXXFLAGS) +AM_CPPFLAGS = $(HARDENED_CPPFLAGS) if EMBEDDED_LEVELDB LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include @@ -14,7 +16,7 @@ $(LIBLEVELDB): $(LIBMEMENV) $(LIBLEVELDB) $(LIBMEMENV): @echo "Building LevelDB ..." && $(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \ CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \ - OPT="$(CXXFLAGS) $(CPPFLAGS) -D__STDC_LIMIT_MACROS" + OPT="$(AM_CXXFLAGS) $(PIE_FLAGS) $(CXXFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -D__STDC_LIMIT_MACROS" endif BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config @@ -227,7 +229,8 @@ obj/build.h: FORCE libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h # server: zcashd -libbitcoin_server_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) +libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) +libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_server_a_SOURCES = \ sendalert.cpp \ addrman.cpp \ @@ -273,6 +276,7 @@ if ENABLE_ZMQ LIBBITCOIN_ZMQ=libbitcoin_zmq.a libbitcoin_zmq_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(ZMQ_CFLAGS) +libbitcoin_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_zmq_a_SOURCES = \ zmq/zmqabstractnotifier.cpp \ zmq/zmqnotificationinterface.cpp \ @@ -290,7 +294,8 @@ libbitcoin_proton_a_SOURCES = \ endif # wallet: zcashd, but only linked when wallet enabled -libbitcoin_wallet_a_CPPFLAGS = $(BITCOIN_INCLUDES) +libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_wallet_a_SOURCES = \ utiltest.cpp \ utiltest.h \ @@ -312,7 +317,8 @@ libbitcoin_wallet_a_SOURCES = \ $(LIBZCASH_H) # crypto primitives library -crypto_libbitcoin_crypto_a_CPPFLAGS = $(BITCOIN_CONFIG_INCLUDES) +crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_CONFIG_INCLUDES) +crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) crypto_libbitcoin_crypto_a_SOURCES = \ crypto/common.h \ crypto/equihash.cpp \ @@ -344,7 +350,8 @@ crypto_libbitcoin_crypto_a_SOURCES += \ endif # common: shared between zcashd and non-server tools -libbitcoin_common_a_CPPFLAGS = $(BITCOIN_INCLUDES) +libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_common_a_SOURCES = \ amount.cpp \ arith_uint256.cpp \ @@ -374,7 +381,8 @@ libbitcoin_common_a_SOURCES = \ # util: shared between all executables. # This library *must* be included to make sure that the glibc # backward-compatibility objects and their sanity checks are linked. -libbitcoin_util_a_CPPFLAGS = $(BITCOIN_INCLUDES) +libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_util_a_SOURCES = \ support/pagelocker.cpp \ chainparamsbase.cpp \ @@ -399,7 +407,8 @@ libbitcoin_util_a_SOURCES += compat/glibc_compat.cpp endif # cli: zcash-cli -libbitcoin_cli_a_CPPFLAGS = $(BITCOIN_INCLUDES) +libbitcoin_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_cli_a_SOURCES = \ rpcclient.cpp \ $(BITCOIN_CORE_H) \ @@ -410,7 +419,8 @@ nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h # bitcoind binary # zcashd_SOURCES = bitcoind.cpp -zcashd_CPPFLAGS = $(BITCOIN_INCLUDES) +zcashd_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +zcashd_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) zcashd_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if TARGET_WINDOWS @@ -453,7 +463,8 @@ endif # bitcoin-cli binary # zcash_cli_SOURCES = bitcoin-cli.cpp -zcash_cli_CPPFLAGS = $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) +zcash_cli_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) +zcash_cli_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) zcash_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if TARGET_WINDOWS @@ -476,7 +487,8 @@ zcash_cli_LDADD = \ # zcash-tx binary # zcash_tx_SOURCES = bitcoin-tx.cpp -zcash_tx_CPPFLAGS = $(BITCOIN_INCLUDES) +zcash_tx_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +zcash_tx_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) zcash_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if TARGET_WINDOWS @@ -545,9 +557,10 @@ if GLIBC_BACK_COMPAT libzcashconsensus_la_SOURCES += compat/glibc_compat.cpp endif -libzcashconsensus_la_LDFLAGS = -no-undefined $(RELDFLAGS) +libzcashconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS) libzcashconsensus_la_LIBADD = $(LIBSECP256K1) -libzcashconsensus_la_CPPFLAGS = -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL +libzcashconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL +libzcashconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) endif # @@ -571,7 +584,7 @@ clean-local: .mm.o: $(AM_V_CXX) $(OBJCXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o $@ $< + $(CPPFLAGS) $(AM_CXXFLAGS) $(AM_CXXFLAGS) $(PIE_FLAGS) $(CXXFLAGS) -c -o $@ $< check-symbols: $(bin_PROGRAMS) if GLIBC_BACK_COMPAT diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 4b85dd502bc..582ecb577c9 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -99,9 +99,10 @@ BITCOIN_TESTS += \ endif test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) -test_test_bitcoin_CPPFLAGS = -fopenmp $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS) +test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) -fopenmp $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS) test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) +test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) if ENABLE_WALLET test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET) endif From ad96d74afe5c5e53644cf87a8e3f7caf893816c6 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 30 Nov 2017 14:21:11 +0000 Subject: [PATCH 118/177] build: Split hardening/fPIE options out in Zcash-specific binaries --- src/Makefile.am | 1 + src/Makefile.gtest.include | 3 ++- src/Makefile.zcash.include | 5 ++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index d9f2adbda07..36f353802cc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -287,6 +287,7 @@ if ENABLE_PROTON LIBBITCOIN_PROTON=libbitcoin_proton.a libbitcoin_proton_a_CPPFLAGS = $(BITCOIN_INCLUDES) +libbitcoin_proton_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_proton_a_SOURCES = \ amqp/amqpabstractnotifier.cpp \ amqp/amqpnotificationinterface.cpp \ diff --git a/src/Makefile.gtest.include b/src/Makefile.gtest.include index 02152f936f4..522bfa84aee 100644 --- a/src/Makefile.gtest.include +++ b/src/Makefile.gtest.include @@ -45,7 +45,8 @@ zcash_gtest_SOURCES += \ wallet/gtest/test_wallet.cpp endif -zcash_gtest_CPPFLAGS = -DMULTICORE -fopenmp -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DSTATIC $(BITCOIN_INCLUDES) +zcash_gtest_CPPFLAGS = $(AM_CPPFLAGS) -DMULTICORE -fopenmp -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DSTATIC $(BITCOIN_INCLUDES) +zcash_gtest_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) zcash_gtest_LDADD = -lgtest -lgmock $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) diff --git a/src/Makefile.zcash.include b/src/Makefile.zcash.include index e5752cb2f4b..177931c889a 100644 --- a/src/Makefile.zcash.include +++ b/src/Makefile.zcash.include @@ -4,6 +4,8 @@ noinst_PROGRAMS += \ # tool for generating our public parameters zcash_GenerateParams_SOURCES = zcash/GenerateParams.cpp +zcash_GenerateParams_CPPFLAGS = $(AM_CPPFLAGS) +zcash_GenerateParams_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) zcash_GenerateParams_LDADD = \ $(BOOST_LIBS) \ $(LIBZCASH) \ @@ -14,7 +16,8 @@ zcash_GenerateParams_LDADD = \ # tool for profiling the creation of joinsplits zcash_CreateJoinSplit_SOURCES = zcash/CreateJoinSplit.cpp -zcash_CreateJoinSplit_CPPFLAGS = $(BITCOIN_INCLUDES) +zcash_CreateJoinSplit_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +zcash_CreateJoinSplit_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) zcash_CreateJoinSplit_LDADD = \ $(LIBBITCOIN_COMMON) \ $(LIBZCASH) \ From 0b2a64f48405904147c786a86e9b7b20fb0e9bc1 Mon Sep 17 00:00:00 2001 From: daniel Date: Thu, 19 Nov 2015 13:28:22 +0800 Subject: [PATCH 119/177] add powerpc build support for openssl lib --- depends/packages/openssl.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index fe19c6734a0..f80cd6d2571 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -85,6 +85,7 @@ $(package)_config_opts_arm_linux=linux-generic32 $(package)_config_opts_aarch64_linux=linux-generic64 $(package)_config_opts_mipsel_linux=linux-generic32 $(package)_config_opts_mips_linux=linux-generic32 +$(package)_config_opts_powerpc_linux=linux-generic32 $(package)_config_opts_x86_64_darwin=darwin64-x86_64-cc $(package)_config_opts_x86_64_mingw32=mingw64 $(package)_config_opts_i686_mingw32=mingw From c5d645e22f5efcf85acacc80647a1ae70bad95ac Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Fri, 1 Apr 2016 12:19:28 -0400 Subject: [PATCH 120/177] build: define base filenames for use elsewhere in the buildsystem Unfortunately, the target namees defined at the Makefile.am level can't be used for *.in substitution. So these new defines will have to stay synced up with those targets. Using the new variables for the deploy targets in the main Makefile.am will ensure that they stay in sync, otherwise build tests will fail. --- Makefile.am | 4 ++-- configure.ac | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index e3142b52aa5..e515395c5a8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,8 +12,8 @@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libzcashconsensus.pc endif -BITCOIND_BIN=$(top_builddir)/src/zcashd$(EXEEXT) -BITCOIN_CLI_BIN=$(top_builddir)/src/zcash-cli$(EXEEXT) +BITCOIND_BIN=$(top_builddir)/src/$(BITCOIN_DAEMON_NAME)$(EXEEXT) +BITCOIN_CLI_BIN=$(top_builddir)/src/$(BITCOIN_CLI_NAME)$(EXEEXT) BITCOIN_WIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EXEEXT) ##OSX_APP=Bitcoin-Qt.app diff --git a/configure.ac b/configure.ac index 4fc9c6ce175..bdcac43bc2b 100644 --- a/configure.ac +++ b/configure.ac @@ -14,6 +14,10 @@ AC_CONFIG_HEADERS([src/config/bitcoin-config.h]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([build-aux/m4]) +BITCOIN_DAEMON_NAME=zcashd +BITCOIN_CLI_NAME=zcash-cli +BITCOIN_TX_NAME=zcash-tx + AC_CANONICAL_HOST AH_TOP([#ifndef BITCOIN_CONFIG_H]) @@ -834,6 +838,9 @@ AC_SUBST(CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION) AC_SUBST(CLIENT_VERSION_BUILD, _CLIENT_VERSION_BUILD) AC_SUBST(CLIENT_VERSION_IS_RELEASE, _CLIENT_VERSION_IS_RELEASE) AC_SUBST(COPYRIGHT_YEAR, _COPYRIGHT_YEAR) +AC_SUBST(BITCOIN_DAEMON_NAME) +AC_SUBST(BITCOIN_CLI_NAME) +AC_SUBST(BITCOIN_TX_NAME) AC_SUBST(RELDFLAGS) AC_SUBST(HARDENED_CXXFLAGS) From 341ab7453295ca387a5e2aaf75f7e5240e8bff96 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 9 Mar 2016 16:45:58 -0500 Subject: [PATCH 121/177] build: quiet annoying warnings without adding new ones Disabling warnings can be tricky, because doing so can cause a different compiler to create new warnings about unsupported disable flags. Also, some warnings don't surface until they're paired with another warning (gcc). For example, adding "-Wno-foo" won't cause any trouble, but if there's a legitimate warning emitted, the "unknown option -Wno-foo" will show up as well. Work around this in 2 ways: 1. When checking to see if -Wno-foo is supported, check for "-Wfoo" instead. 2. Enable -Werror while checking 1. If "-Werror -Wfoo" compiles, "-Wno-foo" is almost guaranteed to be supported. -Werror itself is also checked. If that fails to compile by itself, it likely means that the user added a flag that adds a warning. In that case, -Werror won't be used while checking, and the build may be extra noisy. The user would need to fix the bad input flag. Also, silence 2 more additional warnings that can show up post-c++11. --- configure.ac | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index bdcac43bc2b..20b42d6e2cb 100644 --- a/configure.ac +++ b/configure.ac @@ -169,6 +169,9 @@ AC_ARG_ENABLE([debug], [enable_debug=$enableval], [enable_debug=no]) +AC_LANG_PUSH([C++]) +AX_CHECK_COMPILE_FLAG([-Werror],[CXXFLAG_WERROR="-Werror"],[CXXFLAG_WERROR=""]) + if test "x$enable_debug" = xyes; then CPPFLAGS="$CPPFLAGS -DDEBUG -DDEBUG_LOCKORDER" if test "x$GCC" = xyes; then @@ -180,11 +183,19 @@ if test "x$enable_debug" = xyes; then fi fi -## TODO: Remove these hard-coded paths and flags. They are here for the sake of -## compatibility with the legacy buildsystem. -## if test "x$CXXFLAGS_overridden" = "xno"; then - CXXFLAGS="$CXXFLAGS -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter -Wno-self-assign" + AX_CHECK_COMPILE_FLAG([-Wall],[CXXFLAGS="$CXXFLAGS -Wall"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wextra],[CXXFLAGS="$CXXFLAGS -Wextra"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wformat],[CXXFLAGS="$CXXFLAGS -Wformat"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wformat-security],[CXXFLAGS="$CXXFLAGS -Wformat-security"],,[[$CXXFLAG_WERROR]]) + + ## Some compilers (gcc) ignore unknown -Wno-* options, but warn about all + ## unknown options if any other warning is produced. Test the -Wfoo case, and + ## set the -Wno-foo case if it works. + AX_CHECK_COMPILE_FLAG([-Wunused-parameter],[CXXFLAGS="$CXXFLAGS -Wno-unused-parameter"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wself-assign],[CXXFLAGS="$CXXFLAGS -Wno-self-assign"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wunused-local-typedef],[CXXFLAGS="$CXXFLAGS -Wno-unused-local-typedef"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wdeprecated-register],[CXXFLAGS="$CXXFLAGS -Wno-deprecated-register"],,[[$CXXFLAG_WERROR]]) fi CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS" @@ -206,8 +217,6 @@ AC_ARG_WITH([daemon], [build_bitcoind=$withval], [build_bitcoind=yes]) -AC_LANG_PUSH([C++]) - use_pkgconfig=yes case $host in *mingw*) From d70027148db87e287c6cdeb00fce631af6fb8c6c Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 7 Jul 2016 13:47:54 -0400 Subject: [PATCH 122/177] build: fix Windows builds without pkg-config - guard PKG_PROG_PKG_CONFIG with an m4_ifdef. If not building for windows, require it - add nops as necessary in case the ifdef reduces the if/then to nothing - AC_SUBST some missing _LIBS. These were split out over time, but not all were properly substituted. They continued to work if pkg-config is installed because it does the AC_SUBST itself --- configure.ac | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/configure.ac b/configure.ac index 20b42d6e2cb..f2f34c19d2b 100644 --- a/configure.ac +++ b/configure.ac @@ -75,9 +75,6 @@ AC_PATH_PROG(HEXDUMP,hexdump) AC_PATH_TOOL(READELF,readelf) AC_PATH_TOOL(CPPFILT,c++filt) -dnl pkg-config check. -PKG_PROG_PKG_CONFIG - # Enable wallet AC_ARG_ENABLE([wallet], [AS_HELP_STRING([--enable-wallet], @@ -345,6 +342,16 @@ case $host in ;; esac +if test x$use_pkgconfig = xyes; then + m4_ifndef([PKG_PROG_PKG_CONFIG], [AC_MSG_ERROR(PKG_PROG_PKG_CONFIG macro not found. Please install pkg-config and re-run autogen.sh.)]) + m4_ifdef([PKG_PROG_PKG_CONFIG], [ + PKG_PROG_PKG_CONFIG + if test x"$PKG_CONFIG" = "x"; then + AC_MSG_ERROR(pkg-config not found.) + fi + ]) +fi + if test x$use_comparison_tool != xno; then if test x$JAVA = x; then AC_MSG_ERROR("comparison tool set but java not found") @@ -619,12 +626,7 @@ BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB $BOOST_PROGRA fi if test x$use_pkgconfig = xyes; then - - if test x"$PKG_CONFIG" = "x"; then - AC_MSG_ERROR(pkg-config not found.) - fi - - : #NOP + : dnl m4_ifdef( [PKG_CHECK_MODULES], [ @@ -861,6 +863,11 @@ AC_SUBST(LIBTOOL_APP_LDFLAGS) AC_SUBST(BOOST_LIBS) AC_SUBST(TESTDEFS) AC_SUBST(LEVELDB_TARGET_FLAGS) +AC_SUBST(CRYPTO_LIBS) +AC_SUBST(SSL_LIBS) +AC_SUBST(EVENT_LIBS) +AC_SUBST(EVENT_PTHREADS_LIBS) +AC_SUBST(ZMQ_LIBS) AC_SUBST(GMP_LIBS) AC_SUBST(GMPXX_LIBS) AC_SUBST(LIBSNARK_DEPINST) From 57ab896ba43af71b6d968fb2c2c4d2bcf65f8945 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sat, 13 Aug 2016 16:03:44 +0200 Subject: [PATCH 123/177] test: Remove java comparison tool --- Makefile.am | 33 ++++----------------------------- configure.ac | 35 ----------------------------------- depends/config.site.in | 4 ---- 3 files changed, 4 insertions(+), 68 deletions(-) diff --git a/Makefile.am b/Makefile.am index e515395c5a8..9157365b616 100644 --- a/Makefile.am +++ b/Makefile.am @@ -41,9 +41,9 @@ WINDOWS_PACKAGING = $(top_srcdir)/share/pixmaps/bitcoin.ico \ ## $(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \ ## $(top_srcdir)/contrib/macdeploy/detached-sig-create.sh -COVERAGE_INFO = baseline_filtered_combined.info baseline.info block_test.info \ +COVERAGE_INFO = baseline_filtered_combined.info baseline.info \ leveldb_baseline.info test_bitcoin_filtered.info total_coverage.info \ - baseline_filtered.info block_test_filtered.info \ + baseline_filtered.info \ leveldb_baseline_filtered.info test_bitcoin_coverage.info test_bitcoin.info \ zcash-gtest.info zcash-gtest_filtered.info zcash-gtest_coverage.info @@ -215,33 +215,14 @@ zcash-gtest_filtered.info: zcash-gtest.info "$(abs_builddir)/src/wallet/test/*" \ -o $@ -block_test.info: test_bitcoin_filtered.info - $(MKDIR_P) qa/tmp - -@TIMEOUT=15 qa/pull-tester/run-bitcoind-for-test.sh $(JAVA) -jar $(JAVA_COMPARISON_TOOL) qa/tmp/compTool 0 - $(LCOV) -c -d $(abs_builddir)/src --t BitcoinJBlockTest -o $@ - $(LCOV) -z -d $(abs_builddir)/src - $(LCOV) -z -d $(abs_builddir)/src/leveldb - -block_test_filtered.info: block_test.info - $(LCOV) -r $< "/usr/include/*" \ - "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \ - "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/boost/*" \ - "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \ - "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \ - "$(abs_builddir)/src/gtest/*" \ - "$(abs_builddir)/src/test/*" \ - "$(abs_builddir)/src/wallet/gtest/*" \ - "$(abs_builddir)/src/wallet/test/*" \ - -o $@ - test_bitcoin_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -o $@ zcash-gtest_coverage.info: baseline_filtered_combined.info zcash-gtest_filtered.info $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a zcash-gtest_filtered.info -o $@ -total_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info zcash-gtest_filtered.info block_test_filtered.info - $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -a zcash-gtest_filtered.info -a block_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt +total_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info zcash-gtest_filtered.info + $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -a zcash-gtest_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt test_bitcoin.coverage/.dirstamp: test_bitcoin_coverage.info $(GENHTML) -s $< -o $(@D) @@ -261,12 +242,6 @@ cov: test_bitcoin.coverage/.dirstamp cov-zcash total.coverage/.dirstamp endif -if USE_COMPARISON_TOOL -check-local: - $(MKDIR_P) qa/tmp - @qa/pull-tester/run-bitcoind-for-test.sh $(JAVA) -jar $(JAVA_COMPARISON_TOOL) qa/tmp/compTool $(COMPARISON_TOOL_REORG_TESTS) 2>&1 -endif - dist_bin_SCRIPTS = zcutil/fetch-params.sh dist_noinst_SCRIPTS = autogen.sh zcutil/build-debian-package.sh zcutil/build.sh diff --git a/configure.ac b/configure.ac index f2f34c19d2b..a7274eec27c 100644 --- a/configure.ac +++ b/configure.ac @@ -66,7 +66,6 @@ AC_PATH_TOOL(RANLIB, ranlib) AC_PATH_TOOL(STRIP, strip) AC_PATH_TOOL(GCOV, gcov) AC_PATH_PROG(LCOV, lcov) -AC_PATH_PROG(JAVA, java) AC_PATH_PROG(GENHTML, genhtml) AC_PATH_PROG([GIT], [git]) AC_PATH_PROG(CCACHE,ccache) @@ -105,16 +104,6 @@ AC_ARG_ENABLE(tests, [use_tests=$enableval], [use_tests=yes]) -AC_ARG_WITH([comparison-tool], - AS_HELP_STRING([--with-comparison-tool],[path to java comparison tool (requires --enable-tests)]), - [use_comparison_tool=$withval], - [use_comparison_tool=no]) - -AC_ARG_ENABLE([comparison-tool-reorg-tests], - AS_HELP_STRING([--enable-comparison-tool-reorg-tests],[enable expensive reorg tests in the comparison tool (default no)]), - [use_comparison_tool_reorg_tests=$enableval], - [use_comparison_tool_reorg_tests=no]) - AC_ARG_ENABLE([hardening], [AS_HELP_STRING([--enable-hardening], [attempt to harden the resulting executables (default is yes)])], @@ -352,22 +341,6 @@ if test x$use_pkgconfig = xyes; then ]) fi -if test x$use_comparison_tool != xno; then - if test x$JAVA = x; then - AC_MSG_ERROR("comparison tool set but java not found") - fi - AC_SUBST(JAVA_COMPARISON_TOOL, $use_comparison_tool) -fi - -if test x$use_comparison_tool_reorg_tests != xno; then - if test x$use_comparison_tool = x; then - AC_MSG_ERROR("comparison tool reorg tests but comparison tool was not specified") - fi - AC_SUBST(COMPARISON_TOOL_REORG_TESTS, 1) -else - AC_SUBST(COMPARISON_TOOL_REORG_TESTS, 0) -fi - if test x$use_lcov = xyes; then if test x$LCOV = x; then AC_MSG_ERROR("lcov testing requested but lcov not found") @@ -375,15 +348,9 @@ if test x$use_lcov = xyes; then if test x$GCOV = x; then AC_MSG_ERROR("lcov testing requested but gcov not found") fi - if test x$JAVA = x; then - AC_MSG_ERROR("lcov testing requested but java not found") - fi if test x$GENHTML = x; then AC_MSG_ERROR("lcov testing requested but genhtml not found") fi - if test x$use_comparison_tool = x; then - AC_MSG_ERROR("lcov testing requested but comparison tool was not specified") - fi LCOV="$LCOV --gcov-tool=$GCOV --rc lcov_branch_coverage=1" GENHTML="$GENHTML --branch-coverage" AX_CHECK_COMPILE_FLAG([--coverage],[CXXFLAGS="$CXXFLAGS --coverage"], @@ -832,8 +799,6 @@ AM_CONDITIONAL([ENABLE_MINING],[test x$enable_mining = xyes]) AM_CONDITIONAL([ENABLE_RUST],[test x$enable_rust = xyes]) AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes]) AM_CONDITIONAL([USE_LCOV],[test x$use_lcov = xyes]) -AM_CONDITIONAL([USE_COMPARISON_TOOL],[test x$use_comparison_tool != xno]) -AM_CONDITIONAL([USE_COMPARISON_TOOL_REORG_TESTS],[test x$use_comparison_tool_reorg_test != xno]) AM_CONDITIONAL([GLIBC_BACK_COMPAT],[test x$use_glibc_compat = xyes]) AM_CONDITIONAL([HARDEN],[test x$use_hardening = xyes]) diff --git a/depends/config.site.in b/depends/config.site.in index 1034863326e..8cdbcd2e4b1 100644 --- a/depends/config.site.in +++ b/depends/config.site.in @@ -7,10 +7,6 @@ ac_tool_prefix=${host_alias}- if test -z $with_boost; then with_boost=$depends_prefix fi -# Disable comparison utility (#592) -#if test -z $with_comparison_tool; then -# with_comparison_tool=$depends_prefix/native/share/BitcoindComparisonTool_jar/BitcoindComparisonTool.jar -#fi if test -z $enable_wallet && test -n "@no_wallet@"; then From 15472b7d84dbdd8916982bd88d6032e49c10f5f6 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 16 Aug 2016 11:16:21 +0200 Subject: [PATCH 124/177] build: Remove check for `openssl/ec.h` We don't use any elliptic curves from OpenSSL anymore, nor include this header anywhere but optionally in the tests of secp256k1 (which has its own autoconf setup). Reported by sinetek on IRC. --- configure.ac | 8 -------- 1 file changed, 8 deletions(-) diff --git a/configure.ac b/configure.ac index a7274eec27c..840b8721eb6 100644 --- a/configure.ac +++ b/configure.ac @@ -691,14 +691,6 @@ fi LIBZCASH_LIBS="-lgmp -lgmpxx -lboost_system-mt -lcrypto -lsodium $RUST_LIBS" -CXXFLAGS_TEMP="$CXXFLAGS" -LIBS_TEMP="$LIBS" -CXXFLAGS="$CXXFLAGS $SSL_CFLAGS $CRYPTO_CFLAGS" -LIBS="$LIBS $SSL_LIBS $CRYPTO_LIBS $GMP_LIBS $GMPXX_LIBS" -AC_CHECK_HEADER([openssl/ec.h],, AC_MSG_ERROR(OpenSSL ec header missing),) -CXXFLAGS="$CXXFLAGS_TEMP" -LIBS="$LIBS_TEMP" - AC_MSG_CHECKING([whether to build bitcoind]) AM_CONDITIONAL([BUILD_BITCOIND], [test x$build_bitcoind = xyes]) AC_MSG_RESULT($build_bitcoind) From d812d95a8f9fa8e2670ea34d03a4f417fac14bca Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Tue, 23 Aug 2016 16:55:15 +1000 Subject: [PATCH 125/177] Add configure check for -latomic --- build-aux/m4/l_atomic.m4 | 40 ++++++++++++++++++++++++++++++++++++++++ configure.ac | 3 +++ 2 files changed, 43 insertions(+) create mode 100644 build-aux/m4/l_atomic.m4 diff --git a/build-aux/m4/l_atomic.m4 b/build-aux/m4/l_atomic.m4 new file mode 100644 index 00000000000..906724b6405 --- /dev/null +++ b/build-aux/m4/l_atomic.m4 @@ -0,0 +1,40 @@ +# Some versions of gcc/libstdc++ require linking with -latomic if +# using the C++ atomic library. +# +# Sourced from http://bugs.debian.org/797228 + +m4_define([_CHECK_ATOMIC_testbody], [[ + #include + #include + + int main() { + std::atomic a{}; + + int64_t v = 5; + int64_t r = a.fetch_add(v); + return static_cast(r); + } +]]) + +AC_DEFUN([CHECK_ATOMIC], [ + + AC_LANG_PUSH(C++) + + AC_MSG_CHECKING([whether std::atomic can be used without link library]) + + AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_ATOMIC_testbody])],[ + AC_MSG_RESULT([yes]) + ],[ + AC_MSG_RESULT([no]) + LIBS="$LIBS -latomic" + AC_MSG_CHECKING([whether std::atomic needs -latomic]) + AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_ATOMIC_testbody])],[ + AC_MSG_RESULT([yes]) + ],[ + AC_MSG_RESULT([no]) + AC_MSG_FAILURE([cannot figure our how to use std::atomic]) + ]) + ]) + + AC_LANG_POP +]) diff --git a/configure.ac b/configure.ac index 840b8721eb6..ad0731a8093 100644 --- a/configure.ac +++ b/configure.ac @@ -57,6 +57,9 @@ case $host in esac dnl Require C++11 compiler (no GNU extensions) AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory]) +dnl Check if -latomic is required for +CHECK_ATOMIC + dnl Libtool init checks. LT_INIT([pic-only]) From 41b28420d29d58079d24f989a41aa61218f31f38 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 23 Jun 2016 16:52:12 +0200 Subject: [PATCH 126/177] devtools: Check for high-entropy ASLR in 64-bit PE executables check_PE_PIE only checked for DYNAMIC_BASE, this is not enough for (secure) ASLR on 64-bit. --- contrib/devtools/security-check.py | 48 +++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py index 84e7fceeace..bee8f3cc151 100755 --- a/contrib/devtools/security-check.py +++ b/contrib/devtools/security-check.py @@ -12,6 +12,7 @@ READELF_CMD = os.getenv('READELF', '/usr/bin/readelf') OBJDUMP_CMD = os.getenv('OBJDUMP', '/usr/bin/objdump') +NONFATAL = {'HIGH_ENTROPY_VA'} # checks which are non-fatal for now but only generate a warning def check_ELF_PIE(executable): ''' @@ -114,26 +115,50 @@ def check_ELF_Canary(executable): def get_PE_dll_characteristics(executable): ''' - Get PE DllCharacteristics bits + Get PE DllCharacteristics bits. + Returns a tuple (arch,bits) where arch is 'i386:x86-64' or 'i386' + and bits is the DllCharacteristics value. ''' p = subprocess.Popen([OBJDUMP_CMD, '-x', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) (stdout, stderr) = p.communicate() if p.returncode: raise IOError('Error opening file') + arch = '' + bits = 0 for line in stdout.split('\n'): tokens = line.split() + if len(tokens)>=2 and tokens[0] == 'architecture:': + arch = tokens[1].rstrip(',') if len(tokens)>=2 and tokens[0] == 'DllCharacteristics': - return int(tokens[1],16) - return 0 + bits = int(tokens[1],16) + return (arch,bits) +IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020 +IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = 0x0040 +IMAGE_DLL_CHARACTERISTICS_NX_COMPAT = 0x0100 -def check_PE_PIE(executable): +def check_PE_DYNAMIC_BASE(executable): '''PIE: DllCharacteristics bit 0x40 signifies dynamicbase (ASLR)''' - return bool(get_PE_dll_characteristics(executable) & 0x40) + (arch,bits) = get_PE_dll_characteristics(executable) + reqbits = IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE + return (bits & reqbits) == reqbits + +# On 64 bit, must support high-entropy 64-bit address space layout randomization in addition to DYNAMIC_BASE +# to have secure ASLR. +def check_PE_HIGH_ENTROPY_VA(executable): + '''PIE: DllCharacteristics bit 0x20 signifies high-entropy ASLR''' + (arch,bits) = get_PE_dll_characteristics(executable) + if arch == 'i386:x86-64': + reqbits = IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA + else: # Unnecessary on 32-bit + assert(arch == 'i386') + reqbits = 0 + return (bits & reqbits) == reqbits def check_PE_NX(executable): '''NX: DllCharacteristics bit 0x100 signifies nxcompat (DEP)''' - return bool(get_PE_dll_characteristics(executable) & 0x100) + (arch,bits) = get_PE_dll_characteristics(executable) + return (bits & IMAGE_DLL_CHARACTERISTICS_NX_COMPAT) == IMAGE_DLL_CHARACTERISTICS_NX_COMPAT CHECKS = { 'ELF': [ @@ -143,7 +168,8 @@ def check_PE_NX(executable): ('Canary', check_ELF_Canary) ], 'PE': [ - ('PIE', check_PE_PIE), + ('DYNAMIC_BASE', check_PE_DYNAMIC_BASE), + ('HIGH_ENTROPY_VA', check_PE_HIGH_ENTROPY_VA), ('NX', check_PE_NX) ] } @@ -168,12 +194,18 @@ def identify_executable(executable): continue failed = [] + warning = [] for (name, func) in CHECKS[etype]: if not func(filename): - failed.append(name) + if name in NONFATAL: + warning.append(name) + else: + failed.append(name) if failed: print('%s: failed %s' % (filename, ' '.join(failed))) retval = 1 + if warning: + print('%s: warning %s' % (filename, ' '.join(warning))) except IOError: print('%s: cannot open' % filename) retval = 1 From 8a932154c56214e37b8e8b7ccf755b19316c2f84 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 23 Jun 2016 16:54:28 +0200 Subject: [PATCH 127/177] build: supply `-Wl,--high-entropy-va` This should enable high-entropy ASLR on 64-bit targets, for better mitigation of exploits. --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index ad0731a8093..3f96fac1279 100644 --- a/configure.ac +++ b/configure.ac @@ -443,6 +443,7 @@ if test x$use_hardening != xno; then # These are only available on Windows. AX_CHECK_LINK_FLAG([[-Wl,--dynamicbase]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--dynamicbase"],[AC_MSG_ERROR(Cannot enable --dynamicbase)]) AX_CHECK_LINK_FLAG([[-Wl,--nxcompat]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--nxcompat"],[AC_MSG_ERROR(Cannot enable --nxcompat)]) + AX_CHECK_LINK_FLAG([[-Wl,--high-entropy-va]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--high-entropy-va"],[AC_MSG_ERROR(Cannot enable ASLR)]) fi case $host in From 0bcd85bee8a4f9e24e9538695f2d3605dccfc2b9 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Mon, 14 Nov 2016 10:55:56 +0100 Subject: [PATCH 128/177] Add compile and link options echo to configure --- configure.ac | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/configure.ac b/configure.ac index 3f96fac1279..af471225ca1 100644 --- a/configure.ac +++ b/configure.ac @@ -876,3 +876,21 @@ case $host in chmod 755 libtool ;; esac + +echo +echo "Options used to compile and link:" +echo " with wallet = $enable_wallet" +echo " with zmq = $use_zmq" +echo " with test = $use_tests" +echo " debug enabled = $enable_debug" +echo +echo " target os = $TARGET_OS" +echo " build os = $BUILD_OS" +echo +echo " CC = $CC" +echo " CFLAGS = $CFLAGS" +echo " CPPFLAGS = $CPPFLAGS" +echo " CXX = $CXX" +echo " CXXFLAGS = $CXXFLAGS" +echo " LDFLAGS = $LDFLAGS" +echo From 943f19fec74a8ce3ee8f511397f6d8e0adb0a649 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 22 Feb 2017 13:33:22 -0500 Subject: [PATCH 129/177] build: force a c++ standard to be specified Newer compilers may switch to newer standards by default. For example, gcc6 uses std=gnu++14 by default. --- build-aux/m4/ax_cxx_compile_stdcxx.m4 | 8 +++++++- configure.ac | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/build-aux/m4/ax_cxx_compile_stdcxx.m4 b/build-aux/m4/ax_cxx_compile_stdcxx.m4 index 2c18e49c56c..f147cee3b11 100644 --- a/build-aux/m4/ax_cxx_compile_stdcxx.m4 +++ b/build-aux/m4/ax_cxx_compile_stdcxx.m4 @@ -57,8 +57,14 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], [$3], [optional], [ax_cxx_compile_cxx$1_required=false], [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) + m4_if([$4], [], [ax_cxx_compile_cxx$1_try_default=true], + [$4], [default], [ax_cxx_compile_cxx$1_try_default=true], + [$4], [nodefault], [ax_cxx_compile_cxx$1_try_default=false], + [m4_fatal([invalid fourth argument `$4' to AX_CXX_COMPILE_STDCXX])]) AC_LANG_PUSH([C++])dnl ac_success=no + + m4_if([$4], [nodefault], [], [dnl AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, ax_cv_cxx_compile_cxx$1, [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], @@ -66,7 +72,7 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl [ax_cv_cxx_compile_cxx$1=no])]) if test x$ax_cv_cxx_compile_cxx$1 = xyes; then ac_success=yes - fi + fi]) m4_if([$2], [noext], [], [dnl if test x$ac_success = xno; then diff --git a/configure.ac b/configure.ac index af471225ca1..c4c139b6d37 100644 --- a/configure.ac +++ b/configure.ac @@ -56,7 +56,7 @@ case $host in ;; esac dnl Require C++11 compiler (no GNU extensions) -AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory]) +AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory], [nodefault]) dnl Check if -latomic is required for CHECK_ATOMIC From d35ebc7b55cd512e9f4530d8e837e9083528a158 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 21 Feb 2017 11:56:07 -0500 Subject: [PATCH 130/177] build: warn about variable length arrays --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index c4c139b6d37..cd7ee65f337 100644 --- a/configure.ac +++ b/configure.ac @@ -176,6 +176,7 @@ if test "x$CXXFLAGS_overridden" = "xno"; then AX_CHECK_COMPILE_FLAG([-Wall],[CXXFLAGS="$CXXFLAGS -Wall"],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-Wextra],[CXXFLAGS="$CXXFLAGS -Wextra"],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-Wformat],[CXXFLAGS="$CXXFLAGS -Wformat"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wvla],[CXXFLAGS="$CXXFLAGS -Wvla"],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-Wformat-security],[CXXFLAGS="$CXXFLAGS -Wformat-security"],,[[$CXXFLAG_WERROR]]) ## Some compilers (gcc) ignore unknown -Wno-* options, but warn about all From 5dd887fdf7632272ea3808f234af3b8cbdfb603f Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 21 Feb 2017 11:56:26 -0500 Subject: [PATCH 131/177] build: add --enable-werror option This turns some compiler warnings into errors. Useful for c-i. --- configure.ac | 17 +++++++++++++++++ src/Makefile.am | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index cd7ee65f337..eb102fec8ee 100644 --- a/configure.ac +++ b/configure.ac @@ -158,6 +158,13 @@ AC_ARG_ENABLE([debug], [enable_debug=$enableval], [enable_debug=no]) +# Turn warnings into errors +AC_ARG_ENABLE([werror], + [AS_HELP_STRING([--enable-werror], + [Treat certain compiler warnings as errors (default is no)])], + [enable_werror=$enableval], + [enable_werror=no]) + AC_LANG_PUSH([C++]) AX_CHECK_COMPILE_FLAG([-Werror],[CXXFLAG_WERROR="-Werror"],[CXXFLAG_WERROR=""]) @@ -172,6 +179,14 @@ if test "x$enable_debug" = xyes; then fi fi +ERROR_CXXFLAGS= +if test "x$enable_werror" = "xyes"; then + if test "x$CXXFLAG_WERROR" = "x"; then + AC_MSG_ERROR("enable-werror set but -Werror is not usable") + fi + AX_CHECK_COMPILE_FLAG([-Werror=vla],[ERROR_CXXFLAGS="$ERROR_CXXFLAGS -Werror=vla"],,[[$CXXFLAG_WERROR]]) +fi + if test "x$CXXFLAGS_overridden" = "xno"; then AX_CHECK_COMPILE_FLAG([-Wall],[CXXFLAGS="$CXXFLAGS -Wall"],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-Wextra],[CXXFLAGS="$CXXFLAGS -Wextra"],,[[$CXXFLAG_WERROR]]) @@ -816,6 +831,7 @@ AC_SUBST(BITCOIN_CLI_NAME) AC_SUBST(BITCOIN_TX_NAME) AC_SUBST(RELDFLAGS) +AC_SUBST(ERROR_CXXFLAGS) AC_SUBST(HARDENED_CXXFLAGS) AC_SUBST(HARDENED_CPPFLAGS) AC_SUBST(HARDENED_LDFLAGS) @@ -884,6 +900,7 @@ echo " with wallet = $enable_wallet" echo " with zmq = $use_zmq" echo " with test = $use_tests" echo " debug enabled = $enable_debug" +echo " werror = $enable_werror" echo echo " target os = $TARGET_OS" echo " build os = $BUILD_OS" diff --git a/src/Makefile.am b/src/Makefile.am index 36f353802cc..4d76176f304 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ DIST_SUBDIRS = secp256k1 univalue AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) -AM_CXXFLAGS = $(HARDENED_CXXFLAGS) +AM_CXXFLAGS = $(HARDENED_CXXFLAGS) $(ERROR_CXXFLAGS) AM_CPPFLAGS = $(HARDENED_CPPFLAGS) if EMBEDDED_LEVELDB From bc9fff113080f5913c63d6eecb3c66a6c7307159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Nyffenegger?= Date: Fri, 7 Jul 2017 16:54:11 +0200 Subject: [PATCH 132/177] Use AC_ARG_VAR to set ARFLAGS. The user can set ARFLAGS in the ./configure step with ./configure ARFLAGS=... If he chooses not to do so, ARFLAGS will be set to cr. --- configure.ac | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/configure.ac b/configure.ac index eb102fec8ee..3497befbdcc 100644 --- a/configure.ac +++ b/configure.ac @@ -18,6 +18,12 @@ BITCOIN_DAEMON_NAME=zcashd BITCOIN_CLI_NAME=zcash-cli BITCOIN_TX_NAME=zcash-tx +dnl Unless the user specified ARFLAGS, force it to be cr +AC_ARG_VAR(ARFLAGS, [Flags for the archiver, defaults to if not set]) +if test "x${ARFLAGS+set}" != "xset"; then + ARFLAGS="cr" +fi + AC_CANONICAL_HOST AH_TOP([#ifndef BITCOIN_CONFIG_H]) @@ -911,4 +917,5 @@ echo " CPPFLAGS = $CPPFLAGS" echo " CXX = $CXX" echo " CXXFLAGS = $CXXFLAGS" echo " LDFLAGS = $LDFLAGS" +echo " ARFLAGS = $ARFLAGS" echo From c1fcdd01dde4495d3181ac963ea589e902f39137 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 30 Nov 2017 22:51:15 +0000 Subject: [PATCH 133/177] Change --enable-werror to apply to all warnings, use it in build.sh --- configure.ac | 4 ++-- zcutil/build.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 3497befbdcc..3b525f94ef3 100644 --- a/configure.ac +++ b/configure.ac @@ -167,7 +167,7 @@ AC_ARG_ENABLE([debug], # Turn warnings into errors AC_ARG_ENABLE([werror], [AS_HELP_STRING([--enable-werror], - [Treat certain compiler warnings as errors (default is no)])], + [Treat all compiler warnings as errors (default is no)])], [enable_werror=$enableval], [enable_werror=no]) @@ -190,7 +190,7 @@ if test "x$enable_werror" = "xyes"; then if test "x$CXXFLAG_WERROR" = "x"; then AC_MSG_ERROR("enable-werror set but -Werror is not usable") fi - AX_CHECK_COMPILE_FLAG([-Werror=vla],[ERROR_CXXFLAGS="$ERROR_CXXFLAGS -Werror=vla"],,[[$CXXFLAG_WERROR]]) + ERROR_CXXFLAGS="$ERROR_CXXFLAGS -Werror" fi if test "x$CXXFLAGS_overridden" = "xno"; then diff --git a/zcutil/build.sh b/zcutil/build.sh index f665088ac8a..119802d71bc 100755 --- a/zcutil/build.sh +++ b/zcutil/build.sh @@ -132,5 +132,5 @@ ld -v HOST="$HOST" BUILD="$BUILD" NO_RUST="$RUST_ARG" NO_PROTON="$PROTON_ARG" "$MAKE" "$@" -C ./depends/ V=1 ./autogen.sh -CC="$CC" CXX="$CXX" ./configure --prefix="${PREFIX}" --host="$HOST" --build="$BUILD" "$RUST_ARG" "$HARDENING_ARG" "$LCOV_ARG" "$TEST_ARG" "$MINING_ARG" "$PROTON_ARG" "$LIBS_ARG" CXXFLAGS='-fwrapv -fno-strict-aliasing -Wno-builtin-declaration-mismatch -Werror -g' +CC="$CC" CXX="$CXX" ./configure --prefix="${PREFIX}" --host="$HOST" --build="$BUILD" "$RUST_ARG" "$HARDENING_ARG" "$LCOV_ARG" "$TEST_ARG" "$MINING_ARG" "$PROTON_ARG" "$LIBS_ARG" --enable-werror CXXFLAGS='-fwrapv -fno-strict-aliasing -Wno-builtin-declaration-mismatch -g' "$MAKE" "$@" V=1 From 704337b2b8fef44a14928c907065a4d5319d8669 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 30 Nov 2017 23:00:43 +0000 Subject: [PATCH 134/177] Move Zcash flags into configure.ac --- configure.ac | 5 +++++ zcutil/build.sh | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 3b525f94ef3..27c000c2c2a 100644 --- a/configure.ac +++ b/configure.ac @@ -715,6 +715,11 @@ else LIBSNARK_DEPINST="$prefix" fi +# Additional Zcash flags +AX_CHECK_COMPILE_FLAG([-fwrapv],[CXXFLAGS="$CXXFLAGS -fwrapv"]) +AX_CHECK_COMPILE_FLAG([-fno-strict-aliasing],[CXXFLAGS="$CXXFLAGS -fno-strict-aliasing"]) +AX_CHECK_COMPILE_FLAG([-Wno-builtin-declaration-mismatch],[CXXFLAGS="$CXXFLAGS -Wno-builtin-declaration-mismatch"],,[[$CXXFLAG_WERROR]]) + LIBZCASH_LIBS="-lgmp -lgmpxx -lboost_system-mt -lcrypto -lsodium $RUST_LIBS" AC_MSG_CHECKING([whether to build bitcoind]) diff --git a/zcutil/build.sh b/zcutil/build.sh index 119802d71bc..17f023991fc 100755 --- a/zcutil/build.sh +++ b/zcutil/build.sh @@ -132,5 +132,5 @@ ld -v HOST="$HOST" BUILD="$BUILD" NO_RUST="$RUST_ARG" NO_PROTON="$PROTON_ARG" "$MAKE" "$@" -C ./depends/ V=1 ./autogen.sh -CC="$CC" CXX="$CXX" ./configure --prefix="${PREFIX}" --host="$HOST" --build="$BUILD" "$RUST_ARG" "$HARDENING_ARG" "$LCOV_ARG" "$TEST_ARG" "$MINING_ARG" "$PROTON_ARG" "$LIBS_ARG" --enable-werror CXXFLAGS='-fwrapv -fno-strict-aliasing -Wno-builtin-declaration-mismatch -g' +CC="$CC" CXX="$CXX" ./configure --prefix="${PREFIX}" --host="$HOST" --build="$BUILD" "$RUST_ARG" "$HARDENING_ARG" "$LCOV_ARG" "$TEST_ARG" "$MINING_ARG" "$PROTON_ARG" "$LIBS_ARG" --enable-werror CXXFLAGS='-g' "$MAKE" "$@" V=1 From 642a1caf93af62fd6b3e8271f547f1cc3fd42a74 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 23 Feb 2017 18:27:41 +0000 Subject: [PATCH 135/177] ViewingKey -> ReceivingKey per zcash/zips#117 --- src/gtest/test_joinsplit.cpp | 2 +- src/gtest/test_keystore.cpp | 12 ++++++------ src/keystore.cpp | 2 +- src/utiltest.cpp | 2 +- src/wallet/asyncrpcoperation_sendmany.cpp | 2 +- src/wallet/crypter.cpp | 8 ++++---- src/wallet/crypter.h | 2 +- src/wallet/gtest/test_wallet.cpp | 2 +- src/wallet/rpcwallet.cpp | 12 ++++++------ src/wallet/wallet.cpp | 12 ++++++------ src/wallet/wallet.h | 4 ++-- src/wallet/walletdb.cpp | 12 ++++++------ src/wallet/walletdb.h | 2 +- src/zcash/Address.cpp | 8 ++++---- src/zcash/Address.hpp | 6 +++--- 15 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/gtest/test_joinsplit.cpp b/src/gtest/test_joinsplit.cpp index 986592e8995..979d0d5185b 100644 --- a/src/gtest/test_joinsplit.cpp +++ b/src/gtest/test_joinsplit.cpp @@ -89,7 +89,7 @@ void test_full_api(ZCJoinSplit* js) // Recipient should decrypt // Now the recipient should spend the money again auto h_sig = js->h_sig(randomSeed, nullifiers, pubKeyHash); - ZCNoteDecryption decryptor(recipient_key.viewing_key()); + ZCNoteDecryption decryptor(recipient_key.receiving_key()); auto note_pt = NotePlaintext::decrypt( decryptor, diff --git a/src/gtest/test_keystore.cpp b/src/gtest/test_keystore.cpp index e94aea53e30..23cc45aaeb2 100644 --- a/src/gtest/test_keystore.cpp +++ b/src/gtest/test_keystore.cpp @@ -43,7 +43,7 @@ TEST(keystore_tests, store_and_retrieve_note_decryptor) { keyStore.AddSpendingKey(sk); EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut)); - EXPECT_EQ(ZCNoteDecryption(sk.viewing_key()), decOut); + EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut); } #ifdef ENABLE_WALLET @@ -72,13 +72,13 @@ TEST(keystore_tests, store_and_retrieve_spending_key_in_encrypted_store) { ASSERT_TRUE(keyStore.GetSpendingKey(addr, keyOut)); ASSERT_EQ(sk, keyOut); EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut)); - EXPECT_EQ(ZCNoteDecryption(sk.viewing_key()), decOut); + EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut); ASSERT_TRUE(keyStore.EncryptKeys(vMasterKey)); ASSERT_TRUE(keyStore.HaveSpendingKey(addr)); ASSERT_FALSE(keyStore.GetSpendingKey(addr, keyOut)); EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut)); - EXPECT_EQ(ZCNoteDecryption(sk.viewing_key()), decOut); + EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut); // Unlocking with a random key should fail uint256 r2 {GetRandHash()}; @@ -109,19 +109,19 @@ TEST(keystore_tests, store_and_retrieve_spending_key_in_encrypted_store) { ASSERT_TRUE(keyStore.GetSpendingKey(addr2, keyOut)); ASSERT_EQ(sk2, keyOut); EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut)); - EXPECT_EQ(ZCNoteDecryption(sk2.viewing_key()), decOut); + EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut); ASSERT_TRUE(keyStore.Lock()); ASSERT_TRUE(keyStore.HaveSpendingKey(addr2)); ASSERT_FALSE(keyStore.GetSpendingKey(addr2, keyOut)); EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut)); - EXPECT_EQ(ZCNoteDecryption(sk2.viewing_key()), decOut); + EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut); ASSERT_TRUE(keyStore.Unlock(vMasterKey)); ASSERT_TRUE(keyStore.GetSpendingKey(addr2, keyOut)); ASSERT_EQ(sk2, keyOut); EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut)); - EXPECT_EQ(ZCNoteDecryption(sk2.viewing_key()), decOut); + EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut); keyStore.GetPaymentAddresses(addrs); ASSERT_EQ(2, addrs.size()); diff --git a/src/keystore.cpp b/src/keystore.cpp index f32ba0c3238..3c32ab58306 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -89,6 +89,6 @@ bool CBasicKeyStore::AddSpendingKey(const libzcash::SpendingKey &sk) LOCK(cs_SpendingKeyStore); auto address = sk.address(); mapSpendingKeys[address] = sk; - mapNoteDecryptors.insert(std::make_pair(address, ZCNoteDecryption(sk.viewing_key()))); + mapNoteDecryptors.insert(std::make_pair(address, ZCNoteDecryption(sk.receiving_key()))); return true; } diff --git a/src/utiltest.cpp b/src/utiltest.cpp index 5cebc1a5dd6..e91a796e33d 100644 --- a/src/utiltest.cpp +++ b/src/utiltest.cpp @@ -63,7 +63,7 @@ CWalletTx GetValidReceive(ZCJoinSplit& params, libzcash::Note GetNote(ZCJoinSplit& params, const libzcash::SpendingKey& sk, const CTransaction& tx, size_t js, size_t n) { - ZCNoteDecryption decryptor {sk.viewing_key()}; + ZCNoteDecryption decryptor {sk.receiving_key()}; auto hSig = tx.vjoinsplit[js].h_sig(params, tx.joinSplitPubKey); auto note_pt = libzcash::NotePlaintext::decrypt( decryptor, diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index 539d5d7d660..59cd3a8fb2d 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/src/wallet/asyncrpcoperation_sendmany.cpp @@ -555,7 +555,7 @@ bool AsyncRPCOperation_sendmany::main_impl() { intermediates.insert(std::make_pair(tree.root(), tree)); // chained js are interstitial (found in between block boundaries) // Decrypt the change note's ciphertext to retrieve some data we need - ZCNoteDecryption decryptor(spendingkey_.viewing_key()); + ZCNoteDecryption decryptor(spendingkey_.receiving_key()); auto hSig = prevJoinSplit.h_sig(*pzcashParams, tx_.joinSplitPubKey); try { NotePlaintext plaintext = NotePlaintext::decrypt( diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp index 69fe55ebdd4..69a2649b16f 100644 --- a/src/wallet/crypter.cpp +++ b/src/wallet/crypter.cpp @@ -316,14 +316,14 @@ bool CCryptoKeyStore::AddSpendingKey(const libzcash::SpendingKey &sk) if (!EncryptSecret(vMasterKey, vchSecret, address.GetHash(), vchCryptedSecret)) return false; - if (!AddCryptedSpendingKey(address, sk.viewing_key(), vchCryptedSecret)) + if (!AddCryptedSpendingKey(address, sk.receiving_key(), vchCryptedSecret)) return false; } return true; } bool CCryptoKeyStore::AddCryptedSpendingKey(const libzcash::PaymentAddress &address, - const libzcash::ViewingKey &vk, + const libzcash::ReceivingKey &rk, const std::vector &vchCryptedSecret) { { @@ -332,7 +332,7 @@ bool CCryptoKeyStore::AddCryptedSpendingKey(const libzcash::PaymentAddress &addr return false; mapCryptedSpendingKeys[address] = vchCryptedSecret; - mapNoteDecryptors.insert(std::make_pair(address, ZCNoteDecryption(vk))); + mapNoteDecryptors.insert(std::make_pair(address, ZCNoteDecryption(rk))); } return true; } @@ -384,7 +384,7 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn) std::vector vchCryptedSecret; if (!EncryptSecret(vMasterKeyIn, vchSecret, address.GetHash(), vchCryptedSecret)) return false; - if (!AddCryptedSpendingKey(address, sk.viewing_key(), vchCryptedSecret)) + if (!AddCryptedSpendingKey(address, sk.receiving_key(), vchCryptedSecret)) return false; } mapSpendingKeys.clear(); diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h index d09cfa8466d..bcee188cfa4 100644 --- a/src/wallet/crypter.h +++ b/src/wallet/crypter.h @@ -201,7 +201,7 @@ class CCryptoKeyStore : public CBasicKeyStore } } virtual bool AddCryptedSpendingKey(const libzcash::PaymentAddress &address, - const libzcash::ViewingKey &vk, + const libzcash::ReceivingKey &rk, const std::vector &vchCryptedSecret); bool AddSpendingKey(const libzcash::SpendingKey &sk); bool HaveSpendingKey(const libzcash::PaymentAddress &address) const diff --git a/src/wallet/gtest/test_wallet.cpp b/src/wallet/gtest/test_wallet.cpp index 9bcc5f533dd..b39275f67f3 100644 --- a/src/wallet/gtest/test_wallet.cpp +++ b/src/wallet/gtest/test_wallet.cpp @@ -328,7 +328,7 @@ TEST(wallet_tests, GetNoteNullifier) { auto sk = libzcash::SpendingKey::random(); auto address = sk.address(); - auto dec = ZCNoteDecryption(sk.viewing_key()); + auto dec = ZCNoteDecryption(sk.receiving_key()); auto wtx = GetValidReceive(sk, 10, true); auto note = GetNote(sk, wtx, 0, 1); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 034147f42fc..d2c558c964b 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2667,7 +2667,7 @@ UniValue zc_raw_receive(const UniValue& params, bool fHelp) } } - ZCNoteDecryption decryptor(k.viewing_key()); + ZCNoteDecryption decryptor(k.receiving_key()); NotePlaintext npt = NotePlaintext::decrypt( decryptor, @@ -2908,20 +2908,20 @@ UniValue zc_raw_keygen(const UniValue& params, bool fHelp) auto k = SpendingKey::random(); auto addr = k.address(); - auto viewing_key = k.viewing_key(); + auto receiving_key = k.receiving_key(); - CDataStream viewing(SER_NETWORK, PROTOCOL_VERSION); + CDataStream receiving(SER_NETWORK, PROTOCOL_VERSION); - viewing << viewing_key; + receiving << receiving_key; CZCPaymentAddress pubaddr(addr); CZCSpendingKey spendingkey(k); - std::string viewing_hex = HexStr(viewing.begin(), viewing.end()); + std::string receiving_hex = HexStr(receiving.begin(), receiving.end()); UniValue result(UniValue::VOBJ); result.push_back(Pair("zcaddress", pubaddr.ToString())); result.push_back(Pair("zcsecretkey", spendingkey.ToString())); - result.push_back(Pair("zcviewingkey", viewing_hex)); + result.push_back(Pair("zcviewingkey", receiving_hex)); return result; } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index a61c1e2f7db..677fec31992 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -190,10 +190,10 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, bool CWallet::AddCryptedSpendingKey(const libzcash::PaymentAddress &address, - const libzcash::ViewingKey &vk, + const libzcash::ReceivingKey &rk, const std::vector &vchCryptedSecret) { - if (!CCryptoKeyStore::AddCryptedSpendingKey(address, vk, vchCryptedSecret)) + if (!CCryptoKeyStore::AddCryptedSpendingKey(address, rk, vchCryptedSecret)) return false; if (!fFileBacked) return true; @@ -201,12 +201,12 @@ bool CWallet::AddCryptedSpendingKey(const libzcash::PaymentAddress &address, LOCK(cs_wallet); if (pwalletdbEncryption) { return pwalletdbEncryption->WriteCryptedZKey(address, - vk, + rk, vchCryptedSecret, mapZKeyMetadata[address]); } else { return CWalletDB(strWalletFile).WriteCryptedZKey(address, - vk, + rk, vchCryptedSecret, mapZKeyMetadata[address]); } @@ -236,9 +236,9 @@ bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret) +bool CWallet::LoadCryptedZKey(const libzcash::PaymentAddress &addr, const libzcash::ReceivingKey &rk, const std::vector &vchCryptedSecret) { - return CCryptoKeyStore::AddCryptedSpendingKey(addr, vk, vchCryptedSecret); + return CCryptoKeyStore::AddCryptedSpendingKey(addr, rk, vchCryptedSecret); } bool CWallet::LoadZKey(const libzcash::SpendingKey &key) diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 2b481d87a8c..57a71a4317f 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -950,9 +950,9 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface //! Load spending key metadata (used by LoadWallet) bool LoadZKeyMetadata(const libzcash::PaymentAddress &addr, const CKeyMetadata &meta); //! Adds an encrypted spending key to the store, without saving it to disk (used by LoadWallet) - bool LoadCryptedZKey(const libzcash::PaymentAddress &addr, const libzcash::ViewingKey &vk, const std::vector &vchCryptedSecret); + bool LoadCryptedZKey(const libzcash::PaymentAddress &addr, const libzcash::ReceivingKey &rk, const std::vector &vchCryptedSecret); //! Adds an encrypted spending key to the store, and saves it to disk (virtual method, declared in crypter.h) - bool AddCryptedSpendingKey(const libzcash::PaymentAddress &address, const libzcash::ViewingKey &vk, const std::vector &vchCryptedSecret); + bool AddCryptedSpendingKey(const libzcash::PaymentAddress &address, const libzcash::ReceivingKey &rk, const std::vector &vchCryptedSecret); /** * Increment the next transaction order id diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index f252243369c..c79a15e3068 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -106,7 +106,7 @@ bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey, } bool CWalletDB::WriteCryptedZKey(const libzcash::PaymentAddress & addr, - const libzcash::ViewingKey &vk, + const libzcash::ReceivingKey &rk, const std::vector& vchCryptedSecret, const CKeyMetadata &keyMeta) { @@ -116,7 +116,7 @@ bool CWalletDB::WriteCryptedZKey(const libzcash::PaymentAddress & addr, if (!Write(std::make_pair(std::string("zkeymeta"), addr), keyMeta)) return false; - if (!Write(std::make_pair(std::string("czkey"), addr), std::make_pair(vk, vchCryptedSecret), false)) + if (!Write(std::make_pair(std::string("czkey"), addr), std::make_pair(rk, vchCryptedSecret), false)) return false; if (fEraseUnencryptedKey) { @@ -585,14 +585,14 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, libzcash::PaymentAddress addr; ssKey >> addr; // Deserialization of a pair is just one item after another - uint256 vkValue; - ssValue >> vkValue; - libzcash::ViewingKey vk(vkValue); + uint256 rkValue; + ssValue >> rkValue; + libzcash::ReceivingKey rk(rkValue); vector vchCryptedSecret; ssValue >> vchCryptedSecret; wss.nCKeys++; - if (!pwallet->LoadCryptedZKey(addr, vk, vchCryptedSecret)) + if (!pwallet->LoadCryptedZKey(addr, rk, vchCryptedSecret)) { strErr = "Error reading wallet database: LoadCryptedZKey failed"; return false; diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index f9f71e00cb0..b901f539c43 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -136,7 +136,7 @@ class CWalletDB : public CDB /// Write spending key to wallet database, where key is payment address and value is spending key. bool WriteZKey(const libzcash::PaymentAddress& addr, const libzcash::SpendingKey& key, const CKeyMetadata &keyMeta); bool WriteCryptedZKey(const libzcash::PaymentAddress & addr, - const libzcash::ViewingKey & vk, + const libzcash::ReceivingKey & rk, const std::vector& vchCryptedSecret, const CKeyMetadata &keyMeta); diff --git a/src/zcash/Address.cpp b/src/zcash/Address.cpp index 3849b2ffc07..75324de4f0a 100644 --- a/src/zcash/Address.cpp +++ b/src/zcash/Address.cpp @@ -12,12 +12,12 @@ uint256 PaymentAddress::GetHash() const { return Hash(ss.begin(), ss.end()); } -uint256 ViewingKey::pk_enc() { +uint256 ReceivingKey::pk_enc() { return ZCNoteEncryption::generate_pubkey(*this); } -ViewingKey SpendingKey::viewing_key() const { - return ViewingKey(ZCNoteEncryption::generate_privkey(*this)); +ReceivingKey SpendingKey::receiving_key() const { + return ReceivingKey(ZCNoteEncryption::generate_privkey(*this)); } SpendingKey SpendingKey::random() { @@ -25,7 +25,7 @@ SpendingKey SpendingKey::random() { } PaymentAddress SpendingKey::address() const { - return PaymentAddress(PRF_addr_a_pk(*this), viewing_key().pk_enc()); + return PaymentAddress(PRF_addr_a_pk(*this), receiving_key().pk_enc()); } } diff --git a/src/zcash/Address.hpp b/src/zcash/Address.hpp index 9bf22663d3a..e76973cb63b 100644 --- a/src/zcash/Address.hpp +++ b/src/zcash/Address.hpp @@ -38,9 +38,9 @@ class PaymentAddress { } }; -class ViewingKey : public uint256 { +class ReceivingKey : public uint256 { public: - ViewingKey(uint256 sk_enc) : uint256(sk_enc) { } + ReceivingKey(uint256 sk_enc) : uint256(sk_enc) { } uint256 pk_enc(); }; @@ -52,7 +52,7 @@ class SpendingKey : public uint252 { static SpendingKey random(); - ViewingKey viewing_key() const; + ReceivingKey receiving_key() const; PaymentAddress address() const; }; From aa666c967341336c1bfb233135c7c9858863168c Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 24 Feb 2017 03:01:00 +0000 Subject: [PATCH 136/177] Implement viewing key storage in the keystore --- src/gtest/test_keystore.cpp | 44 +++++++++++++++++++++++++++++++++++++ src/keystore.cpp | 34 ++++++++++++++++++++++++++++ src/keystore.h | 13 +++++++++++ src/zcash/Address.cpp | 12 ++++++++-- src/zcash/Address.hpp | 31 +++++++++++++++++++++++++- 5 files changed, 131 insertions(+), 3 deletions(-) diff --git a/src/gtest/test_keystore.cpp b/src/gtest/test_keystore.cpp index 23cc45aaeb2..903a48839e4 100644 --- a/src/gtest/test_keystore.cpp +++ b/src/gtest/test_keystore.cpp @@ -46,6 +46,50 @@ TEST(keystore_tests, store_and_retrieve_note_decryptor) { EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut); } +TEST(keystore_tests, StoreAndRetrieveViewingKey) { + CBasicKeyStore keyStore; + libzcash::ViewingKey vkOut; + libzcash::SpendingKey skOut; + ZCNoteDecryption decOut; + + auto sk = libzcash::SpendingKey::random(); + auto vk = sk.viewing_key(); + auto addr = sk.address(); + + // Sanity-check: we can't get a viewing key we haven't added + EXPECT_FALSE(keyStore.HaveViewingKey(addr)); + EXPECT_FALSE(keyStore.GetViewingKey(addr, vkOut)); + + // and we shouldn't have a spending key or decryptor either + EXPECT_FALSE(keyStore.HaveSpendingKey(addr)); + EXPECT_FALSE(keyStore.GetSpendingKey(addr, skOut)); + EXPECT_FALSE(keyStore.GetNoteDecryptor(addr, decOut)); + + keyStore.AddViewingKey(vk); + EXPECT_TRUE(keyStore.HaveViewingKey(addr)); + EXPECT_TRUE(keyStore.GetViewingKey(addr, vkOut)); + EXPECT_EQ(vk, vkOut); + + // We should still not have the spending key... + EXPECT_FALSE(keyStore.HaveSpendingKey(addr)); + EXPECT_FALSE(keyStore.GetSpendingKey(addr, skOut)); + + // ... but we should have a decryptor + EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut)); + EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut); + + keyStore.RemoveViewingKey(vk); + EXPECT_FALSE(keyStore.HaveViewingKey(addr)); + EXPECT_FALSE(keyStore.GetViewingKey(addr, vkOut)); + EXPECT_FALSE(keyStore.HaveSpendingKey(addr)); + EXPECT_FALSE(keyStore.GetSpendingKey(addr, skOut)); + + // We still have a decryptor because those are cached in memory + // (and also we only remove viewing keys when adding a spending key) + EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut)); + EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut); +} + #ifdef ENABLE_WALLET class TestCCryptoKeyStore : public CCryptoKeyStore { diff --git a/src/keystore.cpp b/src/keystore.cpp index 3c32ab58306..323fe710cc7 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -92,3 +92,37 @@ bool CBasicKeyStore::AddSpendingKey(const libzcash::SpendingKey &sk) mapNoteDecryptors.insert(std::make_pair(address, ZCNoteDecryption(sk.receiving_key()))); return true; } + +bool CBasicKeyStore::AddViewingKey(const libzcash::ViewingKey &vk) +{ + LOCK(cs_SpendingKeyStore); + auto address = vk.address(); + mapViewingKeys[address] = vk; + mapNoteDecryptors.insert(std::make_pair(address, ZCNoteDecryption(vk.sk_enc))); + return true; +} + +bool CBasicKeyStore::RemoveViewingKey(const libzcash::ViewingKey &vk) +{ + LOCK(cs_SpendingKeyStore); + mapViewingKeys.erase(vk.address()); + return true; +} + +bool CBasicKeyStore::HaveViewingKey(const libzcash::PaymentAddress &address) const +{ + LOCK(cs_SpendingKeyStore); + return mapViewingKeys.count(address) > 0; +} + +bool CBasicKeyStore::GetViewingKey(const libzcash::PaymentAddress &address, + libzcash::ViewingKey &vkOut) const +{ + LOCK(cs_SpendingKeyStore); + ViewingKeyMap::const_iterator mi = mapViewingKeys.find(address); + if (mi != mapViewingKeys.end()) { + vkOut = mi->second; + return true; + } + return false; +} diff --git a/src/keystore.h b/src/keystore.h index 84595cfb0f4..0b548920b31 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -55,12 +55,19 @@ class CKeyStore virtual bool HaveSpendingKey(const libzcash::PaymentAddress &address) const =0; virtual bool GetSpendingKey(const libzcash::PaymentAddress &address, libzcash::SpendingKey& skOut) const =0; virtual void GetPaymentAddresses(std::set &setAddress) const =0; + + //! Support for viewing keys + virtual bool AddViewingKey(const libzcash::ViewingKey &vk) =0; + virtual bool RemoveViewingKey(const libzcash::ViewingKey &vk) =0; + virtual bool HaveViewingKey(const libzcash::PaymentAddress &address) const =0; + virtual bool GetViewingKey(const libzcash::PaymentAddress &address, libzcash::ViewingKey& vkOut) const =0; }; typedef std::map KeyMap; typedef std::map ScriptMap; typedef std::set WatchOnlySet; typedef std::map SpendingKeyMap; +typedef std::map ViewingKeyMap; typedef std::map NoteDecryptorMap; /** Basic key store, that keeps keys in an address->secret map */ @@ -71,6 +78,7 @@ class CBasicKeyStore : public CKeyStore ScriptMap mapScripts; WatchOnlySet setWatchOnly; SpendingKeyMap mapSpendingKeys; + ViewingKeyMap mapViewingKeys; NoteDecryptorMap mapNoteDecryptors; public: @@ -168,6 +176,11 @@ class CBasicKeyStore : public CKeyStore } } } + + virtual bool AddViewingKey(const libzcash::ViewingKey &vk); + virtual bool RemoveViewingKey(const libzcash::ViewingKey &vk); + virtual bool HaveViewingKey(const libzcash::PaymentAddress &address) const; + virtual bool GetViewingKey(const libzcash::PaymentAddress &address, libzcash::ViewingKey& vkOut) const; }; typedef std::vector > CKeyingMaterial; diff --git a/src/zcash/Address.cpp b/src/zcash/Address.cpp index 75324de4f0a..baefeae4e05 100644 --- a/src/zcash/Address.cpp +++ b/src/zcash/Address.cpp @@ -12,20 +12,28 @@ uint256 PaymentAddress::GetHash() const { return Hash(ss.begin(), ss.end()); } -uint256 ReceivingKey::pk_enc() { +uint256 ReceivingKey::pk_enc() const { return ZCNoteEncryption::generate_pubkey(*this); } +PaymentAddress ViewingKey::address() const { + return PaymentAddress(a_pk, sk_enc.pk_enc()); +} + ReceivingKey SpendingKey::receiving_key() const { return ReceivingKey(ZCNoteEncryption::generate_privkey(*this)); } +ViewingKey SpendingKey::viewing_key() const { + return ViewingKey(PRF_addr_a_pk(*this), receiving_key()); +} + SpendingKey SpendingKey::random() { return SpendingKey(random_uint252()); } PaymentAddress SpendingKey::address() const { - return PaymentAddress(PRF_addr_a_pk(*this), receiving_key().pk_enc()); + return viewing_key().address(); } } diff --git a/src/zcash/Address.hpp b/src/zcash/Address.hpp index e76973cb63b..4287fee4f57 100644 --- a/src/zcash/Address.hpp +++ b/src/zcash/Address.hpp @@ -40,9 +40,37 @@ class PaymentAddress { class ReceivingKey : public uint256 { public: + ReceivingKey() { } ReceivingKey(uint256 sk_enc) : uint256(sk_enc) { } - uint256 pk_enc(); + uint256 pk_enc() const; +}; + +class ViewingKey { +public: + uint256 a_pk; + ReceivingKey sk_enc; + + ViewingKey() : a_pk(), sk_enc() { } + ViewingKey(uint256 a_pk, ReceivingKey sk_enc) : a_pk(a_pk), sk_enc(sk_enc) { } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(a_pk); + READWRITE(sk_enc); + } + + PaymentAddress address() const; + + friend inline bool operator==(const ViewingKey& a, const ViewingKey& b) { + return a.a_pk == b.a_pk && a.sk_enc == b.sk_enc; + } + friend inline bool operator<(const ViewingKey& a, const ViewingKey& b) { + return (a.a_pk < b.a_pk || + (a.a_pk == b.a_pk && a.sk_enc < b.sk_enc)); + } }; class SpendingKey : public uint252 { @@ -53,6 +81,7 @@ class SpendingKey : public uint252 { static SpendingKey random(); ReceivingKey receiving_key() const; + ViewingKey viewing_key() const; PaymentAddress address() const; }; From 13933e4c1344c84e55071e5a6517e484710aa8d4 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 1 Mar 2017 11:09:41 -0800 Subject: [PATCH 137/177] Factor out common logic from CZCPaymentAddress and CZCSpendingKey --- src/base58.cpp | 67 ++++++++++++++++++++------------------------------ src/base58.h | 27 ++++++++++++++------ 2 files changed, 45 insertions(+), 49 deletions(-) diff --git a/src/base58.cpp b/src/base58.cpp index 12e2496da9b..2fd2475fea3 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -323,67 +323,52 @@ bool CBitcoinSecret::SetString(const std::string& strSecret) return SetString(strSecret.c_str()); } -bool CZCPaymentAddress::Set(const libzcash::PaymentAddress& addr) +template +bool CZCEncoding::Set(const DATA_TYPE& addr) { CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << addr; std::vector addrSerialized(ss.begin(), ss.end()); - assert(addrSerialized.size() == libzcash::SerializedPaymentAddressSize); - SetData(Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS), &addrSerialized[0], libzcash::SerializedPaymentAddressSize); + assert(addrSerialized.size() == SER_SIZE); + SetData(Params().Base58Prefix(PREFIX), &addrSerialized[0], SER_SIZE); return true; } -libzcash::PaymentAddress CZCPaymentAddress::Get() const +template +DATA_TYPE CZCEncoding::Get() const { - if (vchData.size() != libzcash::SerializedPaymentAddressSize) { + if (vchData.size() != SER_SIZE) { throw std::runtime_error( - "payment address is invalid" + PrependName(" is invalid") ); } - if (vchVersion != Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS)) { + if (vchVersion != Params().Base58Prefix(PREFIX)) { throw std::runtime_error( - "payment address is for wrong network type" + PrependName(" is for wrong network type") ); } std::vector serialized(vchData.begin(), vchData.end()); CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION); - libzcash::PaymentAddress ret; - ss >> ret; - return ret; -} - -bool CZCSpendingKey::Set(const libzcash::SpendingKey& addr) -{ - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << addr; - std::vector addrSerialized(ss.begin(), ss.end()); - assert(addrSerialized.size() == libzcash::SerializedSpendingKeySize); - SetData(Params().Base58Prefix(CChainParams::ZCSPENDING_KEY), &addrSerialized[0], libzcash::SerializedSpendingKeySize); - return true; -} - -libzcash::SpendingKey CZCSpendingKey::Get() const -{ - if (vchData.size() != libzcash::SerializedSpendingKeySize) { - throw std::runtime_error( - "spending key is invalid" - ); - } - - if (vchVersion != Params().Base58Prefix(CChainParams::ZCSPENDING_KEY)) { - throw std::runtime_error( - "spending key is for wrong network type" - ); - } - - std::vector serialized(vchData.begin(), vchData.end()); - - CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION); - libzcash::SpendingKey ret; + DATA_TYPE ret; ss >> ret; return ret; } +// Explicit instantiations for libzcash::PaymentAddress +template bool CZCEncoding::Set(const libzcash::PaymentAddress& addr); +template libzcash::PaymentAddress CZCEncoding::Get() const; + +// Explicit instantiations for libzcash::SpendingKey +template bool CZCEncoding::Set(const libzcash::SpendingKey& sk); +template libzcash::SpendingKey CZCEncoding::Get() const; diff --git a/src/base58.h b/src/base58.h index 88efadbd6ed..c239e0e999f 100644 --- a/src/base58.h +++ b/src/base58.h @@ -96,26 +96,37 @@ class CBase58Data bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; } }; -class CZCPaymentAddress : public CBase58Data { +template +class CZCEncoding : public CBase58Data { +protected: + virtual std::string PrependName(const std::string& s) const = 0; + +public: + bool Set(const DATA_TYPE& addr); + + DATA_TYPE Get() const; +}; + +class CZCPaymentAddress : public CZCEncoding { +protected: + std::string PrependName(const std::string& s) const { return "payment address" + s; } + public: - bool Set(const libzcash::PaymentAddress& addr); CZCPaymentAddress() {} CZCPaymentAddress(const std::string& strAddress) { SetString(strAddress.c_str(), 2); } CZCPaymentAddress(const libzcash::PaymentAddress& addr) { Set(addr); } - - libzcash::PaymentAddress Get() const; }; -class CZCSpendingKey : public CBase58Data { +class CZCSpendingKey : public CZCEncoding { +protected: + std::string PrependName(const std::string& s) const { return "spending key" + s; } + public: - bool Set(const libzcash::SpendingKey& addr); CZCSpendingKey() {} CZCSpendingKey(const std::string& strAddress) { SetString(strAddress.c_str(), 2); } CZCSpendingKey(const libzcash::SpendingKey& addr) { Set(addr); } - - libzcash::SpendingKey Get() const; }; /** base58-encoded Bitcoin addresses. From 221405b830582c17904fe77f9abb5f03a4eedb5e Mon Sep 17 00:00:00 2001 From: backendmaster <34057530+backendmaster@users.noreply.github.com> Date: Thu, 7 Dec 2017 04:53:16 +0200 Subject: [PATCH 138/177] fixing some errors --- README.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9bc4cd6dc3d..ea2825a1560 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ sudo apt-get install \ ### Obtain the ZERO software from GitHub ``` -git clone https://github.com/zerocurrency/zero.git +git clone https://github.com/backendmaster/zero.git cd zero git checkout master ``` @@ -75,8 +75,16 @@ echo "rpcport=23800" >> ~/.zero/zero.conf ### Seeder Nodes As of 10/4/2017 the following seeder nodes work: ``` -zeropool.cloud -54.144.219.55 +addnode=zeropool.cloud:23801 +addnode=139.162.188.122:23801 +addnode=188.166.2.55:23801 +addnode=94.176.235.178:23801 +addnode=2a01:4f8:a0:8298::2:23801 +addnode=2a02:168:5829:0:b486:978b:2017:dd2:23801 +addnode=213.239.212.246:23801 +addnode=213.32.78.132:23801 +addnode=64.237.50.236:23801 +addnode=139.162.188.122:23801 ``` Check the thread for seeder node updates. From e6c95f05cdcd0fbd20f47efd79b0149776c4fee7 Mon Sep 17 00:00:00 2001 From: backendmaster <34057530+backendmaster@users.noreply.github.com> Date: Thu, 7 Dec 2017 04:55:35 +0200 Subject: [PATCH 139/177] changing date --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ea2825a1560..e790752db71 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ echo "rpcport=23800" >> ~/.zero/zero.conf ``` ### Seeder Nodes -As of 10/4/2017 the following seeder nodes work: +As of 07/12/2017 the following seeder nodes work: ``` addnode=zeropool.cloud:23801 addnode=139.162.188.122:23801 From df8474bd84aaf9fa2236d2338b31e042e313061c Mon Sep 17 00:00:00 2001 From: backendmaster <34057530+backendmaster@users.noreply.github.com> Date: Thu, 7 Dec 2017 04:57:15 +0200 Subject: [PATCH 140/177] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index e790752db71..42ce76b9438 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,10 @@ Announcement Launch date: 2017-02-19 https://bitcointalk.org/index.php?topic=1796036.0 +Comunity took over: +2017-12-05 +https://bitcointalk.org/index.php?topic=2525344.0 + Security Warnings ----------------- From 61345ae70320f2242e83181c799eb044e6af3461 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 7 Dec 2017 10:11:43 -0800 Subject: [PATCH 141/177] Closes #2746. Payment disclosure blobs now use 'zpd:' prefix. --- qa/rpc-tests/paymentdisclosure.py | 11 +++++++++++ src/gtest/test_paymentdisclosure.cpp | 4 +++- src/paymentdisclosure.h | 2 ++ src/wallet/rpcdisclosure.cpp | 18 ++++++++++++------ 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/qa/rpc-tests/paymentdisclosure.py b/qa/rpc-tests/paymentdisclosure.py index 60d6f188f7a..bc873897aa1 100755 --- a/qa/rpc-tests/paymentdisclosure.py +++ b/qa/rpc-tests/paymentdisclosure.py @@ -175,6 +175,17 @@ def run_test (self): assert_equal(result["message"], message) assert_equal(result["value"], output_value_sum) + # Confirm that payment disclosure begins with prefix zpd: + assert(pd.startswith("zpd:")) + + # Confirm that payment disclosure without prefix zpd: fails validation + try: + self.nodes[1].z_validatepaymentdisclosure(pd[4:]) + assert(False) + except JSONRPCException as e: + errorString = e.error['message'] + assert("payment disclosure prefix not found" in errorString) + # Check that total value of output index 0 and index 1 should equal shielding amount of 40 less standard fee. pd = self.nodes[0].z_getpaymentdisclosure(txid, 0, 1) result = self.nodes[0].z_validatepaymentdisclosure(pd) diff --git a/src/gtest/test_paymentdisclosure.cpp b/src/gtest/test_paymentdisclosure.cpp index e87c892975d..ddab3c7e643 100644 --- a/src/gtest/test_paymentdisclosure.cpp +++ b/src/gtest/test_paymentdisclosure.cpp @@ -87,7 +87,9 @@ class PaymentDisclosureDBTest : public PaymentDisclosureDB { // This test creates random payment disclosure blobs and checks that they can be // 1. inserted and retrieved from a database -// 2. serialized and deserialized without corruption +// 2. serialized and deserialized without corruption +// Note that the zpd: prefix is not part of the payment disclosure blob itself. It is only +// used as convention to improve the user experience when sharing payment disclosure blobs. TEST(paymentdisclosure, mainnet) { ECC_Start(); SelectParams(CBaseChainParams::MAIN); diff --git a/src/paymentdisclosure.h b/src/paymentdisclosure.h index b4f56eb459a..e6a995ab4f8 100644 --- a/src/paymentdisclosure.h +++ b/src/paymentdisclosure.h @@ -28,6 +28,8 @@ #define PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL 0 +#define PAYMENT_DISCLOSURE_BLOB_STRING_PREFIX "zpd:" + typedef JSOutPoint PaymentDisclosureKey; struct PaymentDisclosureInfo { diff --git a/src/wallet/rpcdisclosure.cpp b/src/wallet/rpcdisclosure.cpp index c1c8cb87c55..539cf4b2a91 100644 --- a/src/wallet/rpcdisclosure.cpp +++ b/src/wallet/rpcdisclosure.cpp @@ -59,7 +59,7 @@ UniValue z_getpaymentdisclosure(const UniValue& params, bool fHelp) "3. \"output_index\" (string, required) \n" "4. \"message\" (string, optional) \n" "\nResult:\n" - "\"paymentblob\" (string) Hex string of payment blob\n" + "\"paymentdisclosure\" (string) Hex data string, with \"zpd:\" prefix.\n" "\nExamples:\n" + HelpExampleCli("z_getpaymentdisclosure", "96f12882450429324d5f3b48630e3168220e49ab7b0f066e5c2935a6b88bb0f2 0 0 \"refund\"") + HelpExampleRpc("z_getpaymentdisclosure", "\"96f12882450429324d5f3b48630e3168220e49ab7b0f066e5c2935a6b88bb0f2\", 0, 0, \"refund\"") @@ -134,7 +134,7 @@ UniValue z_getpaymentdisclosure(const UniValue& params, bool fHelp) CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << pd; string strHex = HexStr(ss.begin(), ss.end()); - return strHex; + return PAYMENT_DISCLOSURE_BLOB_STRING_PREFIX + strHex; } @@ -160,10 +160,10 @@ UniValue z_validatepaymentdisclosure(const UniValue& params, bool fHelp) "\nEXPERIMENTAL FEATURE\n" + strPaymentDisclosureDisabledMsg + "\nArguments:\n" - "1. \"paymentdisclosure\" (string, required) Hex data string\n" + "1. \"paymentdisclosure\" (string, required) Hex data string, with \"zpd:\" prefix.\n" "\nExamples:\n" - + HelpExampleCli("z_validatepaymentdisclosure", "\"hexblob\"") - + HelpExampleRpc("z_validatepaymentdisclosure", "\"hexblob\"") + + HelpExampleCli("z_validatepaymentdisclosure", "\"zpd:706462ff004c561a0447ba2ec51184e6c204...\"") + + HelpExampleRpc("z_validatepaymentdisclosure", "\"zpd:706462ff004c561a0447ba2ec51184e6c204...\"") ); if (!fEnablePaymentDisclosure) { @@ -174,7 +174,13 @@ UniValue z_validatepaymentdisclosure(const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(); - string hexInput = params[0].get_str(); + // Verify the payment disclosure input begins with "zpd:" prefix. + string strInput = params[0].get_str(); + size_t pos = strInput.find(PAYMENT_DISCLOSURE_BLOB_STRING_PREFIX); + if (pos != 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, payment disclosure prefix not found."); + } + string hexInput = strInput.substr(strlen(PAYMENT_DISCLOSURE_BLOB_STRING_PREFIX)); if (!IsHex(hexInput)) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected payment disclosure data in hexadecimal format."); From ad6a36ad02de357db6fb44605774ebabb4d4806f Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 9 Nov 2017 22:09:54 +0000 Subject: [PATCH 142/177] Track net value entering and exiting the Sprout circuit Delta values will be stored for new blocks; old blocks can be filled in by re-indexing. The net value currently in the Sprout circuit is only calculated when delta values for all previous blocks are present. --- src/chain.h | 21 +++++++++ src/gtest/test_validation.cpp | 86 +++++++++++++++++++++++++++++++++++ src/main.cpp | 25 ++++++++++ src/txdb.cpp | 1 + 4 files changed, 133 insertions(+) diff --git a/src/chain.h b/src/chain.h index b7e8a9176e2..5e5258339bc 100644 --- a/src/chain.h +++ b/src/chain.h @@ -16,6 +16,8 @@ #include +static const int SPROUT_VALUE_VERSION = 1001400; + struct CDiskBlockPos { int nFile; @@ -144,6 +146,15 @@ class CBlockIndex //! (memory only) The anchor for the tree state up to the end of this block uint256 hashAnchorEnd; + //! Change in value held by the Sprout circuit over this block. + //! Will be boost::none for older blocks on old nodes until a reindex has taken place. + boost::optional nSproutValue; + + //! (memory only) Total value held by the Sprout circuit up to and including this block. + //! Will be boost::none for on old nodes until a reindex has taken place. + //! Will be boost::none if nChainTx is zero. + boost::optional nChainSproutValue; + //! block header int nVersion; uint256 hashMerkleRoot; @@ -172,6 +183,8 @@ class CBlockIndex hashAnchor = uint256(); hashAnchorEnd = uint256(); nSequenceId = 0; + nSproutValue = boost::none; + nChainSproutValue = boost::none; nVersion = 0; hashMerkleRoot = uint256(); @@ -339,6 +352,14 @@ class CDiskBlockIndex : public CBlockIndex READWRITE(nBits); READWRITE(nNonce); READWRITE(nSolution); + + // Only read/write nSproutValue if the client version used to create + // this index was storing them. + // TODO: See if we can get away with not serializing the boost::optional + // one-byte header, without requiring users to reindex on upgrade. + if (nType & SER_DISK && nVersion >= SPROUT_VALUE_VERSION) { + READWRITE(nSproutValue); + } } uint256 GetBlockHash() const diff --git a/src/gtest/test_validation.cpp b/src/gtest/test_validation.cpp index 21ed20d8461..6f603eaecbb 100644 --- a/src/gtest/test_validation.cpp +++ b/src/gtest/test_validation.cpp @@ -2,6 +2,18 @@ #include "consensus/validation.h" #include "main.h" +#include "utiltest.h" + +extern ZCJoinSplit* params; + +extern bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos); + +void ExpectOptionalAmount(CAmount expected, boost::optional actual) { + EXPECT_TRUE((bool)actual); + if (actual) { + EXPECT_EQ(expected, *actual); + } +} // Fake an empty view class FakeCoinsViewDB : public CCoinsView { @@ -61,3 +73,77 @@ TEST(Validation, ContextualCheckInputsPassesWithCoinbase) { CValidationState state; EXPECT_TRUE(ContextualCheckInputs(tx, state, view, false, 0, false, Params(CBaseChainParams::MAIN).GetConsensus())); } + +TEST(Validation, ReceivedBlockTransactions) { + auto sk = libzcash::SpendingKey::random(); + + // Create a fake genesis block + CBlock block1; + block1.vtx.push_back(GetValidReceive(*params, sk, 5, true)); + block1.hashMerkleRoot = block1.BuildMerkleTree(); + CBlockIndex fakeIndex1 {block1}; + + // Create a fake child block + CBlock block2; + block2.hashPrevBlock = block1.GetHash(); + block2.vtx.push_back(GetValidReceive(*params, sk, 10, true)); + block2.hashMerkleRoot = block2.BuildMerkleTree(); + CBlockIndex fakeIndex2 {block2}; + fakeIndex2.pprev = &fakeIndex1; + + CDiskBlockPos pos1; + CDiskBlockPos pos2; + + // Set initial state of indices + ASSERT_TRUE(fakeIndex1.RaiseValidity(BLOCK_VALID_TREE)); + ASSERT_TRUE(fakeIndex2.RaiseValidity(BLOCK_VALID_TREE)); + EXPECT_TRUE(fakeIndex1.IsValid(BLOCK_VALID_TREE)); + EXPECT_TRUE(fakeIndex2.IsValid(BLOCK_VALID_TREE)); + EXPECT_FALSE(fakeIndex1.IsValid(BLOCK_VALID_TRANSACTIONS)); + EXPECT_FALSE(fakeIndex2.IsValid(BLOCK_VALID_TRANSACTIONS)); + + // Sprout pool values should not be set + EXPECT_FALSE((bool)fakeIndex1.nSproutValue); + EXPECT_FALSE((bool)fakeIndex1.nChainSproutValue); + EXPECT_FALSE((bool)fakeIndex2.nSproutValue); + EXPECT_FALSE((bool)fakeIndex2.nChainSproutValue); + + // Mark the second block's transactions as received first + CValidationState state; + EXPECT_TRUE(ReceivedBlockTransactions(block2, state, &fakeIndex2, pos2)); + EXPECT_FALSE(fakeIndex1.IsValid(BLOCK_VALID_TRANSACTIONS)); + EXPECT_TRUE(fakeIndex2.IsValid(BLOCK_VALID_TRANSACTIONS)); + + // Sprout pool value delta should now be set for the second block, + // but not any chain totals + EXPECT_FALSE((bool)fakeIndex1.nSproutValue); + EXPECT_FALSE((bool)fakeIndex1.nChainSproutValue); + { + SCOPED_TRACE("ExpectOptionalAmount call"); + ExpectOptionalAmount(20, fakeIndex2.nSproutValue); + } + EXPECT_FALSE((bool)fakeIndex2.nChainSproutValue); + + // Now mark the first block's transactions as received + EXPECT_TRUE(ReceivedBlockTransactions(block1, state, &fakeIndex1, pos1)); + EXPECT_TRUE(fakeIndex1.IsValid(BLOCK_VALID_TRANSACTIONS)); + EXPECT_TRUE(fakeIndex2.IsValid(BLOCK_VALID_TRANSACTIONS)); + + // Sprout pool values should now be set for both blocks + { + SCOPED_TRACE("ExpectOptionalAmount call"); + ExpectOptionalAmount(10, fakeIndex1.nSproutValue); + } + { + SCOPED_TRACE("ExpectOptionalAmount call"); + ExpectOptionalAmount(10, fakeIndex1.nChainSproutValue); + } + { + SCOPED_TRACE("ExpectOptionalAmount call"); + ExpectOptionalAmount(20, fakeIndex2.nSproutValue); + } + { + SCOPED_TRACE("ExpectOptionalAmount call"); + ExpectOptionalAmount(30, fakeIndex2.nChainSproutValue); + } +} diff --git a/src/main.cpp b/src/main.cpp index a8ec0740349..d8e47caac2a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2835,6 +2835,15 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl { pindexNew->nTx = block.vtx.size(); pindexNew->nChainTx = 0; + CAmount sproutValue = 0; + for (auto tx : block.vtx) { + for (auto js : tx.vjoinsplit) { + sproutValue += js.vpub_old; + sproutValue -= js.vpub_new; + } + } + pindexNew->nSproutValue = sproutValue; + pindexNew->nChainSproutValue = boost::none; pindexNew->nFile = pos.nFile; pindexNew->nDataPos = pos.nPos; pindexNew->nUndoPos = 0; @@ -2852,6 +2861,15 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl CBlockIndex *pindex = queue.front(); queue.pop_front(); pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx; + if (pindex->pprev) { + if (pindex->pprev->nChainSproutValue && pindex->nSproutValue) { + pindex->nChainSproutValue = *pindex->pprev->nChainSproutValue + *pindex->nSproutValue; + } else { + pindex->nChainSproutValue = boost::none; + } + } else { + pindex->nChainSproutValue = pindex->nSproutValue; + } { LOCK(cs_nBlockSequenceId); pindex->nSequenceId = nBlockSequenceId++; @@ -3522,12 +3540,19 @@ bool static LoadBlockIndexDB() if (pindex->pprev) { if (pindex->pprev->nChainTx) { pindex->nChainTx = pindex->pprev->nChainTx + pindex->nTx; + if (pindex->pprev->nChainSproutValue && pindex->nSproutValue) { + pindex->nChainSproutValue = *pindex->pprev->nChainSproutValue + *pindex->nSproutValue; + } else { + pindex->nChainSproutValue = boost::none; + } } else { pindex->nChainTx = 0; + pindex->nChainSproutValue = boost::none; mapBlocksUnlinked.insert(std::make_pair(pindex->pprev, pindex)); } } else { pindex->nChainTx = pindex->nTx; + pindex->nChainSproutValue = pindex->nSproutValue; } } if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == NULL)) diff --git a/src/txdb.cpp b/src/txdb.cpp index 004b0be2cec..e1e29d9aca8 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -310,6 +310,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts() pindexNew->nSolution = diskindex.nSolution; pindexNew->nStatus = diskindex.nStatus; pindexNew->nTx = diskindex.nTx; + pindexNew->nSproutValue = diskindex.nSproutValue; if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus())) return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString()); From e319633435e3cd8c1726ebd3d6245200ae3f17c5 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 14 Dec 2017 15:18:08 +0000 Subject: [PATCH 143/177] Add Sprout value pool to getblock and getblockchaininfo --- qa/rpc-tests/wallet_protectcoinbase.py | 34 ++++++++++++++++++++++++-- src/rpcblockchain.cpp | 29 +++++++++++++++++++++- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/qa/rpc-tests/wallet_protectcoinbase.py b/qa/rpc-tests/wallet_protectcoinbase.py index e407f0914ef..5423dcd640a 100755 --- a/qa/rpc-tests/wallet_protectcoinbase.py +++ b/qa/rpc-tests/wallet_protectcoinbase.py @@ -14,6 +14,16 @@ import timeit from decimal import Decimal +def check_value_pool(node, name, total): + value_pools = node.getblockchaininfo()['valuePools'] + found = False + for pool in value_pools: + if pool['id'] == name: + found = True + assert_equal(pool['monitored'], True) + assert_equal(pool['chainValue'], total) + assert(found) + class WalletProtectCoinbaseTest (BitcoinTestFramework): def setup_chain(self): @@ -76,6 +86,11 @@ def run_test (self): assert_equal(self.nodes[2].getbalance(), 0) assert_equal(self.nodes[3].getbalance(), 0) + check_value_pool(self.nodes[0], 'sprout', 0) + check_value_pool(self.nodes[1], 'sprout', 0) + check_value_pool(self.nodes[2], 'sprout', 0) + check_value_pool(self.nodes[3], 'sprout', 0) + # Send will fail because we are enforcing the consensus rule that # coinbase utxos can only be sent to a zaddr. errorString = "" @@ -141,8 +156,9 @@ def run_test (self): assert_equal("wallet does not allow any change" in errorString, True) # This send will succeed. We send two coinbase utxos totalling 20.0 less a fee of 0.00010000, with no change. + shieldvalue = Decimal('20.0') - Decimal('0.0001') recipients = [] - recipients.append({"address":myzaddr, "amount": Decimal('20.0') - Decimal('0.0001')}) + recipients.append({"address":myzaddr, "amount": shieldvalue}) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) mytxid = self.wait_and_assert_operationid_status(myopid) self.sync_all() @@ -169,6 +185,10 @@ def run_test (self): assert_equal(Decimal(resp["private"]), Decimal('19.9999')) assert_equal(Decimal(resp["total"]), Decimal('39.9999')) + # The Sprout value pool should reflect the send + sproutvalue = shieldvalue + check_value_pool(self.nodes[0], 'sprout', sproutvalue) + # A custom fee of 0 is okay. Here the node will send the note value back to itself. recipients = [] recipients.append({"address":myzaddr, "amount": Decimal('19.9999')}) @@ -182,9 +202,13 @@ def run_test (self): assert_equal(Decimal(resp["private"]), Decimal('19.9999')) assert_equal(Decimal(resp["total"]), Decimal('39.9999')) + # The Sprout value pool should be unchanged + check_value_pool(self.nodes[0], 'sprout', sproutvalue) + # convert note to transparent funds + unshieldvalue = Decimal('10.0') recipients = [] - recipients.append({"address":mytaddr, "amount":Decimal('10.0')}) + recipients.append({"address":mytaddr, "amount": unshieldvalue}) myopid = self.nodes[0].z_sendmany(myzaddr, recipients) mytxid = self.wait_and_assert_operationid_status(myopid) assert(mytxid is not None) @@ -198,10 +222,12 @@ def run_test (self): self.sync_all() # check balances + sproutvalue -= unshieldvalue + Decimal('0.0001') resp = self.nodes[0].z_gettotalbalance() assert_equal(Decimal(resp["transparent"]), Decimal('30.0')) assert_equal(Decimal(resp["private"]), Decimal('9.9998')) assert_equal(Decimal(resp["total"]), Decimal('39.9998')) + check_value_pool(self.nodes[0], 'sprout', sproutvalue) # z_sendmany will return an error if there is transparent change output considered dust. # UTXO selection in z_sendmany sorts in ascending order, so smallest utxos are consumed first. @@ -277,7 +303,9 @@ def run_test (self): # check balance node2balance = amount_per_recipient * num_t_recipients + sproutvalue -= node2balance + Decimal('0.0001') assert_equal(self.nodes[2].getbalance(), node2balance) + check_value_pool(self.nodes[0], 'sprout', sproutvalue) # Send will fail because fee is negative try: @@ -336,6 +364,8 @@ def run_test (self): assert_equal(Decimal(resp["private"]), send_amount) resp = self.nodes[0].z_getbalance(myzaddr) assert_equal(Decimal(resp), zbalance - custom_fee - send_amount) + sproutvalue -= custom_fee + check_value_pool(self.nodes[0], 'sprout', sproutvalue) if __name__ == '__main__': WalletProtectCoinbaseTest().main() diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index cbc7109ddb6..363872ede93 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -77,6 +77,25 @@ double GetNetworkDifficulty(const CBlockIndex* blockindex) return GetDifficultyINTERNAL(blockindex, true); } +static UniValue ValuePoolDesc( + const std::string &name, + const boost::optional chainValue, + const boost::optional valueDelta) +{ + UniValue rv(UniValue::VOBJ); + rv.push_back(Pair("id", name)); + rv.push_back(Pair("monitored", (bool)chainValue)); + if (chainValue) { + rv.push_back(Pair("chainValue", ValueFromAmount(*chainValue))); + rv.push_back(Pair("chainValueZat", *chainValue)); + } + if (valueDelta) { + rv.push_back(Pair("valueDelta", ValueFromAmount(*valueDelta))); + rv.push_back(Pair("valueDeltaZat", *valueDelta)); + } + return rv; +} + UniValue blockheaderToJSON(const CBlockIndex* blockindex) { UniValue result(UniValue::VOBJ); @@ -138,6 +157,10 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); result.push_back(Pair("anchor", blockindex->hashAnchorEnd.GetHex())); + UniValue valuePools(UniValue::VARR); + valuePools.push_back(ValuePoolDesc("sprout", blockindex->nChainSproutValue, blockindex->nSproutValue)); + result.push_back(Pair("valuePools", valuePools)); + if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); CBlockIndex *pnext = chainActive.Next(blockindex); @@ -688,8 +711,12 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) pcoinsTip->GetAnchorAt(pcoinsTip->GetBestAnchor(), tree); obj.push_back(Pair("commitments", tree.size())); - const Consensus::Params& consensusParams = Params().GetConsensus(); CBlockIndex* tip = chainActive.Tip(); + UniValue valuePools(UniValue::VARR); + valuePools.push_back(ValuePoolDesc("sprout", tip->nChainSproutValue, boost::none)); + obj.push_back(Pair("valuePools", valuePools)); + + const Consensus::Params& consensusParams = Params().GetConsensus(); UniValue softforks(UniValue::VARR); softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams)); softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams)); From d66bf190cb0796c2551f2fcb00943fb7eeb539ee Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 15 Dec 2017 10:02:54 +0000 Subject: [PATCH 144/177] Apply -fstack-protector-all to libsnark --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index 797fdcfe990..437fc682850 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -45,7 +45,7 @@ $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) -include collate-libsnark collate-libsnark: $(LIBSNARK) -LIBSNARK_CXXFLAGS = -fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1 +LIBSNARK_CXXFLAGS = -fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1 -fstack-protector-all LIBSNARK_CONFIG_FLAGS = CURVE=ALT_BN128 NO_PROCPS=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT NO_COPY_DEPINST=1 NO_COMPILE_LIBGTEST=1 if HAVE_OPENMP LIBSNARK_CONFIG_FLAGS += MULTICORE=1 From 4a617475ecc5d5a5821920de4f49871bd9ba99d4 Mon Sep 17 00:00:00 2001 From: syd Date: Mon, 20 Nov 2017 19:26:34 -0500 Subject: [PATCH 145/177] Fix libsnark test failure. The shorten() method was copying too much into the destination buffer, overflowing it and affecting neighboring data. --- src/snark/src/algebra/fields/bigint.tcc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/snark/src/algebra/fields/bigint.tcc b/src/snark/src/algebra/fields/bigint.tcc index f81addf4530..c1777ad4666 100644 --- a/src/snark/src/algebra/fields/bigint.tcc +++ b/src/snark/src/algebra/fields/bigint.tcc @@ -201,7 +201,7 @@ inline bigint bigint::shorten(const bigint& q, const char *msg) const } } bigint res; - mpn_copyi(res.data, data, n); + mpn_copyi(res.data, data, m); res.limit(q, msg); return res; } From 0100c79405d29239f0495c94fce921b9978bdddb Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 15 Dec 2017 13:03:33 +0000 Subject: [PATCH 146/177] Add Rust and Proton to configure options printout --- configure.ac | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure.ac b/configure.ac index 27c000c2c2a..b44b486a367 100644 --- a/configure.ac +++ b/configure.ac @@ -908,6 +908,8 @@ esac echo echo "Options used to compile and link:" echo " with wallet = $enable_wallet" +echo " with rust = $enable_rust" +echo " with proton = $use_proton" echo " with zmq = $use_zmq" echo " with test = $use_tests" echo " debug enabled = $enable_debug" From 73b220cb0f747016ab83bcee2252cd880f0b3227 Mon Sep 17 00:00:00 2001 From: Jay Graber Date: Mon, 27 Nov 2017 19:55:38 -0800 Subject: [PATCH 147/177] Add rpc test that exercises z_importkey --- qa/pull-tester/rpc-tests.sh | 1 + qa/rpc-tests/zkey_import_export.py | 192 +++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100755 qa/rpc-tests/zkey_import_export.py diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index a09edaf0370..dfbd78f9aea 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -43,6 +43,7 @@ testScripts=( 'disablewallet.py' 'zcjoinsplit.py' 'zcjoinsplitdoublespend.py' + 'zkey_import_export.py' 'getblocktemplate.py' 'bip65-cltv-p2p.py' 'bipdersig-p2p.py' diff --git a/qa/rpc-tests/zkey_import_export.py b/qa/rpc-tests/zkey_import_export.py new file mode 100755 index 00000000000..e9cd94253e0 --- /dev/null +++ b/qa/rpc-tests/zkey_import_export.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python2 +# Copyright (c) 2017 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from decimal import Decimal +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal, assert_greater_than, start_nodes, initialize_chain_clean, connect_nodes_bi + +import logging +import time +import math + +logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO) + + +class ZkeyImportExportTest (BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 5) + + def setup_network(self, split=False): + self.nodes = start_nodes(5, self.options.tmpdir ) + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + connect_nodes_bi(self.nodes,0,3) + connect_nodes_bi(self.nodes,0,4) + self.is_network_split=False + self.sync_all() + + # TODO: Refactor in z_addr test_framework file + # Returns txid if operation was a success or None + def wait_and_assert_operationid_status(self, node, myopid, in_status='success', in_errormsg=None): + print('waiting for async operation {}'.format(myopid)) + opids = [] + opids.append(myopid) + timeout = 300 + status = None + errormsg = None + txid = None + for x in xrange(1, timeout): + results = node.z_getoperationresult(opids) + if len(results)==0: + time.sleep(1) + else: + print("Results", results[0]) + status = results[0]["status"] + if status == "failed": + errormsg = results[0]['error']['message'] + elif status == "success": + txid = results[0]['result']['txid'] + break + print('...returned status: {}'.format(status)) + assert_equal(in_status, status) + if errormsg is not None: + assert(in_errormsg is not None) + assert_equal(in_errormsg in errormsg, True) + print('...returned error: {}'.format(errormsg)) + return txid + + def run_test(self): + [alice, bob, charlie, david, miner] = self.nodes + + def z_send(from_node, from_addr, to_addr, amount): + opid = from_node.z_sendmany(from_addr, [{"address": to_addr, "amount": Decimal(amount)}]) + txid = self.wait_and_assert_operationid_status(from_node, opid) + self.sync_all() + miner.generate(1) + self.sync_all() + + def z_getbalance(node, zaddr): + bal = node.z_getbalance(zaddr) + # Ignore fees for sake of comparison + round_balance = math.ceil(bal*100)/100 + return round_balance + + def verify_utxos(node, amts, zaddr): + amts.sort(reverse=True) + txs = node.z_listreceivedbyaddress(zaddr) + + def cmp_confirmations_high_to_low(a, b): + return cmp(b["amount"], a["amount"]) + + txs.sort(cmp_confirmations_high_to_low) + print("Sorted txs", txs) + print("amts", amts) + + try: + assert_equal(amts, [tx["amount"] for tx in txs]) + except AssertionError: + logging.error( + 'Expected amounts: %r; txs: %r', + amts, txs) + raise + + def get_private_balance(node): + balance = node.z_gettotalbalance() + return balance['private'] + + def find_imported_key(node, import_zaddr): + zaddrs = node.z_listaddresses() + assert(import_zaddr in zaddrs) + return import_zaddr + + # Seed Alice with some funds + alice.generate(10) + self.sync_all() + miner.generate(100) + self.sync_all() + # Shield Alice's coinbase funds to her zaddr + alice_zaddr = alice.z_getnewaddress() + res = alice.z_shieldcoinbase("*", alice_zaddr) + txid = self.wait_and_assert_operationid_status(alice, res['opid']) + miner.generate(6) + self.sync_all() + # List funds + funds = alice.z_listreceivedbyaddress(alice_zaddr) + # print("Alice's funds after shield", funds) + + # Now get a pristine z-address for receiving transfers: + bob_zaddr = bob.z_getnewaddress() + verify_utxos(bob, [], bob_zaddr) + # TODO: Verify that charlie doesn't have funds in addr + # verify_utxos(charlie, []) + + # the amounts of each txn embodied which generates a single UTXO: + amounts = map(Decimal, ['2.3', '3.7', '0.1', '0.5', '1.0', '0.19']) + + # Internal test consistency assertion: + assert_greater_than( + get_private_balance(alice), + reduce(Decimal.__add__, amounts)) + + logging.info("Sending pre-export txns...") + for amount in amounts[0:2]: + z_send(alice, alice_zaddr, bob_zaddr, amount) + + logging.info("Exporting privkey from bob...") + privkey = bob.z_exportkey(bob_zaddr) + + logging.info("Sending post-export txns...") + for amount in amounts[2:4]: + z_send(alice, alice_zaddr, bob_zaddr, amount) + + print("Bob amounts:", amounts[:4]) + verify_utxos(bob, amounts[:4], bob_zaddr) + # verify_utxos(charlie, []) + + logging.info("Importing privkey into charlie...") + # z_importkey rescan defaults to "whenkeyisnew", so should rescan here + charlie.z_importkey(privkey) + ipk_zaddr = find_imported_key(charlie, bob_zaddr) + + # z_importkey should have rescanned for new key, so this should pass: + verify_utxos(charlie, amounts[:4], ipk_zaddr) + + # Verify idempotent behavior: + charlie.z_importkey(privkey) + ipk_zaddr2 = find_imported_key(charlie, bob_zaddr) + + # amounts should be unchanged + verify_utxos(charlie, amounts[:4], ipk_zaddr2) + + logging.info("Sending post-import txns...") + for amount in amounts[4:]: + z_send(alice, alice_zaddr, bob_zaddr, amount) + + verify_utxos(bob, amounts, bob_zaddr) + verify_utxos(charlie, amounts, ipk_zaddr) + verify_utxos(charlie, amounts, ipk_zaddr2) + + # Try to reproduce zombie balance reported in #1936 + # At generated zaddr, receive ZEC, and send ZEC back out. bob -> alice + for amount in amounts[:2]: + print("Sending amount from bob to alice: ", amount) + z_send(bob, bob_zaddr, alice_zaddr, amount) + + balance = float(sum(amounts) - sum(amounts[:2])) + assert_equal(z_getbalance(bob, bob_zaddr), balance) + + # z_import onto new node "david" (blockchain rescan, default or True?) + david.z_importkey(privkey) + d_ipk_zaddr = find_imported_key(david, bob_zaddr) + + # Check if amt bob spent is deducted for charlie and david + assert_equal(z_getbalance(charlie, ipk_zaddr), balance) + assert_equal(z_getbalance(david, d_ipk_zaddr), balance) + +if __name__ == '__main__': + ZkeyImportExportTest().main() From 9d0c70e9e7bec8fc90a533b6f8838807424be9f7 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 15 Dec 2017 18:36:05 +0000 Subject: [PATCH 148/177] Clarify operator precedence in serialization of nSproutValue --- src/chain.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chain.h b/src/chain.h index 5e5258339bc..9d858a609f2 100644 --- a/src/chain.h +++ b/src/chain.h @@ -357,7 +357,7 @@ class CDiskBlockIndex : public CBlockIndex // this index was storing them. // TODO: See if we can get away with not serializing the boost::optional // one-byte header, without requiring users to reindex on upgrade. - if (nType & SER_DISK && nVersion >= SPROUT_VALUE_VERSION) { + if ((nType & SER_DISK) && (nVersion >= SPROUT_VALUE_VERSION)) { READWRITE(nSproutValue); } } From e365ca1c53d996960dce64b75193fe7b809c86fb Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sat, 16 Dec 2017 10:01:26 +0000 Subject: [PATCH 149/177] Remove nSproutValue TODO from CDiskBlockIndex Block indices are flushed to disk when they are marked as dirty, and this happens via enough distinct pathways that it would be sufficiently complex to update nSproutValue via all of them. Thus it is necessary to be able to serialize "no value" for writes by upgraded clients. --- src/chain.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/chain.h b/src/chain.h index 9d858a609f2..a3b1b7ae992 100644 --- a/src/chain.h +++ b/src/chain.h @@ -355,8 +355,6 @@ class CDiskBlockIndex : public CBlockIndex // Only read/write nSproutValue if the client version used to create // this index was storing them. - // TODO: See if we can get away with not serializing the boost::optional - // one-byte header, without requiring users to reindex on upgrade. if ((nType & SER_DISK) && (nVersion >= SPROUT_VALUE_VERSION)) { READWRITE(nSproutValue); } From 8993edfb778832823e825769a116e002cb3aa4bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20Gr=C3=B6n?= Date: Wed, 13 Dec 2017 07:38:46 +0000 Subject: [PATCH 150/177] Deduplicate test utility method wait_and_assert_operationid_status Strictly speaking this is not a true deduplication; the test output will be slightly different (due to inconsistent print statements) but I think this is close enough. --- qa/rpc-tests/mempool_tx_input_limit.py | 33 ++---------------- qa/rpc-tests/paymentdisclosure.py | 35 ++------------------ qa/rpc-tests/prioritisetransaction.py | 28 ---------------- qa/rpc-tests/test_framework/util.py | 28 ++++++++++++++++ qa/rpc-tests/wallet_1941.py | 29 ++-------------- qa/rpc-tests/wallet_protectcoinbase.py | 18 +++++----- qa/rpc-tests/wallet_shieldcoinbase.py | 46 +++++--------------------- qa/rpc-tests/wallet_treestate.py | 36 ++++---------------- 8 files changed, 60 insertions(+), 193 deletions(-) diff --git a/qa/rpc-tests/mempool_tx_input_limit.py b/qa/rpc-tests/mempool_tx_input_limit.py index 538122671c1..c48d73be01c 100755 --- a/qa/rpc-tests/mempool_tx_input_limit.py +++ b/qa/rpc-tests/mempool_tx_input_limit.py @@ -6,7 +6,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, initialize_chain_clean, \ - start_node, connect_nodes + start_node, connect_nodes, wait_and_assert_operationid_status import time from decimal import Decimal @@ -33,34 +33,7 @@ def call_z_sendmany(self, from_addr, to_addr, amount): recipients = [] recipients.append({"address": to_addr, "amount": amount}) myopid = self.nodes[0].z_sendmany(from_addr, recipients) - return self.wait_and_assert_operationid_status(myopid) - - def wait_and_assert_operationid_status(self, myopid, in_status='success', in_errormsg=None): - print('waiting for async operation {}'.format(myopid)) - opids = [] - opids.append(myopid) - timeout = 300 - status = None - errormsg = None - txid = None - for x in xrange(1, timeout): - results = self.nodes[0].z_getoperationresult(opids) - if len(results)==0: - time.sleep(1) - else: - status = results[0]["status"] - if status == "failed": - errormsg = results[0]['error']['message'] - elif status == "success": - txid = results[0]['result']['txid'] - break - print('...returned status: {}'.format(status)) - assert_equal(in_status, status) - if errormsg is not None: - assert(in_errormsg is not None) - assert_equal(in_errormsg in errormsg, True) - print('...returned error: {}'.format(errormsg)) - return txid + return wait_and_assert_operationid_status(self.nodes[0], myopid) def run_test(self): self.nodes[0].generate(100) @@ -126,7 +99,7 @@ def run_test(self): recipients.append({"address":self.nodes[1].getnewaddress(), "amount": spend_taddr_amount - spend_taddr_output - spend_taddr_output}) myopid = self.nodes[0].z_sendmany(node0_zaddr, recipients) - self.wait_and_assert_operationid_status(myopid) + wait_and_assert_operationid_status(self.nodes[0], myopid) self.nodes[1].generate(1) self.sync_all() diff --git a/qa/rpc-tests/paymentdisclosure.py b/qa/rpc-tests/paymentdisclosure.py index 60d6f188f7a..30f0f93d5f5 100755 --- a/qa/rpc-tests/paymentdisclosure.py +++ b/qa/rpc-tests/paymentdisclosure.py @@ -6,9 +6,8 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, initialize_chain_clean, \ - start_node, connect_nodes_bi + start_node, connect_nodes_bi, wait_and_assert_operationid_status -import time from decimal import Decimal class PaymentDisclosureTest (BitcoinTestFramework): @@ -31,34 +30,6 @@ def setup_network(self, split=False): self.is_network_split=False self.sync_all() - # Returns txid if operation was a success or None - def wait_and_assert_operationid_status(self, nodeid, myopid, in_status='success', in_errormsg=None): - print('waiting for async operation {}'.format(myopid)) - opids = [] - opids.append(myopid) - timeout = 300 - status = None - errormsg = None - txid = None - for x in xrange(1, timeout): - results = self.nodes[nodeid].z_getoperationresult(opids) - if len(results)==0: - time.sleep(1) - else: - status = results[0]["status"] - if status == "failed": - errormsg = results[0]['error']['message'] - elif status == "success": - txid = results[0]['result']['txid'] - break - print('...returned status: {}'.format(status)) - assert_equal(in_status, status) - if errormsg is not None: - assert(in_errormsg is not None) - assert(in_errormsg in errormsg) - print('...returned error: {}'.format(errormsg)) - return txid - def run_test (self): print "Mining blocks..." @@ -97,7 +68,7 @@ def run_test (self): # Shield coinbase utxos from node 0 of value 40, standard fee of 0.00010000 recipients = [{"address":myzaddr, "amount":Decimal('40.0')-Decimal('0.0001')}] myopid = self.nodes[0].z_sendmany(mytaddr, recipients) - txid = self.wait_and_assert_operationid_status(0, myopid) + txid = wait_and_assert_operationid_status(self.nodes[0], myopid) # Check the tx has joinsplits assert( len(self.nodes[0].getrawtransaction("" + txid, 1)["vjoinsplit"]) > 0 ) @@ -185,7 +156,7 @@ def run_test (self): node1zaddr = self.nodes[1].z_getnewaddress() recipients = [{"address":node1zaddr, "amount":Decimal('1')}] myopid = self.nodes[0].z_sendmany(myzaddr, recipients) - txid = self.wait_and_assert_operationid_status(0, myopid) + txid = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() diff --git a/qa/rpc-tests/prioritisetransaction.py b/qa/rpc-tests/prioritisetransaction.py index 9eeb72e8cd9..134b9b1607b 100755 --- a/qa/rpc-tests/prioritisetransaction.py +++ b/qa/rpc-tests/prioritisetransaction.py @@ -26,34 +26,6 @@ def setup_network(self, split=False): self.is_network_split=False self.sync_all() - # Returns txid if operation was a success or None - def wait_and_assert_operationid_status(self, myopid, in_status='success', in_errormsg=None): - print('waiting for async operation {}'.format(myopid)) - opids = [] - opids.append(myopid) - timeout = 300 - status = None - errormsg = None - txid = None - for x in xrange(1, timeout): - results = self.nodes[0].z_getoperationresult(opids) - if len(results)==0: - time.sleep(1) - else: - status = results[0]["status"] - if status == "failed": - errormsg = results[0]['error']['message'] - elif status == "success": - txid = results[0]['result']['txid'] - break - print('...returned status: {}'.format(status)) - assert_equal(in_status, status) - if errormsg is not None: - assert(in_errormsg is not None) - assert_equal(in_errormsg in errormsg, True) - print('...returned error: {}'.format(errormsg)) - return txid - def run_test (self): # tx priority is calculated: priority = sum(input_value_in_base_units * input_age)/size_in_bytes diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index 8ac09f47256..92e1b399637 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -368,3 +368,31 @@ def assert_raises(exc, fun, *args, **kwds): raise AssertionError("Unexpected exception raised: "+type(e).__name__) else: raise AssertionError("No exception raised") + +# Returns txid if operation was a success or None +def wait_and_assert_operationid_status(node, myopid, in_status='success', in_errormsg=None): + print('waiting for async operation {}'.format(myopid)) + opids = [] + opids.append(myopid) + timeout = 300 + status = None + errormsg = None + txid = None + for x in xrange(1, timeout): + results = node.z_getoperationresult(opids) + if len(results)==0: + time.sleep(1) + else: + status = results[0]["status"] + if status == "failed": + errormsg = results[0]['error']['message'] + elif status == "success": + txid = results[0]['result']['txid'] + break + print('...returned status: {}'.format(status)) + assert_equal(in_status, status) + if errormsg is not None: + assert(in_errormsg is not None) + assert_equal(in_errormsg in errormsg, True) + print('...returned error: {}'.format(errormsg)) + return txid diff --git a/qa/rpc-tests/wallet_1941.py b/qa/rpc-tests/wallet_1941.py index d6f024020de..d70b514fca7 100755 --- a/qa/rpc-tests/wallet_1941.py +++ b/qa/rpc-tests/wallet_1941.py @@ -8,9 +8,8 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, initialize_chain_clean, \ initialize_datadir, start_nodes, start_node, connect_nodes_bi, \ - bitcoind_processes + bitcoind_processes, wait_and_assert_operationid_status -import time from decimal import Decimal starttime = 1388534400 @@ -41,30 +40,6 @@ def restart_second_node(self, extra_args=[]): connect_nodes_bi(self.nodes, 0, 1) self.sync_all() - def wait_and_assert_operationid_status(self, myopid, in_status='success', in_errormsg=None): - print('waiting for async operation {}'.format(myopid)) - opids = [] - opids.append(myopid) - timeout = 300 - status = None - errormsg = None - for x in xrange(1, timeout): - results = self.nodes[0].z_getoperationresult(opids) - if len(results)==0: - time.sleep(1) - else: - status = results[0]["status"] - if status == "failed": - errormsg = results[0]['error']['message'] - break - print('...returned status: {}'.format(status)) - print('...error msg: {}'.format(errormsg)) - assert_equal(in_status, status) - if errormsg is not None: - assert(in_errormsg is not None) - assert_equal(in_errormsg in errormsg, True) - print('...returned error: {}'.format(errormsg)) - def run_test (self): print "Mining blocks..." @@ -78,7 +53,7 @@ def run_test (self): recipients = [] recipients.append({"address":myzaddr, "amount":Decimal('10.0') - Decimal('0.0001')}) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) - self.wait_and_assert_operationid_status(myopid) + wait_and_assert_operationid_status(self.nodes[0], myopid) self.nodes[0].generate(1) # Ensure the block times of the latest blocks exceed the variability diff --git a/qa/rpc-tests/wallet_protectcoinbase.py b/qa/rpc-tests/wallet_protectcoinbase.py index e407f0914ef..90f9653ba57 100755 --- a/qa/rpc-tests/wallet_protectcoinbase.py +++ b/qa/rpc-tests/wallet_protectcoinbase.py @@ -7,7 +7,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, initialize_chain_clean, \ - start_nodes, connect_nodes_bi, stop_node + start_nodes, connect_nodes_bi, stop_node, wait_and_assert_operationid_status import sys import time @@ -144,7 +144,7 @@ def run_test (self): recipients = [] recipients.append({"address":myzaddr, "amount": Decimal('20.0') - Decimal('0.0001')}) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) - mytxid = self.wait_and_assert_operationid_status(myopid) + mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[1].generate(1) self.sync_all() @@ -173,7 +173,7 @@ def run_test (self): recipients = [] recipients.append({"address":myzaddr, "amount": Decimal('19.9999')}) myopid = self.nodes[0].z_sendmany(myzaddr, recipients, 1, Decimal('0.0')) - mytxid = self.wait_and_assert_operationid_status(myopid) + mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[1].generate(1) self.sync_all() @@ -186,7 +186,7 @@ def run_test (self): recipients = [] recipients.append({"address":mytaddr, "amount":Decimal('10.0')}) myopid = self.nodes[0].z_sendmany(myzaddr, recipients) - mytxid = self.wait_and_assert_operationid_status(myopid) + mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) assert(mytxid is not None) self.sync_all() @@ -210,7 +210,7 @@ def run_test (self): amount = Decimal('10.0') - Decimal('0.00010000') - Decimal('0.00000001') # this leaves change at 1 zatoshi less than dust threshold recipients.append({"address":self.nodes[0].getnewaddress(), "amount":amount }) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) - self.wait_and_assert_operationid_status(myopid, "failed", "Insufficient transparent funds, have 10.00, need 0.00000053 more to avoid creating invalid change output 0.00000001 (dust threshold is 0.00000054)") + wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "Insufficient transparent funds, have 10.00, need 0.00000053 more to avoid creating invalid change output 0.00000001 (dust threshold is 0.00000054)") # Send will fail because send amount is too big, even when including coinbase utxos errorString = "" @@ -224,9 +224,9 @@ def run_test (self): recipients = [] recipients.append({"address":self.nodes[1].getnewaddress(), "amount":Decimal('10000.0')}) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) - self.wait_and_assert_operationid_status(myopid, "failed", "Insufficient transparent funds, have 10.00, need 10000.0001") + wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "Insufficient transparent funds, have 10.00, need 10000.0001") myopid = self.nodes[0].z_sendmany(myzaddr, recipients) - self.wait_and_assert_operationid_status(myopid, "failed", "Insufficient protected funds, have 9.9998, need 10000.0001") + wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "Insufficient protected funds, have 9.9998, need 10000.0001") # Send will fail because of insufficient funds unless sender uses coinbase utxos try: @@ -263,7 +263,7 @@ def run_test (self): myopid = self.nodes[0].z_sendmany(myzaddr, recipients) try: - self.wait_and_assert_operationid_status(myopid) + wait_and_assert_operationid_status(self.nodes[0], myopid) except JSONRPCException as e: print("JSONRPC error: "+e.error['message']) assert(False) @@ -326,7 +326,7 @@ def run_test (self): newzaddr = self.nodes[2].z_getnewaddress() recipients.append({"address":newzaddr, "amount":amount_per_recipient}) myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, custom_fee) - self.wait_and_assert_operationid_status(myopid) + wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[1].generate(1) self.sync_all() diff --git a/qa/rpc-tests/wallet_shieldcoinbase.py b/qa/rpc-tests/wallet_shieldcoinbase.py index 693326c8a63..b77fedcf005 100755 --- a/qa/rpc-tests/wallet_shieldcoinbase.py +++ b/qa/rpc-tests/wallet_shieldcoinbase.py @@ -6,9 +6,9 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, initialize_chain_clean, \ - start_node, connect_nodes_bi, sync_blocks, sync_mempools + start_node, connect_nodes_bi, sync_blocks, sync_mempools, \ + wait_and_assert_operationid_status -import time from decimal import Decimal class WalletShieldCoinbaseTest (BitcoinTestFramework): @@ -30,34 +30,6 @@ def setup_network(self, split=False): self.is_network_split=False self.sync_all() - # Returns txid if operation was a success or None - def wait_and_assert_operationid_status(self, nodeid, myopid, in_status='success', in_errormsg=None): - print('waiting for async operation {}'.format(myopid)) - opids = [] - opids.append(myopid) - timeout = 300 - status = None - errormsg = None - txid = None - for x in xrange(1, timeout): - results = self.nodes[nodeid].z_getoperationresult(opids) - if len(results)==0: - time.sleep(1) - else: - status = results[0]["status"] - if status == "failed": - errormsg = results[0]['error']['message'] - elif status == "success": - txid = results[0]['result']['txid'] - break - print('...returned status: {}'.format(status)) - assert_equal(in_status, status) - if errormsg is not None: - assert(in_errormsg is not None) - assert_equal(in_errormsg in errormsg, True) - print('...returned error: {}'.format(errormsg)) - return txid - def run_test (self): print "Mining blocks..." @@ -130,7 +102,7 @@ def run_test (self): # Shield coinbase utxos from node 0 of value 40, standard fee of 0.00010000 result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr) - self.wait_and_assert_operationid_status(0, result['opid']) + wait_and_assert_operationid_status(self.nodes[0], result['opid']) self.sync_all() self.nodes[1].generate(1) self.sync_all() @@ -144,7 +116,7 @@ def run_test (self): # Shield coinbase utxos from any node 2 taddr, and set fee to 0 result = self.nodes[2].z_shieldcoinbase("*", myzaddr, 0) - self.wait_and_assert_operationid_status(2, result['opid']) + wait_and_assert_operationid_status(self.nodes[2], result['opid']) self.sync_all() self.nodes[1].generate(1) self.sync_all() @@ -181,8 +153,8 @@ def run_test (self): opid2 = result['opid'] # wait for both aysnc operations to complete - self.wait_and_assert_operationid_status(0, opid1) - self.wait_and_assert_operationid_status(0, opid2) + wait_and_assert_operationid_status(self.nodes[0], opid1) + wait_and_assert_operationid_status(self.nodes[0], opid2) # sync_all() invokes sync_mempool() but node 2's mempool limit will cause tx1 and tx2 to be rejected. # So instead, we sync on blocks and mempool for node 0 and node 1, and after a new block is generated @@ -198,7 +170,7 @@ def run_test (self): result = self.nodes[2].z_shieldcoinbase(mytaddr, myzaddr, Decimal('0.0001'), 0) assert_equal(result["shieldingUTXOs"], Decimal('7')) assert_equal(result["remainingUTXOs"], Decimal('13')) - self.wait_and_assert_operationid_status(2, result['opid']) + wait_and_assert_operationid_status(self.nodes[2], result['opid']) self.sync_all() self.nodes[1].generate(1) self.sync_all() @@ -210,13 +182,13 @@ def run_test (self): result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, Decimal('0.0001')) assert_equal(result["shieldingUTXOs"], Decimal('50')) assert_equal(result["remainingUTXOs"], Decimal('50')) - self.wait_and_assert_operationid_status(0, result['opid']) + wait_and_assert_operationid_status(self.nodes[0], result['opid']) # Verify maximum number of utxos which node 0 can shield can be set by the limit parameter result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, Decimal('0.0001'), 33) assert_equal(result["shieldingUTXOs"], Decimal('33')) assert_equal(result["remainingUTXOs"], Decimal('17')) - self.wait_and_assert_operationid_status(0, result['opid']) + wait_and_assert_operationid_status(self.nodes[0], result['opid']) # Don't sync node 2 which rejects the tx due to its mempooltxinputlimit sync_blocks(self.nodes[:2]) sync_mempools(self.nodes[:2]) diff --git a/qa/rpc-tests/wallet_treestate.py b/qa/rpc-tests/wallet_treestate.py index c7fe9bf255a..b3edcd7c5cc 100755 --- a/qa/rpc-tests/wallet_treestate.py +++ b/qa/rpc-tests/wallet_treestate.py @@ -6,7 +6,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, initialize_chain_clean, \ - start_nodes, connect_nodes_bi + start_nodes, connect_nodes_bi, wait_and_assert_operationid_status import time from decimal import Decimal @@ -26,30 +26,6 @@ def setup_network(self, split=False): self.is_network_split=False self.sync_all() - def wait_and_assert_operationid_status(self, myopid, in_status='success', in_errormsg=None): - print('waiting for async operation {}'.format(myopid)) - opids = [] - opids.append(myopid) - timeout = 300 - status = None - errormsg = None - for x in xrange(1, timeout): - results = self.nodes[0].z_getoperationresult(opids) - if len(results)==0: - time.sleep(1) - else: - status = results[0]["status"] - if status == "failed": - errormsg = results[0]['error']['message'] - break - print('...returned status: {}'.format(status)) - print('...error msg: {}'.format(errormsg)) - assert_equal(in_status, status) - if errormsg is not None: - assert(in_errormsg is not None) - assert_equal(in_errormsg in errormsg, True) - print('...returned error: {}'.format(errormsg)) - def run_test (self): print "Mining blocks..." @@ -65,17 +41,17 @@ def run_test (self): recipients = [] recipients.append({"address":myzaddr, "amount":Decimal('10.0') - Decimal('0.0001')}) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) - self.wait_and_assert_operationid_status(myopid) + wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[1].generate(1) self.sync_all() myopid = self.nodes[0].z_sendmany(mytaddr, recipients) - self.wait_and_assert_operationid_status(myopid) + wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[1].generate(1) self.sync_all() myopid = self.nodes[0].z_sendmany(mytaddr, recipients) - self.wait_and_assert_operationid_status(myopid) + wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[1].generate(1) self.sync_all() @@ -92,7 +68,7 @@ def run_test (self): recipients = [] recipients.append({"address":self.nodes[2].z_getnewaddress(), "amount":Decimal('10.0') - Decimal('0.0001')}) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) - self.wait_and_assert_operationid_status(myopid) + wait_and_assert_operationid_status(self.nodes[0], myopid) # Tx 2 will consume all three notes, which must take at least two joinsplits. This is regardless of # the z_sendmany implementation because there are only two inputs per joinsplit. @@ -115,7 +91,7 @@ def run_test (self): self.sync_all() # Wait for Tx 2 to be created - self.wait_and_assert_operationid_status(myopid) + wait_and_assert_operationid_status(self.nodes[0], myopid) # Note that a bug existed in v1.0.0-1.0.3 where Tx 2 creation would fail with an error: # "Witness for spendable note does not have same anchor as change input" From d4ab94a6d945515ee58fcf869641d2bc530dc9d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20Gr=C3=B6n?= Date: Wed, 13 Dec 2017 07:42:10 +0000 Subject: [PATCH 151/177] Print result of RPC call in test only when PYTHON_DEBUG is set --- qa/rpc-tests/test_framework/util.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index 92e1b399637..20267521f35 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -389,10 +389,12 @@ def wait_and_assert_operationid_status(node, myopid, in_status='success', in_err elif status == "success": txid = results[0]['result']['txid'] break - print('...returned status: {}'.format(status)) assert_equal(in_status, status) if errormsg is not None: assert(in_errormsg is not None) assert_equal(in_errormsg in errormsg, True) - print('...returned error: {}'.format(errormsg)) + if os.getenv("PYTHON_DEBUG", ""): + print('...returned status: {}'.format(status)) + if errormsg is not None: + print('...returned error: {}'.format(errormsg)) return txid From a55c186a74aff36a4be6803770d6f07ec8534ec6 Mon Sep 17 00:00:00 2001 From: syd Date: Fri, 24 Nov 2017 13:54:17 -0500 Subject: [PATCH 152/177] Fix libsnark dependency build. This changes libsnark to build in-place, instead of copying first to a build directory. Previously, modifications made to the original sources wouldn't get rebuilt without a 'make clean' because users would be pointing to the copies. This closes #2689. --- src/Makefile.am | 16 +-- src/snark/.gitignore | 83 +++++------ src/snark/Makefile | 134 +++++++++--------- .../algebra/curves/alt_bn128/alt_bn128_g1.cpp | 0 .../algebra/curves/alt_bn128/alt_bn128_g1.hpp | 0 .../algebra/curves/alt_bn128/alt_bn128_g2.cpp | 0 .../algebra/curves/alt_bn128/alt_bn128_g2.hpp | 0 .../curves/alt_bn128/alt_bn128_init.cpp | 0 .../curves/alt_bn128/alt_bn128_init.hpp | 0 .../curves/alt_bn128/alt_bn128_pairing.cpp | 0 .../curves/alt_bn128/alt_bn128_pairing.hpp | 0 .../algebra/curves/alt_bn128/alt_bn128_pp.cpp | 0 .../algebra/curves/alt_bn128/alt_bn128_pp.hpp | 0 .../algebra/curves/curve_utils.hpp | 0 .../algebra/curves/curve_utils.tcc | 0 .../algebra/curves/public_params.hpp | 0 .../algebra/curves/tests/test_bilinearity.cpp | 0 .../algebra/curves/tests/test_groups.cpp | 0 .../domains/basic_radix2_domain.hpp | 0 .../domains/basic_radix2_domain.tcc | 0 .../domains/basic_radix2_domain_aux.hpp | 0 .../domains/basic_radix2_domain_aux.tcc | 0 .../evaluation_domain/evaluation_domain.hpp | 0 .../evaluation_domain/evaluation_domain.tcc | 0 .../algebra/exponentiation/exponentiation.hpp | 0 .../algebra/exponentiation/exponentiation.tcc | 0 .../algebra/fields/bigint.hpp | 0 .../algebra/fields/bigint.tcc | 0 .../algebra/fields/field_utils.hpp | 0 .../algebra/fields/field_utils.tcc | 0 .../{src => libsnark}/algebra/fields/fp.hpp | 0 .../{src => libsnark}/algebra/fields/fp.tcc | 0 .../algebra/fields/fp12_2over3over2.hpp | 0 .../algebra/fields/fp12_2over3over2.tcc | 0 .../{src => libsnark}/algebra/fields/fp2.hpp | 0 .../{src => libsnark}/algebra/fields/fp2.tcc | 0 .../algebra/fields/fp6_3over2.hpp | 0 .../algebra/fields/fp6_3over2.tcc | 0 .../algebra/fields/fp_aux.tcc | 0 .../algebra/fields/tests/test_bigint.cpp | 0 .../algebra/fields/tests/test_fields.cpp | 0 .../knowledge_commitment.hpp | 0 .../knowledge_commitment.tcc | 0 .../scalar_multiplication/kc_multiexp.hpp | 0 .../scalar_multiplication/kc_multiexp.tcc | 0 .../scalar_multiplication/multiexp.hpp | 0 .../scalar_multiplication/multiexp.tcc | 0 .../algebra/scalar_multiplication/wnaf.hpp | 0 .../algebra/scalar_multiplication/wnaf.tcc | 0 .../common/assert_except.hpp | 0 .../data_structures/accumulation_vector.hpp | 0 .../data_structures/accumulation_vector.tcc | 0 .../common/data_structures/merkle_tree.hpp | 0 .../common/data_structures/merkle_tree.tcc | 0 .../common/data_structures/sparse_vector.hpp | 0 .../common/data_structures/sparse_vector.tcc | 0 .../common/default_types/ec_pp.hpp | 0 .../default_types/r1cs_ppzksnark_pp.hpp | 0 .../{src => libsnark}/common/profiling.cpp | 0 .../{src => libsnark}/common/profiling.hpp | 0 .../common/serialization.hpp | 0 .../common/serialization.tcc | 0 .../common/template_utils.hpp | 0 src/snark/{src => libsnark}/common/utils.cpp | 0 src/snark/{src => libsnark}/common/utils.hpp | 0 src/snark/{src => libsnark}/common/utils.tcc | 0 .../gadgetlib1/constraint_profiling.cpp | 0 .../gadgetlib1/constraint_profiling.hpp | 0 .../gadgetlib1/examples/simple_example.hpp | 0 .../gadgetlib1/examples/simple_example.tcc | 0 .../{src => libsnark}/gadgetlib1/gadget.hpp | 0 .../{src => libsnark}/gadgetlib1/gadget.tcc | 0 .../gadgetlib1/gadgets/basic_gadgets.hpp | 0 .../gadgetlib1/gadgets/basic_gadgets.tcc | 0 .../gadgetlib1/gadgets/gadget_from_r1cs.hpp | 0 .../gadgetlib1/gadgets/gadget_from_r1cs.tcc | 0 .../gadgets/hashes/digest_selector_gadget.hpp | 0 .../gadgets/hashes/digest_selector_gadget.tcc | 0 .../gadgetlib1/gadgets/hashes/hash_io.hpp | 0 .../gadgetlib1/gadgets/hashes/hash_io.tcc | 0 .../gadgets/hashes/sha256/sha256_aux.hpp | 0 .../gadgets/hashes/sha256/sha256_aux.tcc | 0 .../hashes/sha256/sha256_components.hpp | 0 .../hashes/sha256/sha256_components.tcc | 0 .../gadgets/hashes/sha256/sha256_gadget.hpp | 0 .../gadgets/hashes/sha256/sha256_gadget.tcc | 0 .../tests/generate_sha256_gadget_tests.py | 0 .../hashes/sha256/tests/pypy_sha256.py | 0 .../sha256/tests/test_sha256_gadget.cpp | 0 .../merkle_authentication_path_variable.hpp | 0 .../merkle_authentication_path_variable.tcc | 0 .../merkle_tree_check_read_gadget.hpp | 0 .../merkle_tree_check_read_gadget.tcc | 0 .../merkle_tree_check_update_gadget.hpp | 0 .../merkle_tree_check_update_gadget.tcc | 0 .../tests/test_merkle_tree_gadgets.cpp | 0 .../gadgetlib1/pb_variable.hpp | 0 .../gadgetlib1/pb_variable.tcc | 0 .../gadgetlib1/protoboard.hpp | 0 .../gadgetlib1/protoboard.tcc | 0 src/snark/{src => libsnark}/gtests.cpp | 0 .../reductions/r1cs_to_qap/r1cs_to_qap.hpp | 0 .../reductions/r1cs_to_qap/r1cs_to_qap.tcc | 0 .../relations/arithmetic_programs/qap/qap.hpp | 0 .../relations/arithmetic_programs/qap/qap.tcc | 0 .../qap/tests/test_qap.cpp | 0 .../r1cs/examples/r1cs_examples.hpp | 0 .../r1cs/examples/r1cs_examples.tcc | 0 .../r1cs/r1cs.hpp | 0 .../r1cs/r1cs.tcc | 0 .../{src => libsnark}/relations/variable.hpp | 0 .../{src => libsnark}/relations/variable.tcc | 0 .../examples/run_r1cs_ppzksnark.hpp | 0 .../examples/run_r1cs_ppzksnark.tcc | 0 .../profiling/profile_r1cs_ppzksnark.cpp | 0 .../r1cs_ppzksnark/r1cs_ppzksnark.hpp | 0 .../r1cs_ppzksnark/r1cs_ppzksnark.tcc | 0 .../r1cs_ppzksnark/r1cs_ppzksnark_params.hpp | 0 .../tests/test_r1cs_ppzksnark.cpp | 0 119 files changed, 114 insertions(+), 119 deletions(-) rename src/snark/{src => libsnark}/algebra/curves/alt_bn128/alt_bn128_g1.cpp (100%) rename src/snark/{src => libsnark}/algebra/curves/alt_bn128/alt_bn128_g1.hpp (100%) rename src/snark/{src => libsnark}/algebra/curves/alt_bn128/alt_bn128_g2.cpp (100%) rename src/snark/{src => libsnark}/algebra/curves/alt_bn128/alt_bn128_g2.hpp (100%) rename src/snark/{src => libsnark}/algebra/curves/alt_bn128/alt_bn128_init.cpp (100%) rename src/snark/{src => libsnark}/algebra/curves/alt_bn128/alt_bn128_init.hpp (100%) rename src/snark/{src => libsnark}/algebra/curves/alt_bn128/alt_bn128_pairing.cpp (100%) rename src/snark/{src => libsnark}/algebra/curves/alt_bn128/alt_bn128_pairing.hpp (100%) rename src/snark/{src => libsnark}/algebra/curves/alt_bn128/alt_bn128_pp.cpp (100%) rename src/snark/{src => libsnark}/algebra/curves/alt_bn128/alt_bn128_pp.hpp (100%) rename src/snark/{src => libsnark}/algebra/curves/curve_utils.hpp (100%) rename src/snark/{src => libsnark}/algebra/curves/curve_utils.tcc (100%) rename src/snark/{src => libsnark}/algebra/curves/public_params.hpp (100%) rename src/snark/{src => libsnark}/algebra/curves/tests/test_bilinearity.cpp (100%) rename src/snark/{src => libsnark}/algebra/curves/tests/test_groups.cpp (100%) rename src/snark/{src => libsnark}/algebra/evaluation_domain/domains/basic_radix2_domain.hpp (100%) rename src/snark/{src => libsnark}/algebra/evaluation_domain/domains/basic_radix2_domain.tcc (100%) rename src/snark/{src => libsnark}/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp (100%) rename src/snark/{src => libsnark}/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc (100%) rename src/snark/{src => libsnark}/algebra/evaluation_domain/evaluation_domain.hpp (100%) rename src/snark/{src => libsnark}/algebra/evaluation_domain/evaluation_domain.tcc (100%) rename src/snark/{src => libsnark}/algebra/exponentiation/exponentiation.hpp (100%) rename src/snark/{src => libsnark}/algebra/exponentiation/exponentiation.tcc (100%) rename src/snark/{src => libsnark}/algebra/fields/bigint.hpp (100%) rename src/snark/{src => libsnark}/algebra/fields/bigint.tcc (100%) rename src/snark/{src => libsnark}/algebra/fields/field_utils.hpp (100%) rename src/snark/{src => libsnark}/algebra/fields/field_utils.tcc (100%) rename src/snark/{src => libsnark}/algebra/fields/fp.hpp (100%) rename src/snark/{src => libsnark}/algebra/fields/fp.tcc (100%) rename src/snark/{src => libsnark}/algebra/fields/fp12_2over3over2.hpp (100%) rename src/snark/{src => libsnark}/algebra/fields/fp12_2over3over2.tcc (100%) rename src/snark/{src => libsnark}/algebra/fields/fp2.hpp (100%) rename src/snark/{src => libsnark}/algebra/fields/fp2.tcc (100%) rename src/snark/{src => libsnark}/algebra/fields/fp6_3over2.hpp (100%) rename src/snark/{src => libsnark}/algebra/fields/fp6_3over2.tcc (100%) rename src/snark/{src => libsnark}/algebra/fields/fp_aux.tcc (100%) rename src/snark/{src => libsnark}/algebra/fields/tests/test_bigint.cpp (100%) rename src/snark/{src => libsnark}/algebra/fields/tests/test_fields.cpp (100%) rename src/snark/{src => libsnark}/algebra/knowledge_commitment/knowledge_commitment.hpp (100%) rename src/snark/{src => libsnark}/algebra/knowledge_commitment/knowledge_commitment.tcc (100%) rename src/snark/{src => libsnark}/algebra/scalar_multiplication/kc_multiexp.hpp (100%) rename src/snark/{src => libsnark}/algebra/scalar_multiplication/kc_multiexp.tcc (100%) rename src/snark/{src => libsnark}/algebra/scalar_multiplication/multiexp.hpp (100%) rename src/snark/{src => libsnark}/algebra/scalar_multiplication/multiexp.tcc (100%) rename src/snark/{src => libsnark}/algebra/scalar_multiplication/wnaf.hpp (100%) rename src/snark/{src => libsnark}/algebra/scalar_multiplication/wnaf.tcc (100%) rename src/snark/{src => libsnark}/common/assert_except.hpp (100%) rename src/snark/{src => libsnark}/common/data_structures/accumulation_vector.hpp (100%) rename src/snark/{src => libsnark}/common/data_structures/accumulation_vector.tcc (100%) rename src/snark/{src => libsnark}/common/data_structures/merkle_tree.hpp (100%) rename src/snark/{src => libsnark}/common/data_structures/merkle_tree.tcc (100%) rename src/snark/{src => libsnark}/common/data_structures/sparse_vector.hpp (100%) rename src/snark/{src => libsnark}/common/data_structures/sparse_vector.tcc (100%) rename src/snark/{src => libsnark}/common/default_types/ec_pp.hpp (100%) rename src/snark/{src => libsnark}/common/default_types/r1cs_ppzksnark_pp.hpp (100%) rename src/snark/{src => libsnark}/common/profiling.cpp (100%) rename src/snark/{src => libsnark}/common/profiling.hpp (100%) rename src/snark/{src => libsnark}/common/serialization.hpp (100%) rename src/snark/{src => libsnark}/common/serialization.tcc (100%) rename src/snark/{src => libsnark}/common/template_utils.hpp (100%) rename src/snark/{src => libsnark}/common/utils.cpp (100%) rename src/snark/{src => libsnark}/common/utils.hpp (100%) rename src/snark/{src => libsnark}/common/utils.tcc (100%) rename src/snark/{src => libsnark}/gadgetlib1/constraint_profiling.cpp (100%) rename src/snark/{src => libsnark}/gadgetlib1/constraint_profiling.hpp (100%) rename src/snark/{src => libsnark}/gadgetlib1/examples/simple_example.hpp (100%) rename src/snark/{src => libsnark}/gadgetlib1/examples/simple_example.tcc (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadget.hpp (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadget.tcc (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/basic_gadgets.hpp (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/basic_gadgets.tcc (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/gadget_from_r1cs.hpp (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/gadget_from_r1cs.tcc (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/hashes/hash_io.hpp (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/hashes/hash_io.tcc (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc (100%) rename src/snark/{src => libsnark}/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp (100%) rename src/snark/{src => libsnark}/gadgetlib1/pb_variable.hpp (100%) rename src/snark/{src => libsnark}/gadgetlib1/pb_variable.tcc (100%) rename src/snark/{src => libsnark}/gadgetlib1/protoboard.hpp (100%) rename src/snark/{src => libsnark}/gadgetlib1/protoboard.tcc (100%) rename src/snark/{src => libsnark}/gtests.cpp (100%) rename src/snark/{src => libsnark}/reductions/r1cs_to_qap/r1cs_to_qap.hpp (100%) rename src/snark/{src => libsnark}/reductions/r1cs_to_qap/r1cs_to_qap.tcc (100%) rename src/snark/{src => libsnark}/relations/arithmetic_programs/qap/qap.hpp (100%) rename src/snark/{src => libsnark}/relations/arithmetic_programs/qap/qap.tcc (100%) rename src/snark/{src => libsnark}/relations/arithmetic_programs/qap/tests/test_qap.cpp (100%) rename src/snark/{src => libsnark}/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp (100%) rename src/snark/{src => libsnark}/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc (100%) rename src/snark/{src => libsnark}/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp (100%) rename src/snark/{src => libsnark}/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc (100%) rename src/snark/{src => libsnark}/relations/variable.hpp (100%) rename src/snark/{src => libsnark}/relations/variable.tcc (100%) rename src/snark/{src => libsnark}/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp (100%) rename src/snark/{src => libsnark}/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc (100%) rename src/snark/{src => libsnark}/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp (100%) rename src/snark/{src => libsnark}/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp (100%) rename src/snark/{src => libsnark}/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc (100%) rename src/snark/{src => libsnark}/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp (100%) rename src/snark/{src => libsnark}/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp (100%) diff --git a/src/Makefile.am b/src/Makefile.am index 25038c1eeef..44b4d8281e2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,8 +23,8 @@ BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include -BITCOIN_INCLUDES += -I$(srcdir)/snark/build/include -BITCOIN_INCLUDES += -I$(srcdir)/snark/build/include/libsnark +BITCOIN_INCLUDES += -I$(srcdir)/snark +BITCOIN_INCLUDES += -I$(srcdir)/snark/libsnark BITCOIN_INCLUDES += -I$(srcdir)/univalue/include LIBBITCOIN_SERVER=libbitcoin_server.a @@ -34,19 +34,13 @@ LIBBITCOIN_CLI=libbitcoin_cli.a LIBBITCOIN_UTIL=libbitcoin_util.a LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a LIBSECP256K1=secp256k1/libsecp256k1.la -LIBSNARK=snark/build/lib/libsnark.a +LIBSNARK=snark/libsnark.a LIBUNIVALUE=univalue/libunivalue.la LIBZCASH=libzcash.a $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) -# A phony target is included here to ensure libsnark is built first, so that its -# header files are collated for use in later build steps. -# See https://stackoverflow.com/a/10726725 --include collate-libsnark -collate-libsnark: $(LIBSNARK) - LIBSNARK_CXXFLAGS = -fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1 -fstack-protector-all LIBSNARK_CONFIG_FLAGS = CURVE=ALT_BN128 NO_PROCPS=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT NO_COPY_DEPINST=1 NO_COMPILE_LIBGTEST=1 if HAVE_OPENMP @@ -54,10 +48,10 @@ LIBSNARK_CONFIG_FLAGS += MULTICORE=1 endif $(LIBSNARK): $(wildcard snark/src/*) - $(AM_V_at) CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ install PREFIX=$(srcdir)/build DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" + $(AM_V_at) CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" libsnark-tests: $(wildcard snark/src/*) - $(AM_V_at) CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ check PREFIX=$(srcdir)/build DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" + $(AM_V_at) CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ check DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" $(LIBUNIVALUE): $(wildcard univalue/lib/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue/ diff --git a/src/snark/.gitignore b/src/snark/.gitignore index bb48e1abade..ea2a20f44a1 100644 --- a/src/snark/.gitignore +++ b/src/snark/.gitignore @@ -2,49 +2,50 @@ *.a *.so *.d +libsnark/gtests depinst/ depsrc/ README.html doxygen/ -src/gtests -src/gadgetlib2/examples/tutorial -src/gadgetlib2/tests/gadgetlib2_test +libsnark/gtests +libsnark/gadgetlib2/examples/tutorial +libsnark/gadgetlib2/tests/gadgetlib2_test -src/algebra/curves/tests/test_bilinearity -src/algebra/curves/tests/test_groups -src/algebra/fields/tests/test_fields -src/common/routing_algorithms/profiling/profile_routing_algorithms -src/common/routing_algorithms/tests/test_routing_algorithms -src/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram -src/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget -src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget -src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets -src/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets -src/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget -src/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget -src/reductions/ram_to_r1cs/examples/demo_arithmetization -src/relations/arithmetic_programs/qap/tests/test_qap -src/relations/arithmetic_programs/ssp/tests/test_ssp -src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd -src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd -src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd -src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd -src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark -src/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark -src/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark -src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark -src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark -src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark -src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark -src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark -src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator -src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover -src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier -src/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark -src/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark -src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark -src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark -src/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark -src/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark -src/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark -src/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark +libsnark/algebra/curves/tests/test_bilinearity +libsnark/algebra/curves/tests/test_groups +libsnark/algebra/fields/tests/test_fields +libsnark/common/routing_algorithms/profiling/profile_routing_algorithms +libsnark/common/routing_algorithms/tests/test_routing_algorithms +libsnark/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram +libsnark/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget +libsnark/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget +libsnark/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets +libsnark/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets +libsnark/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget +libsnark/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget +libsnark/reductions/ram_to_r1cs/examples/demo_arithmetization +libsnark/relations/arithmetic_programs/qap/tests/test_qap +libsnark/relations/arithmetic_programs/ssp/tests/test_ssp +libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd +libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd +libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd +libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd +libsnark/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark +libsnark/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark +libsnark/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark +libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark +libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark +libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark +libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark +libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark +libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator +libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover +libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier +libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark +libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark +libsnark/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark +libsnark/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark +libsnark/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark +libsnark/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark +libsnark/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark +libsnark/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark diff --git a/src/snark/Makefile b/src/snark/Makefile index 1583facf786..b865f992f1d 100644 --- a/src/snark/Makefile +++ b/src/snark/Makefile @@ -17,7 +17,7 @@ CXXFLAGS += -std=c++11 -Wall -Wextra -Wno-unused-parameter -Wno-comment -Wfatal- DEPSRC = depsrc DEPINST = depinst -CXXFLAGS += -I$(DEPINST)/include -Isrc +CXXFLAGS += -I$(DEPINST)/include -Ilibsnark LDFLAGS += -L$(DEPINST)/lib -Wl,-rpath,$(DEPINST)/lib LDLIBS += -lgmpxx -lgmp -lboost_program_options-mt -lsodium # List of .a files to include within libsnark.a and libsnark.so: @@ -44,23 +44,23 @@ ifneq ($(NO_SUPERCOP),1) endif LIB_SRCS = \ - src/algebra/curves/alt_bn128/alt_bn128_g1.cpp \ - src/algebra/curves/alt_bn128/alt_bn128_g2.cpp \ - src/algebra/curves/alt_bn128/alt_bn128_init.cpp \ - src/algebra/curves/alt_bn128/alt_bn128_pairing.cpp \ - src/algebra/curves/alt_bn128/alt_bn128_pp.cpp \ - src/common/profiling.cpp \ - src/common/utils.cpp \ - src/gadgetlib1/constraint_profiling.cpp \ + libsnark/algebra/curves/alt_bn128/alt_bn128_g1.cpp \ + libsnark/algebra/curves/alt_bn128/alt_bn128_g2.cpp \ + libsnark/algebra/curves/alt_bn128/alt_bn128_init.cpp \ + libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.cpp \ + libsnark/algebra/curves/alt_bn128/alt_bn128_pp.cpp \ + libsnark/common/profiling.cpp \ + libsnark/common/utils.cpp \ + libsnark/gadgetlib1/constraint_profiling.cpp \ ifeq ($(CURVE),BN128) LIB_SRCS += \ - src/algebra/curves/bn128/bn128_g1.cpp \ - src/algebra/curves/bn128/bn128_g2.cpp \ - src/algebra/curves/bn128/bn128_gt.cpp \ - src/algebra/curves/bn128/bn128_init.cpp \ - src/algebra/curves/bn128/bn128_pairing.cpp \ - src/algebra/curves/bn128/bn128_pp.cpp + libsnark/algebra/curves/bn128/bn128_g1.cpp \ + libsnark/algebra/curves/bn128/bn128_g2.cpp \ + libsnark/algebra/curves/bn128/bn128_gt.cpp \ + libsnark/algebra/curves/bn128/bn128_init.cpp \ + libsnark/algebra/curves/bn128/bn128_pairing.cpp \ + libsnark/algebra/curves/bn128/bn128_pp.cpp CXXFLAGS += -DBN_SUPPORT_SNARK AR_LIBS += $(DEPINST)/lib/libzm.a @@ -68,56 +68,56 @@ endif # FIXME: most of these are broken due to removed code. DISABLED_EXECUTABLES = \ - src/common/routing_algorithms/profiling/profile_routing_algorithms \ - src/common/routing_algorithms/tests/test_routing_algorithms \ - src/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram \ - src/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget \ - src/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets \ - src/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget \ - src/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget \ - src/reductions/ram_to_r1cs/examples/demo_arithmetization \ - src/relations/arithmetic_programs/ssp/tests/test_ssp \ - src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd \ - src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd \ - src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd \ - src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd \ - src/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark \ - src/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark \ - src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark \ - src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark \ - src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark \ - src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark \ - src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator \ - src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover \ - src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier \ - src/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark \ - src/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark \ - src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark \ - src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark \ - src/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark \ - src/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark \ - src/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark \ - src/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark + libsnark/common/routing_algorithms/profiling/profile_routing_algorithms \ + libsnark/common/routing_algorithms/tests/test_routing_algorithms \ + libsnark/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram \ + libsnark/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget \ + libsnark/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets \ + libsnark/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget \ + libsnark/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget \ + libsnark/reductions/ram_to_r1cs/examples/demo_arithmetization \ + libsnark/relations/arithmetic_programs/ssp/tests/test_ssp \ + libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd \ + libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd \ + libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd \ + libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd \ + libsnark/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator \ + libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover \ + libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier \ + libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark \ + libsnark/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark \ + libsnark/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark EXECUTABLES = EXECUTABLES_WITH_GTEST = EXECUTABLES_WITH_SUPERCOP = \ - src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark + libsnark/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark -GTEST_TESTS = src/gtests +GTEST_TESTS = libsnark/gtests GTEST_SRCS = \ - src/algebra/curves/tests/test_bilinearity.cpp \ - src/algebra/curves/tests/test_groups.cpp \ - src/algebra/fields/tests/test_bigint.cpp \ - src/algebra/fields/tests/test_fields.cpp \ - src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp \ - src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp \ - src/relations/arithmetic_programs/qap/tests/test_qap.cpp \ - src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp \ - src/gtests.cpp + libsnark/algebra/curves/tests/test_bilinearity.cpp \ + libsnark/algebra/curves/tests/test_groups.cpp \ + libsnark/algebra/fields/tests/test_bigint.cpp \ + libsnark/algebra/fields/tests/test_fields.cpp \ + libsnark/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp \ + libsnark/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp \ + libsnark/relations/arithmetic_programs/qap/tests/test_qap.cpp \ + libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp \ + libsnark/gtests.cpp DOCS = README.html @@ -192,7 +192,7 @@ $(LIB_OBJS) $(if $(NO_GTEST),,$(GTEST_OBJS)) $(EXEC_OBJS): %.o: %.cpp LIBGTEST_A = $(DEPINST)/lib/libgtest.a -$(LIBGTEST_A): $(GTESTDIR)/src/gtest-all.cc $(DEPINST_EXISTS) +$(LIBGTEST_A): $(GTESTDIR)/libsnark/gtest-all.cc $(DEPINST_EXISTS) $(CXX) -o $(DEPINST)/lib/gtest-all.o -I $(GTESTDIR) -c -isystem $(GTESTDIR)/include $< $(CXXFLAGS) $(AR) -rv $(LIBGTEST_A) $(DEPINST)/lib/gtest-all.o @@ -205,13 +205,13 @@ $(LIBSNARK_A): $(LIB_OBJS) $(AR_LIBS) libsnark.so: $(LIBSNARK_A) $(DEPINST_EXISTS) $(CXX) -o $@ --shared -Wl,--whole-archive $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) -Wl,--no-whole-archive $(LDLIBS) -src/gadgetlib2/tests/gadgetlib2_test: \ - src/gadgetlib2/tests/adapters_UTEST.cpp \ - src/gadgetlib2/tests/constraint_UTEST.cpp \ - src/gadgetlib2/tests/gadget_UTEST.cpp \ - src/gadgetlib2/tests/integration_UTEST.cpp \ - src/gadgetlib2/tests/protoboard_UTEST.cpp \ - src/gadgetlib2/tests/variable_UTEST.cpp +libsnark/gadgetlib2/tests/gadgetlib2_test: \ + libsnark/gadgetlib2/tests/adapters_UTEST.cpp \ + libsnark/gadgetlib2/tests/constraint_UTEST.cpp \ + libsnark/gadgetlib2/tests/gadget_UTEST.cpp \ + libsnark/gadgetlib2/tests/integration_UTEST.cpp \ + libsnark/gadgetlib2/tests/protoboard_UTEST.cpp \ + libsnark/gadgetlib2/tests/variable_UTEST.cpp $(EXECUTABLES): %: %.o $(LIBSNARK_A) $(DEPINST_EXISTS) $(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(LDLIBS) @@ -243,10 +243,10 @@ ifeq ($(PREFIX),) install: $(error Please provide PREFIX. E.g. make install PREFIX=/usr) else -HEADERS_SRC=$(shell find src -name '*.hpp' -o -name '*.tcc') -HEADERS_DEST=$(patsubst src/%,$(PREFIX)/include/libsnark/%,$(HEADERS_SRC)) +HEADERS_SRC=$(shell find libsnark -name '*.hpp' -o -name '*.tcc') +HEADERS_DEST=$(patsubst libsnark/%,$(PREFIX)/include/libsnark/%,$(HEADERS_SRC)) -$(HEADERS_DEST): $(PREFIX)/include/libsnark/%: src/% +$(HEADERS_DEST): $(PREFIX)/include/libsnark/%: libsnark/% mkdir -p $(shell dirname $@) cp $< $@ diff --git a/src/snark/src/algebra/curves/alt_bn128/alt_bn128_g1.cpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g1.cpp similarity index 100% rename from src/snark/src/algebra/curves/alt_bn128/alt_bn128_g1.cpp rename to src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g1.cpp diff --git a/src/snark/src/algebra/curves/alt_bn128/alt_bn128_g1.hpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g1.hpp similarity index 100% rename from src/snark/src/algebra/curves/alt_bn128/alt_bn128_g1.hpp rename to src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g1.hpp diff --git a/src/snark/src/algebra/curves/alt_bn128/alt_bn128_g2.cpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.cpp similarity index 100% rename from src/snark/src/algebra/curves/alt_bn128/alt_bn128_g2.cpp rename to src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.cpp diff --git a/src/snark/src/algebra/curves/alt_bn128/alt_bn128_g2.hpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.hpp similarity index 100% rename from src/snark/src/algebra/curves/alt_bn128/alt_bn128_g2.hpp rename to src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.hpp diff --git a/src/snark/src/algebra/curves/alt_bn128/alt_bn128_init.cpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_init.cpp similarity index 100% rename from src/snark/src/algebra/curves/alt_bn128/alt_bn128_init.cpp rename to src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_init.cpp diff --git a/src/snark/src/algebra/curves/alt_bn128/alt_bn128_init.hpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_init.hpp similarity index 100% rename from src/snark/src/algebra/curves/alt_bn128/alt_bn128_init.hpp rename to src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_init.hpp diff --git a/src/snark/src/algebra/curves/alt_bn128/alt_bn128_pairing.cpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.cpp similarity index 100% rename from src/snark/src/algebra/curves/alt_bn128/alt_bn128_pairing.cpp rename to src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.cpp diff --git a/src/snark/src/algebra/curves/alt_bn128/alt_bn128_pairing.hpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.hpp similarity index 100% rename from src/snark/src/algebra/curves/alt_bn128/alt_bn128_pairing.hpp rename to src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.hpp diff --git a/src/snark/src/algebra/curves/alt_bn128/alt_bn128_pp.cpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pp.cpp similarity index 100% rename from src/snark/src/algebra/curves/alt_bn128/alt_bn128_pp.cpp rename to src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pp.cpp diff --git a/src/snark/src/algebra/curves/alt_bn128/alt_bn128_pp.hpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pp.hpp similarity index 100% rename from src/snark/src/algebra/curves/alt_bn128/alt_bn128_pp.hpp rename to src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pp.hpp diff --git a/src/snark/src/algebra/curves/curve_utils.hpp b/src/snark/libsnark/algebra/curves/curve_utils.hpp similarity index 100% rename from src/snark/src/algebra/curves/curve_utils.hpp rename to src/snark/libsnark/algebra/curves/curve_utils.hpp diff --git a/src/snark/src/algebra/curves/curve_utils.tcc b/src/snark/libsnark/algebra/curves/curve_utils.tcc similarity index 100% rename from src/snark/src/algebra/curves/curve_utils.tcc rename to src/snark/libsnark/algebra/curves/curve_utils.tcc diff --git a/src/snark/src/algebra/curves/public_params.hpp b/src/snark/libsnark/algebra/curves/public_params.hpp similarity index 100% rename from src/snark/src/algebra/curves/public_params.hpp rename to src/snark/libsnark/algebra/curves/public_params.hpp diff --git a/src/snark/src/algebra/curves/tests/test_bilinearity.cpp b/src/snark/libsnark/algebra/curves/tests/test_bilinearity.cpp similarity index 100% rename from src/snark/src/algebra/curves/tests/test_bilinearity.cpp rename to src/snark/libsnark/algebra/curves/tests/test_bilinearity.cpp diff --git a/src/snark/src/algebra/curves/tests/test_groups.cpp b/src/snark/libsnark/algebra/curves/tests/test_groups.cpp similarity index 100% rename from src/snark/src/algebra/curves/tests/test_groups.cpp rename to src/snark/libsnark/algebra/curves/tests/test_groups.cpp diff --git a/src/snark/src/algebra/evaluation_domain/domains/basic_radix2_domain.hpp b/src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain.hpp similarity index 100% rename from src/snark/src/algebra/evaluation_domain/domains/basic_radix2_domain.hpp rename to src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain.hpp diff --git a/src/snark/src/algebra/evaluation_domain/domains/basic_radix2_domain.tcc b/src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain.tcc similarity index 100% rename from src/snark/src/algebra/evaluation_domain/domains/basic_radix2_domain.tcc rename to src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain.tcc diff --git a/src/snark/src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp b/src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp similarity index 100% rename from src/snark/src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp rename to src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp diff --git a/src/snark/src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc b/src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc similarity index 100% rename from src/snark/src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc rename to src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc diff --git a/src/snark/src/algebra/evaluation_domain/evaluation_domain.hpp b/src/snark/libsnark/algebra/evaluation_domain/evaluation_domain.hpp similarity index 100% rename from src/snark/src/algebra/evaluation_domain/evaluation_domain.hpp rename to src/snark/libsnark/algebra/evaluation_domain/evaluation_domain.hpp diff --git a/src/snark/src/algebra/evaluation_domain/evaluation_domain.tcc b/src/snark/libsnark/algebra/evaluation_domain/evaluation_domain.tcc similarity index 100% rename from src/snark/src/algebra/evaluation_domain/evaluation_domain.tcc rename to src/snark/libsnark/algebra/evaluation_domain/evaluation_domain.tcc diff --git a/src/snark/src/algebra/exponentiation/exponentiation.hpp b/src/snark/libsnark/algebra/exponentiation/exponentiation.hpp similarity index 100% rename from src/snark/src/algebra/exponentiation/exponentiation.hpp rename to src/snark/libsnark/algebra/exponentiation/exponentiation.hpp diff --git a/src/snark/src/algebra/exponentiation/exponentiation.tcc b/src/snark/libsnark/algebra/exponentiation/exponentiation.tcc similarity index 100% rename from src/snark/src/algebra/exponentiation/exponentiation.tcc rename to src/snark/libsnark/algebra/exponentiation/exponentiation.tcc diff --git a/src/snark/src/algebra/fields/bigint.hpp b/src/snark/libsnark/algebra/fields/bigint.hpp similarity index 100% rename from src/snark/src/algebra/fields/bigint.hpp rename to src/snark/libsnark/algebra/fields/bigint.hpp diff --git a/src/snark/src/algebra/fields/bigint.tcc b/src/snark/libsnark/algebra/fields/bigint.tcc similarity index 100% rename from src/snark/src/algebra/fields/bigint.tcc rename to src/snark/libsnark/algebra/fields/bigint.tcc diff --git a/src/snark/src/algebra/fields/field_utils.hpp b/src/snark/libsnark/algebra/fields/field_utils.hpp similarity index 100% rename from src/snark/src/algebra/fields/field_utils.hpp rename to src/snark/libsnark/algebra/fields/field_utils.hpp diff --git a/src/snark/src/algebra/fields/field_utils.tcc b/src/snark/libsnark/algebra/fields/field_utils.tcc similarity index 100% rename from src/snark/src/algebra/fields/field_utils.tcc rename to src/snark/libsnark/algebra/fields/field_utils.tcc diff --git a/src/snark/src/algebra/fields/fp.hpp b/src/snark/libsnark/algebra/fields/fp.hpp similarity index 100% rename from src/snark/src/algebra/fields/fp.hpp rename to src/snark/libsnark/algebra/fields/fp.hpp diff --git a/src/snark/src/algebra/fields/fp.tcc b/src/snark/libsnark/algebra/fields/fp.tcc similarity index 100% rename from src/snark/src/algebra/fields/fp.tcc rename to src/snark/libsnark/algebra/fields/fp.tcc diff --git a/src/snark/src/algebra/fields/fp12_2over3over2.hpp b/src/snark/libsnark/algebra/fields/fp12_2over3over2.hpp similarity index 100% rename from src/snark/src/algebra/fields/fp12_2over3over2.hpp rename to src/snark/libsnark/algebra/fields/fp12_2over3over2.hpp diff --git a/src/snark/src/algebra/fields/fp12_2over3over2.tcc b/src/snark/libsnark/algebra/fields/fp12_2over3over2.tcc similarity index 100% rename from src/snark/src/algebra/fields/fp12_2over3over2.tcc rename to src/snark/libsnark/algebra/fields/fp12_2over3over2.tcc diff --git a/src/snark/src/algebra/fields/fp2.hpp b/src/snark/libsnark/algebra/fields/fp2.hpp similarity index 100% rename from src/snark/src/algebra/fields/fp2.hpp rename to src/snark/libsnark/algebra/fields/fp2.hpp diff --git a/src/snark/src/algebra/fields/fp2.tcc b/src/snark/libsnark/algebra/fields/fp2.tcc similarity index 100% rename from src/snark/src/algebra/fields/fp2.tcc rename to src/snark/libsnark/algebra/fields/fp2.tcc diff --git a/src/snark/src/algebra/fields/fp6_3over2.hpp b/src/snark/libsnark/algebra/fields/fp6_3over2.hpp similarity index 100% rename from src/snark/src/algebra/fields/fp6_3over2.hpp rename to src/snark/libsnark/algebra/fields/fp6_3over2.hpp diff --git a/src/snark/src/algebra/fields/fp6_3over2.tcc b/src/snark/libsnark/algebra/fields/fp6_3over2.tcc similarity index 100% rename from src/snark/src/algebra/fields/fp6_3over2.tcc rename to src/snark/libsnark/algebra/fields/fp6_3over2.tcc diff --git a/src/snark/src/algebra/fields/fp_aux.tcc b/src/snark/libsnark/algebra/fields/fp_aux.tcc similarity index 100% rename from src/snark/src/algebra/fields/fp_aux.tcc rename to src/snark/libsnark/algebra/fields/fp_aux.tcc diff --git a/src/snark/src/algebra/fields/tests/test_bigint.cpp b/src/snark/libsnark/algebra/fields/tests/test_bigint.cpp similarity index 100% rename from src/snark/src/algebra/fields/tests/test_bigint.cpp rename to src/snark/libsnark/algebra/fields/tests/test_bigint.cpp diff --git a/src/snark/src/algebra/fields/tests/test_fields.cpp b/src/snark/libsnark/algebra/fields/tests/test_fields.cpp similarity index 100% rename from src/snark/src/algebra/fields/tests/test_fields.cpp rename to src/snark/libsnark/algebra/fields/tests/test_fields.cpp diff --git a/src/snark/src/algebra/knowledge_commitment/knowledge_commitment.hpp b/src/snark/libsnark/algebra/knowledge_commitment/knowledge_commitment.hpp similarity index 100% rename from src/snark/src/algebra/knowledge_commitment/knowledge_commitment.hpp rename to src/snark/libsnark/algebra/knowledge_commitment/knowledge_commitment.hpp diff --git a/src/snark/src/algebra/knowledge_commitment/knowledge_commitment.tcc b/src/snark/libsnark/algebra/knowledge_commitment/knowledge_commitment.tcc similarity index 100% rename from src/snark/src/algebra/knowledge_commitment/knowledge_commitment.tcc rename to src/snark/libsnark/algebra/knowledge_commitment/knowledge_commitment.tcc diff --git a/src/snark/src/algebra/scalar_multiplication/kc_multiexp.hpp b/src/snark/libsnark/algebra/scalar_multiplication/kc_multiexp.hpp similarity index 100% rename from src/snark/src/algebra/scalar_multiplication/kc_multiexp.hpp rename to src/snark/libsnark/algebra/scalar_multiplication/kc_multiexp.hpp diff --git a/src/snark/src/algebra/scalar_multiplication/kc_multiexp.tcc b/src/snark/libsnark/algebra/scalar_multiplication/kc_multiexp.tcc similarity index 100% rename from src/snark/src/algebra/scalar_multiplication/kc_multiexp.tcc rename to src/snark/libsnark/algebra/scalar_multiplication/kc_multiexp.tcc diff --git a/src/snark/src/algebra/scalar_multiplication/multiexp.hpp b/src/snark/libsnark/algebra/scalar_multiplication/multiexp.hpp similarity index 100% rename from src/snark/src/algebra/scalar_multiplication/multiexp.hpp rename to src/snark/libsnark/algebra/scalar_multiplication/multiexp.hpp diff --git a/src/snark/src/algebra/scalar_multiplication/multiexp.tcc b/src/snark/libsnark/algebra/scalar_multiplication/multiexp.tcc similarity index 100% rename from src/snark/src/algebra/scalar_multiplication/multiexp.tcc rename to src/snark/libsnark/algebra/scalar_multiplication/multiexp.tcc diff --git a/src/snark/src/algebra/scalar_multiplication/wnaf.hpp b/src/snark/libsnark/algebra/scalar_multiplication/wnaf.hpp similarity index 100% rename from src/snark/src/algebra/scalar_multiplication/wnaf.hpp rename to src/snark/libsnark/algebra/scalar_multiplication/wnaf.hpp diff --git a/src/snark/src/algebra/scalar_multiplication/wnaf.tcc b/src/snark/libsnark/algebra/scalar_multiplication/wnaf.tcc similarity index 100% rename from src/snark/src/algebra/scalar_multiplication/wnaf.tcc rename to src/snark/libsnark/algebra/scalar_multiplication/wnaf.tcc diff --git a/src/snark/src/common/assert_except.hpp b/src/snark/libsnark/common/assert_except.hpp similarity index 100% rename from src/snark/src/common/assert_except.hpp rename to src/snark/libsnark/common/assert_except.hpp diff --git a/src/snark/src/common/data_structures/accumulation_vector.hpp b/src/snark/libsnark/common/data_structures/accumulation_vector.hpp similarity index 100% rename from src/snark/src/common/data_structures/accumulation_vector.hpp rename to src/snark/libsnark/common/data_structures/accumulation_vector.hpp diff --git a/src/snark/src/common/data_structures/accumulation_vector.tcc b/src/snark/libsnark/common/data_structures/accumulation_vector.tcc similarity index 100% rename from src/snark/src/common/data_structures/accumulation_vector.tcc rename to src/snark/libsnark/common/data_structures/accumulation_vector.tcc diff --git a/src/snark/src/common/data_structures/merkle_tree.hpp b/src/snark/libsnark/common/data_structures/merkle_tree.hpp similarity index 100% rename from src/snark/src/common/data_structures/merkle_tree.hpp rename to src/snark/libsnark/common/data_structures/merkle_tree.hpp diff --git a/src/snark/src/common/data_structures/merkle_tree.tcc b/src/snark/libsnark/common/data_structures/merkle_tree.tcc similarity index 100% rename from src/snark/src/common/data_structures/merkle_tree.tcc rename to src/snark/libsnark/common/data_structures/merkle_tree.tcc diff --git a/src/snark/src/common/data_structures/sparse_vector.hpp b/src/snark/libsnark/common/data_structures/sparse_vector.hpp similarity index 100% rename from src/snark/src/common/data_structures/sparse_vector.hpp rename to src/snark/libsnark/common/data_structures/sparse_vector.hpp diff --git a/src/snark/src/common/data_structures/sparse_vector.tcc b/src/snark/libsnark/common/data_structures/sparse_vector.tcc similarity index 100% rename from src/snark/src/common/data_structures/sparse_vector.tcc rename to src/snark/libsnark/common/data_structures/sparse_vector.tcc diff --git a/src/snark/src/common/default_types/ec_pp.hpp b/src/snark/libsnark/common/default_types/ec_pp.hpp similarity index 100% rename from src/snark/src/common/default_types/ec_pp.hpp rename to src/snark/libsnark/common/default_types/ec_pp.hpp diff --git a/src/snark/src/common/default_types/r1cs_ppzksnark_pp.hpp b/src/snark/libsnark/common/default_types/r1cs_ppzksnark_pp.hpp similarity index 100% rename from src/snark/src/common/default_types/r1cs_ppzksnark_pp.hpp rename to src/snark/libsnark/common/default_types/r1cs_ppzksnark_pp.hpp diff --git a/src/snark/src/common/profiling.cpp b/src/snark/libsnark/common/profiling.cpp similarity index 100% rename from src/snark/src/common/profiling.cpp rename to src/snark/libsnark/common/profiling.cpp diff --git a/src/snark/src/common/profiling.hpp b/src/snark/libsnark/common/profiling.hpp similarity index 100% rename from src/snark/src/common/profiling.hpp rename to src/snark/libsnark/common/profiling.hpp diff --git a/src/snark/src/common/serialization.hpp b/src/snark/libsnark/common/serialization.hpp similarity index 100% rename from src/snark/src/common/serialization.hpp rename to src/snark/libsnark/common/serialization.hpp diff --git a/src/snark/src/common/serialization.tcc b/src/snark/libsnark/common/serialization.tcc similarity index 100% rename from src/snark/src/common/serialization.tcc rename to src/snark/libsnark/common/serialization.tcc diff --git a/src/snark/src/common/template_utils.hpp b/src/snark/libsnark/common/template_utils.hpp similarity index 100% rename from src/snark/src/common/template_utils.hpp rename to src/snark/libsnark/common/template_utils.hpp diff --git a/src/snark/src/common/utils.cpp b/src/snark/libsnark/common/utils.cpp similarity index 100% rename from src/snark/src/common/utils.cpp rename to src/snark/libsnark/common/utils.cpp diff --git a/src/snark/src/common/utils.hpp b/src/snark/libsnark/common/utils.hpp similarity index 100% rename from src/snark/src/common/utils.hpp rename to src/snark/libsnark/common/utils.hpp diff --git a/src/snark/src/common/utils.tcc b/src/snark/libsnark/common/utils.tcc similarity index 100% rename from src/snark/src/common/utils.tcc rename to src/snark/libsnark/common/utils.tcc diff --git a/src/snark/src/gadgetlib1/constraint_profiling.cpp b/src/snark/libsnark/gadgetlib1/constraint_profiling.cpp similarity index 100% rename from src/snark/src/gadgetlib1/constraint_profiling.cpp rename to src/snark/libsnark/gadgetlib1/constraint_profiling.cpp diff --git a/src/snark/src/gadgetlib1/constraint_profiling.hpp b/src/snark/libsnark/gadgetlib1/constraint_profiling.hpp similarity index 100% rename from src/snark/src/gadgetlib1/constraint_profiling.hpp rename to src/snark/libsnark/gadgetlib1/constraint_profiling.hpp diff --git a/src/snark/src/gadgetlib1/examples/simple_example.hpp b/src/snark/libsnark/gadgetlib1/examples/simple_example.hpp similarity index 100% rename from src/snark/src/gadgetlib1/examples/simple_example.hpp rename to src/snark/libsnark/gadgetlib1/examples/simple_example.hpp diff --git a/src/snark/src/gadgetlib1/examples/simple_example.tcc b/src/snark/libsnark/gadgetlib1/examples/simple_example.tcc similarity index 100% rename from src/snark/src/gadgetlib1/examples/simple_example.tcc rename to src/snark/libsnark/gadgetlib1/examples/simple_example.tcc diff --git a/src/snark/src/gadgetlib1/gadget.hpp b/src/snark/libsnark/gadgetlib1/gadget.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadget.hpp rename to src/snark/libsnark/gadgetlib1/gadget.hpp diff --git a/src/snark/src/gadgetlib1/gadget.tcc b/src/snark/libsnark/gadgetlib1/gadget.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadget.tcc rename to src/snark/libsnark/gadgetlib1/gadget.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/basic_gadgets.hpp b/src/snark/libsnark/gadgetlib1/gadgets/basic_gadgets.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/basic_gadgets.hpp rename to src/snark/libsnark/gadgetlib1/gadgets/basic_gadgets.hpp diff --git a/src/snark/src/gadgetlib1/gadgets/basic_gadgets.tcc b/src/snark/libsnark/gadgetlib1/gadgets/basic_gadgets.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/basic_gadgets.tcc rename to src/snark/libsnark/gadgetlib1/gadgets/basic_gadgets.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/gadget_from_r1cs.hpp b/src/snark/libsnark/gadgetlib1/gadgets/gadget_from_r1cs.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/gadget_from_r1cs.hpp rename to src/snark/libsnark/gadgetlib1/gadgets/gadget_from_r1cs.hpp diff --git a/src/snark/src/gadgetlib1/gadgets/gadget_from_r1cs.tcc b/src/snark/libsnark/gadgetlib1/gadgets/gadget_from_r1cs.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/gadget_from_r1cs.tcc rename to src/snark/libsnark/gadgetlib1/gadgets/gadget_from_r1cs.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp b/src/snark/libsnark/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc b/src/snark/libsnark/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/hash_io.hpp b/src/snark/libsnark/gadgetlib1/gadgets/hashes/hash_io.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/hash_io.hpp rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/hash_io.hpp diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/hash_io.tcc b/src/snark/libsnark/gadgetlib1/gadgets/hashes/hash_io.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/hash_io.tcc rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/hash_io.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp diff --git a/src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp rename to src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp diff --git a/src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc rename to src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp rename to src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp diff --git a/src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc rename to src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp rename to src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp diff --git a/src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc rename to src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp rename to src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp diff --git a/src/snark/src/gadgetlib1/pb_variable.hpp b/src/snark/libsnark/gadgetlib1/pb_variable.hpp similarity index 100% rename from src/snark/src/gadgetlib1/pb_variable.hpp rename to src/snark/libsnark/gadgetlib1/pb_variable.hpp diff --git a/src/snark/src/gadgetlib1/pb_variable.tcc b/src/snark/libsnark/gadgetlib1/pb_variable.tcc similarity index 100% rename from src/snark/src/gadgetlib1/pb_variable.tcc rename to src/snark/libsnark/gadgetlib1/pb_variable.tcc diff --git a/src/snark/src/gadgetlib1/protoboard.hpp b/src/snark/libsnark/gadgetlib1/protoboard.hpp similarity index 100% rename from src/snark/src/gadgetlib1/protoboard.hpp rename to src/snark/libsnark/gadgetlib1/protoboard.hpp diff --git a/src/snark/src/gadgetlib1/protoboard.tcc b/src/snark/libsnark/gadgetlib1/protoboard.tcc similarity index 100% rename from src/snark/src/gadgetlib1/protoboard.tcc rename to src/snark/libsnark/gadgetlib1/protoboard.tcc diff --git a/src/snark/src/gtests.cpp b/src/snark/libsnark/gtests.cpp similarity index 100% rename from src/snark/src/gtests.cpp rename to src/snark/libsnark/gtests.cpp diff --git a/src/snark/src/reductions/r1cs_to_qap/r1cs_to_qap.hpp b/src/snark/libsnark/reductions/r1cs_to_qap/r1cs_to_qap.hpp similarity index 100% rename from src/snark/src/reductions/r1cs_to_qap/r1cs_to_qap.hpp rename to src/snark/libsnark/reductions/r1cs_to_qap/r1cs_to_qap.hpp diff --git a/src/snark/src/reductions/r1cs_to_qap/r1cs_to_qap.tcc b/src/snark/libsnark/reductions/r1cs_to_qap/r1cs_to_qap.tcc similarity index 100% rename from src/snark/src/reductions/r1cs_to_qap/r1cs_to_qap.tcc rename to src/snark/libsnark/reductions/r1cs_to_qap/r1cs_to_qap.tcc diff --git a/src/snark/src/relations/arithmetic_programs/qap/qap.hpp b/src/snark/libsnark/relations/arithmetic_programs/qap/qap.hpp similarity index 100% rename from src/snark/src/relations/arithmetic_programs/qap/qap.hpp rename to src/snark/libsnark/relations/arithmetic_programs/qap/qap.hpp diff --git a/src/snark/src/relations/arithmetic_programs/qap/qap.tcc b/src/snark/libsnark/relations/arithmetic_programs/qap/qap.tcc similarity index 100% rename from src/snark/src/relations/arithmetic_programs/qap/qap.tcc rename to src/snark/libsnark/relations/arithmetic_programs/qap/qap.tcc diff --git a/src/snark/src/relations/arithmetic_programs/qap/tests/test_qap.cpp b/src/snark/libsnark/relations/arithmetic_programs/qap/tests/test_qap.cpp similarity index 100% rename from src/snark/src/relations/arithmetic_programs/qap/tests/test_qap.cpp rename to src/snark/libsnark/relations/arithmetic_programs/qap/tests/test_qap.cpp diff --git a/src/snark/src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp b/src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp similarity index 100% rename from src/snark/src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp rename to src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp diff --git a/src/snark/src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc b/src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc similarity index 100% rename from src/snark/src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc rename to src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc diff --git a/src/snark/src/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp b/src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp similarity index 100% rename from src/snark/src/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp rename to src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp diff --git a/src/snark/src/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc b/src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc similarity index 100% rename from src/snark/src/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc rename to src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc diff --git a/src/snark/src/relations/variable.hpp b/src/snark/libsnark/relations/variable.hpp similarity index 100% rename from src/snark/src/relations/variable.hpp rename to src/snark/libsnark/relations/variable.hpp diff --git a/src/snark/src/relations/variable.tcc b/src/snark/libsnark/relations/variable.tcc similarity index 100% rename from src/snark/src/relations/variable.tcc rename to src/snark/libsnark/relations/variable.tcc diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp similarity index 100% rename from src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp rename to src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc similarity index 100% rename from src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc rename to src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp similarity index 100% rename from src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp rename to src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp similarity index 100% rename from src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp rename to src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc similarity index 100% rename from src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc rename to src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp similarity index 100% rename from src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp rename to src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp similarity index 100% rename from src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp rename to src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp From 49cf707d2ced72698cd44c6f4f3f64072c2fc308 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 1 Mar 2017 11:20:42 -0800 Subject: [PATCH 153/177] Add Base58 encoding of viewing keys --- src/base58.cpp | 8 ++++++++ src/base58.h | 11 +++++++++++ src/chainparams.cpp | 4 ++++ src/chainparams.h | 1 + src/zcash/Address.hpp | 1 + 5 files changed, 25 insertions(+) diff --git a/src/base58.cpp b/src/base58.cpp index 2fd2475fea3..09977ea35e0 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -365,6 +365,14 @@ template libzcash::PaymentAddress CZCEncoding::Get() const; +// Explicit instantiations for libzcash::ViewingKey +template bool CZCEncoding::Set(const libzcash::ViewingKey& vk); +template libzcash::ViewingKey CZCEncoding::Get() const; + // Explicit instantiations for libzcash::SpendingKey template bool CZCEncoding { +protected: + std::string PrependName(const std::string& s) const { return "viewing key" + s; } + +public: + CZCViewingKey() {} + + CZCViewingKey(const std::string& strViewingKey) { SetString(strViewingKey.c_str(), 3); } + CZCViewingKey(const libzcash::ViewingKey& vk) { Set(vk); } +}; + class CZCSpendingKey : public CZCEncoding { protected: std::string PrependName(const std::string& s) const { return "spending key" + s; } diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 034eee6b2b3..23544f488e1 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -110,6 +110,8 @@ class CMainParams : public CChainParams { base58Prefixes[EXT_SECRET_KEY] = {0x04,0x88,0xAD,0xE4}; // guarantees the first 2 characters, when base58 encoded, are "zc" base58Prefixes[ZCPAYMENT_ADDRRESS] = {0x16,0x9A}; + // guarantees the first 4 characters, when base58 encoded, are "ZiVK" + base58Prefixes[ZCVIEWING_KEY] = {0xA8,0xAB,0xD3}; // guarantees the first 2 characters, when base58 encoded, are "SK" base58Prefixes[ZCSPENDING_KEY] = {0xAB,0x36}; @@ -241,6 +243,8 @@ class CTestNetParams : public CMainParams { base58Prefixes[EXT_SECRET_KEY] = {0x04,0x35,0x83,0x94}; // guarantees the first 2 characters, when base58 encoded, are "zt" base58Prefixes[ZCPAYMENT_ADDRRESS] = {0x16,0xB6}; + // guarantees the first 4 characters, when base58 encoded, are "ZiVt" + base58Prefixes[ZCVIEWING_KEY] = {0xA8,0xAC,0x0C}; // guarantees the first 2 characters, when base58 encoded, are "ST" base58Prefixes[ZCSPENDING_KEY] = {0xAC,0x08}; diff --git a/src/chainparams.h b/src/chainparams.h index a1de7b493a2..0de8d01b592 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -44,6 +44,7 @@ class CChainParams ZCPAYMENT_ADDRRESS, ZCSPENDING_KEY, + ZCVIEWING_KEY, MAX_BASE58_TYPES }; diff --git a/src/zcash/Address.hpp b/src/zcash/Address.hpp index 4287fee4f57..2dbe10a6071 100644 --- a/src/zcash/Address.hpp +++ b/src/zcash/Address.hpp @@ -8,6 +8,7 @@ namespace libzcash { const size_t SerializedPaymentAddressSize = 64; +const size_t SerializedViewingKeySize = 64; const size_t SerializedSpendingKeySize = 32; class PaymentAddress { From 167cd333741c234f7fee87f82aa678af653463af Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 1 Mar 2017 16:10:34 -0800 Subject: [PATCH 154/177] Implement viewing key storage in the wallet --- src/wallet/gtest/test_wallet_zkeys.cpp | 91 ++++++++++++++++++++++++++ src/wallet/wallet.cpp | 31 +++++++++ src/wallet/wallet.h | 6 ++ src/wallet/walletdb.cpp | 26 ++++++++ src/wallet/walletdb.h | 3 + 5 files changed, 157 insertions(+) diff --git a/src/wallet/gtest/test_wallet_zkeys.cpp b/src/wallet/gtest/test_wallet_zkeys.cpp index 554a4ee977b..b40479e8733 100644 --- a/src/wallet/gtest/test_wallet_zkeys.cpp +++ b/src/wallet/gtest/test_wallet_zkeys.cpp @@ -66,6 +66,53 @@ TEST(wallet_zkeys_tests, store_and_load_zkeys) { ASSERT_EQ(m.nCreateTime, now); } +/** + * This test covers methods on CWallet + * AddViewingKey() + * RemoveViewingKey() + * LoadViewingKey() + */ +TEST(wallet_zkeys_tests, StoreAndLoadViewingKeys) { + SelectParams(CBaseChainParams::MAIN); + + CWallet wallet; + + // wallet should be empty + std::set addrs; + wallet.GetPaymentAddresses(addrs); + ASSERT_EQ(0, addrs.size()); + + // manually add new viewing key to wallet + auto sk = libzcash::SpendingKey::random(); + auto vk = sk.viewing_key(); + ASSERT_TRUE(wallet.AddViewingKey(vk)); + + // verify wallet did add it + auto addr = sk.address(); + ASSERT_TRUE(wallet.HaveViewingKey(addr)); + // and that we don't have the corresponding spending key + ASSERT_FALSE(wallet.HaveSpendingKey(addr)); + + // verify viewing key stored correctly + libzcash::ViewingKey vkOut; + wallet.GetViewingKey(addr, vkOut); + ASSERT_EQ(vk, vkOut); + + // Load a second viewing key into the wallet + auto sk2 = libzcash::SpendingKey::random(); + ASSERT_TRUE(wallet.LoadViewingKey(sk2.viewing_key())); + + // verify wallet did add it + auto addr2 = sk2.address(); + ASSERT_TRUE(wallet.HaveViewingKey(addr2)); + ASSERT_FALSE(wallet.HaveSpendingKey(addr2)); + + // Remove the first viewing key + ASSERT_TRUE(wallet.RemoveViewingKey(vk)); + ASSERT_FALSE(wallet.HaveViewingKey(addr)); + ASSERT_TRUE(wallet.HaveViewingKey(addr2)); +} + /** * This test covers methods on CWalletDB * WriteZKey() @@ -138,6 +185,50 @@ TEST(wallet_zkeys_tests, write_zkey_direct_to_db) { ASSERT_EQ(m.nCreateTime, now); } +/** + * This test covers methods on CWalletDB + * WriteViewingKey() + */ +TEST(wallet_zkeys_tests, WriteViewingKeyDirectToDB) { + SelectParams(CBaseChainParams::TESTNET); + + // Get temporary and unique path for file. + // Note: / operator to append paths + boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + boost::filesystem::create_directories(pathTemp); + mapArgs["-datadir"] = pathTemp.string(); + + bool fFirstRun; + CWallet wallet("wallet-vkey.dat"); + ASSERT_EQ(DB_LOAD_OK, wallet.LoadWallet(fFirstRun)); + + // No default CPubKey set + ASSERT_TRUE(fFirstRun); + + // create random viewing key and add it to database directly, bypassing wallet + auto sk = libzcash::SpendingKey::random(); + auto vk = sk.viewing_key(); + auto addr = sk.address(); + int64_t now = GetTime(); + CKeyMetadata meta(now); + CWalletDB db("wallet-vkey.dat"); + db.WriteViewingKey(vk); + + // wallet should not be aware of viewing key + ASSERT_FALSE(wallet.HaveViewingKey(addr)); + + // load the wallet again + ASSERT_EQ(DB_LOAD_OK, wallet.LoadWallet(fFirstRun)); + + // wallet can now see the viewing key + ASSERT_TRUE(wallet.HaveViewingKey(addr)); + + // check key is the same + libzcash::ViewingKey vkOut; + wallet.GetViewingKey(addr, vkOut); + ASSERT_EQ(vk, vkOut); +} + /** diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 677fec31992..9e7bba0038b 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -107,6 +107,10 @@ bool CWallet::AddZKey(const libzcash::SpendingKey &key) if (!CCryptoKeyStore::AddSpendingKey(key)) return false; + // check if we need to remove from viewing keys + if (HaveViewingKey(addr)) + RemoveViewingKey(key.viewing_key()); + if (!fFileBacked) return true; @@ -246,6 +250,33 @@ bool CWallet::LoadZKey(const libzcash::SpendingKey &key) return CCryptoKeyStore::AddSpendingKey(key); } +bool CWallet::AddViewingKey(const libzcash::ViewingKey &vk) +{ + if (!CCryptoKeyStore::AddViewingKey(vk)) + return false; + nTimeFirstKey = 1; // No birthday information for viewing keys. + if (!fFileBacked) + return true; + return CWalletDB(strWalletFile).WriteViewingKey(vk); +} + +bool CWallet::RemoveViewingKey(const libzcash::ViewingKey &vk) +{ + AssertLockHeld(cs_wallet); + if (!CCryptoKeyStore::RemoveViewingKey(vk)) + return false; + if (fFileBacked) + if (!CWalletDB(strWalletFile).EraseViewingKey(vk)) + return false; + + return true; +} + +bool CWallet::LoadViewingKey(const libzcash::ViewingKey &vk) +{ + return CCryptoKeyStore::AddViewingKey(vk); +} + bool CWallet::AddCScript(const CScript& redeemScript) { if (!CCryptoKeyStore::AddCScript(redeemScript)) diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 57a71a4317f..878a23a5d84 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -954,6 +954,12 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface //! Adds an encrypted spending key to the store, and saves it to disk (virtual method, declared in crypter.h) bool AddCryptedSpendingKey(const libzcash::PaymentAddress &address, const libzcash::ReceivingKey &rk, const std::vector &vchCryptedSecret); + //! Adds a viewing key to the store, and saves it to disk. + bool AddViewingKey(const libzcash::ViewingKey &vk); + bool RemoveViewingKey(const libzcash::ViewingKey &vk); + //! Adds a viewing key to the store, without saving it to disk (used by LoadWallet) + bool LoadViewingKey(const libzcash::ViewingKey &dest); + /** * Increment the next transaction order id * @return next transaction order id diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index c79a15e3068..4bf19138041 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -142,6 +142,18 @@ bool CWalletDB::WriteZKey(const libzcash::PaymentAddress& addr, const libzcash:: return Write(std::make_pair(std::string("zkey"), addr), key, false); } +bool CWalletDB::WriteViewingKey(const libzcash::ViewingKey &vk) +{ + nWalletDBUpdated++; + return Write(std::make_pair(std::string("vkey"), vk), '1'); +} + +bool CWalletDB::EraseViewingKey(const libzcash::ViewingKey &vk) +{ + nWalletDBUpdated++; + return Erase(std::make_pair(std::string("vkey"), vk)); +} + bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript) { nWalletDBUpdated++; @@ -471,6 +483,19 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, // so set the wallet birthday to the beginning of time. pwallet->nTimeFirstKey = 1; } + else if (strType == "vkey") + { + libzcash::ViewingKey vk; + ssKey >> vk; + char fYes; + ssValue >> fYes; + if (fYes == '1') + pwallet->LoadViewingKey(vk); + + // Viewing keys have no birthday information for now, + // so set the wallet birthday to the beginning of time. + pwallet->nTimeFirstKey = 1; + } else if (strType == "zkey") { libzcash::PaymentAddress addr; @@ -694,6 +719,7 @@ static bool IsKeyType(string strType) { return (strType== "key" || strType == "wkey" || strType == "zkey" || strType == "czkey" || + strType == "vkey" || strType == "mkey" || strType == "ckey"); } diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index b901f539c43..e455ad953d3 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -140,6 +140,9 @@ class CWalletDB : public CDB const std::vector& vchCryptedSecret, const CKeyMetadata &keyMeta); + bool WriteViewingKey(const libzcash::ViewingKey &vk); + bool EraseViewingKey(const libzcash::ViewingKey &vk); + private: CWalletDB(const CWalletDB&); void operator=(const CWalletDB&); From e85b33a52e8c568cb1026862fd7a4a7c78c1a1c9 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 8 Mar 2017 16:13:39 +1300 Subject: [PATCH 155/177] Add RPC methods for exporting/importing viewing keys --- contrib/zcash-cli.bash-completion | 6 +- src/rpcclient.cpp | 1 + src/rpcserver.cpp | 2 + src/rpcserver.h | 2 + src/wallet/rpcdump.cpp | 125 ++++++++++++++++++++++++++++++ 5 files changed, 135 insertions(+), 1 deletion(-) diff --git a/contrib/zcash-cli.bash-completion b/contrib/zcash-cli.bash-completion index 79b57a06395..37fa1d1160c 100644 --- a/contrib/zcash-cli.bash-completion +++ b/contrib/zcash-cli.bash-completion @@ -82,10 +82,14 @@ _zcash_cli() { COMPREPLY=( $( compgen -W "add remove" -- "$cur" ) ) return 0 ;; - fundrawtransaction|getblock|getblockheader|getmempoolancestors|getmempooldescendants|getrawtransaction|gettransaction|listaccounts|listreceivedbyaccount|listreceivedbyaddress|sendrawtransaction|z_importkey) + fundrawtransaction|getblock|getblockheader|getmempoolancestors|getmempooldescendants|getrawtransaction|gettransaction|listaccounts|listreceivedbyaccount|listreceivedbyaddress|sendrawtransaction) COMPREPLY=( $( compgen -W "true false" -- "$cur" ) ) return 0 ;; + z_importkey|z_importviewingkey) + COMPREPLY=( $( compgen -W "yes no whenkeyisnew" -- "$cur" ) ) + return 0 + ;; move|setaccount) _zcash_accounts return 0 diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index c02c51991c0..7ac5db92681 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -114,6 +114,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "z_getoperationstatus", 0}, { "z_getoperationresult", 0}, { "z_importkey", 2 }, + { "z_importviewingkey", 2 }, { "z_getpaymentdisclosure", 1}, { "z_getpaymentdisclosure", 2} }; diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 7a38809025a..4859a5ee3ab 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -395,6 +395,8 @@ static const CRPCCommand vRPCCommands[] = { "wallet", "z_listaddresses", &z_listaddresses, true }, { "wallet", "z_exportkey", &z_exportkey, true }, { "wallet", "z_importkey", &z_importkey, true }, + { "wallet", "z_exportviewingkey", &z_exportviewingkey, true }, + { "wallet", "z_importviewingkey", &z_importviewingkey, true }, { "wallet", "z_exportwallet", &z_exportwallet, true }, { "wallet", "z_importwallet", &z_importwallet, true }, diff --git a/src/rpcserver.h b/src/rpcserver.h index 321568748f6..5359f46dd20 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -279,6 +279,8 @@ extern UniValue getblocksubsidy(const UniValue& params, bool fHelp); extern UniValue z_exportkey(const UniValue& params, bool fHelp); // in rpcdump.cpp extern UniValue z_importkey(const UniValue& params, bool fHelp); // in rpcdump.cpp +extern UniValue z_exportviewingkey(const UniValue& params, bool fHelp); // in rpcdump.cpp +extern UniValue z_importviewingkey(const UniValue& params, bool fHelp); // in rpcdump.cpp extern UniValue z_getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp extern UniValue z_listaddresses(const UniValue& params, bool fHelp); // in rpcwallet.cpp extern UniValue z_exportwallet(const UniValue& params, bool fHelp); // in rpcdump.cpp diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index fe5b83e8d4d..76a20d66bd3 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -644,6 +644,91 @@ UniValue z_importkey(const UniValue& params, bool fHelp) return NullUniValue; } +UniValue z_importviewingkey(const UniValue& params, bool fHelp) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "z_importviewingkey \"vkey\" ( rescan startHeight )\n" + "\nAdds a viewing key (as returned by z_exportviewingkey) to your wallet.\n" + "\nArguments:\n" + "1. \"vkey\" (string, required) The viewing key (see z_exportviewingkey)\n" + "2. rescan (string, optional, default=\"whenkeyisnew\") Rescan the wallet for transactions - can be \"yes\", \"no\" or \"whenkeyisnew\"\n" + "3. startHeight (numeric, optional, default=0) Block height to start rescan from\n" + "\nNote: This call can take minutes to complete if rescan is true.\n" + "\nExamples:\n" + "\nImport a viewing key\n" + + HelpExampleCli("z_importviewingkey", "\"vkey\"") + + "\nImport the viewing key without rescan\n" + + HelpExampleCli("z_importviewingkey", "\"vkey\", no") + + "\nImport the viewing key with partial rescan\n" + + HelpExampleCli("z_importviewingkey", "\"vkey\" whenkeyisnew 30000") + + "\nRe-import the viewing key with longer partial rescan\n" + + HelpExampleCli("z_importviewingkey", "\"vkey\" yes 20000") + + "\nAs a JSON-RPC call\n" + + HelpExampleRpc("z_importviewingkey", "\"vkey\", \"no\"") + ); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + EnsureWalletIsUnlocked(); + + // Whether to perform rescan after import + bool fRescan = true; + bool fIgnoreExistingKey = true; + if (params.size() > 1) { + auto rescan = params[1].get_str(); + if (rescan.compare("whenkeyisnew") != 0) { + fIgnoreExistingKey = false; + if (rescan.compare("no") == 0) { + fRescan = false; + } else if (rescan.compare("yes") != 0) { + throw JSONRPCError( + RPC_INVALID_PARAMETER, + "rescan must be \"yes\", \"no\" or \"whenkeyisnew\""); + } + } + } + + // Height to rescan from + int nRescanHeight = 0; + if (params.size() > 2) + nRescanHeight = params[2].get_int(); + if (nRescanHeight < 0 || nRescanHeight > chainActive.Height()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); + } + + string strVKey = params[0].get_str(); + CZCViewingKey viewingkey(strVKey); + auto vkey = viewingkey.Get(); + auto addr = vkey.address(); + + { + if (pwalletMain->HaveSpendingKey(addr)) + throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this viewing key"); + + // Don't throw error in case a viewing key is already there + if (pwalletMain->HaveViewingKey(addr)) { + if (fIgnoreExistingKey) { + return NullUniValue; + } + } else { + pwalletMain->MarkDirty(); + + if (!pwalletMain->AddViewingKey(vkey)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error adding viewing key to wallet"); + } + + // We want to scan for transactions and notes + if (fRescan) { + pwalletMain->ScanForWalletTransactions(chainActive[nRescanHeight], true); + } + } + + return NullUniValue; +} UniValue z_exportkey(const UniValue& params, bool fHelp) { @@ -682,3 +767,43 @@ UniValue z_exportkey(const UniValue& params, bool fHelp) return spendingkey.ToString(); } +UniValue z_exportviewingkey(const UniValue& params, bool fHelp) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() != 1) + throw runtime_error( + "z_exportviewingkey \"zaddr\"\n" + "\nReveals the viewing key corresponding to 'zaddr'.\n" + "Then the z_importviewingkey can be used with this output\n" + "\nArguments:\n" + "1. \"zaddr\" (string, required) The zaddr for the viewing key\n" + "\nResult:\n" + "\"vkey\" (string) The viewing key\n" + "\nExamples:\n" + + HelpExampleCli("z_exportviewingkey", "\"myaddress\"") + + HelpExampleRpc("z_exportviewingkey", "\"myaddress\"") + ); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + EnsureWalletIsUnlocked(); + + string strAddress = params[0].get_str(); + + CZCPaymentAddress address(strAddress); + auto addr = address.Get(); + + libzcash::ViewingKey vk; + if (!pwalletMain->GetViewingKey(addr, vk)) { + libzcash::SpendingKey k; + if (!pwalletMain->GetSpendingKey(addr, k)) { + throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private key or viewing key for this zaddr"); + } + vk = k.viewing_key(); + } + + CZCViewingKey viewingkey(vk); + return viewingkey.ToString(); +} From 9a2b8ae57fdae7d05bd52e6424b5b1ccf19c45c4 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 8 Mar 2017 16:31:59 +1300 Subject: [PATCH 156/177] Update wallet logic to account for viewing keys The wallet code previously assumed that an unlocked wallet would always have a spending key associated with a note decryptor. Viewing keys break this assumption. --- src/wallet/wallet.cpp | 35 ++++++++++++++++++++++------------- src/wallet/wallet.h | 6 +++++- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 9e7bba0038b..b2300c2b4b1 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -977,7 +977,8 @@ void CWallet::MarkDirty() } /** - * Ensure that every note in the wallet has a cached nullifier. + * Ensure that every note in the wallet (for which we possess a spending key) + * has a cached nullifier. */ bool CWallet::UpdateNullifierNoteMap() { @@ -991,16 +992,17 @@ bool CWallet::UpdateNullifierNoteMap() for (std::pair& wtxItem : mapWallet) { for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) { if (!item.second.nullifier) { - auto i = item.first.js; - GetNoteDecryptor(item.second.address, dec); - auto hSig = wtxItem.second.vjoinsplit[i].h_sig( - *pzcashParams, wtxItem.second.joinSplitPubKey); - item.second.nullifier = GetNoteNullifier( - wtxItem.second.vjoinsplit[i], - item.second.address, - dec, - hSig, - item.first.n); + if (GetNoteDecryptor(item.second.address, dec)) { + auto i = item.first.js; + auto hSig = wtxItem.second.vjoinsplit[i].h_sig( + *pzcashParams, wtxItem.second.joinSplitPubKey); + item.second.nullifier = GetNoteNullifier( + wtxItem.second.vjoinsplit[i], + item.second.address, + dec, + hSig, + item.first.n); + } } } UpdateNullifierNoteMapWithTx(wtxItem.second); @@ -1262,7 +1264,9 @@ boost::optional CWallet::GetNoteNullifier(const JSDescription& jsdesc, hSig, (unsigned char) n); auto note = note_pt.note(address); - // SpendingKeys are only available if the wallet is unlocked + // SpendingKeys are only available if: + // - We have them (this isn't a viewing key) + // - The wallet is unlocked libzcash::SpendingKey key; if (GetSpendingKey(address, key)) { ret = note.nullifier(key); @@ -3639,7 +3643,7 @@ bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee) * Find notes in the wallet filtered by payment address, min depth and ability to spend. * These notes are decrypted and added to the output parameter vector, outEntries. */ -void CWallet::GetFilteredNotes(std::vector & outEntries, std::string address, int minDepth, bool ignoreSpent) +void CWallet::GetFilteredNotes(std::vector & outEntries, std::string address, int minDepth, bool ignoreSpent, bool ignoreUnspendable) { bool fFilterAddress = false; libzcash::PaymentAddress filterPaymentAddress; @@ -3677,6 +3681,11 @@ void CWallet::GetFilteredNotes(std::vector & outEntries, st continue; } + // skip notes which cannot be spent + if (ignoreUnspendable && !HaveSpendingKey(pa)) { + continue; + } + int i = jsop.js; // Index into CTransaction.vjoinsplit int j = jsop.n; // Index into JSDescription.ciphertexts diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 878a23a5d84..eaaf6bbdf4a 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1121,7 +1121,11 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface void SetBroadcastTransactions(bool broadcast) { fBroadcastTransactions = broadcast; } /* Find notes filtered by payment address, min depth, ability to spend */ - void GetFilteredNotes(std::vector & outEntries, std::string address, int minDepth=1, bool ignoreSpent=true); + void GetFilteredNotes(std::vector & outEntries, + std::string address, + int minDepth=1, + bool ignoreSpent=true, + bool ignoreUnspendable=true); }; From 44e37656bf182fb04de051bd2f748bc6fdd897fc Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 21 Apr 2017 00:59:54 +1200 Subject: [PATCH 157/177] Add watch-only support to Zcash RPC methods Balance totals do not include spends linked to viewing key addresses, as nullifiers cannot be calculated and therefore spends cannot be detected. --- qa/rpc-tests/wallet_nullifiers.py | 45 ++++++++++++++++++++++++++ src/gtest/test_keystore.cpp | 13 ++++++++ src/keystore.h | 6 ++++ src/rpcclient.cpp | 3 ++ src/wallet/rpcwallet.cpp | 52 +++++++++++++++++++++---------- 5 files changed, 102 insertions(+), 17 deletions(-) diff --git a/qa/rpc-tests/wallet_nullifiers.py b/qa/rpc-tests/wallet_nullifiers.py index b7e94b6a67c..743af7c925b 100755 --- a/qa/rpc-tests/wallet_nullifiers.py +++ b/qa/rpc-tests/wallet_nullifiers.py @@ -170,5 +170,50 @@ def run_test (self): assert_equal(self.nodes[1].z_getbalance(myzaddr), zaddrremaining2) assert_equal(self.nodes[2].z_getbalance(myzaddr), zaddrremaining2) + # Test viewing keys + + node3mined = Decimal('250.0') + assert_equal({k: Decimal(v) for k, v in self.nodes[3].z_gettotalbalance().items()}, { + 'transparent': node3mined, + 'private': zsendmany2notevalue, + 'total': node3mined + zsendmany2notevalue, + }) + + # add node 1 address and node 2 viewing key to node 3 + myzvkey = self.nodes[2].z_exportviewingkey(myzaddr) + self.nodes[3].importaddress(mytaddr1) + self.nodes[3].z_importviewingkey(myzvkey) + + # Check the address has been imported + assert_equal(myzaddr in self.nodes[3].z_listaddresses(), False) + assert_equal(myzaddr in self.nodes[3].z_listaddresses(True), True) + + # Node 3 should see the same received notes as node 2 + assert_equal( + self.nodes[2].z_listreceivedbyaddress(myzaddr), + self.nodes[3].z_listreceivedbyaddress(myzaddr)) + + # Node 3's balances should be unchanged without explicitly requesting + # to include watch-only balances + assert_equal({k: Decimal(v) for k, v in self.nodes[3].z_gettotalbalance().items()}, { + 'transparent': node3mined, + 'private': zsendmany2notevalue, + 'total': node3mined + zsendmany2notevalue, + }) + + # Wallet can't cache nullifiers for notes received by addresses it only has a + # viewing key for, and therefore can't detect spends. So it sees a balance + # corresponding to the sum of all notes the address received. + # TODO: Fix this during the Sapling upgrade (via #2277) + assert_equal({k: Decimal(v) for k, v in self.nodes[3].z_gettotalbalance(1, True).items()}, { + 'transparent': node3mined + Decimal('1.0'), + 'private': zsendmany2notevalue + zsendmanynotevalue + zaddrremaining + zaddrremaining2, + 'total': node3mined + Decimal('1.0') + zsendmany2notevalue + zsendmanynotevalue + zaddrremaining + zaddrremaining2, + }) + + # Check individual balances reflect the above + assert_equal(self.nodes[3].z_getbalance(mytaddr1), Decimal('1.0')) + assert_equal(self.nodes[3].z_getbalance(myzaddr), zsendmanynotevalue + zaddrremaining + zaddrremaining2) + if __name__ == '__main__': WalletNullifiersTest().main () diff --git a/src/gtest/test_keystore.cpp b/src/gtest/test_keystore.cpp index 903a48839e4..76b57cd9fbc 100644 --- a/src/gtest/test_keystore.cpp +++ b/src/gtest/test_keystore.cpp @@ -65,6 +65,11 @@ TEST(keystore_tests, StoreAndRetrieveViewingKey) { EXPECT_FALSE(keyStore.GetSpendingKey(addr, skOut)); EXPECT_FALSE(keyStore.GetNoteDecryptor(addr, decOut)); + // and we can't find it in our list of addresses + std::set addresses; + keyStore.GetPaymentAddresses(addresses); + EXPECT_FALSE(addresses.count(addr)); + keyStore.AddViewingKey(vk); EXPECT_TRUE(keyStore.HaveViewingKey(addr)); EXPECT_TRUE(keyStore.GetViewingKey(addr, vkOut)); @@ -78,11 +83,19 @@ TEST(keystore_tests, StoreAndRetrieveViewingKey) { EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut)); EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut); + // ... and we should find it in our list of addresses + addresses.clear(); + keyStore.GetPaymentAddresses(addresses); + EXPECT_TRUE(addresses.count(addr)); + keyStore.RemoveViewingKey(vk); EXPECT_FALSE(keyStore.HaveViewingKey(addr)); EXPECT_FALSE(keyStore.GetViewingKey(addr, vkOut)); EXPECT_FALSE(keyStore.HaveSpendingKey(addr)); EXPECT_FALSE(keyStore.GetSpendingKey(addr, skOut)); + addresses.clear(); + keyStore.GetPaymentAddresses(addresses); + EXPECT_FALSE(addresses.count(addr)); // We still have a decryptor because those are cached in memory // (and also we only remove viewing keys when adding a spending key) diff --git a/src/keystore.h b/src/keystore.h index 0b548920b31..b1ad32a423c 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -174,6 +174,12 @@ class CBasicKeyStore : public CKeyStore setAddress.insert((*mi).first); mi++; } + ViewingKeyMap::const_iterator mvi = mapViewingKeys.begin(); + while (mvi != mapViewingKeys.end()) + { + setAddress.insert((*mvi).first); + mvi++; + } } } diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 7ac5db92681..def32500d5b 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -103,9 +103,12 @@ static const CRPCConvertParam vRPCConvertParams[] = { "zcbenchmark", 1 }, { "zcbenchmark", 2 }, { "getblocksubsidy", 0}, + { "z_listaddresses", 0}, { "z_listreceivedbyaddress", 1}, { "z_getbalance", 1}, { "z_gettotalbalance", 0}, + { "z_gettotalbalance", 1}, + { "z_gettotalbalance", 2}, { "z_sendmany", 1}, { "z_sendmany", 2}, { "z_sendmany", 3}, diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index d2c558c964b..4e0a798acf0 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2960,9 +2960,10 @@ UniValue z_listaddresses(const UniValue& params, bool fHelp) if (fHelp || params.size() > 1) throw runtime_error( - "z_listaddresses\n" + "z_listaddresses ( includeWatchonly )\n" "\nReturns the list of zaddr belonging to the wallet.\n" "\nArguments:\n" + "1. includeWatchonly (bool, optional, default=false) Also include watchonly addresses (see 'z_importviewingkey')\n" "\nResult:\n" "[ (json array of string)\n" " \"zaddr\" (string) a zaddr belonging to the wallet\n" @@ -2975,16 +2976,23 @@ UniValue z_listaddresses(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); + bool fIncludeWatchonly = false; + if (params.size() > 0) { + fIncludeWatchonly = params[0].get_bool(); + } + UniValue ret(UniValue::VARR); std::set addresses; pwalletMain->GetPaymentAddresses(addresses); for (auto addr : addresses ) { - ret.push_back(CZCPaymentAddress(addr).ToString()); + if (fIncludeWatchonly || pwalletMain->HaveSpendingKey(addr)) { + ret.push_back(CZCPaymentAddress(addr).ToString()); + } } return ret; } -CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1) { +CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1, bool ignoreUnspendable=true) { set setAddress; vector vecOutputs; CAmount balance = 0; @@ -3006,6 +3014,10 @@ CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1) { continue; } + if (ignoreUnspendable && !out.fSpendable) { + continue; + } + if (setAddress.size()) { CTxDestination address; if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) { @@ -3023,11 +3035,11 @@ CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1) { return balance; } -CAmount getBalanceZaddr(std::string address, int minDepth = 1) { +CAmount getBalanceZaddr(std::string address, int minDepth = 1, bool ignoreUnspendable=true) { CAmount balance = 0; std::vector entries; LOCK2(cs_main, pwalletMain->cs_wallet); - pwalletMain->GetFilteredNotes(entries, address, minDepth); + pwalletMain->GetFilteredNotes(entries, address, minDepth, true, ignoreUnspendable); for (auto & entry : entries) { balance += CAmount(entry.plaintext.value); } @@ -3076,14 +3088,14 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr."); } - if (!pwalletMain->HaveSpendingKey(zaddr)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found."); + if (!(pwalletMain->HaveSpendingKey(zaddr) || pwalletMain->HaveViewingKey(zaddr))) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found."); } UniValue result(UniValue::VARR); std::vector entries; - pwalletMain->GetFilteredNotes(entries, fromaddress, nMinDepth, false); + pwalletMain->GetFilteredNotes(entries, fromaddress, nMinDepth, false, false); for (CNotePlaintextEntry & entry : entries) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("txid",entry.jsop.hash.ToString())); @@ -3142,16 +3154,16 @@ UniValue z_getbalance(const UniValue& params, bool fHelp) } catch (const std::runtime_error&) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr."); } - if (!pwalletMain->HaveSpendingKey(zaddr)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found."); + if (!(pwalletMain->HaveSpendingKey(zaddr) || pwalletMain->HaveViewingKey(zaddr))) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found."); } } CAmount nBalance = 0; if (fromTaddr) { - nBalance = getBalanceTaddr(fromaddress, nMinDepth); + nBalance = getBalanceTaddr(fromaddress, nMinDepth, false); } else { - nBalance = getBalanceZaddr(fromaddress, nMinDepth); + nBalance = getBalanceZaddr(fromaddress, nMinDepth, false); } return ValueFromAmount(nBalance); @@ -3163,12 +3175,13 @@ UniValue z_gettotalbalance(const UniValue& params, bool fHelp) if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - if (fHelp || params.size() > 1) + if (fHelp || params.size() > 2) throw runtime_error( - "z_gettotalbalance ( minconf )\n" + "z_gettotalbalance ( minconf includeWatchonly )\n" "\nReturn the total value of funds stored in the node’s wallet.\n" "\nArguments:\n" "1. minconf (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n" + "2. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress' and 'z_importviewingkey')\n" "\nResult:\n" "{\n" " \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n" @@ -3187,19 +3200,24 @@ UniValue z_gettotalbalance(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); int nMinDepth = 1; - if (params.size() == 1) { + if (params.size() > 0) { nMinDepth = params[0].get_int(); } if (nMinDepth < 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0"); } + bool fIncludeWatchonly = false; + if (params.size() > 1) { + fIncludeWatchonly = params[1].get_bool(); + } + // getbalance and "getbalance * 1 true" should return the same number // but they don't because wtx.GetAmounts() does not handle tx where there are no outputs // pwalletMain->GetBalance() does not accept min depth parameter // so we use our own method to get balance of utxos. - CAmount nBalance = getBalanceTaddr("", nMinDepth); - CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth); + CAmount nBalance = getBalanceTaddr("", nMinDepth, !fIncludeWatchonly); + CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth, !fIncludeWatchonly); CAmount nTotalBalance = nBalance + nPrivateBalance; UniValue result(UniValue::VOBJ); result.push_back(Pair("transparent", FormatMoney(nBalance))); From 7b8d4f87ec9c9d1988debf124739fbb95da55b8d Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 18 Dec 2017 16:09:43 +0000 Subject: [PATCH 158/177] Modify zcrawkeygen RPC method to set "zcviewingkey" to the viewing key The "zcviewingkey" field has never been documented before, and the method itself is deprecated; this just ensures it is consistent with the rest of the RPC. --- src/wallet/rpcwallet.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 4e0a798acf0..696c71c711b 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2902,26 +2902,23 @@ UniValue zc_raw_keygen(const UniValue& params, bool fHelp) "Output: {\n" " \"zcaddress\": zcaddr,\n" " \"zcsecretkey\": zcsecretkey,\n" + " \"zcviewingkey\": zcviewingkey,\n" "}\n" ); } auto k = SpendingKey::random(); auto addr = k.address(); - auto receiving_key = k.receiving_key(); - - CDataStream receiving(SER_NETWORK, PROTOCOL_VERSION); - - receiving << receiving_key; + auto viewing_key = k.viewing_key(); CZCPaymentAddress pubaddr(addr); CZCSpendingKey spendingkey(k); - std::string receiving_hex = HexStr(receiving.begin(), receiving.end()); + CZCViewingKey viewingkey(viewing_key); UniValue result(UniValue::VOBJ); result.push_back(Pair("zcaddress", pubaddr.ToString())); result.push_back(Pair("zcsecretkey", spendingkey.ToString())); - result.push_back(Pair("zcviewingkey", receiving_hex)); + result.push_back(Pair("zcviewingkey", viewingkey.ToString())); return result; } From bec223514819c931f2d6a8abe87611567846d141 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 20 Dec 2017 11:18:59 +0000 Subject: [PATCH 159/177] Cleanup: Add braces for clarity --- src/wallet/rpcdump.cpp | 9 ++++++--- src/wallet/wallet.cpp | 15 ++++++++++----- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 76a20d66bd3..52169fe67c3 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -694,8 +694,9 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp) // Height to rescan from int nRescanHeight = 0; - if (params.size() > 2) + if (params.size() > 2) { nRescanHeight = params[2].get_int(); + } if (nRescanHeight < 0 || nRescanHeight > chainActive.Height()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); } @@ -706,8 +707,9 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp) auto addr = vkey.address(); { - if (pwalletMain->HaveSpendingKey(addr)) + if (pwalletMain->HaveSpendingKey(addr)) { throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this viewing key"); + } // Don't throw error in case a viewing key is already there if (pwalletMain->HaveViewingKey(addr)) { @@ -717,8 +719,9 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp) } else { pwalletMain->MarkDirty(); - if (!pwalletMain->AddViewingKey(vkey)) + if (!pwalletMain->AddViewingKey(vkey)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding viewing key to wallet"); + } } // We want to scan for transactions and notes diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index b2300c2b4b1..06dae5e8316 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -252,22 +252,27 @@ bool CWallet::LoadZKey(const libzcash::SpendingKey &key) bool CWallet::AddViewingKey(const libzcash::ViewingKey &vk) { - if (!CCryptoKeyStore::AddViewingKey(vk)) + if (!CCryptoKeyStore::AddViewingKey(vk)) { return false; + } nTimeFirstKey = 1; // No birthday information for viewing keys. - if (!fFileBacked) + if (!fFileBacked) { return true; + } return CWalletDB(strWalletFile).WriteViewingKey(vk); } bool CWallet::RemoveViewingKey(const libzcash::ViewingKey &vk) { AssertLockHeld(cs_wallet); - if (!CCryptoKeyStore::RemoveViewingKey(vk)) + if (!CCryptoKeyStore::RemoveViewingKey(vk)) { return false; - if (fFileBacked) - if (!CWalletDB(strWalletFile).EraseViewingKey(vk)) + } + if (fFileBacked) { + if (!CWalletDB(strWalletFile).EraseViewingKey(vk)) { return false; + } + } return true; } From 2bbfe6c4e829655ca48dec0349b7e72134b97e17 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 20 Dec 2017 11:24:51 +0000 Subject: [PATCH 160/177] Add cautions to z_getbalance and z_gettotalbalance help text about viewing keys --- src/wallet/rpcwallet.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 696c71c711b..829c5c7116e 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3114,6 +3114,8 @@ UniValue z_getbalance(const UniValue& params, bool fHelp) throw runtime_error( "z_getbalance \"address\" ( minconf )\n" "\nReturns the balance of a taddr or zaddr belonging to the node’s wallet.\n" + "\nCAUTION: If address is a watch-only zaddr, the returned balance may be larger than the actual balance," + "\nbecause spends cannot be detected with incoming viewing keys.\n" "\nArguments:\n" "1. \"address\" (string) The selected address. It may be a transparent or private address.\n" "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n" @@ -3176,6 +3178,8 @@ UniValue z_gettotalbalance(const UniValue& params, bool fHelp) throw runtime_error( "z_gettotalbalance ( minconf includeWatchonly )\n" "\nReturn the total value of funds stored in the node’s wallet.\n" + "\nCAUTION: If the wallet contains watch-only zaddrs, the returned private balance may be larger than the actual balance," + "\nbecause spends cannot be detected with incoming viewing keys.\n" "\nArguments:\n" "1. minconf (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n" "2. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress' and 'z_importviewingkey')\n" From c4c7c6630befb30386c00e4bb35d529ca35f72bb Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 4 Oct 2017 14:41:40 +0100 Subject: [PATCH 161/177] Scope the ECDSA constant sizes to CPubKey / CKey classes --- src/key.cpp | 25 +++++++++++-------------- src/key.h | 24 ++++++++++++++---------- src/pubkey.cpp | 4 ++-- src/pubkey.h | 31 ++++++++++++++++--------------- 4 files changed, 43 insertions(+), 41 deletions(-) diff --git a/src/key.cpp b/src/key.cpp index 4cf693a97a5..c93f8d15d42 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -85,16 +85,13 @@ static int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *ou * . The optional parameters and publicKey fields are * included. * - * privkey must point to an output buffer of length at least PRIVATE_KEY_SIZE bytes. + * privkey must point to an output buffer of length at least CKey::PRIVATE_KEY_SIZE bytes. * privkeylen must initially be set to the size of the privkey buffer. Upon return it * will be set to the number of bytes used in the buffer. * key32 must point to a 32-byte raw private key. */ static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) { - assert(*privkeylen >= PRIVATE_KEY_SIZE); - static_assert( - PRIVATE_KEY_SIZE >= COMPRESSED_PRIVATE_KEY_SIZE, - "COMPRESSED_PRIVATE_KEY_SIZE is larger than PRIVATE_KEY_SIZE"); + assert(*privkeylen >= CKey::PRIVATE_KEY_SIZE); secp256k1_pubkey pubkey; size_t pubkeylen = 0; if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) { @@ -120,11 +117,11 @@ static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *pr memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); memcpy(ptr, key32, 32); ptr += 32; memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); - pubkeylen = COMPRESSED_PUBLIC_KEY_SIZE; + pubkeylen = CPubKey::COMPRESSED_PUBLIC_KEY_SIZE; secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED); ptr += pubkeylen; *privkeylen = ptr - privkey; - assert(*privkeylen == COMPRESSED_PRIVATE_KEY_SIZE); + assert(*privkeylen == CKey::COMPRESSED_PRIVATE_KEY_SIZE); } else { static const unsigned char begin[] = { 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20 @@ -146,11 +143,11 @@ static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *pr memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); memcpy(ptr, key32, 32); ptr += 32; memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); - pubkeylen = PUBLIC_KEY_SIZE; + pubkeylen = CPubKey::PUBLIC_KEY_SIZE; secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED); ptr += pubkeylen; *privkeylen = ptr - privkey; - assert(*privkeylen == PRIVATE_KEY_SIZE); + assert(*privkeylen == CKey::PRIVATE_KEY_SIZE); } return 1; } @@ -191,7 +188,7 @@ CPrivKey CKey::GetPrivKey() const { CPubKey CKey::GetPubKey() const { assert(fValid); secp256k1_pubkey pubkey; - size_t clen = PUBLIC_KEY_SIZE; + size_t clen = CPubKey::PUBLIC_KEY_SIZE; CPubKey result; int ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, begin()); assert(ret); @@ -204,8 +201,8 @@ CPubKey CKey::GetPubKey() const { bool CKey::Sign(const uint256 &hash, std::vector& vchSig, uint32_t test_case) const { if (!fValid) return false; - vchSig.resize(SIGNATURE_SIZE); - size_t nSigLen = SIGNATURE_SIZE; + vchSig.resize(CPubKey::SIGNATURE_SIZE); + size_t nSigLen = CPubKey::SIGNATURE_SIZE; unsigned char extra_entropy[32] = {0}; WriteLE32(extra_entropy, test_case); secp256k1_ecdsa_signature sig; @@ -233,7 +230,7 @@ bool CKey::VerifyPubKey(const CPubKey& pubkey) const { bool CKey::SignCompact(const uint256 &hash, std::vector& vchSig) const { if (!fValid) return false; - vchSig.resize(COMPACT_SIGNATURE_SIZE); + vchSig.resize(CPubKey::COMPACT_SIGNATURE_SIZE); int rec = -1; secp256k1_ecdsa_recoverable_signature sig; int ret = secp256k1_ecdsa_sign_recoverable(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, NULL); @@ -264,7 +261,7 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const LockObject(out); if ((nChild >> 31) == 0) { CPubKey pubkey = GetPubKey(); - assert(pubkey.size() == COMPRESSED_PUBLIC_KEY_SIZE); + assert(pubkey.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE); BIP32Hash(cc, nChild, *pubkey.begin(), pubkey.begin()+1, out); } else { assert(size() == 32); diff --git a/src/key.h b/src/key.h index 292769098b9..c2b75935ce3 100644 --- a/src/key.h +++ b/src/key.h @@ -16,16 +16,6 @@ #include -/** - * secp256k1: - */ -const unsigned int PRIVATE_KEY_SIZE = 279; -const unsigned int COMPRESSED_PRIVATE_KEY_SIZE = 214; -/** - * see www.keylength.com - * script supports up to 75 for single byte push - */ - /** * secure_allocator is defined in allocators.h * CPrivKey is a serialized private key, with all parameters included @@ -36,6 +26,20 @@ typedef std::vector > CPrivKey; /** An encapsulated private key. */ class CKey { +public: + /** + * secp256k1: + */ + static const unsigned int PRIVATE_KEY_SIZE = 279; + static const unsigned int COMPRESSED_PRIVATE_KEY_SIZE = 214; + /** + * see www.keylength.com + * script supports up to 75 for single byte push + */ + static_assert( + PRIVATE_KEY_SIZE >= COMPRESSED_PRIVATE_KEY_SIZE, + "COMPRESSED_PRIVATE_KEY_SIZE is larger than PRIVATE_KEY_SIZE"); + private: //! Whether this private key is valid. We check for correctness when modifying the key //! data, so fValid should always correspond to the actual state. diff --git a/src/pubkey.cpp b/src/pubkey.cpp index 6e50a133407..0b87bb526e6 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -104,8 +104,8 @@ void CExtPubKey::Encode(unsigned char code[74]) const { code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF; code[7] = (nChild >> 8) & 0xFF; code[8] = (nChild >> 0) & 0xFF; memcpy(code+9, chaincode.begin(), 32); - assert(pubkey.size() == COMPRESSED_PUBLIC_KEY_SIZE); - memcpy(code+41, pubkey.begin(), COMPRESSED_PUBLIC_KEY_SIZE); + assert(pubkey.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE); + memcpy(code+41, pubkey.begin(), CPubKey::COMPRESSED_PUBLIC_KEY_SIZE); } void CExtPubKey::Decode(const unsigned char code[74]) { diff --git a/src/pubkey.h b/src/pubkey.h index fcfa019cfbd..237237e0561 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -14,18 +14,6 @@ #include #include -/** - * secp256k1: - */ -const unsigned int PUBLIC_KEY_SIZE = 65; -const unsigned int COMPRESSED_PUBLIC_KEY_SIZE = 33; -const unsigned int SIGNATURE_SIZE = 72; -const unsigned int COMPACT_SIGNATURE_SIZE = 65; -/** - * see www.keylength.com - * script supports up to 75 for single byte push - */ - /** A reference to a CKey: the Hash160 of its serialized public key */ class CKeyID : public uint160 { @@ -39,6 +27,22 @@ typedef uint256 ChainCode; /** An encapsulated public key. */ class CPubKey { +public: + /** + * secp256k1: + */ + static const unsigned int PUBLIC_KEY_SIZE = 65; + static const unsigned int COMPRESSED_PUBLIC_KEY_SIZE = 33; + static const unsigned int SIGNATURE_SIZE = 72; + static const unsigned int COMPACT_SIGNATURE_SIZE = 65; + /** + * see www.keylength.com + * script supports up to 75 for single byte push + */ + static_assert( + PUBLIC_KEY_SIZE >= COMPRESSED_PUBLIC_KEY_SIZE, + "COMPRESSED_PUBLIC_KEY_SIZE is larger than PUBLIC_KEY_SIZE"); + private: /** @@ -46,9 +50,6 @@ class CPubKey * Its length can very cheaply be computed from the first byte. */ unsigned char vch[PUBLIC_KEY_SIZE]; - static_assert( - PUBLIC_KEY_SIZE >= COMPRESSED_PUBLIC_KEY_SIZE, - "COMPRESSED_PUBLIC_KEY_SIZE is larger than PUBLIC_KEY_SIZE"); //! Compute the length of a pubkey with a given first byte. unsigned int static GetLen(unsigned char chHeader) From 5221220c6ceed705c3cb3d2d2d9b2eb13a6ac253 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 20 Dec 2017 18:14:40 +0000 Subject: [PATCH 162/177] Add release notes for incoming viewing keys --- doc/release-notes.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/doc/release-notes.md b/doc/release-notes.md index a29094b5174..21c31787bd8 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -4,3 +4,31 @@ release-notes at release time) Notable changes =============== +Incoming viewing keys +--------------------- + +Support for incoming viewing keys, as described in +[the Zcash protocol spec](https://github.com/zcash/zips/blob/master/protocol/protocol.pdf), +has been added to the wallet. + +Use the `z_exportviewingkey` RPC method to obtain the incoming viewing key for a +z-address in a node's wallet. For Sprout z-addresses, these always begin with +"ZiVK" (or "ZiVt" for testnet z-addresses). Use `z_importviewingkey` to import +these into another node. + +A node that possesses an incoming viewing key for a z-address can view all past +transactions received by that address, as well as all future transactions sent +to it, by using `z_listreceivedbyaddress`. They cannot spend any funds from the +address. This is similar to the behaviour of "watch-only" t-addresses. + +`z_gettotalbalance` now has an additional boolean parameter for including the +balance of "watch-only" addresses (both transparent and shielded), which is set +to `false` by default. `z_getbalance` has also been updated to work with +watch-only addresses. + +- **Caution:** for z-addresses, these balances will **not** be accurate if any + funds have been sent from the address. This is because incoming viewing keys + cannot detect spends, and so the "balance" is just the sum of all received + notes, including ones that have been spent. Some future use-cases for incoming + viewing keys will include synchronization data to keep their balances accurate + (e.g. [#2542](https://github.com/zcash/zcash/issues/2542)). From 2b38d11eda1977e9d3d75a0f32666744ae79f07b Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 20 Dec 2017 23:39:39 +0000 Subject: [PATCH 163/177] Create release notes starting from the previous non-beta non-RC release --- zcutil/make-release.py | 55 +++++++++++++++++++++++++++++++++++------ zcutil/release-notes.py | 32 +++++++++++++++--------- 2 files changed, 69 insertions(+), 18 deletions(-) diff --git a/zcutil/make-release.py b/zcutil/make-release.py index 7d505c27932..c1954431263 100755 --- a/zcutil/make-release.py +++ b/zcutil/make-release.py @@ -26,6 +26,7 @@ def main(args=sys.argv[1:]): main_logged( opts.RELEASE_VERSION, opts.RELEASE_PREV, + opts.RELEASE_FROM, opts.RELEASE_HEIGHT, opts.HOTFIX, ) @@ -61,6 +62,11 @@ def parse_args(args): type=Version.parse_arg, help='The previously released version.', ) + p.add_argument( + 'RELEASE_FROM', + type=Version.parse_arg, + help='The previously released non-beta non-RC version. May be the same as RELEASE_PREV.', + ) p.add_argument( 'RELEASE_HEIGHT', type=int, @@ -70,8 +76,8 @@ def parse_args(args): # Top-level flow: -def main_logged(release, releaseprev, releaseheight, hotfix): - verify_releaseprev_tag(releaseprev) +def main_logged(release, releaseprev, releasefrom, releaseheight, hotfix): + verify_tags(releaseprev, releasefrom) verify_version(release, releaseprev, hotfix) initialize_git(release, hotfix) patch_version_in_files(release, releaseprev) @@ -82,7 +88,7 @@ def main_logged(release, releaseprev, releaseheight, hotfix): gen_manpages() commit('Updated manpages for {}.'.format(release.novtext)) - gen_release_notes(release) + gen_release_notes(release, releasefrom) update_debian_changelog(release) commit( 'Updated release notes and changelog for {}.'.format( @@ -101,8 +107,8 @@ def g(*a, **kw): return deco -@phase('Checking RELEASE_PREV tag.') -def verify_releaseprev_tag(releaseprev): +@phase('Checking tags.') +def verify_tags(releaseprev, releasefrom): candidates = [] # Any tag beginning with a 'v' followed by [1-9] must be a version @@ -130,6 +136,31 @@ def verify_releaseprev_tag(releaseprev): ), ) + candidates.reverse() + prev_tags = [] + for candidate in candidates: + if releasefrom == candidate: + break + else: + prev_tags.append(candidate) + else: + raise SystemExit( + '{} does not appear in `git tag --list`' + .format( + releasefrom.vtext, + ), + ) + + for tag in prev_tags: + if not tag.betarc: + raise SystemExit( + '{} appears to be a more recent non-beta non-RC release than {}' + .format( + tag.vtext, + releasefrom.vtext, + ), + ) + @phase('Checking version.') def verify_version(release, releaseprev, hotfix): @@ -238,8 +269,18 @@ def gen_manpages(): @phase('Generating release notes.') -def gen_release_notes(release): - sh_log('python', './zcutil/release-notes.py', '--version', release.novtext) +def gen_release_notes(release, releasefrom): + release_notes = [ + 'python', + './zcutil/release-notes.py', + '--version', + release.novtext, + '--prev', + releasefrom.vtext, + ] + if not release.betarc: + release_notes.append('--clear') + sh_log(*release_notes) sh_log( 'git', 'add', diff --git a/zcutil/release-notes.py b/zcutil/release-notes.py index 24adff0d09f..b09c8774eb4 100755 --- a/zcutil/release-notes.py +++ b/zcutil/release-notes.py @@ -83,11 +83,14 @@ def document_authors(): f.write("{0} ({1})\n".format(n, c)) ## Writes release note to ./doc/release-notes based on git shortlog when current version number is specified -def generate_release_note(version, filename): +def generate_release_note(version, filename, prev, clear): print "Automatically generating release notes for {0} from git shortlog. Should review {1} for accuracy.".format(version, filename) - # fetches latest tags, so that latest_tag will be correct - subprocess.Popen(['git fetch -t'], shell=True, stdout=subprocess.PIPE).communicate()[0] - latest_tag = subprocess.Popen(['git describe --abbrev=0'], shell=True, stdout=subprocess.PIPE).communicate()[0].strip() + if prev: + latest_tag = prev + else: + # fetches latest tags, so that latest_tag will be correct + subprocess.Popen(['git fetch -t'], shell=True, stdout=subprocess.PIPE).communicate()[0] + latest_tag = subprocess.Popen(['git describe --abbrev=0'], shell=True, stdout=subprocess.PIPE).communicate()[0].strip() print "Previous release tag: ", latest_tag notes = subprocess.Popen(['git shortlog --no-merges {0}..HEAD'.format(latest_tag)], shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE).communicate()[0] lines = notes.split('\n') @@ -105,25 +108,32 @@ def generate_release_note(version, filename): f.writelines(notable_changes) f.writelines(RELEASE_NOTES_CHANGELOG_HEADING) f.writelines('\n'.join(lines)) - # Clear temporary release notes file - with open(temp_release_note, 'w') as f: - f.writelines(TEMP_RELEASE_NOTES_HEADER) + if clear: + # Clear temporary release notes file + with open(temp_release_note, 'w') as f: + f.writelines(TEMP_RELEASE_NOTES_HEADER) -def main(version, filename): +def main(version, filename, prev, clear): if version != None: - generate_release_note(version, filename) + generate_release_note(version, filename, prev, clear) document_authors() if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument('--version') + parser.add_argument('--version', help='Upcoming version, without leading v') + parser.add_argument('--prev', help='Previous version, with leading v') + parser.add_argument('--clear', help='Wipe doc/release-notes.md', action='store_true') args = parser.parse_args() root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) doc_dir = os.path.join(root_dir, 'doc') version = None filename = None + prev = None + clear = False if args.version: version = args.version filename = 'release-notes-{0}.md'.format(version) - main(version, filename) + prev = args.prev + clear = args.clear + main(version, filename, prev, clear) From d436db662c4c22b20392d102029b9e1a666f49af Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 20 Dec 2017 23:41:08 +0000 Subject: [PATCH 164/177] release-notes.py: Remove unnecessary parameter --- zcutil/release-notes.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/zcutil/release-notes.py b/zcutil/release-notes.py index b09c8774eb4..3413aacaf7e 100755 --- a/zcutil/release-notes.py +++ b/zcutil/release-notes.py @@ -83,7 +83,8 @@ def document_authors(): f.write("{0} ({1})\n".format(n, c)) ## Writes release note to ./doc/release-notes based on git shortlog when current version number is specified -def generate_release_note(version, filename, prev, clear): +def generate_release_note(version, prev, clear): + filename = 'release-notes-{0}.md'.format(version) print "Automatically generating release notes for {0} from git shortlog. Should review {1} for accuracy.".format(version, filename) if prev: latest_tag = prev @@ -103,7 +104,7 @@ def generate_release_note(version, filename, prev, clear): notable_changes = notable_changes[3:] + ['\n'] else: notable_changes = [] - release_note = os.path.join(doc_dir, 'release-notes', 'release-notes-{0}.md'.format(version)) + release_note = os.path.join(doc_dir, 'release-notes', filename) with open(release_note, 'w') as f: f.writelines(notable_changes) f.writelines(RELEASE_NOTES_CHANGELOG_HEADING) @@ -113,9 +114,9 @@ def generate_release_note(version, filename, prev, clear): with open(temp_release_note, 'w') as f: f.writelines(TEMP_RELEASE_NOTES_HEADER) -def main(version, filename, prev, clear): +def main(version, prev, clear): if version != None: - generate_release_note(version, filename, prev, clear) + generate_release_note(version, prev, clear) document_authors() if __name__ == "__main__": @@ -128,12 +129,10 @@ def main(version, filename, prev, clear): root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) doc_dir = os.path.join(root_dir, 'doc') version = None - filename = None prev = None clear = False if args.version: version = args.version - filename = 'release-notes-{0}.md'.format(version) prev = args.prev clear = args.clear - main(version, filename, prev, clear) + main(version, prev, clear) From fd08c5024729239c3d7bcb61dbbd595cd2b66d19 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 21 Dec 2017 00:24:43 +0000 Subject: [PATCH 165/177] Regenerate previous release notes to conform to new format Pre-1.0.0 release notes are excluded, as they were operating under a different RC timeline, and make more sense separated. --- doc/release-notes/release-notes-1.0.11.md | 42 ++++++++- doc/release-notes/release-notes-1.0.12.md | 55 ++++++++++- doc/release-notes/release-notes-1.0.13-rc1.md | 2 +- doc/release-notes/release-notes-1.0.13-rc2.md | 86 ++++++++++++++++- doc/release-notes/release-notes-1.0.13.md | 93 ++++++++++++++++++- 5 files changed, 272 insertions(+), 6 deletions(-) diff --git a/doc/release-notes/release-notes-1.0.11.md b/doc/release-notes/release-notes-1.0.11.md index 7a36c0be6dc..d5a12a222e4 100644 --- a/doc/release-notes/release-notes-1.0.11.md +++ b/doc/release-notes/release-notes-1.0.11.md @@ -1,7 +1,47 @@ Changelog ========= -Jack Grigg (2): +Ariel Gabizon (3): + make-release.py: Versioning changes for 1.0.11-rc1. + make-release.py: Updated manpages for 1.0.11-rc1. + make-release.py: Updated release notes and changelog for 1.0.11-rc1. + +Daira Hopwood (7): + Clean up imports to be pyflakes-checkable. fixes #2450 + For unused variables reported by pyflakes, either remove the variable, suppress the warning, or fix a bug (if the wrong variable was used). refs #2450 + Cosmetics (trailing whitespace, comment conventions, etc.) + Alert 1004 (version 1.0.10 only) + Remove UPnP support. fixes #2500 + Change wording in Security Warnings section of README.md. + Document our criteria for adding CI workers. closes #2499 + +Jack Grigg (17): + Pull in temporary release notes during the release process + Ansible playbook for installing Zcash dependencies and Buildbot worker + Variable overrides for Debian, Ubuntu and Fedora + Variable overrides for FreeBSD + Simplify Python installation, inform user if they need to manually configure + Add test for issue #2444 + Add Buildbot worker setup to Ansible playbook + Add steps for setting up a latent worker on Amazon EC2 + Add pyblake2 to required Python modules + Remove Buildbot version from host file + Add a separate Buildbot host info template for EC2 + Add pyflakes to required Python modules + Add block download progress to metrics UI + Correct and extend EstimateNetHeightInner tests + Improve network height estimation make-release.py: Versioning changes for 1.0.11. make-release.py: Updated manpages for 1.0.11. +Simon Liu (3): + Closes #2446 by adding generated field to listunspent. + Fixes #2519. When sending from a zaddr, minconf cannot be zero. + Fixes #2480. Null entry in map was dereferenced leading to a segfault. + +Wladimir J. van der Laan (1): + rpc: Add WWW-Authenticate header to 401 response + +practicalswift (1): + Net: Fix resource leak in ReadBinaryFile(...) + diff --git a/doc/release-notes/release-notes-1.0.12.md b/doc/release-notes/release-notes-1.0.12.md index ca919026800..6aa6cd65121 100644 --- a/doc/release-notes/release-notes-1.0.12.md +++ b/doc/release-notes/release-notes-1.0.12.md @@ -1,14 +1,65 @@ Changelog ========= -Jack Grigg (5): +Ariel (1): + add examples to z_getoperationresult + +Ariel Gabizon (1): + add load-wallet benchmark + +Bjorn Hjortsberg (2): + Do not warn on built in declaration mismatch + Remove deprecated exception specification + +Jack Grigg (26): + ci-workers: Enable pipelining, and use root to set admin and host details + Variable overrides for Arch Linux + Rationalize currency unit to "ZEC" + ci-workers: Fail if Python is not version 2.7 + ci-workers: Variable overrides and process tweaks for CentOS 7 + Add build progress to the release script if progressbar module is available + Add hotfix support to release script + Document the hotfix release process + Enforce sequential hotfix versioning + Benchmark time to call sendtoaddress with many UTXOs + Fix bug in benchmark data generation script + Adjust instructions for UTXO dataset creation + Add GitHub release notes to release process + Clarify branching and force-building operations in hotfix process + Update user guide translations as part of release process + make-release.py: Send stderr to stdout + List dependencies for release script in release process doc + Additional test cases for importprivkey RPC test + make-release.py: Versioning changes for 1.0.12-rc1. + make-release.py: Updated manpages for 1.0.12-rc1. + make-release.py: Updated release notes and changelog for 1.0.12-rc1. Fix pyflakes warnings in RPC tests Individualise performance-measurements.sh errors for debugging Fix incorrect failure in memory benchmark make-release.py: Versioning changes for 1.0.12. make-release.py: Updated manpages for 1.0.12. -Simon Liu (2): +Jason Davies (1): + Fix deprecation policy comment. + +Nathan Wilcox (5): + key_import_export rpc-test: verify that UTXO view co-evolves for nodes sharing a key. + Add a new rpc-test-specified requirement: `importprivkey` outputs the associated address. (Test fails.) + [tests pass] Output address on new key import. + Add a new requirement that `importprivkey` API is idempotent. + [tests pass] Ensure `importprivkey` outputs the address in case key is already imported. + +Ross Nicoll (1): + Rationalize currency unit to "BTC" + +Simon Liu (5): + Closes #2583. Exclude watch-only utxos from z_sendmany coin selection. + Set up a clean chain. Delete redundant method wait_until_miner_sees() via use of sync_all(). + Implement RPC shield_coinbase #2448. Update which lock to synchronize on when calling GetBestAnchor(). Closes #2637. Make z_shieldcoinbase an experimental feature where it can be enabled with: zcashd -experimentalfeatures -zshieldcoinbase. +kpcyrd (2): + Fetch params from ipfs if possible + Prefer wget over ipfs + diff --git a/doc/release-notes/release-notes-1.0.13-rc1.md b/doc/release-notes/release-notes-1.0.13-rc1.md index 90e2306adf1..4d8a37a7ca1 100644 --- a/doc/release-notes/release-notes-1.0.13-rc1.md +++ b/doc/release-notes/release-notes-1.0.13-rc1.md @@ -13,7 +13,7 @@ Cory Fields (1): Duke Leto (1): Update performance-measurements.sh -Jack Grigg (36): +Jack Grigg (37): Squashed 'src/snark/' content from commit 9ada3f8 Add libsnark compile flag to not copy DEPINST to PREFIX Add Ansible playbook for grind workers diff --git a/doc/release-notes/release-notes-1.0.13-rc2.md b/doc/release-notes/release-notes-1.0.13-rc2.md index 0b60ffc9afb..6ade7d9221e 100644 --- a/doc/release-notes/release-notes-1.0.13-rc2.md +++ b/doc/release-notes/release-notes-1.0.13-rc2.md @@ -1,7 +1,57 @@ Changelog ========= -Jack Grigg (6): +Ariel Gabizon (1): + boost::format -> tinyformat + +Bruno Arueira (1): + Removes out bitcoin mention in favor for zcash + +Cory Fields (1): + httpserver: explicitly detach worker threads + +Duke Leto (1): + Update performance-measurements.sh + +Jack Grigg (44): + Squashed 'src/snark/' content from commit 9ada3f8 + Add libsnark compile flag to not copy DEPINST to PREFIX + Add Ansible playbook for grind workers + Add connections in BIP65 and BIP66 tests to the test manager + Add benchmark for listunspent + [Test] MiniNode: Implement JSDescription parsing + [Test] MiniNode: Implement v2 CTransaction parsing + [Test] MiniNode: Implement Zcash block parsing + [Test] MiniNode: Update protocol version and network magics + [Test] MiniNode: Use Zcash PoW + [Test] MiniNode: Fix coinbase creation + [Test] MiniNode: Coerce OP_PUSHDATA bytearrays to bytes + [Test] MiniNode: Implement Zcash coinbase + Fix BIP65 and BIP66 tests + Un-indent RPC test output in test runner + Replace full-test-suite.sh with a new test suite driver script + Move ensure-no-dot-so-in-depends.py into full_test_suite.py + Move check-security-hardening.sh into full_test_suite.py + Add memory benchmark for validatelargetx + Migrate libsnark test code to Google Test + Remove test code corresponding to removed code + Add alt_bn128 to QAP and Merkle tree gadget tests + Update libsnark LDLIBS + Add "make check" to libsnark that runs the Google Tests + Add "make libsnark-tests" that runs libsnark's "make check" + Changes to get test_r1cs_ppzksnark passing + Add bitcoin-util-test.py to full_test_suite.py + Add stdout notice if any stage fails + Add libsnark to "make clean" + Ensure that libsnark is built first, so its headers are available + Remove OpenSSL libraries from libsnark LDLIBS + Add libsnark tests to full_test_suite.py + Add --list-stages argument to full_test_suite.py + Fix NPE in rpc_wallet_tests + make-release.py: Versioning changes for 1.0.13-rc1. + make-release.py: Updated manpages for 1.0.13-rc1. + make-release.py: Updated release notes and changelog for 1.0.13-rc1. + Change auto-senescence cycle to 16 weeks Move libsnark from DIST_SUBDIRS into EXTRA_DIST Pass correct dependencies path to libsnark from both Gitian and build.sh Mark libsnark includes as library includes @@ -9,3 +59,37 @@ Jack Grigg (6): make-release.py: Versioning changes for 1.0.13-rc2. make-release.py: Updated manpages for 1.0.13-rc2. +Jason Davies (1): + Replace "bitcoin" with "Zcash". + +Jay Graber (1): + s/zcash/Zcash + +Jonathan "Duke" Leto (1): + Fix bug where performance-measurements.sh fails hards when given no args + +João Barbosa (1): + Improve shutdown process + +Sean Bowe (5): + Remove libsnark from depends system and integrate it into build system. + Remove crusty old "loadVerifyingKey"/"loadProvingKey" APIs and associated invariants. + Refactor proof generation function. + Add streaming prover. + Integrate low memory prover. + +Simon Liu (7): + Replace 'bitcoin address' with 'zcash address'. + Closes #2639. z_shieldcoinbase is now supported, no longer experimental. + Closes #2263 fixing broken pipe error. + Closes #2576. Update link to security info on z.cash website. + Closes #2639. Adds optional limit parameter with a default value of 50. + Fix an issue where qa test wallet_shieldcoinbase could hang. + Add payment disclosure as experimental feature. + +Wladimir J. van der Laan (4): + Make HTTP server shutdown more graceful + http: Wait for worker threads to exit + http: Force-exit event loop after predefined time + http: speed up shutdown + diff --git a/doc/release-notes/release-notes-1.0.13.md b/doc/release-notes/release-notes-1.0.13.md index d6552168798..3a1a950a94c 100644 --- a/doc/release-notes/release-notes-1.0.13.md +++ b/doc/release-notes/release-notes-1.0.13.md @@ -1,7 +1,98 @@ Changelog ========= -Jack Grigg (2): +Ariel Gabizon (1): + boost::format -> tinyformat + +Bruno Arueira (1): + Removes out bitcoin mention in favor for zcash + +Cory Fields (1): + httpserver: explicitly detach worker threads + +Duke Leto (1): + Update performance-measurements.sh + +Jack Grigg (47): + Squashed 'src/snark/' content from commit 9ada3f8 + Add libsnark compile flag to not copy DEPINST to PREFIX + Add Ansible playbook for grind workers + Add connections in BIP65 and BIP66 tests to the test manager + Add benchmark for listunspent + [Test] MiniNode: Implement JSDescription parsing + [Test] MiniNode: Implement v2 CTransaction parsing + [Test] MiniNode: Implement Zcash block parsing + [Test] MiniNode: Update protocol version and network magics + [Test] MiniNode: Use Zcash PoW + [Test] MiniNode: Fix coinbase creation + [Test] MiniNode: Coerce OP_PUSHDATA bytearrays to bytes + [Test] MiniNode: Implement Zcash coinbase + Fix BIP65 and BIP66 tests + Un-indent RPC test output in test runner + Replace full-test-suite.sh with a new test suite driver script + Move ensure-no-dot-so-in-depends.py into full_test_suite.py + Move check-security-hardening.sh into full_test_suite.py + Add memory benchmark for validatelargetx + Migrate libsnark test code to Google Test + Remove test code corresponding to removed code + Add alt_bn128 to QAP and Merkle tree gadget tests + Update libsnark LDLIBS + Add "make check" to libsnark that runs the Google Tests + Add "make libsnark-tests" that runs libsnark's "make check" + Changes to get test_r1cs_ppzksnark passing + Add bitcoin-util-test.py to full_test_suite.py + Add stdout notice if any stage fails + Add libsnark to "make clean" + Ensure that libsnark is built first, so its headers are available + Remove OpenSSL libraries from libsnark LDLIBS + Add libsnark tests to full_test_suite.py + Add --list-stages argument to full_test_suite.py + Fix NPE in rpc_wallet_tests + make-release.py: Versioning changes for 1.0.13-rc1. + make-release.py: Updated manpages for 1.0.13-rc1. + make-release.py: Updated release notes and changelog for 1.0.13-rc1. + Change auto-senescence cycle to 16 weeks + Move libsnark from DIST_SUBDIRS into EXTRA_DIST + Pass correct dependencies path to libsnark from both Gitian and build.sh + Mark libsnark includes as library includes + Add the tar-pax option to automake + make-release.py: Versioning changes for 1.0.13-rc2. + make-release.py: Updated manpages for 1.0.13-rc2. + make-release.py: Updated release notes and changelog for 1.0.13-rc2. make-release.py: Versioning changes for 1.0.13. make-release.py: Updated manpages for 1.0.13. +Jason Davies (1): + Replace "bitcoin" with "Zcash". + +Jay Graber (1): + s/zcash/Zcash + +Jonathan "Duke" Leto (1): + Fix bug where performance-measurements.sh fails hards when given no args + +João Barbosa (1): + Improve shutdown process + +Sean Bowe (5): + Remove libsnark from depends system and integrate it into build system. + Remove crusty old "loadVerifyingKey"/"loadProvingKey" APIs and associated invariants. + Refactor proof generation function. + Add streaming prover. + Integrate low memory prover. + +Simon Liu (7): + Replace 'bitcoin address' with 'zcash address'. + Closes #2639. z_shieldcoinbase is now supported, no longer experimental. + Closes #2263 fixing broken pipe error. + Closes #2576. Update link to security info on z.cash website. + Closes #2639. Adds optional limit parameter with a default value of 50. + Fix an issue where qa test wallet_shieldcoinbase could hang. + Add payment disclosure as experimental feature. + +Wladimir J. van der Laan (4): + Make HTTP server shutdown more graceful + http: Wait for worker threads to exit + http: Force-exit event loop after predefined time + http: speed up shutdown + From 5d8ab776f09475b0108f0a05c3e1bf2a1da69d1f Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 21 Dec 2017 00:25:29 +0000 Subject: [PATCH 166/177] Exclude beta and RC release notes from author tallies (except for pre-1.0.0, per previous commit) --- doc/authors.md | 4 ++-- zcutil/release-notes.py | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/authors.md b/doc/authors.md index 7094aff8beb..a6dedffbc15 100644 --- a/doc/authors.md +++ b/doc/authors.md @@ -1,7 +1,7 @@ Zcash Contributors ================== -Jack Grigg (514) +Jack Grigg (518) Simon Liu (281) Sean Bowe (193) Daira Hopwood (102) @@ -19,6 +19,7 @@ fanquake (5) MarcoFalke (5) Johnathan Corgan (5) Gregory Maxwell (5) +Ariel Gabizon (5) Philip Kaufmann (4) Peter Todd (4) Patrick Strateman (4) @@ -27,7 +28,6 @@ Karl-Johan Alm (4) Jeff Garzik (4) David Mercer (4) Daniel Cousens (4) -Ariel Gabizon (4) lpescher (3) kozyilmaz (3) Pavel Janík (3) diff --git a/zcutil/release-notes.py b/zcutil/release-notes.py index 3413aacaf7e..01f658f07d9 100755 --- a/zcutil/release-notes.py +++ b/zcutil/release-notes.py @@ -70,6 +70,10 @@ def document_authors(): f.write('Zcash Contributors\n==================\n\n') total_contrib = {} for notes in os.listdir(os.path.join(doc_dir, 'release-notes')): + # Commits are duplicated across beta, RC and final release notes, + # except for the pre-launch release notes. + if ('-beta' in notes or '-rc' in notes) and '1.0.0-' not in notes: + continue authors = authors_in_release_notes(notes) for author in authors: commits = int(authors[author]) From 5d9cf8ae2362c5f67197783692cf32eb3351f53e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 21 Dec 2017 18:19:42 +0000 Subject: [PATCH 167/177] Fix pyflakes warnings in zkey_import_export RPC test --- qa/rpc-tests/zkey_import_export.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/qa/rpc-tests/zkey_import_export.py b/qa/rpc-tests/zkey_import_export.py index e9cd94253e0..f6d7af765d7 100755 --- a/qa/rpc-tests/zkey_import_export.py +++ b/qa/rpc-tests/zkey_import_export.py @@ -65,7 +65,7 @@ def run_test(self): def z_send(from_node, from_addr, to_addr, amount): opid = from_node.z_sendmany(from_addr, [{"address": to_addr, "amount": Decimal(amount)}]) - txid = self.wait_and_assert_operationid_status(from_node, opid) + self.wait_and_assert_operationid_status(from_node, opid) self.sync_all() miner.generate(1) self.sync_all() @@ -112,12 +112,9 @@ def find_imported_key(node, import_zaddr): # Shield Alice's coinbase funds to her zaddr alice_zaddr = alice.z_getnewaddress() res = alice.z_shieldcoinbase("*", alice_zaddr) - txid = self.wait_and_assert_operationid_status(alice, res['opid']) + self.wait_and_assert_operationid_status(alice, res['opid']) miner.generate(6) self.sync_all() - # List funds - funds = alice.z_listreceivedbyaddress(alice_zaddr) - # print("Alice's funds after shield", funds) # Now get a pristine z-address for receiving transfers: bob_zaddr = bob.z_getnewaddress() From 275f21ad4bd278d80873160c08e3fc4af40aad91 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 22 Dec 2017 09:59:01 +0000 Subject: [PATCH 168/177] make-release.py: Versioning changes for 1.0.14-rc1. --- README.md | 2 +- configure.ac | 4 ++-- contrib/gitian-descriptors/gitian-linux.yml | 2 +- src/clientversion.h | 4 ++-- src/deprecation.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 2efce727afb..28e50f21a51 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Zcash 1.0.13 +Zcash 1.0.14-rc1 ============= What is Zcash? diff --git a/configure.ac b/configure.ac index b44b486a367..11a729fb8c9 100644 --- a/configure.ac +++ b/configure.ac @@ -2,8 +2,8 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) -define(_CLIENT_VERSION_REVISION, 13) -define(_CLIENT_VERSION_BUILD, 50) +define(_CLIENT_VERSION_REVISION, 14) +define(_CLIENT_VERSION_BUILD, 25) define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50))) define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1))) define(_CLIENT_VERSION_IS_RELEASE, true) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 3096a7f0ddf..52de67b0a4b 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,5 +1,5 @@ --- -name: "zcash-1.0.13" +name: "zcash-1.0.14-rc1" enable_cache: true distro: "debian" suites: diff --git a/src/clientversion.h b/src/clientversion.h index f1081d55320..6be6222181e 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -17,8 +17,8 @@ //! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it #define CLIENT_VERSION_MAJOR 1 #define CLIENT_VERSION_MINOR 0 -#define CLIENT_VERSION_REVISION 13 -#define CLIENT_VERSION_BUILD 50 +#define CLIENT_VERSION_REVISION 14 +#define CLIENT_VERSION_BUILD 25 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true diff --git a/src/deprecation.h b/src/deprecation.h index 434a81f3668..0272c26fec6 100644 --- a/src/deprecation.h +++ b/src/deprecation.h @@ -8,7 +8,7 @@ // Deprecation policy: // * Shut down 16 weeks' worth of blocks after the estimated release block height. // * A warning is shown during the 2 weeks' worth of blocks prior to shut down. -static const int APPROX_RELEASE_HEIGHT = 222900; +static const int APPROX_RELEASE_HEIGHT = 241200; static const int WEEKS_UNTIL_DEPRECATION = 16; static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 24); From f059d520383a8a75398851788f62dd1ecf3ff017 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 22 Dec 2017 10:12:30 +0000 Subject: [PATCH 169/177] make-release.py: Updated manpages for 1.0.14-rc1. --- doc/man/zcash-cli.1 | 6 +++--- doc/man/zcash-tx.1 | 6 +++--- doc/man/zcashd.1 | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/man/zcash-cli.1 b/doc/man/zcash-cli.1 index a77b67ffce8..aecbadd3330 100644 --- a/doc/man/zcash-cli.1 +++ b/doc/man/zcash-cli.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH ZCASH-CLI "1" "November 2017" "zcash-cli v1.0.13" "User Commands" +.TH ZCASH-CLI "1" "December 2017" "zcash-cli v1.0.14-rc1" "User Commands" .SH NAME -zcash-cli \- manual page for zcash-cli v1.0.13 +zcash-cli \- manual page for zcash-cli v1.0.14-rc1 .SH DESCRIPTION -Zcash RPC client version v1.0.13 +Zcash RPC client version v1.0.14\-rc1 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . diff --git a/doc/man/zcash-tx.1 b/doc/man/zcash-tx.1 index fb54abf116f..37a7c6bad82 100644 --- a/doc/man/zcash-tx.1 +++ b/doc/man/zcash-tx.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH ZCASH-TX "1" "November 2017" "zcash-tx v1.0.13" "User Commands" +.TH ZCASH-TX "1" "December 2017" "zcash-tx v1.0.14-rc1" "User Commands" .SH NAME -zcash-tx \- manual page for zcash-tx v1.0.13 +zcash-tx \- manual page for zcash-tx v1.0.14-rc1 .SH DESCRIPTION -Zcash zcash\-tx utility version v1.0.13 +Zcash zcash\-tx utility version v1.0.14\-rc1 .SS "Usage:" .TP zcash\-tx [options] [commands] diff --git a/doc/man/zcashd.1 b/doc/man/zcashd.1 index e6ea1b8dc55..6bf56c3150e 100644 --- a/doc/man/zcashd.1 +++ b/doc/man/zcashd.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH ZCASHD "1" "November 2017" "zcashd v1.0.13" "User Commands" +.TH ZCASHD "1" "December 2017" "zcashd v1.0.14-rc1" "User Commands" .SH NAME -zcashd \- manual page for zcashd v1.0.13 +zcashd \- manual page for zcashd v1.0.14-rc1 .SH DESCRIPTION -Zcash Daemon version v1.0.13 +Zcash Daemon version v1.0.14\-rc1 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . @@ -54,7 +54,7 @@ Specify data directory \fB\-disabledeprecation=\fR .IP Disable block\-height node deprecation and automatic shutdown (example: -\fB\-disabledeprecation\fR=\fI\,1\/\fR.0.13) +\fB\-disabledeprecation\fR=\fI\,1\/\fR.0.14\-rc1) .HP \fB\-exportdir=\fR .IP From ea6ec713ea2183da159eb1c011b9fa17437b4370 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 22 Dec 2017 10:12:41 +0000 Subject: [PATCH 170/177] make-release.py: Updated release notes and changelog for 1.0.14-rc1. --- contrib/debian/changelog | 6 + doc/release-notes/release-notes-1.0.14-rc1.md | 156 ++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 doc/release-notes/release-notes-1.0.14-rc1.md diff --git a/contrib/debian/changelog b/contrib/debian/changelog index 71e8b0b589b..66e6a3a42c9 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,9 @@ +zcash (1.0.14~rc1) stable; urgency=medium + + * 1.0.14-rc1 release. + + -- Zcash Company Fri, 22 Dec 2017 10:12:41 +0000 + zcash (1.0.13) stable; urgency=medium * 1.0.13 release. diff --git a/doc/release-notes/release-notes-1.0.14-rc1.md b/doc/release-notes/release-notes-1.0.14-rc1.md new file mode 100644 index 00000000000..1654bf48344 --- /dev/null +++ b/doc/release-notes/release-notes-1.0.14-rc1.md @@ -0,0 +1,156 @@ +Notable changes +=============== + +Incoming viewing keys +--------------------- + +Support for incoming viewing keys, as described in +[the Zcash protocol spec](https://github.com/zcash/zips/blob/master/protocol/protocol.pdf), +has been added to the wallet. + +Use the `z_exportviewingkey` RPC method to obtain the incoming viewing key for a +z-address in a node's wallet. For Sprout z-addresses, these always begin with +"ZiVK" (or "ZiVt" for testnet z-addresses). Use `z_importviewingkey` to import +these into another node. + +A node that possesses an incoming viewing key for a z-address can view all past +transactions received by that address, as well as all future transactions sent +to it, by using `z_listreceivedbyaddress`. They cannot spend any funds from the +address. This is similar to the behaviour of "watch-only" t-addresses. + +`z_gettotalbalance` now has an additional boolean parameter for including the +balance of "watch-only" addresses (both transparent and shielded), which is set +to `false` by default. `z_getbalance` has also been updated to work with +watch-only addresses. + +- **Caution:** for z-addresses, these balances will **not** be accurate if any + funds have been sent from the address. This is because incoming viewing keys + cannot detect spends, and so the "balance" is just the sum of all received + notes, including ones that have been spent. Some future use-cases for incoming + viewing keys will include synchronization data to keep their balances accurate + (e.g. [#2542](https://github.com/zcash/zcash/issues/2542)). + +Changelog +========= + +Anthony Towns (1): + Add configure check for -latomic + +Cory Fields (12): + c++11: don't throw from the reverselock destructor + c++11: CAccountingEntry must be defined before use in a list + c++11: fix libbdb build against libc++ in c++11 mode + depends: use c++11 + depends: bump OSX toolchain + build: Split hardening/fPIE options out + build: define base filenames for use elsewhere in the buildsystem + build: quiet annoying warnings without adding new ones + build: fix Windows builds without pkg-config + build: force a c++ standard to be specified + build: warn about variable length arrays + build: add --enable-werror option + +Jack Grigg (36): + Squashed 'src/secp256k1/' changes from 84973d3..6ad5cdb + Use g-prefixed coreutils commands if they are available + Replace hard-coded defaults for HOST and BUILD with config.guess + Remove manual -std=c++11 flag + Replace "install -D" with "mkdir -p && install" + Check if OpenMP is available before using it + [libsnark] Use POSIX-compliant ar arguments + Include endian-ness compatibility layer in Equihash implementation + build: Split hardening/fPIE options out in Zcash-specific binaries + Change --enable-werror to apply to all warnings, use it in build.sh + Move Zcash flags into configure.ac + ViewingKey -> ReceivingKey per zcash/zips#117 + Implement viewing key storage in the keystore + Factor out common logic from CZCPaymentAddress and CZCSpendingKey + Track net value entering and exiting the Sprout circuit + Add Sprout value pool to getblock and getblockchaininfo + Apply -fstack-protector-all to libsnark + Add Rust and Proton to configure options printout + Clarify operator precedence in serialization of nSproutValue + Remove nSproutValue TODO from CDiskBlockIndex + Add Base58 encoding of viewing keys + Implement viewing key storage in the wallet + Add RPC methods for exporting/importing viewing keys + Update wallet logic to account for viewing keys + Add watch-only support to Zcash RPC methods + Modify zcrawkeygen RPC method to set "zcviewingkey" to the viewing key + Cleanup: Add braces for clarity + Add cautions to z_getbalance and z_gettotalbalance help text about viewing keys + Add release notes for incoming viewing keys + Create release notes starting from the previous non-beta non-RC release + release-notes.py: Remove unnecessary parameter + Regenerate previous release notes to conform to new format + Exclude beta and RC release notes from author tallies + Fix pyflakes warnings in zkey_import_export RPC test + make-release.py: Versioning changes for 1.0.14-rc1. + make-release.py: Updated manpages for 1.0.14-rc1. + +Jay Graber (3): + Add cli and rpc examples for z_sendmany + Fix cli help result for z_shieldcoinbase + Add rpc test that exercises z_importkey + +Jonas Schnelli (1): + Add compile and link options echo to configure + +Luke Dashjr (4): + depends: Use curl for fetching on Linux + Travis: Use curl rather than wget for Mac SDK + Bugfix: depends/Travis: Use --location (follow redirects) and --fail [on HTTP error response] with curl + Travis: Use Blue Box VMs for IPv6 loopback support + +MarcoFalke (2): + Fix url in .travis.yml + [depends] builders: No need to set -L and --location for curl + +Per Grön (2): + Deduplicate test utility method wait_and_assert_operationid_status + Print result of RPC call in test only when PYTHON_DEBUG is set + +René Nyffenegger (1): + Use AC_ARG_VAR to set ARFLAGS. + +Simon Liu (5): + RPC dumpwallet and z_exportwallet updated to no longer allow overwriting an existing file. + Add documentation for shielding coinbase utxos. + Add documentation for payment disclosure. + Closes #2759. Fixes broken pipe error with QA test wallet.py. + Closes #2746. Payment disclosure blobs now use 'zpd:' prefix. + +Wladimir J. van der Laan (6): + build: Enable C++11 build, require C++11 compiler + build: update ax_cxx_compile_stdcxx to serial 4 + test: Remove java comparison tool + build: Remove check for `openssl/ec.h` + devtools: Check for high-entropy ASLR in 64-bit PE executables + build: supply `-Wl,--high-entropy-va` + +daniel (1): + add powerpc build support for openssl lib + +fanquake (3): + [build-aux] Update Boost & check macros to latest serials + [depends] Add -stdlib=libc++ to darwin CXX flags + [depends] Set OSX_MIN_VERSION to 10.8 + +kozyilmaz (1): + empty spaces in PATH variable cause build failure + +syd (13): + Upgrade googletest to 1.8.0 + Get the sec-hard tests to run correctly. + Update libsodium from 1.0.11 to 1.0.15 + Remove Boost conditional compilation. + Update to address @daira comments wrt fixing configure.ac + Get rid of consensus.fPowAllowMinDifficultyBlocks. + Don't compile libgtest.a when building libsnark. + Add gtests to .gitignore + Get rid of fp3 from libsnark, it is not used. + InitGoogleMock instead of InitGoogleTest per CR + Get rid of underscore prefixes for include guards. + Rename bash completion files so that they refer to zcash and not bitcoin. + Fix libsnark test failure. + From 5cbf238b96059382227eaa2145a47f85eb39d65c Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 22 Dec 2017 10:13:40 +0000 Subject: [PATCH 171/177] Update release process --- doc/release-process.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/release-process.md b/doc/release-process.md index bcbab4946c9..93a8e8362e7 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -61,11 +61,12 @@ Run the release script, which will verify you are on the latest clean checkout of master, create a branch, then commit standard automated changes to that branch locally: - $ ./zcutil/make-release.py + $ ./zcutil/make-release.py -Example: +Examples: - $ ./zcutil/make-release.py v1.0.9 v1.0.8-1 120000 + $ ./zcutil/make-release.py v1.0.9 v1.0.8-1 v1.0.8-1 120000 + $ ./zcutil/make-release.py v1.0.13 v1.0.13-rc1 v1.0.12 222900 ### Create, Review, and Merge the release branch pull request From 2091cf23ae5569be2174a7ff5c23c56a4a8415f8 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 3 Jan 2018 23:44:51 +0100 Subject: [PATCH 172/177] make-release.py: Versioning changes for 1.0.14. --- README.md | 2 +- configure.ac | 2 +- contrib/gitian-descriptors/gitian-linux.yml | 2 +- src/clientversion.h | 2 +- src/deprecation.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 28e50f21a51..3b8f56c2cb1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Zcash 1.0.14-rc1 +Zcash 1.0.14 ============= What is Zcash? diff --git a/configure.ac b/configure.ac index 11a729fb8c9..df8d3fdbe0c 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 14) -define(_CLIENT_VERSION_BUILD, 25) +define(_CLIENT_VERSION_BUILD, 50) define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50))) define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1))) define(_CLIENT_VERSION_IS_RELEASE, true) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 52de67b0a4b..558d386e1db 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,5 +1,5 @@ --- -name: "zcash-1.0.14-rc1" +name: "zcash-1.0.14" enable_cache: true distro: "debian" suites: diff --git a/src/clientversion.h b/src/clientversion.h index 6be6222181e..6873c1a39a9 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -18,7 +18,7 @@ #define CLIENT_VERSION_MAJOR 1 #define CLIENT_VERSION_MINOR 0 #define CLIENT_VERSION_REVISION 14 -#define CLIENT_VERSION_BUILD 25 +#define CLIENT_VERSION_BUILD 50 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true diff --git a/src/deprecation.h b/src/deprecation.h index 0272c26fec6..eb9899c1b2f 100644 --- a/src/deprecation.h +++ b/src/deprecation.h @@ -8,7 +8,7 @@ // Deprecation policy: // * Shut down 16 weeks' worth of blocks after the estimated release block height. // * A warning is shown during the 2 weeks' worth of blocks prior to shut down. -static const int APPROX_RELEASE_HEIGHT = 241200; +static const int APPROX_RELEASE_HEIGHT = 249000; static const int WEEKS_UNTIL_DEPRECATION = 16; static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 24); From d3c1949cf1caa83c4341235cb09b9969b51092a4 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 3 Jan 2018 23:54:00 +0100 Subject: [PATCH 173/177] make-release.py: Updated manpages for 1.0.14. --- doc/man/zcash-cli.1 | 6 +++--- doc/man/zcash-tx.1 | 6 +++--- doc/man/zcashd.1 | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/man/zcash-cli.1 b/doc/man/zcash-cli.1 index aecbadd3330..52af9437f90 100644 --- a/doc/man/zcash-cli.1 +++ b/doc/man/zcash-cli.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH ZCASH-CLI "1" "December 2017" "zcash-cli v1.0.14-rc1" "User Commands" +.TH ZCASH-CLI "1" "January 2018" "zcash-cli v1.0.14" "User Commands" .SH NAME -zcash-cli \- manual page for zcash-cli v1.0.14-rc1 +zcash-cli \- manual page for zcash-cli v1.0.14 .SH DESCRIPTION -Zcash RPC client version v1.0.14\-rc1 +Zcash RPC client version v1.0.14 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . diff --git a/doc/man/zcash-tx.1 b/doc/man/zcash-tx.1 index 37a7c6bad82..a065ca04a28 100644 --- a/doc/man/zcash-tx.1 +++ b/doc/man/zcash-tx.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH ZCASH-TX "1" "December 2017" "zcash-tx v1.0.14-rc1" "User Commands" +.TH ZCASH-TX "1" "January 2018" "zcash-tx v1.0.14" "User Commands" .SH NAME -zcash-tx \- manual page for zcash-tx v1.0.14-rc1 +zcash-tx \- manual page for zcash-tx v1.0.14 .SH DESCRIPTION -Zcash zcash\-tx utility version v1.0.14\-rc1 +Zcash zcash\-tx utility version v1.0.14 .SS "Usage:" .TP zcash\-tx [options] [commands] diff --git a/doc/man/zcashd.1 b/doc/man/zcashd.1 index 6bf56c3150e..91917eece67 100644 --- a/doc/man/zcashd.1 +++ b/doc/man/zcashd.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH ZCASHD "1" "December 2017" "zcashd v1.0.14-rc1" "User Commands" +.TH ZCASHD "1" "January 2018" "zcashd v1.0.14" "User Commands" .SH NAME -zcashd \- manual page for zcashd v1.0.14-rc1 +zcashd \- manual page for zcashd v1.0.14 .SH DESCRIPTION -Zcash Daemon version v1.0.14\-rc1 +Zcash Daemon version v1.0.14 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . @@ -54,7 +54,7 @@ Specify data directory \fB\-disabledeprecation=\fR .IP Disable block\-height node deprecation and automatic shutdown (example: -\fB\-disabledeprecation\fR=\fI\,1\/\fR.0.14\-rc1) +\fB\-disabledeprecation\fR=\fI\,1\/\fR.0.14) .HP \fB\-exportdir=\fR .IP From 6bfa0fb79dc9988e10e30fc98bb8f6b8e740b7a7 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 3 Jan 2018 23:54:16 +0100 Subject: [PATCH 174/177] make-release.py: Updated release notes and changelog for 1.0.14. --- contrib/debian/changelog | 6 + doc/authors.md | 25 ++-- doc/release-notes.md | 28 ---- doc/release-notes/release-notes-1.0.14.md | 160 ++++++++++++++++++++++ 4 files changed, 181 insertions(+), 38 deletions(-) create mode 100644 doc/release-notes/release-notes-1.0.14.md diff --git a/contrib/debian/changelog b/contrib/debian/changelog index 66e6a3a42c9..606b33b9069 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,9 @@ +zcash (1.0.14) stable; urgency=medium + + * 1.0.14 release. + + -- Zcash Company Wed, 03 Jan 2018 23:54:16 +0100 + zcash (1.0.14~rc1) stable; urgency=medium * 1.0.14-rc1 release. diff --git a/doc/authors.md b/doc/authors.md index a6dedffbc15..e576a5e2c87 100644 --- a/doc/authors.md +++ b/doc/authors.md @@ -1,25 +1,28 @@ Zcash Contributors ================== -Jack Grigg (518) -Simon Liu (281) +Jack Grigg (558) +Simon Liu (286) Sean Bowe (193) Daira Hopwood (102) -Wladimir J. van der Laan (65) +Wladimir J. van der Laan (71) Taylor Hornby (65) Nathan Wilcox (56) -Jay Graber (50) -Jonas Schnelli (48) +Jay Graber (53) +Jonas Schnelli (49) Kevin Gallagher (38) +Cory Fields (28) Pieter Wuille (16) -Cory Fields (16) +syd (13) nomnombtc (9) Paige Peterson (9) -fanquake (5) -MarcoFalke (5) +fanquake (8) +MarcoFalke (7) +Luke Dashjr (6) Johnathan Corgan (5) Gregory Maxwell (5) Ariel Gabizon (5) +kozyilmaz (4) Philip Kaufmann (4) Peter Todd (4) Patrick Strateman (4) @@ -29,7 +32,6 @@ Jeff Garzik (4) David Mercer (4) Daniel Cousens (4) lpescher (3) -kozyilmaz (3) Pavel Janík (3) João Barbosa (3) Alfie John (3) @@ -39,7 +41,7 @@ kpcyrd (2) aniemerg (2) Scott (2) Robert C. Seacord (2) -Luke Dashjr (2) +Per Grön (2) Joe Turgeon (2) Jason Davies (2) Jack Gavigan (2) @@ -57,12 +59,14 @@ isle2983 (1) instagibbs (1) emilrus (1) dexX7 (1) +daniel (1) calebogden (1) ayleph (1) Tom Ritter (1) Stephen (1) S. Matthew English (1) Ross Nicoll (1) +René Nyffenegger (1) Pavel Vasin (1) Paul Georgiou (1) Paragon Initiative Enterprises, LLC (1) @@ -94,6 +98,7 @@ Boris Hajduk (1) Bob McElrath (1) Bitcoin Error Log (1) Ariel (1) +Anthony Towns (1) Allan Niemerg (1) Alex van der Peet (1) Alex (1) diff --git a/doc/release-notes.md b/doc/release-notes.md index 21c31787bd8..a29094b5174 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -4,31 +4,3 @@ release-notes at release time) Notable changes =============== -Incoming viewing keys ---------------------- - -Support for incoming viewing keys, as described in -[the Zcash protocol spec](https://github.com/zcash/zips/blob/master/protocol/protocol.pdf), -has been added to the wallet. - -Use the `z_exportviewingkey` RPC method to obtain the incoming viewing key for a -z-address in a node's wallet. For Sprout z-addresses, these always begin with -"ZiVK" (or "ZiVt" for testnet z-addresses). Use `z_importviewingkey` to import -these into another node. - -A node that possesses an incoming viewing key for a z-address can view all past -transactions received by that address, as well as all future transactions sent -to it, by using `z_listreceivedbyaddress`. They cannot spend any funds from the -address. This is similar to the behaviour of "watch-only" t-addresses. - -`z_gettotalbalance` now has an additional boolean parameter for including the -balance of "watch-only" addresses (both transparent and shielded), which is set -to `false` by default. `z_getbalance` has also been updated to work with -watch-only addresses. - -- **Caution:** for z-addresses, these balances will **not** be accurate if any - funds have been sent from the address. This is because incoming viewing keys - cannot detect spends, and so the "balance" is just the sum of all received - notes, including ones that have been spent. Some future use-cases for incoming - viewing keys will include synchronization data to keep their balances accurate - (e.g. [#2542](https://github.com/zcash/zcash/issues/2542)). diff --git a/doc/release-notes/release-notes-1.0.14.md b/doc/release-notes/release-notes-1.0.14.md new file mode 100644 index 00000000000..4b9cd0810d8 --- /dev/null +++ b/doc/release-notes/release-notes-1.0.14.md @@ -0,0 +1,160 @@ +Notable changes +=============== + +Incoming viewing keys +--------------------- + +Support for incoming viewing keys, as described in +[the Zcash protocol spec](https://github.com/zcash/zips/blob/master/protocol/protocol.pdf), +has been added to the wallet. + +Use the `z_exportviewingkey` RPC method to obtain the incoming viewing key for a +z-address in a node's wallet. For Sprout z-addresses, these always begin with +"ZiVK" (or "ZiVt" for testnet z-addresses). Use `z_importviewingkey` to import +these into another node. + +A node that possesses an incoming viewing key for a z-address can view all past +transactions received by that address, as well as all future transactions sent +to it, by using `z_listreceivedbyaddress`. They cannot spend any funds from the +address. This is similar to the behaviour of "watch-only" t-addresses. + +`z_gettotalbalance` now has an additional boolean parameter for including the +balance of "watch-only" addresses (both transparent and shielded), which is set +to `false` by default. `z_getbalance` has also been updated to work with +watch-only addresses. + +- **Caution:** for z-addresses, these balances will **not** be accurate if any + funds have been sent from the address. This is because incoming viewing keys + cannot detect spends, and so the "balance" is just the sum of all received + notes, including ones that have been spent. Some future use-cases for incoming + viewing keys will include synchronization data to keep their balances accurate + (e.g. [#2542](https://github.com/zcash/zcash/issues/2542)). + +Changelog +========= + +Anthony Towns (1): + Add configure check for -latomic + +Cory Fields (12): + c++11: don't throw from the reverselock destructor + c++11: CAccountingEntry must be defined before use in a list + c++11: fix libbdb build against libc++ in c++11 mode + depends: use c++11 + depends: bump OSX toolchain + build: Split hardening/fPIE options out + build: define base filenames for use elsewhere in the buildsystem + build: quiet annoying warnings without adding new ones + build: fix Windows builds without pkg-config + build: force a c++ standard to be specified + build: warn about variable length arrays + build: add --enable-werror option + +Jack Grigg (40): + Squashed 'src/secp256k1/' changes from 84973d3..6ad5cdb + Use g-prefixed coreutils commands if they are available + Replace hard-coded defaults for HOST and BUILD with config.guess + Remove manual -std=c++11 flag + Replace "install -D" with "mkdir -p && install" + Check if OpenMP is available before using it + [libsnark] Use POSIX-compliant ar arguments + Include endian-ness compatibility layer in Equihash implementation + build: Split hardening/fPIE options out in Zcash-specific binaries + Change --enable-werror to apply to all warnings, use it in build.sh + Move Zcash flags into configure.ac + ViewingKey -> ReceivingKey per zcash/zips#117 + Implement viewing key storage in the keystore + Factor out common logic from CZCPaymentAddress and CZCSpendingKey + Track net value entering and exiting the Sprout circuit + Add Sprout value pool to getblock and getblockchaininfo + Apply -fstack-protector-all to libsnark + Add Rust and Proton to configure options printout + Clarify operator precedence in serialization of nSproutValue + Remove nSproutValue TODO from CDiskBlockIndex + Add Base58 encoding of viewing keys + Implement viewing key storage in the wallet + Add RPC methods for exporting/importing viewing keys + Update wallet logic to account for viewing keys + Add watch-only support to Zcash RPC methods + Modify zcrawkeygen RPC method to set "zcviewingkey" to the viewing key + Cleanup: Add braces for clarity + Add cautions to z_getbalance and z_gettotalbalance help text about viewing keys + Add release notes for incoming viewing keys + Create release notes starting from the previous non-beta non-RC release + release-notes.py: Remove unnecessary parameter + Regenerate previous release notes to conform to new format + Exclude beta and RC release notes from author tallies + Fix pyflakes warnings in zkey_import_export RPC test + make-release.py: Versioning changes for 1.0.14-rc1. + make-release.py: Updated manpages for 1.0.14-rc1. + make-release.py: Updated release notes and changelog for 1.0.14-rc1. + Update release process + make-release.py: Versioning changes for 1.0.14. + make-release.py: Updated manpages for 1.0.14. + +Jay Graber (3): + Add cli and rpc examples for z_sendmany + Fix cli help result for z_shieldcoinbase + Add rpc test that exercises z_importkey + +Jonas Schnelli (1): + Add compile and link options echo to configure + +Luke Dashjr (4): + depends: Use curl for fetching on Linux + Travis: Use curl rather than wget for Mac SDK + Bugfix: depends/Travis: Use --location (follow redirects) and --fail [on HTTP error response] with curl + Travis: Use Blue Box VMs for IPv6 loopback support + +MarcoFalke (2): + Fix url in .travis.yml + [depends] builders: No need to set -L and --location for curl + +Per Grön (2): + Deduplicate test utility method wait_and_assert_operationid_status + Print result of RPC call in test only when PYTHON_DEBUG is set + +René Nyffenegger (1): + Use AC_ARG_VAR to set ARFLAGS. + +Simon Liu (5): + RPC dumpwallet and z_exportwallet updated to no longer allow overwriting an existing file. + Add documentation for shielding coinbase utxos. + Add documentation for payment disclosure. + Closes #2759. Fixes broken pipe error with QA test wallet.py. + Closes #2746. Payment disclosure blobs now use 'zpd:' prefix. + +Wladimir J. van der Laan (6): + build: Enable C++11 build, require C++11 compiler + build: update ax_cxx_compile_stdcxx to serial 4 + test: Remove java comparison tool + build: Remove check for `openssl/ec.h` + devtools: Check for high-entropy ASLR in 64-bit PE executables + build: supply `-Wl,--high-entropy-va` + +daniel (1): + add powerpc build support for openssl lib + +fanquake (3): + [build-aux] Update Boost & check macros to latest serials + [depends] Add -stdlib=libc++ to darwin CXX flags + [depends] Set OSX_MIN_VERSION to 10.8 + +kozyilmaz (1): + empty spaces in PATH variable cause build failure + +syd (13): + Upgrade googletest to 1.8.0 + Get the sec-hard tests to run correctly. + Update libsodium from 1.0.11 to 1.0.15 + Remove Boost conditional compilation. + Update to address @daira comments wrt fixing configure.ac + Get rid of consensus.fPowAllowMinDifficultyBlocks. + Don't compile libgtest.a when building libsnark. + Add gtests to .gitignore + Get rid of fp3 from libsnark, it is not used. + InitGoogleMock instead of InitGoogleTest per CR + Get rid of underscore prefixes for include guards. + Rename bash completion files so that they refer to zcash and not bitcoin. + Fix libsnark test failure. + From ea79b3baa2d630f98399fb945ea94d00d7108c70 Mon Sep 17 00:00:00 2001 From: backendmaster <34057530+backendmaster@users.noreply.github.com> Date: Thu, 4 Jan 2018 22:55:10 +0200 Subject: [PATCH 175/177] Updating donation address --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 42ce76b9438..04345545a3f 100644 --- a/README.md +++ b/README.md @@ -122,5 +122,5 @@ The usage is currently the same as for ZCash. For more information see the [ZCas Donations -------------------- Donations for running nodes and for development are welcomed here: -t1gUHkWqcC9ruk6iGkeDKnxtPAsrgm8AGVt +t1XpvXbN3UoBZf4yEsmz3oQt9UGp2TCEUu3 From b6a990def08c9f08cec6d09922a6140570a4a5ff Mon Sep 17 00:00:00 2001 From: syd Date: Fri, 24 Nov 2017 12:09:27 -0500 Subject: [PATCH 176/177] Remove OSX and Windows files from Makefile + share directory. These are stale holdovers from bitcoin. This closes #2169. --- Makefile.am | 100 +--- configure.ac | 2 +- share/certs/BitcoinFoundation_Apple_Cert.pem | 37 -- share/certs/BitcoinFoundation_Comodo_Cert.pem | 37 -- share/certs/PrivateKeyNotes.md | 46 -- share/pixmaps/addressbook16.bmp | Bin 1334 -> 0 bytes share/pixmaps/addressbook16mask.bmp | Bin 126 -> 0 bytes share/pixmaps/addressbook20.bmp | Bin 1478 -> 0 bytes share/pixmaps/addressbook20mask.bmp | Bin 142 -> 0 bytes share/pixmaps/bitcoin-bc.ico | Bin 22486 -> 0 bytes share/pixmaps/bitcoin.ico | Bin 68756 -> 0 bytes share/pixmaps/bitcoin128.png | Bin 10639 -> 0 bytes share/pixmaps/bitcoin128.xpm | 384 --------------- share/pixmaps/bitcoin16.png | Bin 827 -> 0 bytes share/pixmaps/bitcoin16.xpm | 181 ------- share/pixmaps/bitcoin256.png | Bin 28182 -> 0 bytes share/pixmaps/bitcoin256.xpm | 465 ------------------ share/pixmaps/bitcoin32.png | Bin 1982 -> 0 bytes share/pixmaps/bitcoin32.xpm | 140 ------ share/pixmaps/bitcoin64.png | Bin 4592 -> 0 bytes share/pixmaps/bitcoin64.xpm | 242 --------- share/pixmaps/check.ico | Bin 766 -> 0 bytes share/pixmaps/favicon.ico | Bin 1150 -> 0 bytes share/pixmaps/nsis-header.bmp | Bin 25818 -> 0 bytes share/pixmaps/nsis-wizard.bmp | Bin 154542 -> 0 bytes share/pixmaps/send16.bmp | Bin 1334 -> 0 bytes share/pixmaps/send16mask.bmp | Bin 126 -> 0 bytes share/pixmaps/send16masknoshadow.bmp | Bin 126 -> 0 bytes share/pixmaps/send20.bmp | Bin 1478 -> 0 bytes share/pixmaps/send20mask.bmp | Bin 142 -> 0 bytes share/setup.nsi.in | 179 ------- share/ui.rc | 15 - src/obj-test/.gitignore | 2 - 33 files changed, 2 insertions(+), 1828 deletions(-) delete mode 100644 share/certs/BitcoinFoundation_Apple_Cert.pem delete mode 100644 share/certs/BitcoinFoundation_Comodo_Cert.pem delete mode 100644 share/certs/PrivateKeyNotes.md delete mode 100644 share/pixmaps/addressbook16.bmp delete mode 100644 share/pixmaps/addressbook16mask.bmp delete mode 100644 share/pixmaps/addressbook20.bmp delete mode 100644 share/pixmaps/addressbook20mask.bmp delete mode 100644 share/pixmaps/bitcoin-bc.ico delete mode 100644 share/pixmaps/bitcoin.ico delete mode 100644 share/pixmaps/bitcoin128.png delete mode 100644 share/pixmaps/bitcoin128.xpm delete mode 100644 share/pixmaps/bitcoin16.png delete mode 100644 share/pixmaps/bitcoin16.xpm delete mode 100644 share/pixmaps/bitcoin256.png delete mode 100644 share/pixmaps/bitcoin256.xpm delete mode 100644 share/pixmaps/bitcoin32.png delete mode 100644 share/pixmaps/bitcoin32.xpm delete mode 100644 share/pixmaps/bitcoin64.png delete mode 100644 share/pixmaps/bitcoin64.xpm delete mode 100644 share/pixmaps/check.ico delete mode 100644 share/pixmaps/favicon.ico delete mode 100644 share/pixmaps/nsis-header.bmp delete mode 100644 share/pixmaps/nsis-wizard.bmp delete mode 100644 share/pixmaps/send16.bmp delete mode 100644 share/pixmaps/send16mask.bmp delete mode 100644 share/pixmaps/send16masknoshadow.bmp delete mode 100644 share/pixmaps/send20.bmp delete mode 100644 share/pixmaps/send20mask.bmp delete mode 100644 share/setup.nsi.in delete mode 100644 share/ui.rc delete mode 100644 src/obj-test/.gitignore diff --git a/Makefile.am b/Makefile.am index 9157365b616..a160fe5f4df 100644 --- a/Makefile.am +++ b/Makefile.am @@ -14,33 +14,12 @@ endif BITCOIND_BIN=$(top_builddir)/src/$(BITCOIN_DAEMON_NAME)$(EXEEXT) BITCOIN_CLI_BIN=$(top_builddir)/src/$(BITCOIN_CLI_NAME)$(EXEEXT) -BITCOIN_WIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EXEEXT) - -##OSX_APP=Bitcoin-Qt.app -##OSX_DMG=Bitcoin-Core.dmg -##OSX_BACKGROUND_IMAGE=background.tiff -##OSX_DEPLOY_SCRIPT=$(top_srcdir)/contrib/macdeploy/macdeployqtplus -##OSX_FANCY_PLIST=$(top_srcdir)/contrib/macdeploy/fancy.plist -##OSX_BASE_LPROJ_DIR=$(top_srcdir)/contrib/macdeploy/Base.lproj/InfoPlist.strings -##OSX_INSTALLER_ICONS=$(top_srcdir)/src/qt/res/icons/bitcoin.icns -##OSX_PLIST=$(top_srcdir)/share/qt/Info.plist #not installed -##OSX_QT_TRANSLATIONS = da,de,es,hu,ru,uk,zh_CN,zh_TW DIST_DOCS = $(wildcard doc/*.md) $(wildcard doc/release-notes/*.md) BIN_CHECKS=$(top_srcdir)/contrib/devtools/symbol-check.py \ $(top_srcdir)/contrib/devtools/security-check.py -WINDOWS_PACKAGING = $(top_srcdir)/share/pixmaps/bitcoin.ico \ - $(top_srcdir)/share/pixmaps/nsis-header.bmp \ - $(top_srcdir)/share/pixmaps/nsis-wizard.bmp - -##OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) $(OSX_BASE_LPROJ_DIR) \ -## $(top_srcdir)/contrib/macdeploy/$(OSX_BACKGROUND_IMAGE) \ -## $(top_srcdir)/contrib/macdeploy/DS_Store \ -## $(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \ -## $(top_srcdir)/contrib/macdeploy/detached-sig-create.sh - COVERAGE_INFO = baseline_filtered_combined.info baseline.info \ leveldb_baseline.info test_bitcoin_filtered.info total_coverage.info \ baseline_filtered.info \ @@ -60,84 +39,9 @@ distcheck-hook: distcleancheck: @: -$(BITCOIN_WIN_INSTALLER): all-recursive - $(MKDIR_P) $(top_builddir)/release - STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIND_BIN) $(top_builddir)/release - STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_CLI_BIN) $(top_builddir)/release - @test -f $(MAKENSIS) && $(MAKENSIS) -V2 $(top_builddir)/share/setup.nsi || \ - echo error: could not build $@ - @echo built $@ - $(if $(findstring src/,$(MAKECMDGOALS)),$(MAKECMDGOALS), none): FORCE $(MAKE) -C src $(patsubst src/%,%,$@) -##$(OSX_APP)/Contents/PkgInfo: -## $(MKDIR_P) $(@D) -## @echo "APPL????" > $@ -## -##$(OSX_APP)/Contents/Resources/empty.lproj: -## $(MKDIR_P) $(@D) -## @touch $@ -## -##$(OSX_APP)/Contents/Info.plist: $(OSX_PLIST) -## $(MKDIR_P) $(@D) -## $(INSTALL_DATA) $< $@ -## -##$(OSX_APP)/Contents/Resources/bitcoin.icns: $(OSX_INSTALLER_ICONS) -## $(MKDIR_P) $(@D) -## $(INSTALL_DATA) $< $@ -## -##$(OSX_APP)/Contents/MacOS/Bitcoin-Qt: $(BITCOIN_QT_BIN) -## $(MKDIR_P) $(@D) -## STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $< $@ -## -##$(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings: $(OSX_BASE_LPROJ_DIR) -## $(MKDIR_P) $(@D) -## $(INSTALL_DATA) $< $@ -## -##OSX_APP_BUILT=$(OSX_APP)/Contents/PkgInfo $(OSX_APP)/Contents/Resources/empty.lproj \ -## $(OSX_APP)/Contents/Resources/bitcoin.icns $(OSX_APP)/Contents/Info.plist \ -## $(OSX_APP)/Contents/MacOS/Bitcoin-Qt $(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings -## -##if BUILD_DARWIN -##$(OSX_DMG): $(OSX_APP_BUILT) $(OSX_PACKAGING) -## $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -add-qt-tr $(OSX_QT_TRANSLATIONS) -translations-dir=$(QT_TRANSLATION_DIR) -dmg -fancy $(OSX_FANCY_PLIST) -verbose 2 -## -##deploydir: $(OSX_DMG) -##else -##APP_DIST_DIR=$(top_builddir)/dist -##APP_DIST_EXTRAS=$(APP_DIST_DIR)/.background/$(OSX_BACKGROUND_IMAGE) $(APP_DIST_DIR)/.DS_Store $(APP_DIST_DIR)/Applications -## -##$(APP_DIST_DIR)/Applications: -## @rm -f $@ -## @cd $(@D); $(LN_S) /Applications $(@F) -## -##$(APP_DIST_EXTRAS): $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt -## -##$(OSX_DMG): $(APP_DIST_EXTRAS) -## $(GENISOIMAGE) -no-cache-inodes -D -l -probe -V "Bitcoin-Core" -no-pad -r -apple -o $@ dist -## -##$(APP_DIST_DIR)/.background/$(OSX_BACKGROUND_IMAGE): contrib/macdeploy/$(OSX_BACKGROUND_IMAGE) -## $(MKDIR_P) $(@D) -## $(INSTALL) $< $@ -##$(APP_DIST_DIR)/.DS_Store: contrib/macdeploy/DS_Store -## $(INSTALL) $< $@ -## -##$(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt: $(OSX_APP_BUILT) $(OSX_PACKAGING) -## INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) -add-qt-tr $(OSX_QT_TRANSLATIONS) -verbose 2 -## -##deploydir: $(APP_DIST_EXTRAS) -##endif -## -##if TARGET_DARWIN -##appbundle: $(OSX_APP_BUILT) -##deploy: $(OSX_DMG) -##endif - -if TARGET_WINDOWS -deploy: $(BITCOIN_WIN_INSTALLER) -endif - $(BITCOIND_BIN): FORCE $(MAKE) -C src $(@F) @@ -250,11 +154,9 @@ EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/rpc-tests.sh qa/pull install-exec-hook: mv $(DESTDIR)$(bindir)/fetch-params.sh $(DESTDIR)$(bindir)/zcash-fetch-params -CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER) - .INTERMEDIATE: $(COVERAGE_INFO) DISTCHECK_CONFIGURE_FLAGS = --enable-man clean-local: - rm -rf test_bitcoin.coverage/ zcash-gtest.coverage/ total.coverage/ $(OSX_APP) + rm -rf test_bitcoin.coverage/ zcash-gtest.coverage/ total.coverage/ diff --git a/configure.ac b/configure.ac index df8d3fdbe0c..f9c0f124698 100644 --- a/configure.ac +++ b/configure.ac @@ -862,7 +862,7 @@ AC_SUBST(GMPXX_LIBS) AC_SUBST(LIBSNARK_DEPINST) AC_SUBST(LIBZCASH_LIBS) AC_SUBST(PROTON_LIBS) -AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi src/test/buildenv.py]) +AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile src/test/buildenv.py]) AC_CONFIG_FILES([qa/pull-tester/run-bitcoind-for-test.sh],[chmod +x qa/pull-tester/run-bitcoind-for-test.sh]) AC_CONFIG_FILES([qa/pull-tester/tests-config.sh],[chmod +x qa/pull-tester/tests-config.sh]) diff --git a/share/certs/BitcoinFoundation_Apple_Cert.pem b/share/certs/BitcoinFoundation_Apple_Cert.pem deleted file mode 100644 index beb0d7073c0..00000000000 --- a/share/certs/BitcoinFoundation_Apple_Cert.pem +++ /dev/null @@ -1,37 +0,0 @@ -Bag Attributes - friendlyName: Developer ID Application: BITCOIN FOUNDATION, INC., THE - localKeyID: 6B 9C 6C A8 A5 73 70 70 E2 57 A3 49 D8 62 FB 97 C7 A5 5D 5E -subject=/UID=PBV4GLS9J4/CN=Developer ID Application: BITCOIN FOUNDATION, INC., THE/OU=PBV4GLS9J4/O=BITCOIN FOUNDATION, INC., THE/C=US -issuer=/CN=Developer ID Certification Authority/OU=Apple Certification Authority/O=Apple Inc./C=US ------BEGIN CERTIFICATE----- -MIIFhzCCBG+gAwIBAgIIJ0r1rumyfZAwDQYJKoZIhvcNAQELBQAweTEtMCsGA1UE -AwwkRGV2ZWxvcGVyIElEIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSYwJAYDVQQL -DB1BcHBsZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUg -SW5jLjELMAkGA1UEBhMCVVMwHhcNMTMwMTEwMjIzOTAxWhcNMTgwMTExMjIzOTAx -WjCBqDEaMBgGCgmSJomT8ixkAQEMClBCVjRHTFM5SjQxQDA+BgNVBAMMN0RldmVs -b3BlciBJRCBBcHBsaWNhdGlvbjogQklUQ09JTiBGT1VOREFUSU9OLCBJTkMuLCBU -SEUxEzARBgNVBAsMClBCVjRHTFM5SjQxJjAkBgNVBAoMHUJJVENPSU4gRk9VTkRB -VElPTiwgSU5DLiwgVEhFMQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBALTd5zURuZVoJviusr119aktXksenb9IN9vq6kBbq38vxEk7 -9wkKMES2XfBRh0HxcEizGzhMNy5OCXuTLMaNMihYdfwYSoBoR2foEU+6kjPUnyJ4 -dQBFLJZJr5/QeQmALmYHEgZ6lwXFD2lU8t92340zeJ4y5LZw5pcEHtH9IummYDut -OGCkCGXDcjL+5nHhNScJiXHhswM+62o6XXsQiP6EWbM1CsgrGTNLtaa0U/UvVDwE -79YKklSC5Bog2LD0jBcTuveI66mFzqu++L9X9u+ZArtebwCl7BPNQ+uboYy5uV2d -zf8lpNNZLfXCFjoLe9bLICKfZ7ub9V5aC8+GhckCAwEAAaOCAeEwggHdMD4GCCsG -AQUFBwEBBDIwMDAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AuYXBwbGUuY29tL29j -c3AtZGV2aWQwMTAdBgNVHQ4EFgQUa5xsqKVzcHDiV6NJ2GL7l8elXV4wDAYDVR0T -AQH/BAIwADAfBgNVHSMEGDAWgBRXF+2iz9x8mKEQ4Py+hy0s8uMXVDCCAQ4GA1Ud -IASCAQUwggEBMIH+BgkqhkiG92NkBQEwgfAwKAYIKwYBBQUHAgEWHGh0dHA6Ly93 -d3cuYXBwbGUuY29tL2FwcGxlY2EwgcMGCCsGAQUFBwICMIG2DIGzUmVsaWFuY2Ug -b24gdGhpcyBjZXJ0aWZpY2F0ZSBieSBhbnkgcGFydHkgYXNzdW1lcyBhY2NlcHRh -bmNlIG9mIHRoZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNv -bmRpdGlvbnMgb2YgdXNlLCBjZXJ0aWZpY2F0ZSBwb2xpY3kgYW5kIGNlcnRpZmlj -YXRpb24gcHJhY3RpY2Ugc3RhdGVtZW50cy4wDgYDVR0PAQH/BAQDAgeAMBYGA1Ud -JQEB/wQMMAoGCCsGAQUFBwMDMBMGCiqGSIb3Y2QGAQ0BAf8EAgUAMA0GCSqGSIb3 -DQEBCwUAA4IBAQAfJ0BjID/1dS2aEeVyhAzPzCBjG8vm0gDf+/qfwRn3+yWeL9vS -nMdbilwM48IyQWTagjGGcojbsAd/vE4N7NhQyHInoCllNoeor1I5xx+blTaGRBK+ -dDhJbbdlGCjsLnH/BczGZi5fyEJds9lUIrp1hJidRcUKO76qb/9gc6qNZpl1vH5k -lDUuJYt7YhAs+L6rTXDyqcK9maeQr0gaOPsRRAQLLwiQCorPeMTUNsbVMdMwZYJs -R+PxiAnk+nyi7rfiFvPoASAYUuI6OzYL/Fa6QU4/gYyPgic944QYVkaQBnc0vEP1 -nXq6LGKwgVGcqJnkr/E2kui5gJoV5C3qll3e ------END CERTIFICATE----- diff --git a/share/certs/BitcoinFoundation_Comodo_Cert.pem b/share/certs/BitcoinFoundation_Comodo_Cert.pem deleted file mode 100644 index dc752d455c9..00000000000 --- a/share/certs/BitcoinFoundation_Comodo_Cert.pem +++ /dev/null @@ -1,37 +0,0 @@ -Bag Attributes - friendlyName: The Bitcoin Foundation, Inc.'s COMODO CA Limited ID - localKeyID: 8C 94 64 E3 B5 B0 41 89 5B 89 B0 57 CC 74 B9 44 E5 B2 92 66 -subject=/C=US/postalCode=98104-1444/ST=WA/L=Seattle/street=Suite 300/street=71 Columbia St/O=The Bitcoin Foundation, Inc./CN=The Bitcoin Foundation, Inc. -issuer=/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO Code Signing CA 2 ------BEGIN CERTIFICATE----- -MIIFeDCCBGCgAwIBAgIRAJVYMd+waOER7lUqtiz3M2IwDQYJKoZIhvcNAQEFBQAw -ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxITAfBgNV -BAMTGENPTU9ETyBDb2RlIFNpZ25pbmcgQ0EgMjAeFw0xMzAxMTYwMDAwMDBaFw0x -NDAxMTYyMzU5NTlaMIG8MQswCQYDVQQGEwJVUzETMBEGA1UEEQwKOTgxMDQtMTQ0 -NDELMAkGA1UECAwCV0ExEDAOBgNVBAcMB1NlYXR0bGUxEjAQBgNVBAkMCVN1aXRl -IDMwMDEXMBUGA1UECQwONzEgQ29sdW1iaWEgU3QxJTAjBgNVBAoMHFRoZSBCaXRj -b2luIEZvdW5kYXRpb24sIEluYy4xJTAjBgNVBAMMHFRoZSBCaXRjb2luIEZvdW5k -YXRpb24sIEluYy4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQChUwLD -u/hu5aFZ/n11B27awONaaDrmHm0pamiWHb01yL4JmTBtaLCrSftF8RhCscQ8jpI0 -UG1Cchmay0e3zH5o5XRs0H9C3x+SM5ozms0TWDmAYiB8aQEghsGovDk0D2nyTQeK -Q0xqyCh0m8ZPOnMnYrakHEmF6WvhLdJvI6Od4KIwbKxgN17cPFIfLVsZ7GrzmmbU -Gdi4wSQCHy5rxzvBxho8Qq/SfBl93uOMUrqOHjOUAPhNuTJG3t/MdhU8Zp24s29M -abHtYkT9W86hMjIiI8RTAR+WHKVglx9SB0cjDabXN8SZ3gME0+H++LyzlySHT8sI -ykepojZ7UBRgp9w3AgMBAAGjggGzMIIBrzAfBgNVHSMEGDAWgBQexbEsfYfaAmh8 -JbwMB4Q/ts/e8TAdBgNVHQ4EFgQUfPf+ZyDWl/4LH0Y5BuJTelkRd/EwDgYDVR0P -AQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEQYJ -YIZIAYb4QgEBBAQDAgQQMEYGA1UdIAQ/MD0wOwYMKwYBBAGyMQECAQMCMCswKQYI -KwYBBQUHAgEWHWh0dHBzOi8vc2VjdXJlLmNvbW9kby5uZXQvQ1BTMEEGA1UdHwQ6 -MDgwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET0NvZGVTaWdu -aW5nQ0EyLmNybDByBggrBgEFBQcBAQRmMGQwPAYIKwYBBQUHMAKGMGh0dHA6Ly9j -cnQuY29tb2RvY2EuY29tL0NPTU9ET0NvZGVTaWduaW5nQ0EyLmNydDAkBggrBgEF -BQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMCgGA1UdEQQhMB+BHWxpbmRz -YXlAYml0Y29pbmZvdW5kYXRpb24ub3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAqibjo -D4HG5XSIIMCmYE5RgQBSEAJfI+EZERk1G9F83ZUWr0yNRZCw4O+RaM7xQhvJhEoD -G2kpk/q2bNOc71/VyZ6SrE1JRVUON41/Flhz4M6cP0BclTicXvh+efVwqZhIz+ws -UxF2hvC/1Xx6rqI7NYAlOYXk2MSUq3HREo+gWUPKM8em4MZZV/7XCH4QbsfxOl1J -xS6EOQmV8hfUN4KRXI5WfGUmedBxq7dM0RSJOSQl8fq2f+JjRLfjQwQucy7LDY+y -pRTsL2TdQV/DuDuI3s0NHRGznQNddoX5jqpXhSQFAAdgrhN1gGkWaaTPzr9IF2TG -qgr6PEp9tIYC+MbM ------END CERTIFICATE----- diff --git a/share/certs/PrivateKeyNotes.md b/share/certs/PrivateKeyNotes.md deleted file mode 100644 index da299d168f0..00000000000 --- a/share/certs/PrivateKeyNotes.md +++ /dev/null @@ -1,46 +0,0 @@ -Code-signing private key notes -== - -The private keys for these certificates were generated on Gavin's main work machine, -following the certificate authoritys' recommendations for generating certificate -signing requests. - -For OSX, the private key was generated by Keychain.app on Gavin's main work machine. -The key and certificate is in a separate, passphrase-protected keychain file that is -unlocked to sign the Bitcoin-Qt.app bundle. - -For Windows, the private key was generated by Firefox running on Gavin's main work machine. -The key and certificate were exported into a separate, passphrase-protected PKCS#12 file, and -then deleted from Firefox's keystore. The exported file is used to sign the Windows setup.exe. - -Threat analysis --- - -Gavin is a single point of failure. He could be coerced to divulge the secret signing keys, -allowing somebody to distribute a Bitcoin-Qt.app or bitcoin-qt-setup.exe with a valid -signature but containing a malicious binary. - -Or the machine Gavin uses to sign the binaries could be compromised, either remotely or -by breaking in to his office, allowing the attacker to get the private key files and then -install a keylogger to get the passphrase that protects them. - -Threat Mitigation --- - -"Air gapping" the machine used to do the signing will not work, because the signing -process needs to access a timestamp server over the network. And it would not -prevent the "rubber hose cryptography" threat (coercing Gavin to sign a bad binary -or divulge the private keys). - -Windows binaries are reproducibly 'gitian-built', and the setup.exe file created -by the NSIS installer system is a 7zip archive, so you could check to make sure -that the bitcoin-qt.exe file inside the installer had not been tampered with. -However, an attacker could modify the installer's code, so when the setup.exe -was run it compromised users' systems. A volunteer to write an auditing tool -that checks the setup.exe for tampering, and checks the files in it against -the list of gitian signatures, is needed. - -The long-term solution is something like the 'gitian downloader' system, which -uses signatures from multiple developers to determine whether or not a binary -should be trusted. However, that just pushes the problem to "how will -non-technical users securely get the gitian downloader code to start?" diff --git a/share/pixmaps/addressbook16.bmp b/share/pixmaps/addressbook16.bmp deleted file mode 100644 index c5576910b1b6b95c23ed7c53adec399a944e610a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1334 zcmZ9MKWrOS9LK*+iDcA*T|jP9K#EfVb%3_kxoL?Sz~+CTKo0?umkcM}a-)X~w`8y~ zWwata$wP;F^b*OVM^AaW@iN6rqzqX?CP!j;d|n(O=-qwq_kQ2^d%y4Zy_2r_Y;|6j z*XnE1Jw~M~TvK5-acvg<`*zOBxvAXL<4n`D6HQM%GM!B(AlC_)PJEuJ;Aq!F>#NkLovPNIJ5$BCNMjXNzRgQ_+*rp!g; zA@kIOH0r69ChE4y+o3w`mbys@n%a#*r9QS=N;g8a!={p`qHa`Dn3U9Rt|@8O6xBjv zRneM91uViXss*BIg-Ct1pujo>E&wqwzyhb34*>)GZGZ*v0ek=-zz6UFd;rgan8}zy z9K*-(2F}14I0I)qN3Dgo@D|R(;UVVyV|>JTi1A?2a=ck4gU;+G$Cp8$Dx%MwXb<4< zWDqq77(5xY4U>i@25o~j0eEeA^bPt3eWn2Qp2vg1gW((~M&aj7mEptAkqMyg_a@XPLPt?d zkC;5hhr8_UYhqQ@*XHJ?wzjskv$LbUy*(Wq9B6-kUx$Z>IyySi@$s=vPfvAzey)p) z3;p%C)5{kxw7tE}>9ScKn#}@lhQO)#%Jtps`s3Lw7VG>=O7B&F`?+#Qdc9t(-w6Nw z{nu~qFaPlTdHBKC%zr1p5Vd?$#kAAwEFRk42>mO|ReC~Q-`SIO_!hG=g_r>}+ss?m65uRi?;YjfP( diff --git a/share/pixmaps/addressbook16mask.bmp b/share/pixmaps/addressbook16mask.bmp deleted file mode 100644 index d3a478d1ad1d4800008fda5be5d583f3d0423480..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 126 tcmZ?rtz&=yJ0PV2!~#&v$iN7eZ~&8-#Q*>Q!Giz)F))yd?S4Sa0{}e{AL0N2 diff --git a/share/pixmaps/addressbook20.bmp b/share/pixmaps/addressbook20.bmp deleted file mode 100644 index 2b33b228aaec9ef51fb3dd46b3eab98f3d61d7df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1478 zcma)+J!~6g9LAp(Xj4#-1LY%>FBd2^1%kPdf|c^&f`Ee-Fy_la3iQe$IKDk(@RGsG z9usXbe`4esg7wT_5VJWhTCq&7#TB`8C#7sMrJhB7@1L`@i5T{jfVq~s9}w4E! zw_*2z22GFXsne(_Y6L`^Q&Ln9)UH?6LQUklMn%-9Rn@6^>eWhWRy~zaBdDkql+^G% zxmCM%<*{$qXH@q}s-X&AKx|alBhM=mUG_yagLz^>b>!A&$jizrda9N1+@k8GJjy9> z3#t{1s-n7^Q?J+hqv|Z8#9m33I+p%fx*CFV4wui69xl=fgy&0 zHi&!}3=9Sa0|TuQJ`4s11A_s;Fh8c5q0o@z)5B-)!(r0iHpf?1ZLO}ZYHe*z8yg$i z+}zam_O`aRwzRXequt$I?d|Ppe}7*G2M0PlJk-Dc8U1tPhSt~DIbB|sAI&C#J4GgAUy7(iLxq5=0b7wD>|14iTJ13pEig)jYa`|ijuj|Xd{$44U-+JXM>s@~B ze0F~B8Rz8vXU<$GJsqUpEY+uS&Pl@Tw=exP@s8g$^ZbVs@0%yToOqAF{OrTj+PqKh z`{=0l_^GM)#Y3On@@AKo&)K~1UcWZ2U08f)$$4~Pap8&8SARLm(^2hh-qP}ew)Tg& zy<4?!7M$E7wco$@8{Qk2Q|5D5QkK+v>=D;`4}9?ACI0Kqe*VH!_CVjizOwS^rPG<` PK3-Y5_U;`Xahmo&>vaK4 diff --git a/share/pixmaps/addressbook20mask.bmp b/share/pixmaps/addressbook20mask.bmp deleted file mode 100644 index 56ce6125dbb83abfac437bbbcdb611f45ee57cff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 142 zcmZ?r?PGudJ0PV2#3E44$iN7e2mq2o+z`wJ7J(4||Nn>c{{KI~KrXi54>yJZ01nMB AR{#J2 diff --git a/share/pixmaps/bitcoin-bc.ico b/share/pixmaps/bitcoin-bc.ico deleted file mode 100644 index 88cc240e2d4f77fa66730593a890a17aab86cbdc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22486 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 IOZolyKiCZ4$N&HU diff --git a/share/pixmaps/bitcoin.ico b/share/pixmaps/bitcoin.ico deleted file mode 100644 index f5480f41616a81cc3b65d0625f4f5e6f01a2f861..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68756 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 diff --git a/share/pixmaps/bitcoin128.xpm b/share/pixmaps/bitcoin128.xpm deleted file mode 100644 index d8e41e9ea44..00000000000 --- a/share/pixmaps/bitcoin128.xpm +++ /dev/null @@ -1,384 +0,0 @@ -/* XPM */ -static char *bitcoin___[] = { -/* columns rows colors chars-per-pixel */ -"128 128 250 2", -" c #845415", -". c #895616", -"X c #84581E", -"o c #8D5C18", -"O c #925A15", -"+ c #925E1C", -"@ c #98621C", -"# c #9E711C", -"$ c #A36E1A", -"% c #A96F1B", -"& c #A6711C", -"* c #AC741C", -"= c #B2741E", -"- c #B37C1E", -"; c #BB7C1E", -": c #835B21", -"> c #8F6125", -", c #956727", -"< c #916B2E", -"1 c #996B2C", -"2 c #B47B23", -"3 c #BD7C20", -"4 c #A17330", -"5 c #AB7D3B", -"6 c #C17F20", -"7 c #B9831F", -"8 c #BB842B", -"9 c #BD8533", -"0 c #B68F3D", -"q c #BE8C3B", -"w c #C4801F", -"e c #FE8C03", -"r c #F38A0F", -"t c #FD8E0A", -"y c #FF910C", -"u c #F78F13", -"i c #F98F10", -"p c #F79016", -"a c #FE9314", -"s c #F6931E", -"d c #FD961B", -"f c #FE991E", -"g c #C58421", -"h c #CD8621", -"j c #C78B21", -"k c #CC8B23", -"l c #C2852B", -"z c #C08B2D", -"x c #D28722", -"c c #D38B25", -"v c #DB8E22", -"b c #D28E2C", -"n c #D49323", -"m c #DC9224", -"M c #DC9B25", -"N c #D4922D", -"B c #DF972A", -"V c #DF982E", -"C c #C18D33", -"Z c #C58E38", -"A c #CB9332", -"S c #C2933C", -"D c #CD9339", -"F c #CC9938", -"G c #D19733", -"H c #DA9230", -"J c #D59935", -"K c #DC9C33", -"L c #DC9E3B", -"P c #E49124", -"I c #EA9426", -"U c #E09D26", -"Y c #EC972B", -"T c #F79625", -"R c #F99524", -"E c #F69A26", -"W c #F89825", -"Q c #F2972B", -"! c #F59A2C", -"~ c #F89B2B", -"^ c #E79D33", -"/ c #EF9D31", -"( c #E19F3A", -") c #EF9D3A", -"_ c #F49C33", -"` c #F99E32", -"' c #F49F39", -"] c #D6A13E", -"[ c #DAA33B", -"{ c #E3A127", -"} c #E7A328", -"| c #EDA32C", -" . c #EDA829", -".. c #FFA325", -"X. c #FFAB25", -"o. c #F3A42B", -"O. c #FFA429", -"+. c #F4A929", -"@. c #FFAC2A", -"#. c #FFB227", -"$. c #FFB32C", -"%. c #FFBA2D", -"&. c #EEA830", -"*. c #F7A334", -"=. c #FAA036", -"-. c #FCAB34", -";. c #F4A13C", -":. c #F9A33B", -">. c #F4A83B", -",. c #FFA83F", -"<. c #FDB432", -"1. c #FFBB33", -"2. c #FFB73A", -"3. c #FDB93E", -"4. c #FFC12F", -"5. c #FFC432", -"6. c #FFC338", -"7. c #D2A043", -"8. c #D8A140", -"9. c #EEA144", -"0. c #E2A840", -"q. c #EDA34B", -"w. c #F4A444", -"e. c #F9A642", -"r. c #FBA945", -"t. c #F3A64B", -"y. c #F4A84E", -"u. c #FBAB4B", -"i. c #EEB041", -"p. c #FABA44", -"a. c #ECA653", -"s. c #EEAC5D", -"d. c #F3AA53", -"f. c #FAAE53", -"g. c #F2AD5A", -"h. c #FBB056", -"j. c #F6B15E", -"k. c #FBB25B", -"l. c #DDAF79", -"z. c #E3A962", -"x. c #EBAE63", -"c. c #E4AC68", -"v. c #EAAF69", -"b. c #EEB065", -"n. c #E7B06C", -"m. c #EEB36B", -"M. c #F5B263", -"N. c #FBB461", -"B. c #E6B274", -"V. c #ECB574", -"C. c #E7B57B", -"Z. c #EAB77C", -"A. c #ECB97C", -"S. c #F2B770", -"D. c #F0BB7A", -"F. c #DBB485", -"G. c #DFB888", -"H. c #E4B984", -"J. c #EDBD82", -"K. c #E5BC8B", -"L. c #EABE8A", -"P. c #F0BE82", -"I. c #E0BF96", -"U. c #EDC089", -"Y. c #F0C28B", -"T. c #E5C194", -"R. c #E9C191", -"E. c #E4C39C", -"W. c #EBC699", -"Q. c #EBC99F", -"!. c #DFC3A0", -"~. c #DDCAAF", -"^. c #CFC7BD", -"/. c #D2CBB6", -"(. c #DBC8B1", -"). c #DBCDBB", -"_. c #E2C6A4", -"`. c #E6C8A5", -"'. c #EACBA5", -"]. c #E1C7A8", -"[. c #E3CBAD", -"{. c #EACCAA", -"}. c #EED1AC", -"|. c #E1CDB3", -" X c #E3CFB8", -".X c #E6D1B6", -"XX c #EBD2B3", -"oX c #E3D1BB", -"OX c #EAD6BB", -"+X c #EBD8BF", -"@X c #D3CDC2", -"#X c #D8CDC2", -"$X c #D0CECA", -"%X c #DDD3C4", -"&X c #D3D2CC", -"*X c #DDD5CB", -"=X c #CCD3D5", -"-X c #C9D7DF", -";X c #D2D4D6", -":X c #DEDAD4", -">X c #DDDCDB", -",X c #E2D4C2", -".N b b b b N >.( C > HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX4 L _ *.@.<.$.X.X...X.X.X.X.X.X...X.@.$.<.@.*./ G , HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX< L -.@.$.X...R R R T T T T W W W W W W T T T T R R W ..X.$.@.*.J HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXD -.%.X.W R T T W W W W W W W W W W W W W W W W W W W W W W T T R W X.%.+.A HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXS -.$.X.R T T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W T T R X.$.-.C HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXF <.@.f R T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W T R W #.<.A HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX[ <.X.f T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W T R X.$.K HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX0.$...R T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E W W W W W W W T R ..%.G HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXS 1...R T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ E W W W W W W W W W T R X.1.A HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX3.X.d T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ E W W W W W W W W W W T R @.2.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX7.5.f T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W T W %.z HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX3.X.s T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W T R $.<.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX1...R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ E E W W W W W W W W W W W W W R ..1.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX0 5.f T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W T W 5.8 HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX8.$.s W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W T R %.N HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXi.#.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W R $.&.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXp.X.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W R @.<.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXp.X.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W R @.<.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXi.X.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ E ~ W R ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` ` ` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W R @.| HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX] #.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ! s e t d ~ ` ` ` ` ` ` =.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W R %.N HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXq %.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E W E ~ ~ ~ ~ y l.=XI.x.) p a =.` ` =.=.=.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W R %.2 HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX5 5.d W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ t (.jXVXNXuX@XF.W ` =.:.` W =.:.=.=.` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W T R 5.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX1.f T W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ R Q eXDXSXSXDXgX#Xa ` =.=.;.q.W a a R ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W T W %.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX3...T W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ` a a.NXSXGXGXAXNXV.a :.:.f c.tX*XE.n.9.R ~ ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W T @.@.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXD #.R W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` t H.VXSXGXGXDXmXy.f :.:.a I.hXBXCXNXiX^.' W ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W R %.g HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX5.d W W W W W W W W W W W W W W W W W W W W W W W W W E ~ W ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` i |.CXGXGXGXCX3X~ ` :.:.R %XCXSXGXAXNX>XW ~ ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W R 5.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX2.W T W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ s t e a W ~ ` ` ` ` ` ` W ! eXFXGXGXSXVX[.d :.:.~ w.uXFXGXGXSXVXW.a ` ` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W T ..@.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHX9 $.R W W W W W W W W W W W W W W W W W W W W W W E W ~ ~ ~ y F./.B.9.T t t a ~ =.` =.a a.hXDXGXGXSXNXA.d :.e.R v.NXSXGXGXSXNXm.a =.` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W R %.= HXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHX6.d W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ W i &XjXNXfX:X].B.q.T t a d e K.VXSXGXGXDXaXd.W e.e.d E.VXSXGXGXDXvXw.W =.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W W W %.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXK X.T W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ a ) uXDXSXFXFXCXNXfX:X_.B.q.r .XFXGXGXGXCX3X=.=.e.,.~ %XCXGXGXGXCX1XW ` =.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W T $.m HXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHX5.R W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ t x.NXSXGXGXGXSXSXDXFXCXNXmX8XcXSXGXGXGXCXW.e :.e.=.t.uXFXGXGXSXVXE.d :.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W W R %.HXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHX^ X.T W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ ~ ~ ` t T.VXSXGXGXGXGXGXGXGXSXSXFXGXGXGXGXGXGXFX}.9.' W e v.VXSXGXGXSXNXm.d :.=.=.=.` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W W T @.P HXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHX1.R W W W W W W W W W W W W W W W W E E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ s ;XNXAXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXFXNX>X|.V.XXFXGXGXGXFXbXy.~ :.:.=.=.` ` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W W R %.HXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXH X.T W W W W W W W W W W W W W W E E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` R ' $XsXNXVXFXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXFXCXCXFXSXGXGXGXCXOXa :.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W T $.c HXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHX1.R W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` ~ t.V.`.5XVXFXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXFXXFXGXGXGXGXGXGXGXSXCX{.e.P.'.2XvXNXBXDXSXGXGXGXGXGXGXGXGXGXSXDXjX~.y W =.` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W W @.HXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHX: 1.R W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` =.=.=.=.=.:.:.:.:.:.:.:.:.e.e.e.~ s.fXDXGXGXGXGXGXGXGXSXNXD.f =.=.,.M.L.oXaXVXDXSXGXGXGXGXGXGXGXGXGXAXVX(.t ~ ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W R %. HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXl #.T W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` =.=.=.=.:.:.:.:.:.:.:.:.:.e.e.e.e.r.W H.NXSXGXGXGXGXGXGXGXDXzXg.r.f.f.f.r.=.=.g.`.fXBXAXGXGXGXGXGXGXGXGXGXAXjXH.t =.` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W T $.6 HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHX~ ..W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` =.=.=.=.=.:.:.:.:.:.:.:.e.e.e.e.e.e.e.r.W |.CXGXGXGXGXGXGXGXGXBX1X,.f.f.f.f.h.h.f.,.~ d.3XVXAXGXGXGXGXGXGXGXGXGXDXsX' f ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W ..~ HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHX$.R W W W W W E ~ ~ ~ ~ ~ ` ` ` ` ` ` =.=.=.=.=.=.:.:.:.:.:.:.:.e.e.e.e.e.r.r.r.,.w.>XFXGXGXGXGXGXGXGXSXNX`.=.f.h.h.h.h.f.f.f.f.=.~ ,XVXSXGXGXGXGXGXGXGXGXSXVXT.y ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W R $.HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXX %.T W W W W W E ~ ~ ~ ~ ~ ` ` ` ` =.=.=.=.=.:.:.:.:.:.:.:.:.e.e.e.e.e.e.r.r.r.u.=.x.fXDXGXGXGXGXGXGXGXSXmXA.,.h.h.h.k.k.h.f.f.f.f.:.~ 5XFXGXGXGXGXGXGXGXGXGXCX:XW ~ ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W T $.. HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHX8 $.T W W W W W W E ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.:.:.:.:.e.e.e.e.e.r.r.r.r.r.u.u.~ K.NXSXGXGXGXGXGXGXGXDXzXj.r.k.k.k.k.k.h.f.f.f.f.f.W V.VXSXGXGXGXGXGXGXGXGXDXuXw.f ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W T $.3 HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXY ..W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.:.e.e.e.e.e.e.r.r.r.r.u.u.u.u.~ |.CXGXGXGXGXGXGXGXGXBX2Xr.f.k.k.k.k.k.k.h.f.f.f.f.,.d.bXFXGXGXGXGXGXGXGXGXDXfXd.d =.` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W O.P HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXO.W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.e.e.e.e.r.r.r.r.r.r.u.u.u.u.r.w.>XFXGXGXGXGXGXGXGXSXNX'.,.k.k.k.k.k.k.k.h.h.f.f.f.e.y.kXFXGXGXGXGXGXGXGXGXDXfXg.d =.` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W O.HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHX$.R W W W W W W W W E ~ ~ ~ ~ ~ ` ` ` ` =.=.=.:.:.:.:.e.e.r.r.r.r.u.u.u.u.u.u.f.=.b.fXDXGXGXGXGXGXGXGXSXmXJ.r.k.k.k.k.k.k.k.h.h.f.f.f.:.s.mXFXGXGXGXGXGXGXGXGXDXpXy.R =.` ` ` ~ ~ ~ ~ ~ E E W W W W W W W W W W W W W W W W W $.HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHX1.R W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.r.u.u.u.u.u.u.u.f.=.K.NXSXGXGXGXGXGXGXGXFXxXM.u.k.k.k.k.k.k.k.k.h.f.f.k.~ K.VXSXGXGXGXGXGXGXGXGXCX5X=.~ =.=.` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W $.HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHX+ $.T W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.r.u.u.u.u.f.f.f.=.|.CXGXGXGXGXGXGXGXGXFXXFXGXGXGXGXGXGXGXGXFX9XA.b.u.r.r.u.u.h.h.h.u.r.O.w.:XCXSXGXGXGXGXGXGXGXGXSXhXL.a :.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W T $.* HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXV X.T W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.r.u.u.u.u.f.,.b.fXFXGXGXGXGXGXGXGXGXSXFXVXpX*X[.R.V.M.g.d.d.g.b.T.pXCXSXGXGXGXGXGXGXGXGXGXDXpXe.~ :.:.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W T $.; HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHX| O.T W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.:.e.e.r.r.u.u.u.u.f.=.K.NXSXGXGXGXGXGXGXGXGXGXGXSXFXFXBXNXmXuX>X3X3XyXmXVXFXSXGXGXGXGXGXGXGXGXGXAXhXE.d :.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W T @.h HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXc @.T W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` ` =.:.:.:.:.:.e.e.e.r.r.u.u.u.u.=.|.BXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXSXSXFXFXFXFXFXSXSXGXGXGXGXGXGXGXGXGXGXAXNX>X~ =.e.:.:.:.=.` ` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W @.h HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXk @.T W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.:.:.:.:.e.e.e.r.r.r.u.u.r.w.>XFXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXZXNXeXe.~ e.:.:.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W @.h HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXc @.T W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.r.u.u.=.x.fXFXGXGXGXGXGXGXGXGXGXFXFXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXFXCXfXoX:.~ r.e.:.:.:.:.:.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W @.h HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXc @.T W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.:.e.e.r.r.r.u.~ K.NXSXGXGXGXGXGXGXGXSXZX6XkXmXNXBXDXAXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGX0X'.S.~ =.u.e.e.e.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W @.h HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXk @.T W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.e.e.e.r.r.u.~ |.CXGXGXGXGXGXGXGXGXFX4X,.k.D.Q.,XkXmXNXDXSXSXGXGXGXGXGXGXGXGXGXGXGXXFXGXGXGXGXGXGXGXSXVX{.,.f.u.r.u.N.J.{.5XNXBXAXSXGXGXGXGXGXGXGXGXGXFXMXH.W r.u.r.e.e.e.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W T @.h HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXo.O.T W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.O.s.fXFXGXGXGXGXGXGXGXSXmXJ.r.N.N.N.N.h.r.r.f.J.1XhXBXAXGXGXGXGXGXGXGXGXSXDXjX!.W e.u.r.e.e.e.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W T @.g HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXB X.T W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.:.:.:.:.:.e.e.r.W H.NXSXGXGXGXGXGXGXGXDXuXM.u.k.k.N.N.N.N.N.h.,.e.D.>XNXSXGXGXGXGXGXGXGXGXSXZXjXE.W r.r.e.e.e.:.:.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W T $.- HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXl @.T W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.r.W |.CXGXGXGXGXGXGXGXGXBX2Xr.h.k.k.k.k.k.k.k.k.k.h.,.,.|.NXZXGXGXGXGXGXGXGXGXGXZXgXV.~ u.e.e.e.:.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W T $.% HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHX@ $.T W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.e.:.' >XFXGXGXGXGXGXGXGXSXNX{.,.k.k.k.k.k.k.k.k.k.k.k.k.u.~ `.NXSXGXGXGXGXGXGXGXGXSXCX>X=.e.r.r.e.e.:.:.:.:.:.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W T $.. HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHX%.R W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.e.~ s.fXFXGXGXGXGXGXGXGXSXNXJ.,.k.k.k.k.k.k.k.k.k.k.h.h.k.u.O.2XCXGXGXGXGXGXGXGXGXGXAXhXV.~ u.r.e.e.e.:.:.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W $.HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHX$.R W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` ` ~ :.:.:.:.e.f Z.VXSXGXGXGXGXGXGXGXDXzXM.r.k.k.k.k.k.k.k.h.h.h.h.f.f.k.=.V.NXSXGXGXGXGXGXGXGXGXSXVX`.W r.e.e.e.e.:.:.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W $.HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXO.W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` =.~ Q a a W =.=.t XCXGXGXGXGXGXGXGXGXBX2Xr.f.k.k.k.k.k.k.h.h.h.h.f.f.f.f.r.y.kXFXGXGXGXGXGXGXGXGXGXBX,X~ :.e.e.e.:.:.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W ~ ..HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXI O.W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` a z.-X_.B.q.! u C.NXSXGXGXGXGXGXGXGXSXNX'.=.h.h.k.k.k.h.h.f.f.f.f.f.f.f.f.r.w.5XFXGXGXGXGXGXGXGXGXGXCX2X=.:.e.:.:.:.:.:.:.:.:.=.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W O.P HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXk @.T W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ t ).jXVXNXaX2X1XBXDXSXGXGXGXGXGXGXGXSXmXA.:.h.h.h.h.h.f.f.f.f.f.f.f.f.f.f.,.d.vXFXGXGXGXGXGXGXGXGXGXCX1X` =.:.:.:.:.:.:.=.=.=.=.=.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W T $.; HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXo %.T W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ` y q.fXZXSXSXFXFXFXSXSXGXGXGXGXGXGXGXGXFXxXj.r.f.h.h.h.f.f.f.f.f.f.f.f.u.u.f.W B.NXSXGXGXGXGXGXGXGXGXSXBXoXW :.:.:.:.:.:.=.=.=.=.=.` ` ` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W %. HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHX$.R W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ` e !.CXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXFX+Xd ,.f.h.h.h.f.f.f.f.f.f.u.u.u.f.,.T :XFXGXGXGXGXGXGXGXGXGXSXNXE.f :.:.:.:.:.=.=.=.=.` ` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W R $.HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHX~ ..W W W W W W W W W W W W W W W W W W W W E ~ ~ a _ aXFXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXFX7XV.s.:.=.:.,.u.f.f.f.f.u.u.u.r.~ s ~.VXSXGXGXGXGXGXGXGXGXGXAXhXV.d :.:.=.=.=.=.=.` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W O.E HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXg $.T W W W W W W W W W W W W W W W W W W W E ~ ~ e G.hXAXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXFXVXpX*X_.Z.x.t.:.` ~ ~ ~ ~ ~ ' x.*XVXSXGXGXGXGXGXGXGXGXGXGXDXuXw.W :.=.=.=.=.` ` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W W W T $.; HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHX %.R W W W W W W W W W W W W W W W W W W W W ~ d T qXgXBXFXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXFXFXBXNXaX>X,X[._.T.T.E.|.:XNXCXSXGXGXGXGXGXGXGXGXGXGXSXVX Xd =.=.=.=.` ` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ E W W W W W W R %.HXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHX@.W W W W W W W W W W W W W W W W W W W W W ~ R ` s.H.oXkXNXNXCXFXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXSXDXFXCXCXBXVXVXBXCXFXSXSXGXGXGXGXGXGXGXGXGXGXGXAXhXm.a :.` =.` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W W W W W W W @.HXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXx @.T W W W W W W W W W W W W W W W W W W W W ~ ~ y t a _ g.L.oXkXhXVXCXFXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXGXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXBX:Xf ~ ` ` ` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ E W W W W W W W W W T $.h HXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHX%.R W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ d a t a ' s.R.oXnXDXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXZXhXg.y =.` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ E ~ E W W W W W W W W W W R %.HXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXO.~ W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ` ` ~ W a a d ! WS?bT0)&MN}OM(^1gC=*lV+*LH2vB+d8tUfTdg-8|gabI-Zl-{C(JfZdyK z&s;x0SeXA{urz;ppmhEHLxtYm$qZlvg8z{OQZwU+hZa6Oezp0@ao_v+u<=R8}g$#+@>f(FK`68bJeSXi+HLRuK9n7>rzb7pMbT z00L+$PaG@eJM^e=R|tHMz-zL;<5^5HOR_c_#ofC|<65wJNqAxZJ2%IHbqT1clRX11 zv$uu`JgOZ>S?f84_4EkpiD4SKmn?y{Oe-&9cUq5rHj+C6D0ysOI(?+O?M+O8z#!x8 zB>g|JyAI)G4`9b)$el;2?>K=r28>2X$-o{pHt<+7Ehk^uGn`3sf+&Po3K9>agvJW0 zn8qU8emRR%pQHZdNrH#=f-xWjok{uJ#h14a%Z_-|PuNiSb%+9t4$;mwqV(fL!e({n zi|E87#N9h6CxNirz-R!~9yfgw9SEWjV+=ZQace6yWg2NaIDdT$kqhZO%3Z=X4X_if zpV3BR49L~m`cFCv!`Aa6mwHDpVgD(VQrLH|5x;#Et8s^B=RvfH!)B1Q2|~iy?XRDLLddigC(rhGQzJ?+xIGK&zz@eZ%6&{1(sg{zmD&FEYE zSALjlo_nDu`8+66wcn`Sp3#9{mAWm9v-~AawM@J*hjA+ep-&hZuHACa{W#aGY=Ja; zCRfa7>`_Yqv1F(dS>1?r`RQgkrM)UdK4GNs0>iE4;6h(vP`+_GSIl+VZzv_O zl>*Z`L}5s%4Sr~tUk)bv&n|4CeBYQpe=R%odoee?GTH4{FL#^DrM+hHVzMGoL@6pn)r*oxm#<~hUyPOBk`ESaOW0VijX~X~k002ovPDHLk FV1j&ih5rBm diff --git a/share/pixmaps/bitcoin16.xpm b/share/pixmaps/bitcoin16.xpm deleted file mode 100644 index 40a0624ac72..00000000000 --- a/share/pixmaps/bitcoin16.xpm +++ /dev/null @@ -1,181 +0,0 @@ -/* XPM */ -static char *bitcoin__[] = { -/* columns rows colors chars-per-pixel */ -"16 16 159 2", -" c #CA7C1E", -". c #CB7D1E", -"X c #D1811E", -"o c #D0801F", -"O c #D1801F", -"+ c #D3821F", -"@ c #D7831F", -"# c #EE8D18", -"$ c #F4931F", -"% c #D78625", -"& c #D88520", -"* c #D98521", -"= c #D98620", -"- c #D78B2D", -"; c #DF8D2A", -": c #DF8F2F", -"> c #DF943B", -", c #D8913C", -"< c #D8923E", -"1 c #DF953E", -"2 c #E28B23", -"3 c #E38B23", -"4 c #EA9023", -"5 c #EB9023", -"6 c #ED9122", -"7 c #ED9123", -"8 c #EE9123", -"9 c #EE9223", -"0 c #F39421", -"q c #F19423", -"w c #F39523", -"e c #F79521", -"r c #F59422", -"t c #F49623", -"y c #F69622", -"u c #F79623", -"i c #F09324", -"p c #F19424", -"a c #F19525", -"s c #F49624", -"d c #F59625", -"f c #F49725", -"g c #F79624", -"h c #F79724", -"j c #F69725", -"k c #F79725", -"l c #F69726", -"z c #F79726", -"x c #F89621", -"c c #F89722", -"v c #F89723", -"b c #F89724", -"n c #F89824", -"m c #F89825", -"M c #F99825", -"N c #F89925", -"B c #F89926", -"V c #F89927", -"C c #F99927", -"Z c #F0972E", -"A c #F7992A", -"S c #F79A2B", -"D c #F79B2C", -"F c #F69A2D", -"G c #F79D2F", -"H c #F89929", -"J c #F89A28", -"K c #F89A29", -"L c #F99A29", -"P c #F99B29", -"I c #F89A2A", -"U c #F89A2B", -"Y c #F99B2B", -"T c #F89B2C", -"R c #F89C2C", -"E c #F99C2D", -"W c #F99C2E", -"Q c #F89D2E", -"! c #F99D2F", -"~ c #E29335", -"^ c #E49639", -"/ c #E2983F", -"( c #F79F35", -") c #F99E31", -"_ c #F89E32", -"` c #F99E32", -"' c #F9A033", -"] c #F9A035", -"[ c #F9A135", -"{ c #F9A036", -"} c #F9A136", -"| c #F9A137", -" . c #F3A03F", -".. c #F7A43F", -"X. c #F8A139", -"o. c #F9A23A", -"O. c #FAA33B", -"+. c #FAA43E", -"@. c #FAA43F", -"#. c #EF9F41", -"$. c #EEA244", -"%. c #ECA34B", -"&. c #F8A440", -"*. c #F9A541", -"=. c #F9A644", -"-. c #F9A947", -";. c #F0A349", -":. c #F5A648", -">. c #F1A74E", -",. c #F7AA4F", -"<. c #E4A458", -"1. c #E4A55B", -"2. c #E8A95E", -"3. c #F2A950", -"4. c #F4AA52", -"5. c #FBAF55", -"6. c #E4A860", -"7. c #EAAC63", -"8. c #EBAF68", -"9. c #F2AF61", -"0. c #EBB16C", -"q. c #F6B568", -"w. c #E3AF71", -"e. c #EBBE89", -"r. c #E0BC93", -"t. c #E3C199", -"y. c #E6C59D", -"u. c #EAC89E", -"i. c #E7C8A2", -"p. c #EACBA6", -"a. c #EBCFAF", -"s. c #F1CCA0", -"d. c #E7CEB1", -"f. c #ECD1B0", -"g. c #E5D2BB", -"h. c #E8D2B8", -"j. c #DFDFDF", -"k. c #E7D5C1", -"l. c #E7D7C4", -"z. c #E5D7C7", -"x. c #E7DACB", -"c. c #EADAC8", -"v. c #E9DCCC", -"b. c #EDDFCE", -"n. c #E5DDD3", -"m. c #E4DFD9", -"M. c #ECE0D1", -"N. c #E4E1DD", -"B. c #EDE3D8", -"V. c #EAE4DD", -"C. c #ECE5DC", -"Z. c #E2E2E2", -"A. c #E5E2E0", -"S. c #E4E4E4", -"D. c #E7E7E7", -"F. c #EAEAE9", -"G. c gray92", -"H. c #EEEEEE", -"J. c None", -/* pixels */ -"J.J.J.J.J.J.J.1 > J.J.J.J.J.J.J.", -"J.J.J.J.J./ ..| ' ( ~ J.J.J.J.J.", -"J.J.J.< *.{ V $ r U W _ - J.J.J.", -"J.J., o.J 0 # <.w.$.F N H % J.J.", -"J.J.o.T e 1.r.k.x.t.S z B u J.J.", -"J.^ [ Y ! #.z.H.M.n.0.d n m 2 J.", -"J.X.) | =. .h.B.5.f.j.;.v B d J.", -": Q M ` &.>.A.V.p.c.l.4.E n d = ", -"; I b A Z 2.D.s.u.F.a.-.} C w & ", -"J.l g y 6.m.G.q.3.b.Z.,.] D 8 J.", -"J.3 k c %.d.C.v.N.S.y.@.L a * J.", -"J.J.j z x 8.i.g.e.9.+.W t 6 J.J.", -"J.J.+ s h G :.7.O.R B s 7 . J.J.", -"J.J.J.O i f P L K d p 5 J.J.J.", -"J.J.J.J.J.@ 9 q i 4 + J.J.J.J.J.", -"J.J.J.J.J.J.J.X o J.J.J.J.J.J.J." -}; diff --git a/share/pixmaps/bitcoin256.png b/share/pixmaps/bitcoin256.png deleted file mode 100644 index 1d42116ef1199d86749d17f1740121a659262f4a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28182 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 diff --git a/share/pixmaps/bitcoin256.xpm b/share/pixmaps/bitcoin256.xpm deleted file mode 100644 index 87bb35cdadd..00000000000 --- a/share/pixmaps/bitcoin256.xpm +++ /dev/null @@ -1,465 +0,0 @@ -/* XPM */ -static char *bitcoin___[] = { -/* columns rows colors chars-per-pixel */ -"256 256 203 2", -" c #BE741B", -". c #C1761B", -"X c #C6791C", -"o c #CC7C1D", -"O c #D07F1D", -"+ c #C67B21", -"@ c #CC7E21", -"# c #D4821E", -"$ c #D9841F", -"% c #ED8E1D", -"& c #EF911F", -"* c #CF8022", -"= c #D48323", -"- c #DB8621", -"; c #DD8922", -": c #D58729", -"> c #D6882B", -", c #DE8C2A", -"< c #CE8C3C", -"1 c #D28934", -"2 c #D98E32", -"3 c #D28E3C", -"4 c #DF9132", -"5 c #D6903E", -"6 c #DD933B", -"7 c #E58C22", -"8 c #E98F23", -"9 c #E38F2B", -"0 c #E88F28", -"q c #ED9124", -"w c #E6922D", -"e c #EB942B", -"r c #EF982F", -"t c #F59624", -"y c #F89723", -"u c #F79826", -"i c #F89825", -"p c #F1972A", -"a c #F59A2C", -"s c #F89B2B", -"d c #E59534", -"f c #EA9632", -"g c #EE9933", -"h c #E3963B", -"j c #E6993D", -"k c #EC9C3B", -"l c #F49C33", -"z c #F99E32", -"x c #F29E3A", -"c c #F7A037", -"v c #F9A036", -"b c #F5A13C", -"n c #F9A33B", -"m c #CE9147", -"M c #D29245", -"N c #DC9641", -"B c #DD9846", -"V c #D2954B", -"C c #DC9A4B", -"Z c #E59C44", -"A c #EA9E43", -"S c #E39E4B", -"D c #E89F49", -"F c #F09F40", -"G c #EDA145", -"H c #E6A14D", -"J c #EBA34B", -"K c #F4A443", -"L c #F9A642", -"P c #F7A847", -"I c #FAA846", -"U c #F3A64A", -"Y c #F8A748", -"T c #F5A94D", -"R c #FAAA4B", -"E c #E6A454", -"W c #EBA552", -"Q c #EDA856", -"! c #E4A55B", -"~ c #E8A75B", -"^ c #E7A95E", -"/ c #EBA95B", -"( c #F0A751", -") c #F4AB53", -"_ c #FAAE53", -"` c #F4AE5A", -"' c #F8AF59", -"] c #FAB057", -"[ c #F6B15E", -"{ c #FAB25B", -"} c #DFAD6F", -"| c #DCAE77", -" . c #DFB27D", -".. c #E5AA64", -"X. c #E8AB61", -"o. c #E5AE6C", -"O. c #E6B06F", -"+. c #ECB16C", -"@. c #F5B365", -"#. c #FBB562", -"$. c #FBB867", -"%. c #F5B66B", -"&. c #FAB768", -"*. c #F4B86F", -"=. c #FBB96A", -"-. c #E1AE71", -";. c #E5B174", -":. c #EBB573", -">. c #EFB977", -",. c #E5B47A", -"<. c #EEBA7B", -"1. c #F3B770", -"2. c #F3B974", -"3. c #FBBC72", -"4. c #F3BC7B", -"5. c #F8BF7A", -"6. c #FAC079", -"7. c #DCB382", -"8. c #DFBB8F", -"9. c #DABB96", -"0. c #DBBD99", -"q. c #E2B682", -"w. c #E4B985", -"e. c #ECBD84", -"r. c #E3BB8B", -"t. c #EABF8C", -"y. c #F1BE83", -"u. c #E2BE92", -"i. c #D3BDA2", -"p. c #DEC09C", -"a. c #EEC28D", -"s. c #F4C286", -"d. c #F8C282", -"f. c #F3C48B", -"g. c #E7C297", -"h. c #ECC393", -"j. c #E2C29D", -"k. c #EAC69B", -"l. c #ECC89F", -"z. c #F1C694", -"x. c #F2C897", -"c. c #F1CA9B", -"v. c #DBC2A3", -"b. c #D6C2AB", -"n. c #DDC7AD", -"m. c #DEC9AF", -"M. c #D3C4B3", -"N. c #DDCAB3", -"B. c #D2C7B9", -"V. c #D6C9BA", -"C. c #DDCEBB", -"Z. c #DFD0BE", -"A. c #E2C5A2", -"S. c #E8C7A0", -"D. c #E6C9A5", -"F. c #EBCBA4", -"G. c #E2C7A8", -"H. c #E3CAAC", -"J. c #EBCDA9", -"K. c #EFD2AF", -"L. c #F3D1A7", -"P. c #F1D1A9", -"I. c #E4CEB3", -"U. c #E8CFB1", -"Y. c #E1CFBA", -"T. c #E6D0B6", -"R. c #E9D1B4", -"E. c #E4D2BC", -"W. c #EAD4BA", -"Q. c #F4D5B0", -"!. c #F4D9B9", -"~. c #CDCDCD", -"^. c #D5CCC3", -"/. c #D4CFCA", -"(. c #DED2C3", -"). c #D3D1CE", -"_. c #DED6CC", -"`. c #D5D5D5", -"'. c #DBD7D1", -"]. c #DEDAD4", -"[. c #DDDDDC", -"{. c #E3D5C3", -"}. c #E9D7C1", -"|. c #EBD9C4", -" X c #E1D6CA", -".X c #E3D9CD", -"XX c #EADDCD", -"oX c #E1DBD4", -"OX c #E8DFD4", -"+X c #E1DEDB", -"@X c #EDE3D7", -"#X c #E3E1DE", -"$X c #E8E3DC", -"%X c #F6E5D2", -"&X c #F4EBDF", -"*X c #E4E4E4", -"=X c #ECE7E2", -"-X c #EDE9E4", -";X c #ECECEC", -":X c #F0EBE7", -">X c #F4F4F4", -",X c #FEFEFE", -"X>X>X>X;X;X*X[.`.r.n n z v v v v c x l p l x x c c v v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u i u X>X>X>X>X>X;X*X[.`.@.n n v v v v v c g E | S k f r l l l z z z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u i e X>X,X,X,X,X>X>X;X*X_.R n v v v v v v x e 0.`.`.V.p.;.H f e e p l l z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y , X>X,X,X,X,X>X>X;X*XI.L n v v v v n n x g V.`.[.[.[.[.[.(.p.;.S f r l z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u u y X,X,X,X,X,X>X>X;X*Xa.n n v v v n n n l A `.[.*X*X-X-X*X*X*X[.`.V.9.K z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u i u X,X,X,X,X,X>X>X-X[.%.n n n n n n n b p o.[.*X;X;X;X>X;X;X*X*X[.`.~.T z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y 0 X>X,X,X,X,X,X>X;X*XoXR L n n n n n n b g u.*X-X;X>X>X>X>X>X;X*X*X[.N.L n z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y X>X,X,X,X,X>X>X;X*XI.L L n n n n n n b g C.*X;X>X>X,X,X,X>X>X;X*X[.g.L n z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u i u X,X,X,X,X,X>X>X;X*Xh.L L n n n n n n l G [.*X;X>X,X,X,X,X>X>X;X*X[.2.n n z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y w X,X,X,X,X,X>X>X-X[.%.L n n n n n n b l o.*X;X>X>X,X,X,X,X,X>X;X*X]._ n v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y X>X,X,X,X,X,X>X;X*XoXR L n n n n n n b g j.*X;X>X>X,X,X,X,X,X>X;X*XE.I n v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y t X>X,X,X,X,X>X>X;X*XT.I L n n n n n n b k Z.*X;X>X,X,X,X,X,X>X>X;X*Xl.L n v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y ; X,X,X,X,X,X>X>X;X*Xh.L L n n n n L L x G [.*X;X>X,X,X,X,X,X>X>X;X*X4.n n v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u i u X>X,X,X,X,X,X>X>X-X[.%.L L n n n L L L l ;.*X;X>X>X,X,X,X,X,X>X;X*X[._ L n v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y q X>X>X>X;X;X;X;X*X*X*X*X].N.q.! d e e r p q ,.-X;X>X>X,X,X,X,X,X>X;X*XoX_ I L n L L L L K g j.*X;X>X>X,X,X,X,X,X>X;X*XE.Y L n v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X>X>X>X>X>X>X>X>X;X;X;X;X*X*X*X*X_.I.r.o.Z w D.;X>X>X,X,X,X,X,X,X>X;X*XW.R I L L L L L L K k Y.*X;X>X,X,X,X,X,X>X>X;X*Xl.L L n v v v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y q X>X,X,X,X,X,X,X>X>X>X>X>X>X;X;X;X;X*X*X*X*X$X}.=X>X>X>X,X,X,X,X,X,X>X;X*Xx.I I L L L L L L x J [.*X;X>X,X,X,X,X,X>X>X;X*X4.L n n v v v v v z z z z z z s s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X;X;X;X;X;X>X>X>X>X,X,X,X,X,X,X,X>X>X;X&.L L L L L L L L x ;.*X;X>X>X,X,X,X,X,X>X;X*X[.' L n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X>X>X@Xb l x x K L L L L k j.*X;X>X>X,X,X,X,X,X>X;X*XE.R L n n n n v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X:XW.g.;.H k k k b F k {.;X>X>X,X,X,X,X,X>X>X;X*XS.I L n n n n v v v v v z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X;X*X+XE.j.,.~ j A =X;X>X>X,X,X,X,X,X>X>X;X*X4.I L n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X;X;X*X*X*X*XXX}.;X>X>X,X,X,X,X,X,X>X>X;X#X{ I n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y t X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X;X;X;X>X>X>X,X,X,X,X,X,X,X>X>X;X|.R I n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X>X>X;XF.L L n n n n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X,X,X,X,X,X,X,X,X,X,X,X>X>X;X@.a x b b n n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X|.e.G g l c b n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 0 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X+XG...k g l b n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X;X*X*X(.w.A g l c c v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t = X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X-X*X*X'.u.A r l x c v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X*X*X].u.k r l c v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X*X*X_.q.g p l z v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 7 X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X*X[.C.W p l c v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X;X;X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X*X*X[.w.r a l z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X-X-X-X*X*X-X;X;X;X;X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X*X[.H.g a z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 0 X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;Xf.3.x.R..X+X*X*X*X*X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X*X*X(.k p z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X$.{ { { $.3.f.F.{.[.*X*X*X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X*X_.W p z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t @ X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X-X|.{ ] _ ] { { { { $.3.h.R..X*X*X*X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X*X'.k p z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 0 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ._ ] _ _ _ _ ] { { { #.$.$.f.T.oX*X*X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X*X_.l a z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xs._ _ _ _ _ _ _ _ _ ] { { { { { =.l..X*X*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X*XH.t z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X+X&.] _ _ _ _ _ _ _ _ _ _ _ _ ] { { { #.k.oX*X-X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.:.t z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.{ { _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ] _ { J.*X*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X'.l s z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XF.{ { _ _ _ _ _ _ _ _ ] _ _ _ _ _ _ _ _ _ _ _ y.oX*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.t.u z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xs.{ ] _ _ _ _ _ ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ ' .X*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X'.z z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X].&.{ ] _ _ _ ] ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ R R oX*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.:.u z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.#.{ _ _ _ _ ] ] ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ I @.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XD.s z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XF.{ { _ ' ] ] ] ] ] { { { ] ] ] _ _ _ _ _ _ _ _ R R _ n k.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X_.n z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xs.{ { ] ] ] ] { { { { { { ] ] ] _ _ _ _ _ _ _ _ R R R I T +X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.T z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.=.{ { ] ] ] { { { { { { { ] ] ] _ _ _ _ _ _ _ _ _ R R R K D.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.%.z z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.#.{ ] ] { { { { { { { { { { ] ] ] _ _ _ _ _ _ _ _ R R R K e.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.<.v v z z z z z z z s s s s s s s s s s s s u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.{ { { { { { { { { { { { { { { ] ] ] _ _ _ _ _ _ _ _ R R K +.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X<.n v v z z z z z z s s s s s s s s s s s s u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xs.#.{ { { { { { { { { { { { { { ] ] ] ] _ _ _ _ _ _ _ _ R U / *X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xe.n n v v z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.=.#.{ { { { { { { { { { { { { { ] ] ] ' _ _ _ _ _ _ _ _ R K +.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X<.n n v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.$.#.{ { { { { { { { { { { { { { { ] ] ] ] _ _ _ _ _ _ _ T K ,.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.>.n n v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t @ X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.#.#.{ { { { { { { { { { { { { { { ] ] ] ] _ _ _ _ _ _ _ T G j.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.%.n n v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t = X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.#.{ { { { { { { { { { { { { { { { { ] ] ] _ _ _ _ _ _ _ T J X-X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X]._ L n v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X#X3.#.{ { { { { { { { { { { { { { { { { { ] ] ] _ _ _ _ _ ) G ..*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X{.R L n v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X|.=.#.{ { { { { { { { { { { { { { { { { { { ] ] ' _ _ _ _ T k E.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XH.L L n v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;Xc.] { { { { { { { { #.{ { { { { { { { { { { ] ] ] _ _ _ ( A w.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.a.L n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;Xx.( Q ( ) ` [ [ { #.#.#.{ { { { { { { { { { { ] ] _ ) T D o.*X;X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.[ L n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;XOXI.u.O./ Q Q ` ` [ [ [ { { { { { { { { { ] ' ) ( J H r.*X-X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XE.R I n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X*X*X_.H.r.;.X./ Q Q ) ) ` ` ` ` ` ) ) ( J H W ,.{.*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.y.I L n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X;X*X*X*X*X].(.H.u.q.;.^ ^ ~ ~ E E ~ o.r.G. X*X*X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X_._ Y L n n n n n v v v z z z z z z z s s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i u t @ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X;X;X*X*X*X*X*X*X[.]..X X XoX+X*X*X*X-X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.f.R I n n n n n n v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t = X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X;X;X;X;X;X;X-X-X*X*X*X-X;X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X;X*X X_ R L n n n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X;X;X;X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.%.R I L n n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i t - X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X*X[.k.R R L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X*X[.l.] _ I L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X-X*X[.l.{ _ Y L L L n n n n n n n n v v v v v v z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X*X*X].h.{ _ R L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X;X*X[.T.3.{ ] R I L L L L L n n n n n n n n n v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X;X;X;X;X;X;X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X*XW.s.#.{ _ R I I L L L L L L n n n n n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X-XQ.|.OX*X*X*X*X*X;X;X;X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X&X!.L.d.#.{ ] R R I I I L L L L L L n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;XXX3.3.3.s.c.R..X[.*X*X*X-X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X%X{ L R _ _ R R R I I I I L L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-XK.&.=.=.&.=.3.3.d.c.R..X[.*X*X*X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;XJ.J K Y R R Y I I I I L L L L L L n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.$.#.#.#.#.&.&.=.=.3.3.f.F.}.+X*X*X*X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;XOX:.K U R R I I I I I L L L L L L n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X-X+X3.$.#.{ { #.#.#.#.$.$.&.=.=.3.6.c.W.+X*X*X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X*Xj.K K R R I I I I I L L L L L n n n n n n n n v v v v v v z z z z z z s s s s s s s s s s s s u u u i i i i i i i i i i i i i i i i i i i i i i u t = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.&.#.{ { { { #.#.#.#.#.#.#.#.$.$.=.=.5.J..X*X*X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X*XH.K K R R I I I I L L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i u t = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.#.#.{ { { { #.#.#.#.#.#.#.#.{ #.#.$.$.$.=.z.{.*X*X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X*X*XC.U K R I I I I I L L L L L L n n n n n n n n v v v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i u q * s u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u u u u s s s s s s s s s s s z z z z z z z v v v v v n n n n n n n n L L L L L L I I K A Z.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.#.#.{ { { { { #.#.#.#.{ { { { { { { #.#.#.#.$.z.{.*X*X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X*XC.b K Y I I I I L L L L L L n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i u q + X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.3.#.{ { { { { { #.#.#.{ { { { { { { { { { { #.#.#.$.F.+X*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.H.b P I I I I I L L L L L n n n n n n n n n v v v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.$.#.{ { { { { { { { { { { { { { { { { { { { { { { #.{ 2.{.*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.e.b Y I I I I L L L L L L n n n n n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.#.#.{ { { { { { { { { { { { { { { { { { { { { { { { { { { U.*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X].T L Y I I I I L L L L L L n n n n n n n n v v v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.#.{ { { { { { { { { { { { { { { { { { { { { { { { { ] { { _ R.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X-X*XD.L R I I I I L L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.=.#.{ { { { { { { { { { { { { { { { { { { { { { ] ] ] ] ] { ' R T.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.` L I I I I I L L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i t 8 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.$.#.{ { { { { { { { { { { { { { { { { { { { ] ] ] ] ] ] ] _ ] _ R oX*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.g.n I Y I I I I L L L L L n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.{ { { { { { { { { { { { { { { { { { { { { ] ] ] ] ] _ _ _ _ _ ] Y <.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X(.I I I I I I L L L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i u t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.{ { { { { { { { { { { { { { { { { { { ] ] ] ] ] ] _ _ _ _ _ _ _ _ T .X-X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.[ L I I I L L L L L L L L n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i u q = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.=.{ { ] { { { { { { { { { { { { { { ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ P g.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.e.n I L L L L L L L L L L n n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.#.{ ] ] { { { { { { { { { { { ] ] ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ Y +.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xg.L I L L L L L L L L L n n n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.{ { ] ] ] { { { { { { { { { ] ] ] ] ] ' _ _ _ _ _ _ _ _ _ _ _ _ _ _ T Q #X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XD.I I L L L L L L L n n n n n n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.{ { ] ] ] ] { { { { { { { ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ Y W +X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XI.I I L L L L L n n n n n n n n n n n n n n n v v v v v v z z z z z z z s s s s s s s s s s u u u u u i i i i i i i i i i i i t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.=.{ ] ] ] ] ] { { { { { ] ] ] ] ] ' _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R T W +X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XE.I L L L L n n n n n n n n n n n n n n v v v v v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i u q ; X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.#.{ _ _ ] ] ] ] { ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R K X.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XE.I L n n n n n n n n n n n n n n n n v v v v v v v v v z z z z z z z z s s s s s s s s s s s s u u u i i i i i i i i i i i t q @ X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.{ { _ _ _ ] ] ] ] ] ] ] ] ' _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R x q.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XD.R L n n n n n n n n n n n n n n n v v v v v v v v v z z z z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i t q X>X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xs.{ ] _ _ _ ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R R R T k G.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XS.I L n n n n n n n n n n n n n v v v v v v v v v z z z z z z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i t q X>X>X,X,X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X#X&.{ _ _ _ _ _ ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R R R R K A oX;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xh.L L n n n n n n n n n n v v v v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s u u u i i i i i i i i i t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X|.{ ] _ _ _ _ _ ] ] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R R R R R U k u.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.2.L L n n n n n n n n n v v v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s u u u u i i i i i i i u q = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;Xc.R _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R R R R R R T k D +X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.' L n n n n n n n n v v v v v v v z v v z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s u u u u i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;Xf.K G G U ) ) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R R R R R R R U A j {.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X{.R L n n n n n n v v v v v v v v v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-XXXH.w.X.J J J T ) ) ) _ _ _ _ _ _ _ _ R R R R R R R R R R R Y K k D Y.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.L L n n n n v v v v v v v v z z z z z z z z z z z z z s z s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i u t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X-X*X#X(.A.q...H J J U U T T T T R R R R R R R R R Y Y U K k A ;..X*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X-X[.4.L n n n v v v v v v v v z z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i t q * X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X;X*X*X*X[.(.H.u.,.^ J D G A J K K U U U U K k k k A E w.Y.*X*X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X]._ L n v v v v v v v v v v z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i t q X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X;X;X;X-X*X*X*X*X[._.N.A.u.;.;...E E E E ..;.q.j.I.+X*X*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XH.I L n v v v v v v v v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i t 8 X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X;X;X;X;X-X*X*X*X*X*X*X*X+X+X+X+X*X*X*X*X*X;X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.1.L n v v v v v v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i u q ; X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X XR L n v v v v v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i t q X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X-X[.a.L n v v v z z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i t 8 X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X]._ L n v z z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i u q ; X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.a.L n v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X_.R L n z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i t 8 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.2.L n z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u s u u u u u u u u i i i i i i i i i i i i i i i i i i t q = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.D.L L v z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X*X XR L n z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i u q 7 X>X,X,X,X,X,X,X,X>X>X>X>X;X;X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X*X'._ I n z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u i u u i i i i i i i i i i i i i i i i i i i i i i t q o X>X,X,X,X,X,X,X>X>X>X=X;X-X-X-X;X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X-X*X].%.L L z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X>X,X,X,X,X,X>X>X;X=X=.5.c.W.oX*X*X-X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X*X*X_.%.I L z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i t q - X>X,X,X,X,X,X>X>X;X|._ _ _ { #.4.l.}.$X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X*X[.E.{ I L v z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u i u i i i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X,X,X,X,X,X>X>X;X*XF.R R R R _ _ { { { 4.-X>X>X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X;X;X*X*X[.k._ I n z z z s s s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q 7 X,X,X,X,X,X>X>X;X*X4.R I I I I R R R b U -X>X>X,X,X,X,X,X,X,X,X>X>X>X>X>X;X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X;X;X;X-X*X*X[.T.*.R L n z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X>X;X*X+X] R I L I I I I P x t.;X>X>X,X,X,X,X,X,X,X>X>X;X;X;X;X-X-X-X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X*X*X*X[.].U.4.R I L v z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q 7 X>X,X,X,X,X>X>X;X*XE.R Y L L I I I I K k I.-X;X>X,X,X,X,X,X,X>X>X;X|.f.J.W..X[.[.*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X[._.I.h.#.R L L n z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u i u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q . X,X,X,X,X,X>X>X;X*Xl.I I L L L I I P K A oX-X>X>X,X,X,X,X,X>X>X;X;Xs.R _ _ { #.4.y.S.l.T.{.{. XoXoXoXoX].oX{.{.E.k.a.2.{ _ I L n v z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q 7 X,X,X,X,X,X>X>X;X[.2.I I L L L L I L x ^ *X;X>X>X,X,X,X,X,X>X>X;X*X#.I I I I Y I R I _ R _ ] { { [ { { { { ] _ R R I I L n n v z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q . X>X,X,X,X,X,X>X;X*X]._ Y L L L L L I L k r.*X;X>X>X,X,X,X,X,X>X;X-X.XR L n n n n n n L L L L L L L n L n n n L n n n c v z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q 7 X>X,X,X,X,X>X>X;X*XT.R I L L L L L L K k H.*X;X>X>X,X,X,X,X>X>X;X*XJ.L L n n n n n v v v v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X,X,X,X,X,X>X>X;X*Xk.I I n L L L L L b k ].*X;X>X,X,X,X,X,X>X>X;X*Xy.L n n n n v v v v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q 7 X,X,X,X,X,X>X>X-X[.2.L L n L L L L L l ^ [.-X>X>X,X,X,X,X,X>X;X*X[.[ L n n n v v v v v v v z z v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X,X,X,X,X,X>X;X*X]._ L L n L L L L K g r.*X;X>X>X,X,X,X,X,X>X;X*X{.R L n v v v v v v v z z z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q - X,X,X,X,X>X>X;X*XE.I L n n n L L L b g H.*X;X>X>X,X,X,X,X>X>X;X*XF.L L v v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q 8 X>X>X,X>X>X>X;X*Xk.L L n n n n L L x k _.*X;X>X,X,X,X,X,X>X>X;X*Xy.n n v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q # X>X>X>X>X;X*X[.2.L L n n n n n b l ~ [.-X>X>X,X,X,X,X,X>X;X*X[.' L n v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s s u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q 7 X>X,X,X,X,X,X>X;X*X{.I n c v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X>X,X,X,X,X>X>X;X*XF.L n v z z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q - X>X,X,X,X,X>X>X;X*X4.n n z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q 7 .L n n n n n n b l E [.*X;X>X>X,X,X,X>X>X;X*X[.' n v z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X>X>X>X>X>X;X*X{.I n z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q - X>X>X;X;X*X[.S.n n z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q 7 DFwwRRLxO5D^qBpo)srZrqw~HrcK2Zgw|)(Kf9~Oj=Njwbec} zR7V||ff)y8u!2>r+PDhcMq6vEm9?;nQb0tY!#p3%FpqohU{3%4%Vq95xE9i+CSOLm zIOlxlobUVp`!fLJF81dhR=;31nbogYP2nZ~eX{)Qo{4^q^>Y5S_>f5J{qq` zOyFgp}@~nmY|BQ#o-M}YtX>}zzc>~7c<6`}Ch;<7fnCC#Ko(Z8Ujg>|& zHTzjQgnhFanOtyk1A7ZTu6!;%U$$q`1PBoL&sp8qx?@SXaG*FQTJj;7W+{LQF#jZQ z(U=KwUlt>h0U~3{;>yInc`s)Z|1SQW<02q~-``_cZWZemv95CN2plzN5UEUMpJ@;o zn8=i&GR=$=BqEI1^_@8u{+)LsaVOdD>(wu<6YCZ-@a(bR)NvXDm1%I8mcdh7jF4$A z!lrCQSP9121gwzApt|vXrbSj_(%lIBvSs_i^~`JX^R|we=i$l}MD!_)Ljeo8Z2+`pJ)PwY6jR|Q+$ zAJKoP1fIQ_@ECGox7*=vIe>_T5$Ns3jkeDq*3P3WC@Ls+MD;3cSoP2>j-?P##_it0 zs)fy><R3*84yYqb9>o2N z=rdfq0DjkZL?Gz3!`Ja|xca`06LAdOfTOVl5k8hQy0@u7HnhL3+QTt9Hg$jO)vQ8~ zF~41)F`7ldHCR>)L6I{Of7NPW%(Tb2rAKn)Z*@&M4&AoWSJE+jBQWYv)VUJ+FP)Bsm{NkpW8$D}wCt$n$33(rhMBuql1NYGv;BHt0`-%1NyX~Za%jH7w z#7nG+`P59J3SqqlSGT4bX-#u4`n1`N|2y|03m~ztp}o%JUkb5)1p*CE!Zp}OT@nG0 z2TrGxK8J^gAqWD3?(g6{UjwP}4 zoJU{c{*wZ}-b)BvFu-x`47^@1fyZJo_-|Zg zpd!;G$iEOTS%s)M7hzU`>TK9Ptsw7Nw@m(hh@E^Mu~RQVXkH6f*LfaHdOp~42*QCP zh+Mh40;a-TS%q}U!f>S;SGJ~Bk6JLfZHxN#XjQs2cIRgzpwGg((vWkm8{yAu;9nfkrCI%PC^ez_&*&eO;cko5~J(A!l= z1J4GrH)kVo;$;e)zwAa6l>W@~F^JL7k}bLvJ|WO1zjdm*`4KBJWXa$+E9FrwetnYIZ2G8uGCB;rmBB*q%8MFDk z4E$`_^iq!TgIBW7carN8Nhm9N4iO=ltp#*wB}knJPQL&5tt6{*B^$@3^xD=WD_a<3 zhq9vOgUU?Fj$gILbgjrvowshDp*87N Q{{R3007*qoM6N<$f>S`#1ONa4 diff --git a/share/pixmaps/bitcoin32.xpm b/share/pixmaps/bitcoin32.xpm deleted file mode 100644 index bffedd4c68e..00000000000 --- a/share/pixmaps/bitcoin32.xpm +++ /dev/null @@ -1,140 +0,0 @@ -/* XPM */ -static char *bitcoin__[] = { -/* columns rows colors chars-per-pixel */ -"32 32 102 2", -" c #CC7D1D", -". c #D5831F", -"X c #D48221", -"o c #D98621", -"O c #DC8820", -"+ c #DC8D2C", -"@ c #D98F36", -"# c #D68F39", -"$ c #DD943E", -"% c #E28B23", -"& c #E98F24", -"* c #E18F2D", -"= c #ED9124", -"- c #EC942A", -"; c #F59624", -": c #F89724", -"> c #F79827", -", c #F89825", -"< c #F0962B", -"1 c #F59A2D", -"2 c #F99B2B", -"3 c #EC9732", -"4 c #EC9A37", -"5 c #E2963B", -"6 c #E6983A", -"7 c #EC9C3B", -"8 c #F69D33", -"9 c #F99E32", -"0 c #F49E3A", -"q c #F9A036", -"w c #F6A13C", -"e c #F9A33B", -"r c #D79341", -"t c #DC9641", -"y c #E39A43", -"u c #EA9D42", -"i c #EFA041", -"p c #EDA34B", -"a c #F5A443", -"s c #F9A643", -"d c #FAA846", -"f c #F2A64C", -"g c #F9AA4B", -"h c #E5A251", -"j c #ECA756", -"k c #EBA758", -"l c #FAAF57", -"z c #FBB057", -"x c #FBB25B", -"c c #DFB179", -"v c #E4AA65", -"b c #EBAE64", -"n c #E9AF69", -"m c #FBB665", -"M c #F1B46A", -"N c #F8B96D", -"B c #E5B071", -"V c #EBB777", -"C c #EEB877", -"Z c #E7B478", -"A c #EBB97D", -"S c #F0B671", -"D c #F2B871", -"F c #EFBC80", -"G c #E6BD8D", -"H c #EDBF88", -"J c #E6BF90", -"K c #F1C187", -"L c #F1C288", -"P c #E5C093", -"I c #EEC493", -"U c #E1C19B", -"Y c #E9C69C", -"T c #ECC89D", -"R c #F1C897", -"E c #DFC5A4", -"W c #DBCBB8", -"Q c #E2C7A7", -"! c #EBCBA6", -"~ c #E6CBAB", -"^ c #E9D2B7", -"/ c #E5D1B9", -"( c #EBD6BD", -") c #EFD9BE", -"_ c #DDD0C2", -"` c #DCD7D2", -"' c #DEDEDE", -"] c #ECDAC5", -"[ c #EDDECB", -"{ c #E9E0D5", -"} c #E7E0D9", -"| c #E9E2DB", -" . c #EFE8DF", -".. c #E5E5E5", -"X. c #EBE7E2", -"o. c #EFEAE6", -"O. c #ECECEC", -"+. c #F2ECE6", -"@. c #F1F0EE", -"#. c #F4F4F4", -"$. c #FBFBFB", -"%. c None", -/* pixels */ -"%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.", -"%.%.%.%.%.%.%.%.%.%.%.%.%.%.t 5 5 $ %.%.%.%.%.%.%.%.%.%.%.%.%.%.", -"%.%.%.%.%.%.%.%.%.%.%.r u w q 9 9 9 8 4 # %.%.%.%.%.%.%.%.%.%.%.", -"%.%.%.%.%.%.%.%.%.y s e 9 2 , , , : > 2 9 q 5 %.%.%.%.%.%.%.%.%.", -"%.%.%.%.%.%.%.%.s q 2 , , , , : , > 2 2 > > 2 9 %.%.%.%.%.%.%.%.", -"%.%.%.%.%.%.t e 1 , , , , : : ; > 2 9 9 2 , , > 2 + %.%.%.%.%.%.", -"%.%.%.%.%.$ e 2 , , , , , , ; u u 8 1 1 2 > , , > > + %.%.%.%.%.", -"%.%.%.%.%.e 2 , , : > ; ; > < ` ` 0 c n 1 2 , , , > , %.%.%.%.%.", -"%.%.%.%.e 1 , , , , ; h v - 3 ..! w ' _ 9 2 > , , , > : %.%.%.%.", -"%.%.%.6 q , : , > 2 > W ..| [ #.H V ..D 9 9 2 , , , , , % %.%.%.", -"%.%.%.e 2 , > 2 2 2 9 b ! #.$.$.#.#.#.Y i 1 2 > , , , > ; %.%.%.", -"%.%.@ q > 2 2 2 9 q e q 0 o.$.+.) { #.#.| b 2 2 , , , , : X %.%.", -"%.%.4 9 2 2 9 q e e s w b O.#.( m x I @.$...f > > , , , : & %.%.", -"%.%.8 > 2 2 9 e s d g a P #.#.L x l a [ $.#.A 2 2 , : , , ; %.%.", -"%.+ 1 , , 2 2 q e d g f / $.#.T n k Z o.$.O.M 9 2 > , , , ; X %.", -"%.* 2 , , , 2 9 q e s f X.$.#.O.O.O.#.$.+.Y g e 9 2 , , , ; o %.", -"%.* 2 , , , 2 2 q e w n O.$.[ R ( O.$.$.[ d s e 9 2 2 , , ; o %.", -"%.+ 2 , , , > 2 8 8 1 G #.#.T m m N ] #.#.~ s e e 9 2 > : ; X %.", -"%.%.> , , , , 2 < v B [ $.O.m z z s b #.$...g e e q 9 2 ; = %.%.", -"%.%.= : , , , : 7 ' O.#.$.@.C j p u ~ #.$.} g q 9 9 2 2 ; % %.%.", -"%.%.o , , , , : 0 G ^ .$.#.O.X.{ X.#.$.#.Y e 9 2 2 > , ; %.%.", -"%.%.%., : , , , 2 2 2 M O.) ] #.#.#.#.O./ d 9 2 > , , ; = %.%.%.", -"%.%.%.& ; , , , , 2 ; Q ..g F O.K A H S s 9 2 > , : , ; o %.%.%.", -"%.%.%.%.; ; , , , , 2 E _ d ' ..d q q 9 2 > , : , , ; = %.%.%.%.", -"%.%.%.%.%.; : , , , 2 q d g U J e 2 2 > , , , , , ; = %.%.%.%.%.", -"%.%.%.%.%.o ; : , , , 2 9 q 9 q 9 > , : , , , , ; = . %.%.%.%.%.", -"%.%.%.%.%.%.. ; ; , , > 2 2 2 > , , , , , , , ; = %.%.%.%.%.%.", -"%.%.%.%.%.%.%.%.= ; : > 2 2 , , : , , , , ; ; & %.%.%.%.%.%.%.%.", -"%.%.%.%.%.%.%.%.%.. = ; > : , , , , ; ; = = X %.%.%.%.%.%.%.%.%.", -"%.%.%.%.%.%.%.%.%.%.%. % = ; ; ; ; & O %.%.%.%.%.%.%.%.%.%.%.", -"%.%.%.%.%.%.%.%.%.%.%.%.%.%. X X %.%.%.%.%.%.%.%.%.%.%.%.%.%.", -"%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%." -}; diff --git a/share/pixmaps/bitcoin64.png b/share/pixmaps/bitcoin64.png deleted file mode 100644 index 08c676ae4afe56ca8baf2a517ef3b598e82a79f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4592 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 a<@g7UP5S@EeV0D~0000 c #FD8E0C", -", c #FF910E", -"< c #F98F14", -"1 c #F79117", -"2 c #FD9314", -"3 c #FC951B", -"4 c #FE9A1D", -"5 c #CA8E22", -"6 c #CC8E2A", -"7 c #D48D23", -"8 c #C39223", -"9 c #CE9925", -"0 c #D19C25", -"q c #D19329", -"w c #D5992B", -"e c #DD9D33", -"r c #D69F3C", -"t c #E29425", -"y c #E79925", -"u c #EA9926", -"i c #E69A2C", -"p c #F79625", -"a c #F99524", -"s c #F79825", -"d c #F89825", -"f c #F3962A", -"g c #F69B2C", -"h c #F89B2B", -"j c #E19F30", -"k c #EE9B34", -"l c #F49D33", -"z c #F99E32", -"x c #F39F3B", -"c c #DFA731", -"v c #D7A43D", -"b c #DCA63C", -"n c #EEA328", -"m c #FFA225", -"M c #FFAB26", -"N c #F3A529", -"B c #FEA429", -"V c #F4AB2A", -"C c #FFAC2A", -"Z c #FFB325", -"A c #FFB42C", -"S c #FFBB2D", -"D c #E3A335", -"F c #E5A438", -"G c #EDA03D", -"H c #F7A037", -"J c #FAA135", -"K c #F3AB31", -"L c #FEAB31", -"P c #F4A13C", -"I c #F9A33B", -"U c #FDB432", -"Y c #FFBF37", -"T c #FFC12F", -"R c #FFC230", -"E c #FFC03E", -"W c #DFAF41", -"Q c #ECA34D", -"! c #EDA84E", -"~ c #F2A343", -"^ c #FAA642", -"/ c #FAA846", -"( c #F1A74C", -") c #F6A94F", -"_ c #FAAA4A", -"` c #E7A451", -"' c #ECA754", -"] c #EFAA56", -"[ c #ECAC5B", -"{ c #F3AA52", -"} c #FCAE52", -"| c #FBB056", -" . c #FBB25C", -".. c #E7AB61", -"X. c #ECB067", -"o. c #E7B36D", -"O. c #EBB36C", -"+. c #F2B163", -"@. c #FCB460", -"#. c #F0B56B", -"$. c #E3B274", -"%. c #EDB672", -"&. c #EDB877", -"*. c #E2B57C", -"=. c #ECB97B", -"-. c #E4BA83", -";. c #EBBD83", -":. c #E7BF8D", -">. c #EBBD88", -",. c #E9C08C", -"<. c #E7C496", -"1. c #EBC393", -"2. c #EBC997", -"3. c #E7C49A", -"4. c #E9C69A", -"5. c #E3CA9D", -"6. c #E9C89E", -"7. c #DCC9AE", -"8. c #DDCBB2", -"9. c #E3C7A2", -"0. c #E5CAA3", -"q. c #E9CBA3", -"w. c #E5CEAB", -"e. c #E8CEAA", -"r. c #E4D4AC", -"t. c #EBD2AF", -"y. c #E7CFB2", -"u. c #E1D4B4", -"i. c #E8D5B6", -"p. c #E5D7BB", -"a. c #E9D6BB", -"s. c #E5D8B9", -"d. c #EAD8BE", -"f. c #F0D6B4", -"g. c #DFDFC6", -"h. c #E3D6C1", -"j. c #E9D7C0", -"k. c #E6DAC5", -"l. c #EBDCC7", -"z. c #E5DCCA", -"x. c #EADEC9", -"c. c #E8DFD0", -"v. c #D7E2D9", -"b. c #E3E0C9", -"n. c #EEE2CB", -"m. c #E6E1D4", -"M. c #E9E2D3", -"N. c #E4E4DC", -"B. c #E9E5DE", -"V. c #F4EDDE", -"C. c #DFE8E6", -"Z. c #DEEEE8", -"A. c #DFF2F3", -"S. c #DDFFFF", -"D. c #E1E6E0", -"F. c #E8E6E2", -"G. c #E8E9E5", -"H. c #E5EFEC", -"J. c #E8E9EA", -"K. c #EAF3EE", -"L. c #F3F3EB", -"P. c #E7EDF2", -"I. c #E8EEF3", -"U. c #E7F4F7", -"Y. c #E9F0F7", -"T. c #EBF5FD", -"R. c #E4FEFF", -"E. c #ECFCFF", -"W. c #F4F5F4", -"Q. c #F4FFFF", -"!. c #FEFFFF", -"~. c None", -/* pixels */ -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.F L h C C A A A A C C h L e ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.D N C m d d a a p a a p a a d m m C N j ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.- K M m a p s d d d d d d d d d d d d s p d m M V % ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.Y M d a d d d d d d d d d d d d d d d d h h d s a d M U ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.E m 4 a d d d d d d d d d d d d d d d d d d h h h d d d a d M U ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.C 4 a d d d d d d d d d d d d d d d d d h h h h h h d d d d d a m C ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.W S a p d d d d d d d d d d d d d d d d h h h h g g h h h d d d d d p a S c ~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.v M a s d d d d d d d d d d d d d d d h h h h h g z z g h h d d d d d d s a C w ~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.r Z a d d d d d d d d d d d d d d d g 4 : 2 h z z z z z h h h h d d d d d d d a S q ~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.b Z a d d d d d d d d d d d d d d h h 4 x $.l a z H h h H z h h h d d d d d d d d a A w ~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.T a s d d d d d d d d d d d d h h h g : $.R.T.7.a B x f > a H h h d d d d d d d d s a R ~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.U a s d d d d d d d d d d d d h h h h z : e.!.!.p.2 3 8.D.5.' a h h h d d d d d d d d p d A ~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.U M p d d d d d d d d d d h h 1 : : 2 h h p B.!.Q.%., l J.!.R.-.> z h h h d d d d d d d d p C N ~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.S a d d d d d d d d d d h d 3 7.r.O.G p ; k E.!.T.( , [ E.!.T.~ 4 z h h h d d d d d d d d d a S ~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.V d s d d d d d d d d h h h 2 l E.!.Q.T.m.:.q.!.!.l.: : -.Q.!.c.a z z z g h h d d d d d d d d s m A ~.~.~.~.~.~.~.", -"~.~.~.~.~.~.@ S a d d d d d d d h h h h z : *.R.!.!.!.!.Q.!.!.!.V.,.Q d.!.Q.1.2 I z z h h h d d d d d d d d d a S X ~.~.~.~.~.~.", -"~.~.~.~.~.~.U d s d d d d d h h h h h g z a [ 5.M.Q.!.!.!.!.!.!.!.Q.E.!.!.Q.&.; 3 J H z h h h d d d d d d d d s h C ~.~.~.~.~.~.", -"~.~.~.~.~.~.S a d d d d h h h h h h z z z I d > < %.W.!.!.!.!.!.!.!.!.!.!.!.W.s.[ > 4 H g h h d d d d d d d d d a S ~.~.~.~.~.~.", -"~.~.~.~.~.i M p d d d h h h h g z z z z J H I I J > x.!.!.!.!.Q.T.E.Q.!.!.!.!.!.E.u.f 2 H h h h d d d d d d d d p C 7 ~.~.~.~.~.", -"~.~.~.~.~.C a d h h h h h g g z z z J J I I I I J P J.!.!.!.!.d.P =.e.G.E.!.!.!.!.Q.Z.f 2 z h h d d d d d d d d d d A ~.~.~.~.~.", -"~.~.~.~.~.A a h h h h h g z z z J H I I I I ^ / d X.E.!.!.!.Q.1.4 I J I ;.U.!.!.!.!.!.N.1 h g h h d d d d d d d d a S ~.~.~.~.~.", -"~.~.~.~.6 C p d h h h z z J J J I I I I ^ ^ ^ _ a 3.Q.!.!.!.E.#.I . ._ 3 ] K.!.!.!.!.E.O., z h h h d d d d d d d p A + ~.~.~.~.", -"~.~.~.~.i B d d h h h g z J I I I I ^ ^ ^ / / _ h k.!.!.!.!.J.) } . .| .3 6.Q.!.!.!.Q.q.> z g h h d d d d d d d d B t ~.~.~.~.", -"~.~.~.~.B d d d d h h h z z J I I ^ / / / _ _ ^ ( I.!.!.!.Q.d.I . . .| .d 1.Q.!.!.!.Q.q.2 z h h h d d d d d d d d d B ~.~.~.~.", -"~.~.~.~.C a d d d d h h g z J H I ^ ^ / _ _ } J %.E.!.!.!.Q.;.4 _ } | } J f m.!.!.!.!.Q.;.2 J z g h h d d d d d d d a A ~.~.~.~.", -"~.~.~.~.C a d d d d h h h z z J I I ^ ^ / _ } z 6.Q.!.!.!.!.n.<.&.+.{ ) ] h.Q.!.!.!.!.R.~ d H z z h h h d d d d d d a A ~.~.~.~.", -"~.~.~.~.A a d d d d d h h g z z H I I ^ / _ _ z k.!.!.!.!.!.!.Q.E.I.F.F.T.Q.!.!.!.!.E.9.2 I J z z h h h d d d d d d d A ~.~.~.~.", -"~.~.~.~.S a d d d d d h h h z z J I I ^ ^ / I ( P.!.!.!.!.Q.Q.!.!.!.!.!.!.!.!.!.!.E.w.d J I I J z h h h d d d d d d d A ~.~.~.~.", -"~.~.~.~.A a d d d d d d h h h z J J I I ^ / h O.E.!.!.!.Q.f.1.z.Y.E.!.!.!.!.!.!.L.! , ^ / I I H z z h h h d d d d d d A ~.~.~.~.", -"~.~.~.~.S p d d d d d d h h h z z J I I ^ / d <.Q.!.!.!.E.+.d _ +.>.k.E.!.!.!.!.Q.s.P J _ ^ I I J z z h h h d d d d d A ~.~.~.~.", -"~.~.~.~.C a d d d d d d d h h g z z H I I ^ d k.!.!.!.!.J.{ | @.} I I O.H.!.!.!.!.Q.C.l I ^ I I H J z g h h d d d d a A ~.~.~.~.", -"~.~.~.~.B a d d d d d d d h h h h z z J I J x P.!.!.!.Q.j.I . . . . .B { K.!.!.!.!.Q.0.a / ^ I I J z z h h h d d d a A ~.~.~.~.", -"~.~.~.~.B d d d d d d d d d h h h J h f 2 ; [ E.!.!.!.Q.1.I . . .| | .d 4.Q.!.!.!.!.m.z I ^ I I I J z h h h h d d d B ~.~.~.~.", -"~.~.~.~.u B d d d d d d d d h h z , ' v.q.X.M.!.!.!.!.E.#.^ . .| } } } d >.Q.!.!.!.!.F.x J I I I J J z z h h h d d C t ~.~.~.~.", -"~.~.~.~.7 C p d d d d d d d d h h : y.Q.Q.Q.!.!.!.!.!.B.d B / _ } } } J 1 k.!.!.!.!.!.c.s J I H J J z z z h h h h s A + ~.~.~.~.", -"~.~.~.~.~.A a d d d d d d d d h > ` R.!.!.!.!.!.!.!.!.L.q.=.[ ~ z h h l 0.Q.!.!.!.!.Q.q.2 I J J z z h h h h h h h a S ~.~.~.~.~.", -"~.~.~.~.~.C d d d d d d d d d d > ..g.Y.E.Q.!.!.!.!.!.!.Q.E.T.B.k.a.d.P.Q.!.!.!.!.!.E.[ 2 J z z z g h h h h d d d d C ~.~.~.~.~.", -"~.~.~.~.~.y C p d d d d d d d d g 3 > l [ <.x.W.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.Q.z.> z z z h h h h h d d d d p C 7 ~.~.~.~.~.", -"~.~.~.~.~.~.S a d d d d d d d d d h h 3 , > ; =.Q.!.W.T.Q.!.!.!.!.!.!.!.!.!.!.!.Q.A.g 2 z h h h h h h d d d d d a S ~.~.~.~.~.~.", -"~.~.~.~.~.~.C h s d d d d d d d d d h g z H : <.!.!.t.l &.V.!.!.Q.Q.Q.Q.!.Q.Q.E.b.l > H h h h h h d d d d d d s m C ~.~.~.~.~.~.", -"~.~.~.~.~.~.X S a d d d d d d d d d h h h h p N.!.Q.=.: < c.!.Q.2.&.e.a.d.i.6.[ < 2 z h h h h d d d d d d d d a S ~.~.~.~.~.~.", -"~.~.~.~.~.~.~.A h s d d d d d d d d d h g 2 ~ E.!.E.{ 2 [ E.!.T.l : 2 1 3 2 > > h z h h h h d d d d d d d d s m A ~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.S a d d d d d d d d d h h : -.R.!.B.h 2 =.Q.!.M.p z z z h h z g h h h d d d d d d d d d d d a S ~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.N C p d d d d d d d d d h 3 ' 2.N.9.2 3 z.!.!.q.> J z h h h h h h d d d d d d d d d d d d p C n ~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.S h p d d d d d d d d d z 3 : p l J g 8.T.S.O.> z h h h h h d d d d d d d d d d d d d p h S ~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.S a s d d d d d d d d h h z d h I J a P o.P d g h h h d d d d d d d d d d d d d d s a S ~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.* S a s d d d d d d d d h h g z J J h 3 > d z h h h d d d d d d d d d d d d d d s a S * ~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.$ T a s d d d d d d d h h h z z z h g g h h d d d d d d d d d d d d d d d d s a T O ~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.& S a p d d d d d d h h h z g h h h h h d d d d d d d d d d d d d d d d p a S # ~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.8 S d p d d d d d d h h g h h h h d d d d d d d d d d d d d d d d d p h S = ~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.S A a s d d d d h h h h h d d d d d d d d d d d d d d d d d s a A S ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.0 T m p d d d d h h h d d d d d d d d d d d d d d d d d p B S 9 ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.V S m a p d h d d d d d d d d d d d d d d d d p a m S V ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.o V S C d p p d d d d d d d d d d d d p p d C S N . ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.5 C S A B d d a a d d a a a d B A S C 5 ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.O t B A A A A A A A A B t O ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~." -}; diff --git a/share/pixmaps/check.ico b/share/pixmaps/check.ico deleted file mode 100644 index 0c4e6e81473d47761346fd71e171a807bda5ec58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 766 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 diff --git a/share/pixmaps/nsis-wizard.bmp b/share/pixmaps/nsis-wizard.bmp deleted file mode 100644 index 71255c6850b00ef1efea82fefd05ff736c90f816..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 154542 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 U34{0`aiBa{9Y{S$UjqXJ0D?~%)Bpeg diff --git a/share/pixmaps/send16masknoshadow.bmp b/share/pixmaps/send16masknoshadow.bmp deleted file mode 100644 index faf24e0d8aa81faf80072c7807e52d749cad63c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 126 zcmZ?rtz&=yJ0PV2!~#&v$iN7eZ~&8-#Q*>Q!Geqp3=E71fcOCre_&wv{{x8s0P#N{ U1}Xv5AU;qWBo9^xQV-Mz01_z}*8l(j diff --git a/share/pixmaps/send20.bmp b/share/pixmaps/send20.bmp deleted file mode 100644 index 2b90422b38467ae30a2b6a866adbf0ad3c3f97f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1478 zcmZXSKWrOi7{;GaLQNamP(c#|QaKSso$~KuQiKB~Sfms~DLR@G4onc1ZpoM-LzWCy zrW+Vekxuf^0gqWCdGvy0mVEN)Oz9FSLza-qkr-Zn=R}0i&wlRv?)Sa-KF@b{`Tn27 z8jRb|N;g@(bgCic2K=|7!F2A@wXWLMR;S-l%UasBO*O5lhBegf^^{nmZnvk{Vs*M* z)vd1NFwv^5s?+Ie*_N3*YNI7vQmfNe&1zceFR9&btA#=fRqNMS(;o#EsMUh^LuMEX z`hm(;R&W?-bCV3Ha#)dXz6w@Qv)Pnqp2A+J@_t##W}?cIic0$>h22o2HmXLWA%EXj z&T>i`iR#U|WKyYDQqT#cz7!|1>IwW%T5c>Wx1Up`g-^$q_F>7g^h631&JZt2J*nI* zs}|R!uH?1I5QkDn3gSSeMoE>pBDEzy@#Qr<`LVB3y(BO3REP`m>+sl9exSU(I()UD ze4X{Gr_uVT@~e48a>x`Fg^DObDS{W_5uDA4MHIm!cnV8lDJ+Gh8Kc(09o)ej%)xjU zk--dR4macD#A8bFIr(tUKP1JUD(39oM0*4yQ;KPdK}x0+@087yCMn)2-b^U-hU1^& zpW@FJqCVqfNXd{|mH@8e;Pen?uDkB#>=(#Rj30j=G8h?*3`Pbc1CJnjlEKJeWN>7l z4Wgb5Mg}8;k%86-P6i``k--RH_&b^z4;n=gJtFQSa@e4ERujonQ;Um>T3K1q`ue&y zHa4`qy{)aSE$!^=Xm@v4dwY92I5^PJ(UFdikM-Bzrr#ew*4o+{Zvdf^`qjovy#Co%$I+@J$@dB6B8f(^6~4>pU}%==y%-wtc z`osH^S7B4r)6+9EckZw;_raBil`&XhDx=xP?CkZot6ui($jfisni}w_EB+5zMp!mp zc<$!Ztz7BRSQc>pbPVUO41f0E-0{K-mo9vH_i9%4?^yU_=-W@Ty#E;s&wTgc|Io$i T{JW>;KP#Mn?J0D&nXUc-U3=Ry diff --git a/share/pixmaps/send20mask.bmp b/share/pixmaps/send20mask.bmp deleted file mode 100644 index f124d0da084e68cac62312e9fa8a0fbf9c7c5075..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 142 zcmZ?r?PGudJ0PV2#3E44$iN7e2mq2o+z`wJ7J(4||Nm!TJix%f_yCAM0PznX{=>jv m|BrzIC" no_smgroup -no_smgroup: - Pop $R0 -SectionEnd - -# Installer functions -Function .onInit - InitPluginsDir -!if "@WINDOWS_BITS@" == "64" - ${If} ${RunningX64} - ; disable registry redirection (enable access to 64-bit portion of registry) - SetRegView 64 - ${Else} - MessageBox MB_OK|MB_ICONSTOP "Cannot install 64-bit version on a 32-bit system." - Abort - ${EndIf} -!endif -FunctionEnd - -# Uninstaller functions -Function un.onInit - ReadRegStr $INSTDIR HKCU "${REGKEY}" Path - !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuGroup - !insertmacro SELECT_UNSECTION Main ${UNSEC0000} -FunctionEnd diff --git a/share/ui.rc b/share/ui.rc deleted file mode 100644 index 063641cba29..00000000000 --- a/share/ui.rc +++ /dev/null @@ -1,15 +0,0 @@ -bitcoin ICON "pixmaps/bitcoin.ico" - -#include "wx/msw/wx.rc" - -check ICON "pixmaps/check.ico" -send16 BITMAP "pixmaps/send16.bmp" -send16mask BITMAP "pixmaps/send16mask.bmp" -send16masknoshadow BITMAP "pixmaps/send16masknoshadow.bmp" -send20 BITMAP "pixmaps/send20.bmp" -send20mask BITMAP "pixmaps/send20mask.bmp" -addressbook16 BITMAP "pixmaps/addressbook16.bmp" -addressbook16mask BITMAP "pixmaps/addressbook16mask.bmp" -addressbook20 BITMAP "pixmaps/addressbook20.bmp" -addressbook20mask BITMAP "pixmaps/addressbook20mask.bmp" -favicon ICON "pixmaps/favicon.ico" diff --git a/src/obj-test/.gitignore b/src/obj-test/.gitignore deleted file mode 100644 index d6b7ef32c84..00000000000 --- a/src/obj-test/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore From acdd35d2f7e09be837e6102a93b4e7f8ccaa6270 Mon Sep 17 00:00:00 2001 From: Walter Karshat Date: Tue, 8 May 2018 23:16:22 -0700 Subject: [PATCH 177/177] Update version strings to 1.0.14-1 and change the name Change DEPRECATION to 26 weeks --- src/clientversion.cpp | 2 +- src/deprecation.h | 10 +++++----- src/sendalert.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/clientversion.cpp b/src/clientversion.cpp index dd704eab2b2..1473c4adb81 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -19,7 +19,7 @@ * for both bitcoind and bitcoin-core, to make it harder for attackers to * target servers or GUI users specifically. */ -const std::string CLIENT_NAME("Pyramiden"); +const std::string CLIENT_NAME("Longyearbyen"); /** * Client version number diff --git a/src/deprecation.h b/src/deprecation.h index 11627109e34..f68d3f56285 100644 --- a/src/deprecation.h +++ b/src/deprecation.h @@ -6,16 +6,16 @@ #define ZCASH_DEPRECATION_H // Deprecation policy: -// * Shut down 16 weeks' worth of blocks after the estimated release block height. -// * A warning is shown during the 2 weeks' worth of blocks prior to shut down. -static const int APPROX_RELEASE_HEIGHT = 249000; -static const int WEEKS_UNTIL_DEPRECATION = 16; +// * Shut down 26 weeks' worth of blocks after the estimated release block height. +// * A warning is shown during the 4 weeks' worth of blocks prior to shut down. +static const int APPROX_RELEASE_HEIGHT = 315000; +static const int WEEKS_UNTIL_DEPRECATION = 26; //Fixing zero day size static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 30); // Number of blocks before deprecation to warn users //Fixing zero day size -static const int DEPRECATION_WARN_LIMIT = 14 * 24 * 30; // 2 weeks +static const int DEPRECATION_WARN_LIMIT = 28 * 24 * 30; // 4 weeks /** * Checks whether the node is deprecated based on the current block height, and diff --git a/src/sendalert.cpp b/src/sendalert.cpp index 2f91b08f00e..273aabbf3bf 100644 --- a/src/sendalert.cpp +++ b/src/sendalert.cpp @@ -95,7 +95,7 @@ void ThreadSendAlert() const std::vector useragents = {"Pyramiden", "Longyearbyen", "Barentsburg", "Qaanaaq"}; BOOST_FOREACH(const std::string& useragent, useragents) { - alert.setSubVer.insert(std::string("/"+useragent+":1.0.12/")); + alert.setSubVer.insert(std::string("/"+useragent+":1.0.14-1/")); } // Sanity check