mirror of
https://github.com/monero-project/monero.git
synced 2024-11-18 10:01:02 +00:00
Merge pull request #1218
3429bfb
ringct: thread verRct and verRctSimple (moneromooo-monero)e06a4da
ringct: remove unneeded type conversions (moneromooo-monero)afc70df
ringct: reserve space in vectors to avoid excessive reallocation (moneromooo-monero)9ebf7b6
ringct: avoid unnecessary memcpy (moneromooo-monero)1fe75c1
ringct: add a few consts where possible (moneromooo-monero)ab002a1
ringct: pass vectors by const ref where possible (moneromooo-monero)
This commit is contained in:
commit
2bb0bdc8b8
4 changed files with 136 additions and 45 deletions
|
@ -320,7 +320,7 @@ namespace rct {
|
||||||
//be careful these are also in crypto namespace
|
//be careful these are also in crypto namespace
|
||||||
//cn_fast_hash for arbitrary multiples of 32 bytes
|
//cn_fast_hash for arbitrary multiples of 32 bytes
|
||||||
void cn_fast_hash(key &hash, const void * data, const std::size_t l) {
|
void cn_fast_hash(key &hash, const void * data, const std::size_t l) {
|
||||||
keccak((uint8_t *)data, l, hash.bytes, 32);
|
keccak((const uint8_t *)data, l, hash.bytes, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hash_to_scalar(key &hash, const void * data, const std::size_t l) {
|
void hash_to_scalar(key &hash, const void * data, const std::size_t l) {
|
||||||
|
@ -330,7 +330,7 @@ namespace rct {
|
||||||
|
|
||||||
//cn_fast_hash for a 32 byte key
|
//cn_fast_hash for a 32 byte key
|
||||||
void cn_fast_hash(key & hash, const key & in) {
|
void cn_fast_hash(key & hash, const key & in) {
|
||||||
keccak((uint8_t *)in.bytes, 32, hash.bytes, 32);
|
keccak((const uint8_t *)in.bytes, 32, hash.bytes, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hash_to_scalar(key & hash, const key & in) {
|
void hash_to_scalar(key & hash, const key & in) {
|
||||||
|
@ -341,7 +341,7 @@ namespace rct {
|
||||||
//cn_fast_hash for a 32 byte key
|
//cn_fast_hash for a 32 byte key
|
||||||
key cn_fast_hash(const key & in) {
|
key cn_fast_hash(const key & in) {
|
||||||
key hash;
|
key hash;
|
||||||
keccak((uint8_t *)in.bytes, 32, hash.bytes, 32);
|
keccak((const uint8_t *)in.bytes, 32, hash.bytes, 32);
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,7 +354,7 @@ namespace rct {
|
||||||
//cn_fast_hash for a 128 byte unsigned char
|
//cn_fast_hash for a 128 byte unsigned char
|
||||||
key cn_fast_hash128(const void * in) {
|
key cn_fast_hash128(const void * in) {
|
||||||
key hash;
|
key hash;
|
||||||
keccak((uint8_t *)in, 128, hash.bytes, 32);
|
keccak((const uint8_t *)in, 128, hash.bytes, 32);
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,20 +367,13 @@ namespace rct {
|
||||||
//cn_fast_hash for multisig purpose
|
//cn_fast_hash for multisig purpose
|
||||||
//This takes the outputs and commitments
|
//This takes the outputs and commitments
|
||||||
//and hashes them into a 32 byte sized key
|
//and hashes them into a 32 byte sized key
|
||||||
key cn_fast_hash(ctkeyV PC) {
|
key cn_fast_hash(const ctkeyV &PC) {
|
||||||
key rv = identity();
|
key rv;
|
||||||
std::size_t l = (std::size_t)PC.size();
|
cn_fast_hash(rv, &PC[0], 64*PC.size());
|
||||||
size_t i = 0, j = 0;
|
|
||||||
vector<char> m(l * 64);
|
|
||||||
for (i = 0 ; i < l ; i++) {
|
|
||||||
memcpy(&m[i * 64], &PC[i].dest, 32);
|
|
||||||
memcpy(&m[i * 64 + 32], &PC[i].mask, 32);
|
|
||||||
}
|
|
||||||
cn_fast_hash(rv, &m[0], 64*l);
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
key hash_to_scalar(ctkeyV PC) {
|
key hash_to_scalar(const ctkeyV &PC) {
|
||||||
key rv = cn_fast_hash(PC);
|
key rv = cn_fast_hash(PC);
|
||||||
sc_reduce32(rv.bytes);
|
sc_reduce32(rv.bytes);
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -391,14 +384,8 @@ namespace rct {
|
||||||
//put them in the key vector and it concatenates them
|
//put them in the key vector and it concatenates them
|
||||||
//and then hashes them
|
//and then hashes them
|
||||||
key cn_fast_hash(const keyV &keys) {
|
key cn_fast_hash(const keyV &keys) {
|
||||||
size_t l = keys.size();
|
|
||||||
vector<unsigned char> m(l * 32);
|
|
||||||
size_t i;
|
|
||||||
for (i = 0 ; i < l ; i++) {
|
|
||||||
memcpy(&m[i * 32], keys[i].bytes, 32);
|
|
||||||
}
|
|
||||||
key rv;
|
key rv;
|
||||||
cn_fast_hash(rv, &m[0], 32 * l);
|
cn_fast_hash(rv, &keys[0], keys.size() * sizeof(keys[0]));
|
||||||
//dp(rv);
|
//dp(rv);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,8 +149,8 @@ namespace rct {
|
||||||
//for mg sigs
|
//for mg sigs
|
||||||
key cn_fast_hash128(const void * in);
|
key cn_fast_hash128(const void * in);
|
||||||
key hash_to_scalar128(const void * in);
|
key hash_to_scalar128(const void * in);
|
||||||
key cn_fast_hash(ctkeyV PC);
|
key cn_fast_hash(const ctkeyV &PC);
|
||||||
key hash_to_scalar(ctkeyV PC);
|
key hash_to_scalar(const ctkeyV &PC);
|
||||||
//for mg sigs
|
//for mg sigs
|
||||||
key cn_fast_hash(const keyV &keys);
|
key cn_fast_hash(const keyV &keys);
|
||||||
key hash_to_scalar(const keyV &keys);
|
key hash_to_scalar(const keyV &keys);
|
||||||
|
|
|
@ -28,14 +28,26 @@
|
||||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#include <boost/asio.hpp>
|
||||||
#include "misc_log_ex.h"
|
#include "misc_log_ex.h"
|
||||||
#include "common/perf_timer.h"
|
#include "common/perf_timer.h"
|
||||||
|
#include "common/util.h"
|
||||||
#include "rctSigs.h"
|
#include "rctSigs.h"
|
||||||
#include "cryptonote_core/cryptonote_format_utils.h"
|
#include "cryptonote_core/cryptonote_format_utils.h"
|
||||||
|
|
||||||
using namespace crypto;
|
using namespace crypto;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
#define KILL_IOSERVICE() \
|
||||||
|
if(ioservice_active) \
|
||||||
|
{ \
|
||||||
|
work.reset(); \
|
||||||
|
while (!ioservice.stopped()) ioservice.poll(); \
|
||||||
|
threadpool.join_all(); \
|
||||||
|
ioservice.stop(); \
|
||||||
|
ioservice_active = false; \
|
||||||
|
}
|
||||||
|
|
||||||
namespace rct {
|
namespace rct {
|
||||||
|
|
||||||
//Schnorr Non-linkable
|
//Schnorr Non-linkable
|
||||||
|
@ -43,7 +55,7 @@ namespace rct {
|
||||||
//Ver Verifies that signer knows an "x" such that xG = one of P1 or P2
|
//Ver Verifies that signer knows an "x" such that xG = one of P1 or P2
|
||||||
//These are called in the below ASNL sig generation
|
//These are called in the below ASNL sig generation
|
||||||
|
|
||||||
void GenSchnorrNonLinkable(key & L1, key & s1, key & s2, const key & x, const key & P1, const key & P2, int index) {
|
void GenSchnorrNonLinkable(key & L1, key & s1, key & s2, const key & x, const key & P1, const key & P2, unsigned int index) {
|
||||||
key c1, c2, L2;
|
key c1, c2, L2;
|
||||||
key a = skGen();
|
key a = skGen();
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
|
@ -95,7 +107,7 @@ namespace rct {
|
||||||
asnlSig rv;
|
asnlSig rv;
|
||||||
rv.s = zero();
|
rv.s = zero();
|
||||||
for (j = 0; j < ATOMS; j++) {
|
for (j = 0; j < ATOMS; j++) {
|
||||||
GenSchnorrNonLinkable(rv.L1[j], s1[j], rv.s2[j], x[j], P1[j], P2[j], (int)indices[j]);
|
GenSchnorrNonLinkable(rv.L1[j], s1[j], rv.s2[j], x[j], P1[j], P2[j], indices[j]);
|
||||||
sc_add(rv.s.bytes, rv.s.bytes, s1[j].bytes);
|
sc_add(rv.s.bytes, rv.s.bytes, s1[j].bytes);
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -348,9 +360,14 @@ namespace rct {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void verRangeWrapper(const key & C, const rangeSig & as, bool &result) {
|
||||||
|
result = verRange(C, as);
|
||||||
|
}
|
||||||
|
|
||||||
key get_pre_mlsag_hash(const rctSig &rv)
|
key get_pre_mlsag_hash(const rctSig &rv)
|
||||||
{
|
{
|
||||||
keyV hashes;
|
keyV hashes;
|
||||||
|
hashes.reserve(3);
|
||||||
hashes.push_back(rv.message);
|
hashes.push_back(rv.message);
|
||||||
crypto::hash h;
|
crypto::hash h;
|
||||||
|
|
||||||
|
@ -364,6 +381,7 @@ namespace rct {
|
||||||
hashes.push_back(hash2rct(h));
|
hashes.push_back(hash2rct(h));
|
||||||
|
|
||||||
keyV kv;
|
keyV kv;
|
||||||
|
kv.reserve((64*3+1) * rv.p.rangeSigs.size());
|
||||||
for (auto r: rv.p.rangeSigs)
|
for (auto r: rv.p.rangeSigs)
|
||||||
{
|
{
|
||||||
for (size_t n = 0; n < 64; ++n)
|
for (size_t n = 0; n < 64; ++n)
|
||||||
|
@ -526,6 +544,10 @@ namespace rct {
|
||||||
return MLSAG_Ver(message, M, mg, rows);
|
return MLSAG_Ver(message, M, mg, rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void verRctMGSimpleWrapper(const key &message, const mgSig &mg, const ctkeyV & pubs, const key & C, bool &result) {
|
||||||
|
result = verRctMGSimple(message, mg, pubs, C);
|
||||||
|
}
|
||||||
|
|
||||||
//These functions get keys from blockchain
|
//These functions get keys from blockchain
|
||||||
//replace these when connecting blockchain
|
//replace these when connecting blockchain
|
||||||
//getKeyFromBlockchain grabs a key from the blockchain at "reference_index" to mix with
|
//getKeyFromBlockchain grabs a key from the blockchain at "reference_index" to mix with
|
||||||
|
@ -743,17 +765,41 @@ namespace rct {
|
||||||
// some rct ops can throw
|
// some rct ops can throw
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
size_t i = 0;
|
boost::asio::io_service ioservice;
|
||||||
bool tmp;
|
boost::thread_group threadpool;
|
||||||
|
std::unique_ptr<boost::asio::io_service::work> work(new boost::asio::io_service::work(ioservice));
|
||||||
|
size_t threads = tools::get_max_concurrency();
|
||||||
|
threads = std::min(threads, rv.outPk.size());
|
||||||
|
for (size_t i = 0; i < threads; ++i)
|
||||||
|
threadpool.create_thread(boost::bind(&boost::asio::io_service::run, &ioservice));
|
||||||
|
bool ioservice_active = threads > 1;
|
||||||
|
std::deque<bool> results(rv.outPk.size(), false);
|
||||||
|
epee::misc_utils::auto_scope_leave_caller ioservice_killer = epee::misc_utils::create_scope_leave_handler([&]() { KILL_IOSERVICE(); });
|
||||||
|
|
||||||
DP("range proofs verified?");
|
DP("range proofs verified?");
|
||||||
for (i = 0; i < rv.outPk.size(); i++) {
|
for (size_t i = 0; i < rv.outPk.size(); i++) {
|
||||||
tmp = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
|
if (threads > 1) {
|
||||||
DP(tmp);
|
ioservice.dispatch(boost::bind(&verRangeWrapper, std::cref(rv.outPk[i].mask), std::cref(rv.p.rangeSigs[i]), std::ref(results[i])));
|
||||||
if (!tmp) {
|
}
|
||||||
LOG_ERROR("Range proof verification failed for input " << i);
|
else {
|
||||||
return false;
|
bool tmp = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
|
||||||
|
DP(tmp);
|
||||||
|
if (!tmp) {
|
||||||
|
LOG_ERROR("Range proof verification failed for input " << i);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
KILL_IOSERVICE();
|
||||||
|
if (threads > 1) {
|
||||||
|
for (size_t i = 0; i < rv.outPk.size(); ++i) {
|
||||||
|
if (!results[i]) {
|
||||||
|
LOG_ERROR("Range proof verified failed for input " << i);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//compute txn fee
|
//compute txn fee
|
||||||
key txnFeeKey = scalarmultH(d2h(rv.txnFee));
|
key txnFeeKey = scalarmultH(d2h(rv.txnFee));
|
||||||
bool mgVerd = verRctMG(rv.p.MGs[0], rv.mixRing, rv.outPk, txnFeeKey, get_pre_mlsag_hash(rv));
|
bool mgVerd = verRctMG(rv.p.MGs[0], rv.mixRing, rv.outPk, txnFeeKey, get_pre_mlsag_hash(rv));
|
||||||
|
@ -784,29 +830,87 @@ namespace rct {
|
||||||
CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.p.MGs");
|
CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.p.MGs");
|
||||||
CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.pseudoOuts and mixRing");
|
CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.pseudoOuts and mixRing");
|
||||||
|
|
||||||
key sumOutpks = identity();
|
{
|
||||||
for (i = 0; i < rv.outPk.size(); i++) {
|
boost::asio::io_service ioservice;
|
||||||
if (!verRange(rv.outPk[i].mask, rv.p.rangeSigs[i])) {
|
boost::thread_group threadpool;
|
||||||
|
std::unique_ptr<boost::asio::io_service::work> work(new boost::asio::io_service::work(ioservice));
|
||||||
|
size_t threads = tools::get_max_concurrency();
|
||||||
|
threads = std::min(threads, rv.outPk.size());
|
||||||
|
for (size_t i = 0; i < threads; ++i)
|
||||||
|
threadpool.create_thread(boost::bind(&boost::asio::io_service::run, &ioservice));
|
||||||
|
bool ioservice_active = threads > 1;
|
||||||
|
std::deque<bool> results(rv.outPk.size(), false);
|
||||||
|
epee::misc_utils::auto_scope_leave_caller ioservice_killer = epee::misc_utils::create_scope_leave_handler([&]() { KILL_IOSERVICE(); });
|
||||||
|
|
||||||
|
for (i = 0; i < rv.outPk.size(); i++) {
|
||||||
|
if (threads > 1) {
|
||||||
|
ioservice.dispatch(boost::bind(&verRangeWrapper, std::cref(rv.outPk[i].mask), std::cref(rv.p.rangeSigs[i]), std::ref(results[i])));
|
||||||
|
}
|
||||||
|
else if (!verRange(rv.outPk[i].mask, rv.p.rangeSigs[i])) {
|
||||||
LOG_ERROR("Range proof verified failed for input " << i);
|
LOG_ERROR("Range proof verified failed for input " << i);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
KILL_IOSERVICE();
|
||||||
|
if (threads > 1) {
|
||||||
|
for (size_t i = 0; i < rv.outPk.size(); ++i) {
|
||||||
|
if (!results[i]) {
|
||||||
|
LOG_ERROR("Range proof verified failed for input " << i);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
key sumOutpks = identity();
|
||||||
|
for (i = 0; i < rv.outPk.size(); i++) {
|
||||||
addKeys(sumOutpks, sumOutpks, rv.outPk[i].mask);
|
addKeys(sumOutpks, sumOutpks, rv.outPk[i].mask);
|
||||||
}
|
}
|
||||||
DP(sumOutpks);
|
DP(sumOutpks);
|
||||||
key txnFeeKey = scalarmultH(d2h(rv.txnFee));
|
key txnFeeKey = scalarmultH(d2h(rv.txnFee));
|
||||||
addKeys(sumOutpks, txnFeeKey, sumOutpks);
|
addKeys(sumOutpks, txnFeeKey, sumOutpks);
|
||||||
|
|
||||||
bool tmpb = false;
|
|
||||||
key message = get_pre_mlsag_hash(rv);
|
key message = get_pre_mlsag_hash(rv);
|
||||||
key sumPseudoOuts = identity();
|
|
||||||
for (i = 0 ; i < rv.mixRing.size() ; i++) {
|
{
|
||||||
tmpb = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], rv.pseudoOuts[i]);
|
boost::asio::io_service ioservice;
|
||||||
addKeys(sumPseudoOuts, sumPseudoOuts, rv.pseudoOuts[i]);
|
boost::thread_group threadpool;
|
||||||
DP(tmpb);
|
std::unique_ptr<boost::asio::io_service::work> work(new boost::asio::io_service::work(ioservice));
|
||||||
if (!tmpb) {
|
size_t threads = tools::get_max_concurrency();
|
||||||
|
threads = std::min(threads, rv.mixRing.size());
|
||||||
|
for (size_t i = 0; i < threads; ++i)
|
||||||
|
threadpool.create_thread(boost::bind(&boost::asio::io_service::run, &ioservice));
|
||||||
|
bool ioservice_active = threads > 1;
|
||||||
|
std::deque<bool> results(rv.mixRing.size(), false);
|
||||||
|
epee::misc_utils::auto_scope_leave_caller ioservice_killer = epee::misc_utils::create_scope_leave_handler([&]() { KILL_IOSERVICE(); });
|
||||||
|
|
||||||
|
for (i = 0 ; i < rv.mixRing.size() ; i++) {
|
||||||
|
if (threads > 1) {
|
||||||
|
ioservice.dispatch(boost::bind(&verRctMGSimpleWrapper, std::cref(message), std::cref(rv.p.MGs[i]), std::cref(rv.mixRing[i]), std::cref(rv.pseudoOuts[i]), std::ref(results[i])));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bool tmpb = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], rv.pseudoOuts[i]);
|
||||||
|
DP(tmpb);
|
||||||
|
if (!tmpb) {
|
||||||
|
LOG_ERROR("verRctMGSimple failed for input " << i);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KILL_IOSERVICE();
|
||||||
|
if (threads > 1) {
|
||||||
|
for (size_t i = 0; i < results.size(); ++i) {
|
||||||
|
if (!results[i]) {
|
||||||
LOG_ERROR("verRctMGSimple failed for input " << i);
|
LOG_ERROR("verRctMGSimple failed for input " << i);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
key sumPseudoOuts = identity();
|
||||||
|
for (i = 0 ; i < rv.mixRing.size() ; i++) {
|
||||||
|
addKeys(sumPseudoOuts, sumPseudoOuts, rv.pseudoOuts[i]);
|
||||||
}
|
}
|
||||||
DP(sumPseudoOuts);
|
DP(sumPseudoOuts);
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ namespace rct {
|
||||||
//Gen Gives a signature (L1, s1, s2) proving that the sender knows "x" such that xG = one of P1 or P2
|
//Gen Gives a signature (L1, s1, s2) proving that the sender knows "x" such that xG = one of P1 or P2
|
||||||
//Ver Verifies that signer knows an "x" such that xG = one of P1 or P2
|
//Ver Verifies that signer knows an "x" such that xG = one of P1 or P2
|
||||||
//These are called in the below ASNL sig generation
|
//These are called in the below ASNL sig generation
|
||||||
void GenSchnorrNonLinkable(key & L1, key & s1, key & s2, const key & x, const key & P1, const key & P2, int index);
|
void GenSchnorrNonLinkable(key & L1, key & s1, key & s2, const key & x, const key & P1, const key & P2, unsigned int index);
|
||||||
bool VerSchnorrNonLinkable(const key & P1, const key & P2, const key & L1, const key & s1, const key & s2);
|
bool VerSchnorrNonLinkable(const key & P1, const key & P2, const key & L1, const key & s1, const key & s2);
|
||||||
|
|
||||||
//Aggregate Schnorr Non-linkable Ring Signature (ASNL)
|
//Aggregate Schnorr Non-linkable Ring Signature (ASNL)
|
||||||
|
|
Loading…
Reference in a new issue