parent
e089dec813
commit
29439de96e
@ -0,0 +1,224 @@
|
||||
1. vendor libsodium crypto_verify to contrib/libsodium
|
||||
2. this should be compatible with "#include <sodium/crypto_verify_32.h>"
|
||||
|
||||
=================
|
||||
|
||||
|
||||
diff -r src/common/base58.cpp /Users/paulshapiro/Documents/Repos/monero-core-custom/common/base58.cpp
|
||||
38,39c38,39
|
||||
< #include "int-util.h"
|
||||
< #include "util.h"
|
||||
---
|
||||
> #include "common/int-util.h"
|
||||
> //#include "util.h"
|
||||
|
||||
// ^----- this doesn't need to be done anymore
|
||||
|
||||
===================
|
||||
|
||||
util.h and util.cpp are heavily modified to include (almost only)
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
|
||||
and support only
|
||||
|
||||
|
||||
|
||||
void set_max_concurrency(unsigned n)
|
||||
{
|
||||
if (n < 1)
|
||||
n = boost::thread::hardware_concurrency();
|
||||
unsigned hwc = boost::thread::hardware_concurrency();
|
||||
if (n > hwc)
|
||||
n = hwc;
|
||||
boost::lock_guard<boost::mutex> lock(max_concurrency_lock);
|
||||
max_concurrency = n;
|
||||
}
|
||||
|
||||
unsigned get_max_concurrency()
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(max_concurrency_lock);
|
||||
return max_concurrency;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
====================
|
||||
|
||||
|
||||
account.cpp:
|
||||
|
||||
< crypto::secret_key account_base::generate(const crypto::secret_key& recovery_key, bool recover, bool two_random)
|
||||
---
|
||||
> crypto::secret_key account_base::generate(const crypto::secret_key& recovery_key, bool recover, bool two_random, bool from_legacy16B_lw_seed)
|
||||
153c87
|
||||
< keccak((uint8_t *)&m_keys.m_spend_secret_key, sizeof(crypto::secret_key), (uint8_t *)&second, sizeof(crypto::secret_key));
|
||||
---
|
||||
> keccak((uint8_t *)&(from_legacy16B_lw_seed ? first : m_keys.m_spend_secret_key), sizeof(crypto::secret_key), (uint8_t *)&second, sizeof(crypto::secret_key));
|
||||
|
||||
====================
|
||||
|
||||
< crypto::secret_key generate(const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false, bool two_random = false);
|
||||
< void create_from_device(const std::string &device_name);
|
||||
< void create_from_device(hw::device &hwdev);
|
||||
---
|
||||
> crypto::secret_key generate(const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false, bool two_random = false, bool from_legacy16B_lw_seed = false);
|
||||
> void create_from_device(const std::string &device_name) ;
|
||||
102,106d89
|
||||
|
||||
====================
|
||||
|
||||
|
||||
diff -r src/cryptonote_basic/cryptonote_basic_impl.cpp /Users/paulshapiro/Documents/Repos/monero-core-custom/cryptonote_basic/cryptonote_basic_impl.cpp
|
||||
44c44
|
||||
< #include "common/dns_utils.h"
|
||||
---
|
||||
> // #include "common/dns_utils.h"
|
||||
|
||||
================
|
||||
|
||||
|
||||
cryptonote_basic_impl
|
||||
|
||||
< bool get_account_address_from_str_or_url(
|
||||
< address_parse_info& info
|
||||
< , network_type nettype
|
||||
< , const std::string& str_or_url
|
||||
< , std::function<std::string(const std::string&, const std::vector<std::string>&, bool)> dns_confirm
|
||||
< )
|
||||
< {
|
||||
< if (get_account_address_from_str(info, nettype, str_or_url))
|
||||
< return true;
|
||||
< bool dnssec_valid;
|
||||
< std::string address_str = tools::dns_utils::get_account_address_as_str_from_url(str_or_url, dnssec_valid, dns_confirm);
|
||||
< return !address_str.empty() &&
|
||||
< get_account_address_from_str(info, nettype, address_str);
|
||||
< }
|
||||
---
|
||||
> // //--------------------------------------------------------------------------------
|
||||
> // bool get_account_address_from_str_or_url(
|
||||
> // address_parse_info& info
|
||||
> // , network_type nettype
|
||||
> // , const std::string& str_or_url
|
||||
> // , std::function<std::string(const std::string&, const std::vector<std::string>&, bool)> dns_confirm
|
||||
> // )
|
||||
> // {
|
||||
> // if (get_account_address_from_str(info, nettype, str_or_url))
|
||||
> // return true;
|
||||
> // bool dnssec_valid;
|
||||
> // std::string address_str = tools::dns_utils::get_account_address_as_str_from_url(str_or_url, dnssec_valid, dns_confirm);
|
||||
> // return !address_str.empty() &&
|
||||
> // get_account_address_from_str(info, nettype, address_str);
|
||||
> // }
|
||||
|
||||
|
||||
|
||||
=======================
|
||||
|
||||
|
||||
diff -r src/cryptonote_core/cryptonote_tx_utils.cpp /Users/paulshapiro/Documents/Repos/monero-core-custom/cryptonote_core/cryptonote_tx_utils.cpp
|
||||
40c40
|
||||
< #include "cryptonote_basic/miner.h"
|
||||
---
|
||||
> //#include "cryptonote_basic/miner.h"
|
||||
|
||||
|
||||
...... and comment functions like construct_miner_tx
|
||||
|
||||
< bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight
|
||||
, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, ui
|
||||
nt8_t hard_fork_version) {
|
||||
|
||||
> // bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, size_t current_block_size, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version) {
|
||||
|
||||
--- and ---
|
||||
|
||||
> // bool generate_genesis_block(
|
||||
> // block& bl
|
||||
> // , std::string const & genesis_tx
|
||||
> // , uint32_t nonce
|
||||
> // )
|
||||
> // {
|
||||
|
||||
|
||||
=============
|
||||
|
||||
|
||||
diff -r src/cryptonote_core/cryptonote_tx_utils.h /Users/paulshapiro/Documents/Repos/monero-core-custom/cryptonote_core/cryptonote_tx_utils.h
|
||||
|
||||
> // bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1);
|
||||
|
||||
-and-
|
||||
|
||||
> // bool generate_genesis_block(
|
||||
> // block& bl
|
||||
> // , std::string const & genesis_tx
|
||||
> // , uint32_t nonce
|
||||
> // );
|
||||
|
||||
============
|
||||
|
||||
|
||||
|
||||
diff -r src/ringct/bulletproofs.cc /Users/paulshapiro/Documents/Repos/monero-core-custom/ringct/bulletproofs.cc
|
||||
32,33d31
|
||||
< #include <openssl/ssl.h>
|
||||
< #include <openssl/bn.h>
|
||||
36,37c34
|
||||
< #include "common/perf_timer.h"
|
||||
< #include "cryptonote_config.h"
|
||||
---
|
||||
> // #include "common/perf_timer.h"
|
||||
|
||||
* comment calls to PERF_TIMER_UNIT / PERF_TIMER_START_BP / PERF_TIMER_STOP
|
||||
|
||||
* replace invert with:
|
||||
|
||||
/* Compute the inverse of a scalar, the naive way */
|
||||
static rct::key invert(const rct::key &x)
|
||||
{
|
||||
static const rct::key l_minus_2 = { {0xeb, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 } };
|
||||
|
||||
rct::key inv = rct::identity();
|
||||
rct::key tmp = x;
|
||||
for (int n = 0; n < 256; ++n)
|
||||
{
|
||||
if (l_minus_2[n>>3] & (1<<(n&7)))
|
||||
sc_mul(inv.bytes, inv.bytes, tmp.bytes);
|
||||
sc_mul(tmp.bytes, tmp.bytes, tmp.bytes);
|
||||
}
|
||||
return inv;
|
||||
}
|
||||
|
||||
|
||||
* probably can remove bulletproof_VERIFY
|
||||
|
||||
|
||||
==============
|
||||
|
||||
|
||||
diff -r src/ringct/rctSigs.cpp /Users/paulshapiro/Documents/Repos/monero-core-custom/ringct/rctSigs.cpp
|
||||
32c32
|
||||
< #include "common/perf_timer.h"
|
||||
---
|
||||
> // #include "common/perf_timer.h"
|
||||
|
||||
|
||||
and comment PERF_TIMER(verRange); etc
|
||||
|
||||
|
||||
==============
|
||||
|
||||
edit multiexp.cc to comment out perf timer include and MULTIEXP_PERF( …
|
||||
|
||||
|
||||
|
||||
============
|
||||
|
||||
|
||||
epee/include/misc_log_ex.h, and logger.h/cpp are heavily customized - don't overwrite -- update them from code shared with back-end
|
||||
|
||||
* add `#include <sstream>` to misc_log_ex.h
|
||||
|
@ -0,0 +1,139 @@
|
||||
// Copyright (c) 2017-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// 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.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "aligned.h"
|
||||
|
||||
static inline int is_power_of_2(size_t n) { return n && (n & (n-1)) == 0; }
|
||||
|
||||
#define MAGIC 0xaa0817161500ff81
|
||||
#define MAGIC_FREED 0xaa0817161500ff82
|
||||
|
||||
static void local_abort(const char *msg)
|
||||
{
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
#ifdef NDEBUG
|
||||
_exit(1);
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint64_t magic;
|
||||
void *raw;
|
||||
size_t bytes;
|
||||
size_t align;
|
||||
} control;
|
||||
|
||||
void *aligned_malloc(size_t bytes, size_t align)
|
||||
{
|
||||
void *raw, *ptr;
|
||||
control *ctrl;
|
||||
|
||||
if (!is_power_of_2(align))
|
||||
return NULL;
|
||||
if (bytes > (size_t)-1 - align)
|
||||
return NULL;
|
||||
if (bytes + align > (size_t)-1 - sizeof(control))
|
||||
return NULL;
|
||||
|
||||
raw = malloc(bytes + sizeof(control) + align);
|
||||
if (!raw)
|
||||
return NULL;
|
||||
ptr = (void*)(((uintptr_t)raw + align + sizeof(control) - 1) & ~(align-1));
|
||||
ctrl = ((control*)ptr) - 1;
|
||||
ctrl->magic = MAGIC;
|
||||
ctrl->raw = raw;
|
||||
ctrl->bytes = bytes;
|
||||
ctrl->align = align;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *aligned_realloc(void *ptr, size_t bytes, size_t align)
|
||||
{
|
||||
void *raw, *ptr2;
|
||||
control *ctrl, *ctrl2;
|
||||
|
||||
if (!ptr)
|
||||
return aligned_malloc(bytes, align);
|
||||
if (!bytes)
|
||||
{
|
||||
aligned_free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
if (!is_power_of_2(align))
|
||||
return NULL;
|
||||
|
||||
ctrl = ((control*)ptr) - 1;
|
||||
if (ctrl->magic == MAGIC_FREED)
|
||||
local_abort("Double free detected");
|
||||
if (ctrl->magic != MAGIC)
|
||||
local_abort("Freeing unallocated memory");
|
||||
if (ctrl->align != align)
|
||||
return NULL;
|
||||
if (ctrl->bytes >= bytes)
|
||||
return ptr;
|
||||
|
||||
if (ctrl->bytes > (size_t)-1 - ctrl->align)
|
||||
return NULL;
|
||||
if (ctrl->bytes + ctrl->align > (size_t)-1 - sizeof(control))
|
||||
return NULL;
|
||||
|
||||
raw = malloc(bytes + sizeof(control) + ctrl->align);
|
||||
if (!raw)
|
||||
return NULL;
|
||||
ptr2 = (void*)(((uintptr_t)raw + ctrl->align + sizeof(control) - 1) & ~(ctrl->align-1));
|
||||
memcpy(ptr2, ptr, ctrl->bytes);
|
||||
ctrl2 = ((control*)ptr2) - 1;
|
||||
ctrl2->magic = MAGIC;
|
||||
ctrl2->raw = raw;
|
||||
ctrl2->bytes = bytes;
|
||||
ctrl2->align = ctrl->align;
|
||||
ctrl->magic = MAGIC_FREED;
|
||||
free(ctrl->raw);
|
||||
return ptr2;
|
||||
}
|
||||
|
||||
void aligned_free(void *ptr)
|
||||
{
|
||||
if (!ptr)
|
||||
return;
|
||||
control *ctrl = ((control*)ptr) - 1;
|
||||
if (ctrl->magic == MAGIC_FREED)
|
||||
local_abort("Double free detected");
|
||||
if (ctrl->magic != MAGIC)
|
||||
local_abort("Freeing unallocated memory");
|
||||
ctrl->magic = MAGIC_FREED;
|
||||
free(ctrl->raw);
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void *aligned_malloc(size_t bytes, size_t align);
|
||||
void *aligned_realloc(void *ptr, size_t bytes, size_t align);
|
||||
void aligned_free(void *ptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// 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.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
#include "include_base_utils.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
namespace tools
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
boost::mutex max_concurrency_lock;
|
||||
unsigned max_concurrency = boost::thread::hardware_concurrency();
|
||||
}
|
||||
|
||||
void set_max_concurrency(unsigned n)
|
||||
{
|
||||
if (n < 1)
|
||||
n = boost::thread::hardware_concurrency();
|
||||
unsigned hwc = boost::thread::hardware_concurrency();
|
||||
if (n > hwc)
|
||||
n = hwc;
|
||||
boost::lock_guard<boost::mutex> lock(max_concurrency_lock);
|
||||
max_concurrency = n;
|
||||
}
|
||||
|
||||
unsigned get_max_concurrency()
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(max_concurrency_lock);
|
||||
return max_concurrency;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
#ifndef crypto_verify_16_H
|
||||
#define crypto_verify_16_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include "export.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define crypto_verify_16_BYTES 16U
|
||||
SODIUM_EXPORT
|
||||
size_t crypto_verify_16_bytes(void);
|
||||
|
||||
SODIUM_EXPORT
|
||||
int crypto_verify_16(const unsigned char *x, const unsigned char *y)
|
||||
__attribute__ ((warn_unused_result));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,23 @@
|
||||
#ifndef crypto_verify_32_H
|
||||
#define crypto_verify_32_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include "export.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define crypto_verify_32_BYTES 32U
|
||||
SODIUM_EXPORT
|
||||
size_t crypto_verify_32_bytes(void);
|
||||
|
||||
SODIUM_EXPORT
|
||||
int crypto_verify_32(const unsigned char *x, const unsigned char *y)
|
||||
__attribute__ ((warn_unused_result));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,23 @@
|
||||
#ifndef crypto_verify_64_H
|
||||
#define crypto_verify_64_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include "export.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define crypto_verify_64_BYTES 64U
|
||||
SODIUM_EXPORT
|
||||
size_t crypto_verify_64_bytes(void);
|
||||
|
||||
SODIUM_EXPORT
|
||||
int crypto_verify_64(const unsigned char *x, const unsigned char *y)
|
||||
__attribute__ ((warn_unused_result));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,57 @@
|
||||
|
||||
#ifndef sodium_export_H
|
||||
#define sodium_export_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
#if !defined(__clang__) && !defined(__GNUC__)
|
||||
# ifdef __attribute__
|
||||
# undef __attribute__
|
||||
# endif
|
||||
# define __attribute__(a)
|
||||
#endif
|
||||
|
||||
#ifdef SODIUM_STATIC
|
||||
# define SODIUM_EXPORT
|
||||
# define SODIUM_EXPORT_WEAK
|
||||
#else
|
||||
# if defined(_MSC_VER)
|
||||
# ifdef SODIUM_DLL_EXPORT
|
||||
# define SODIUM_EXPORT __declspec(dllexport)
|
||||
# else
|
||||
# define SODIUM_EXPORT __declspec(dllimport)
|
||||
# endif
|
||||
# else
|
||||
# if defined(__SUNPRO_C)
|
||||
# ifndef __GNU_C__
|
||||
# define SODIUM_EXPORT __attribute__ (visibility(__global))
|
||||
# else
|
||||
# define SODIUM_EXPORT __attribute__ __global
|
||||
# endif
|
||||
# elif defined(_MSG_VER)
|
||||
# define SODIUM_EXPORT extern __declspec(dllexport)
|
||||
# else
|
||||
# define SODIUM_EXPORT __attribute__ ((visibility ("default")))
|
||||
# endif
|
||||
# endif
|
||||
# if defined(__ELF__) && !defined(SODIUM_DISABLE_WEAK_FUNCTIONS)
|
||||
# define SODIUM_EXPORT_WEAK SODIUM_EXPORT __attribute__((weak))
|
||||
# else
|
||||
# define SODIUM_EXPORT_WEAK SODIUM_EXPORT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef CRYPTO_ALIGN
|
||||
# if defined(__INTEL_COMPILER) || defined(_MSC_VER)
|
||||
# define CRYPTO_ALIGN(x) __declspec(align(x))
|
||||
# else
|
||||
# define CRYPTO_ALIGN(x) __attribute__ ((aligned(x)))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define SODIUM_MIN(A, B) ((A) < (B) ? (A) : (B))
|
||||
#define SODIUM_SIZE_MAX SODIUM_MIN(UINT64_MAX, SIZE_MAX)
|
||||
|
||||
#endif
|
@ -0,0 +1,98 @@
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "crypto_verify_16.h"
|
||||
#include "crypto_verify_32.h"
|
||||
#include "crypto_verify_64.h"
|
||||
|
||||
size_t
|
||||
crypto_verify_16_bytes(void)
|
||||
{
|
||||
return crypto_verify_16_BYTES;
|
||||
}
|
||||
|
||||
size_t
|
||||
crypto_verify_32_bytes(void)
|
||||
{
|
||||
return crypto_verify_32_BYTES;
|
||||
}
|
||||
|
||||
size_t
|
||||
crypto_verify_64_bytes(void)
|
||||
{
|
||||
return crypto_verify_64_BYTES;
|
||||
}
|
||||
|
||||
#if defined(HAVE_EMMINTRIN_H) && defined(__SSE2__)
|
||||
|
||||
# ifdef __GNUC__
|
||||
# pragma GCC target("sse2")
|
||||
# endif
|
||||
# include <emmintrin.h>
|
||||
|
||||
static inline int
|
||||
crypto_verify_n(const unsigned char *x_, const unsigned char *y_,
|
||||
const int n)
|
||||
{
|
||||
const __m128i zero = _mm_setzero_si128();
|
||||
volatile __m128i v1, v2, z;
|
||||
volatile int m;
|
||||
int i;
|
||||
|
||||
const volatile __m128i *volatile x =
|
||||
(const volatile __m128i *volatile) (const void *) x_;
|
||||
const volatile __m128i *volatile y =
|
||||
(const volatile __m128i *volatile) (const void *) y_;
|
||||
v1 = _mm_loadu_si128((const __m128i *) &x[0]);
|
||||
v2 = _mm_loadu_si128((const __m128i *) &y[0]);
|
||||
z = _mm_xor_si128(v1, v2);
|
||||
for (i = 1; i < n / 16; i++) {
|
||||
v1 = _mm_loadu_si128((const __m128i *) &x[i]);
|
||||
v2 = _mm_loadu_si128((const __m128i *) &y[i]);
|
||||
z = _mm_or_si128(z, _mm_xor_si128(v1, v2));
|
||||
}
|
||||
m = _mm_movemask_epi8(_mm_cmpeq_epi32(z, zero));
|
||||
v1 = zero; v2 = zero; z = zero;
|
||||
|
||||
return (int) (((uint32_t) m + 1U) >> 16) - 1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline int
|
||||
crypto_verify_n(const unsigned char *x_, const unsigned char *y_,
|
||||
const int n)
|
||||
{
|
||||
const volatile unsigned char *volatile x =
|
||||
(const volatile unsigned char *volatile) x_;
|
||||
const volatile unsigned char *volatile y =
|
||||
(const volatile unsigned char *volatile) y_;
|
||||
volatile uint_fast16_t d = 0U;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
d |= x[i] ^ y[i];
|
||||
}
|
||||
return (1 & ((d - 1) >> 8)) - 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int
|
||||
crypto_verify_16(const unsigned char *x, const unsigned char *y)
|
||||
{
|
||||
return crypto_verify_n(x, y, crypto_verify_16_BYTES);
|
||||
}
|
||||
|
||||
int
|
||||
crypto_verify_32(const unsigned char *x, const unsigned char *y)
|
||||
{
|
||||
return crypto_verify_n(x, y, crypto_verify_32_BYTES);
|
||||
}
|
||||
|
||||
int
|
||||
crypto_verify_64(const unsigned char *x, const unsigned char *y)
|
||||
{
|
||||
return crypto_verify_n(x, y, crypto_verify_64_BYTES);
|
||||
}
|
@ -0,0 +1,163 @@
|
||||
#ifndef VARIANT2_INT_SQRT_H
|
||||
#define VARIANT2_INT_SQRT_H
|
||||
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
#define VARIANT2_INTEGER_MATH_SQRT_STEP_SSE2() \
|
||||
do { \
|
||||
const __m128i exp_double_bias = _mm_set_epi64x(0, 1023ULL << 52); \
|
||||
__m128d x = _mm_castsi128_pd(_mm_add_epi64(_mm_cvtsi64_si128(sqrt_input >> 12), exp_double_bias)); \
|
||||
x = _mm_sqrt_sd(_mm_setzero_pd(), x); \
|
||||
sqrt_result = (uint64_t)(_mm_cvtsi128_si64(_mm_sub_epi64(_mm_castpd_si128(x), exp_double_bias))) >> 19; \
|
||||
} while(0)
|
||||
|
||||
#define VARIANT2_INTEGER_MATH_SQRT_STEP_FP64() \
|
||||
do { \
|
||||
sqrt_result = sqrt(sqrt_input + 18446744073709551616.0) * 2.0 - 8589934592.0; \
|
||||
} while(0)
|
||||
|
||||
#define VARIANT2_INTEGER_MATH_SQRT_STEP_REF() \
|
||||
sqrt_result = integer_square_root_v2(sqrt_input)
|
||||
|
||||
// Reference implementation of the integer square root for Cryptonight variant 2
|
||||
// Computes integer part of "sqrt(2^64 + n) * 2 - 2^33"
|
||||
//
|
||||
// In other words, given 64-bit unsigned integer n:
|
||||
// 1) Write it as x = 1.NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN000... in binary (1 <= x < 2, all 64 bits of n are used)
|
||||
// 2) Calculate sqrt(x) = 1.0RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR... (1 <= sqrt(x) < sqrt(2), so it will always start with "1.0" in binary)
|
||||
// 3) Take 32 bits that come after "1.0" and return them as a 32-bit unsigned integer, discard all remaining bits
|
||||
//
|
||||
// Some sample inputs and outputs:
|
||||
//
|
||||
// Input | Output | Exact value of "sqrt(2^64 + n) * 2 - 2^33"
|
||||
// -----------------|------------|-------------------------------------------
|
||||
// 0 | 0 | 0
|
||||
// 2^32 | 0 | 0.99999999994179233909330885695244...
|
||||
// 2^32 + 1 | 1 | 1.0000000001746229827200734316305...
|
||||
// 2^50 | 262140 | 262140.00012206565608606978175873...
|
||||
// 2^55 + 20963331 | 8384515 | 8384515.9999999997673963974959744...
|
||||
// 2^55 + 20963332 | 8384516 | 8384516
|
||||
// 2^62 + 26599786 | 1013904242 | 1013904242.9999999999479374853545...
|
||||
// 2^62 + 26599787 | 1013904243 | 1013904243.0000000001561875439364...
|
||||
// 2^64 - 1 | 3558067407 | 3558067407.9041987696409179931096...
|
||||
|
||||
// The reference implementation as it is now uses only unsigned int64 arithmetic, so it can't have undefined behavior
|
||||
// It was tested once for all edge cases and confirmed correct
|
||||
static inline uint32_t integer_square_root_v2(uint64_t n)
|
||||
{
|
||||
uint64_t r = 1ULL << 63;
|
||||
|
||||
for (uint64_t bit = 1ULL << 60; bit; bit >>= 2)
|
||||
{
|
||||
const bool b = (n < r + bit);
|
||||
const uint64_t n_next = n - (r + bit);
|
||||
const uint64_t r_next = r + bit * 2;
|
||||
n = b ? n : n_next;
|
||||
r = b ? r : r_next;
|
||||
r >>= 1;
|
||||
}
|
||||
|
||||
return r * 2 + ((n > r) ? 1 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
VARIANT2_INTEGER_MATH_SQRT_FIXUP checks that "r" is an integer part of "sqrt(2^64 + sqrt_input) * 2 - 2^33" and adds or subtracts 1 if needed
|
||||
It's hard to understand how it works, so here is a full calculation of formulas used in VARIANT2_INTEGER_MATH_SQRT_FIXUP
|
||||
|
||||
The following inequalities must hold for r if it's an integer part of "sqrt(2^64 + sqrt_input) * 2 - 2^33":
|
||||
1) r <= sqrt(2^64 + sqrt_input) * 2 - 2^33
|
||||
2) r + 1 > sqrt(2^64 + sqrt_input) * 2 - 2^33
|
||||
|
||||
We need to check them using only unsigned integer arithmetic to avoid rounding errors and undefined behavior
|
||||
|
||||
First inequality: r <= sqrt(2^64 + sqrt_input) * 2 - 2^33
|
||||
-----------------------------------------------------------------------------------
|
||||
r <= sqrt(2^64 + sqrt_input) * 2 - 2^33
|
||||
r + 2^33 <= sqrt(2^64 + sqrt_input) * 2
|
||||
r/2 + 2^32 <= sqrt(2^64 + sqrt_input)
|
||||
(r/2 + 2^32)^2 <= 2^64 + sqrt_input
|
||||
|
||||
Rewrite r as r = s * 2 + b (s = trunc(r/2), b is 0 or 1)
|
||||
|
||||
((s*2+b)/2 + 2^32)^2 <= 2^64 + sqrt_input
|
||||
(s*2+b)^2/4 + 2*2^32*(s*2+b)/2 + 2^64 <= 2^64 + sqrt_input
|
||||
(s*2+b)^2/4 + 2*2^32*(s*2+b)/2 <= sqrt_input
|
||||
(s*2+b)^2/4 + 2^32*r <= sqrt_input
|
||||
(s^2*4+2*s*2*b+b^2)/4 + 2^32*r <= sqrt_input
|
||||
s^2+s*b+b^2/4 + 2^32*r <= sqrt_input
|
||||
s*(s+b) + b^2/4 + 2^32*r <= sqrt_input
|
||||
|
||||
Let r2 = s*(s+b) + r*2^32
|
||||
r2 + b^2/4 <= sqrt_input
|
||||
|
||||
If this inequality doesn't hold, then we must decrement r: IF "r2 + b^2/4 > sqrt_input" THEN r = r - 1
|
||||
|
||||
b can be 0 or 1
|
||||
If b is 0 then we need to compare "r2 > sqrt_input"
|
||||
If b is 1 then b^2/4 = 0.25, so we need to compare "r2 + 0.25 > sqrt_input"
|
||||
Since both r2 and sqrt_input are integers, we can safely replace it with "r2 + 1 > sqrt_input"
|
||||
-----------------------------------------------------------------------------------
|
||||
Both cases can be merged to a single expression "r2 + b > sqrt_input"
|
||||
-----------------------------------------------------------------------------------
|
||||
There will be no overflow when calculating "r2 + b", so it's safe to compare with sqrt_input:
|
||||
r2 + b = s*(s+b) + r*2^32 + b
|
||||
The largest value s, b and r can have is s = 1779033703, b = 1, r = 3558067407 when sqrt_input = 2^64 - 1
|
||||
r2 + b <= 1779033703*1779033704 + 3558067407*2^32 + 1 = 18446744068217447385 < 2^64
|
||||
|
||||
Second inequality: r + 1 > sqrt(2^64 + sqrt_input) * 2 - 2^33
|
||||
-----------------------------------------------------------------------------------
|
||||
r + 1 > sqrt(2^64 + sqrt_input) * 2 - 2^33
|
||||
r + 1 + 2^33 > sqrt(2^64 + sqrt_input) * 2
|
||||
((r+1)/2 + 2^32)^2 > 2^64 + sqrt_input
|
||||
|
||||
Rewrite r as r = s * 2 + b (s = trunc(r/2), b is 0 or 1)
|
||||
|
||||
((s*2+b+1)/2 + 2^32)^2 > 2^64 + sqrt_input
|
||||
(s*2+b+1)^2/4 + 2*(s*2+b+1)/2*2^32 + 2^64 > 2^64 + sqrt_input
|
||||
(s*2+b+1)^2/4 + (s*2+b+1)*2^32 > sqrt_input
|
||||
(s*2+b+1)^2/4 + (r+1)*2^32 > sqrt_input
|
||||
(s*2+(b+1))^2/4 + r*2^32 + 2^32 > sqrt_input
|
||||
(s^2*4+2*s*2*(b+1)+(b+1)^2)/4 + r*2^32 + 2^32 > sqrt_input
|
||||
s^2+s*(b+1)+(b+1)^2/4 + r*2^32 + 2^32 > sqrt_input
|
||||
s*(s+b) + s + (b+1)^2/4 + r*2^32 + 2^32 > sqrt_input
|
||||
|
||||
Let r2 = s*(s+b) + r*2^32
|
||||
|
||||
r2 + s + (b+1)^2/4 + 2^32 > sqrt_input
|
||||
r2 + 2^32 + (b+1)^2/4 > sqrt_input - s
|
||||
|
||||
If this inequality doesn't hold, then we must decrement r: IF "r2 + 2^32 + (b+1)^2/4 <= sqrt_input - s" THEN r = r - 1
|
||||
b can be 0 or 1
|
||||
If b is 0 then we need to compare "r2 + 2^32 + 1/4 <= sqrt_input - s" which is equal to "r2 + 2^32 < sqrt_input - s" because all numbers here are integers
|
||||
If b is 1 then (b+1)^2/4 = 1, so we need to compare "r2 + 2^32 + 1 <= sqrt_input - s" which is also equal to "r2 + 2^32 < sqrt_input - s"
|
||||
-----------------------------------------------------------------------------------
|
||||
Both cases can be merged to a single expression "r2 + 2^32 < sqrt_input - s"
|
||||
-----------------------------------------------------------------------------------
|
||||
There will be no overflow when calculating "r2 + 2^32":
|
||||
r2 + 2^32 = s*(s+b) + r*2^32 + 2^32 = s*(s+b) + (r+1)*2^32
|
||||
The largest value s, b and r can have is s = 1779033703, b = 1, r = 3558067407 when sqrt_input = 2^64 - 1
|
||||
r2 + b <= 1779033703*1779033704 + 3558067408*2^32 = 18446744072512414680 < 2^64
|
||||
|
||||
There will be no integer overflow when calculating "sqrt_input - s", i.e. "sqrt_input >= s" at all times:
|
||||
s = trunc(r/2) = trunc(sqrt(2^64 + sqrt_input) - 2^32) < sqrt(2^64 + sqrt_input) - 2^32 + 1
|
||||
sqrt_input > sqrt(2^64 + sqrt_input) - 2^32 + 1
|
||||
sqrt_input + 2^32 - 1 > sqrt(2^64 + sqrt_input)
|
||||
(sqrt_input + 2^32 - 1)^2 > sqrt_input + 2^64
|
||||
sqrt_input^2 + 2*sqrt_input*(2^32 - 1) + (2^32-1)^2 > sqrt_input + 2^64
|
||||
sqrt_input^2 + sqrt_input*(2^33 - 2) + (2^32-1)^2 > sqrt_input + 2^64
|
||||
sqrt_input^2 + sqrt_input*(2^33 - 3) + (2^32-1)^2 > 2^64
|
||||
sqrt_input^2 + sqrt_input*(2^33 - 3) + 2^64-2^33+1 > 2^64
|
||||
sqrt_input^2 + sqrt_input*(2^33 - 3) - 2^33 + 1 > 0
|
||||
This inequality is true if sqrt_input > 1 and it's easy to check that s = 0 if sqrt_input is 0 or 1, so there will be no integer overflow
|
||||
*/
|
||||
|
||||
#define VARIANT2_INTEGER_MATH_SQRT_FIXUP(r) \
|
||||
do { \
|
||||
const uint64_t s = r >> 1; \
|
||||
const uint64_t b = r & 1; \
|
||||
const uint64_t r2 = (uint64_t)(s) * (s + b) + (r << 32); \
|
||||
r += ((r2 + b > sqrt_input) ? -1 : 0) + ((r2 + (1ULL << 32) < sqrt_input - s) ? 1 : 0); \
|
||||
} while(0)
|
||||
|
||||
#endif
|
@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
||||
namespace fnv
|
||||
{
|
||||
inline uint64_t FNV1a(const char *ptr, size_t sz)
|
||||
{
|
||||
uint64_t h = 0xcbf29ce484222325;
|
||||
for (size_t i = 0; i < sz; ++i)
|
||||
h = (h ^ *(const uint8_t*)ptr++) * 0x100000001b3;
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
// Copyright (c) 2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
namespace epee
|
||||
{
|
||||
class mlocker
|
||||
{
|
||||
public:
|
||||
mlocker(void *ptr, size_t len);
|
||||
~mlocker();
|
||||
|
||||
static size_t get_page_size();
|
||||
static size_t get_num_locked_pages();
|
||||
static size_t get_num_locked_objects();
|
||||
|
||||
static void lock(void *ptr, size_t len);
|
||||
static void unlock(void *ptr, size_t len);
|
||||
|
||||
private:
|
||||
static size_t page_size;
|
||||
static size_t num_locked_objects;
|
||||
|
||||
static boost::mutex &mutex();
|
||||
static std::map<size_t, unsigned int> &map();
|
||||
static void lock_page(size_t page);
|
||||
static void unlock_page(size_t page);
|
||||
|
||||
void *ptr;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
/// Locks memory while in scope
|
||||
///
|
||||
/// Primarily useful for making sure that private keys don't get swapped out
|
||||
// to disk
|
||||
template <class T>
|
||||
struct mlocked : public T {
|
||||
using type = T;
|
||||
|
||||
mlocked(): T() { mlocker::lock(this, sizeof(T)); }
|
||||
mlocked(const T &t): T(t) { mlocker::lock(this, sizeof(T)); }
|
||||
mlocked(const mlocked<T> &mt): T(mt) { mlocker::lock(this, sizeof(T)); }
|
||||
mlocked(const T &&t): T(t) { mlocker::lock(this, sizeof(T)); }
|
||||
mlocked(const mlocked<T> &&mt): T(mt) { mlocker::lock(this, sizeof(T)); }
|
||||
mlocked<T> &operator=(const mlocked<T> &mt) { T::operator=(mt); return *this; }
|
||||
~mlocked() { mlocker::unlock(this, sizeof(T)); }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
T& unwrap(mlocked<T>& src) { return src; }
|
||||
|
||||
template<typename T>
|
||||
const T& unwrap(mlocked<T> const& src) { return src; }
|
||||
|
||||
template <class T, size_t N>
|
||||
using mlocked_arr = mlocked<std::array<T, N>>;
|
||||
}
|
@ -0,0 +1,182 @@
|
||||
// Copyright (c) 2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// 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.
|
||||
|
||||
#if defined __GNUC__ && !defined _WIN32
|
||||
#define HAVE_MLOCK 1
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#if defined HAVE_MLOCK
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#include "misc_log_ex.h"
|
||||
#include "syncobj.h"
|
||||
#include "mlocker.h"
|
||||
|
||||
static size_t query_page_size()
|
||||
{
|
||||
#if defined HAVE_MLOCK
|
||||
long ret = sysconf(_SC_PAGESIZE);
|
||||
if (ret <= 0)
|
||||
{
|
||||
MERROR("Failed to determine page size");
|
||||
return 0;
|
||||
}
|
||||
MINFO("Page size: " << ret);
|
||||
return ret;
|
||||
#else
|
||||
#warning Missing query_page_size implementation
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void do_lock(void *ptr, size_t len)
|
||||
{
|
||||
#if defined HAVE_MLOCK
|
||||
int ret = mlock(ptr, len);
|
||||
if (ret < 0)
|
||||
MERROR("Error locking page at " << ptr << ": " << strerror(errno));
|
||||
#else
|
||||
#warning Missing do_lock implementation
|
||||
#endif
|
||||
}
|
||||
|
||||
static void do_unlock(void *ptr, size_t len)
|
||||
{
|
||||
#if defined HAVE_MLOCK
|
||||
int ret = munlock(ptr, len);
|
||||
if (ret < 0)
|
||||
MERROR("Error unlocking page at " << ptr << ": " << strerror(errno));
|
||||
#else
|
||||
#warning Missing implementation of page size detection
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace epee
|
||||
{
|
||||
size_t mlocker::page_size = 0;
|
||||
size_t mlocker::num_locked_objects = 0;
|
||||
|
||||
boost::mutex &mlocker::mutex()
|
||||
{
|
||||
static boost::mutex vmutex;
|
||||
return vmutex;
|
||||
}
|
||||
std::map<size_t, unsigned int> &mlocker::map()
|
||||
{
|
||||
static std::map<size_t, unsigned int> vmap;
|
||||
return vmap;
|
||||
}
|
||||
|
||||
size_t mlocker::get_page_size()
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(mutex());
|
||||
if (page_size == 0)
|
||||
page_size = query_page_size();
|
||||
return page_size;
|
||||
}
|
||||
|
||||
mlocker::mlocker(void *ptr, size_t len): ptr(ptr), len(len)
|
||||
{
|
||||
lock(ptr, len);
|
||||
}
|
||||
|
||||
mlocker::~mlocker()
|
||||
{
|
||||
unlock(ptr, len);
|
||||
}
|
||||
|
||||
void mlocker::lock(void *ptr, size_t len)
|
||||
{
|
||||
size_t page_size = get_page_size();
|
||||
if (page_size == 0)
|
||||
return;
|
||||
|
||||
CRITICAL_REGION_LOCAL(mutex());
|
||||
const size_t first = ((uintptr_t)ptr) / page_size;
|
||||
const size_t last = (((uintptr_t)ptr) + len - 1) / page_size;
|
||||
for (size_t page = first; page <= last; ++page)
|
||||
lock_page(page);
|
||||
++num_locked_objects;
|
||||
}
|
||||
|
||||
void mlocker::unlock(void *ptr, size_t len)
|
||||
{
|
||||
size_t page_size = get_page_size();
|
||||
if (page_size == 0)
|
||||
return;
|
||||
CRITICAL_REGION_LOCAL(mutex());
|
||||
const size_t first = ((uintptr_t)ptr) / page_size;
|
||||
const size_t last = (((uintptr_t)ptr) + len - 1) / page_size;
|
||||
for (size_t page = first; page <= last; ++page)
|
||||
unlock_page(page);
|
||||
--num_locked_objects;
|
||||
}
|
||||
|
||||
size_t mlocker::get_num_locked_pages()
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(mutex());
|
||||
return map().size();
|
||||
}
|
||||
|
||||
size_t mlocker::get_num_locked_objects()
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(mutex());
|
||||
return num_locked_objects;
|
||||
}
|
||||
|
||||
void mlocker::lock_page(size_t page)
|
||||
{
|
||||
std::pair<std::map<size_t, unsigned int>::iterator, bool> p = map().insert(std::make_pair(page, 1));
|
||||
if (p.second)
|
||||
{
|
||||
do_lock((void*)(page * page_size), page_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
++p.first->second;
|
||||
}
|
||||
}
|
||||
|
||||
void mlocker::unlock_page(size_t page)
|
||||
{
|
||||
std::map<size_t, unsigned int>::iterator i = map().find(page);
|
||||
if (i == map().end())
|
||||
{
|
||||
MERROR("Attempt to unlock unlocked page at " << (void*)(page * page_size));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!--i->second)
|
||||
{
|
||||
map().erase(i);
|
||||
do_unlock((void*)(page * page_size), page_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,665 @@
|
||||
// Copyright (c) 2017, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// 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.
|
||||
//
|
||||
// Adapted from Python code by Sarang Noether
|
||||
|
||||
#include "misc_log_ex.h"
|
||||
// #include "common/perf_timer.h"
|
||||
extern "C"
|
||||
{
|
||||
#include "crypto/crypto-ops.h"
|
||||
}
|
||||
#include "common/aligned.h"
|
||||
#include "rctOps.h"
|
||||
#include "multiexp.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "multiexp"
|
||||
|
||||
// #define MULTIEXP_PERF(x) x
|
||||
// #define MULTIEXP_PERF(x)
|
||||
|
||||
#define RAW_MEMORY_BLOCK
|
||||
//#define ALTERNATE_LAYOUT
|
||||
//#define TRACK_STRAUS_ZERO_IDENTITY
|
||||
|
||||
// per points us for N/B points (B point bands)
|
||||
// raw alt 128/192 4096/192 4096/4096
|
||||
// 0 0 52.6 71 71.2
|
||||
// 0 1 53.2 72.2 72.4
|
||||
// 1 0 52.7 67 67.1
|
||||
// 1 1 52.8 70.4 70.2
|
||||
|
||||
// Pippenger:
|
||||
// 1 2 3 4 5 6 7 8 9 bestN
|
||||
// 2 555 598 621 804 1038 1733 2486 5020 8304 1
|
||||
// 4 783 747 800 1006 1428 2132 3285 5185 9806 2
|
||||
// 8 1174 1071 1095 1286 1640 2398 3869 6378 12080 2
|
||||
// 16 2279 1874 1745 1739 2144 2831 4209 6964 12007 4
|
||||
// 32 3910 3706 2588 2477 2782 3467 4856 7489 12618 4
|
||||
// 64 7184 5429 4710 4368 4010 4672 6027 8559 13684 5
|
||||
// 128 14097 10574 8452 7297 6841 6718 8615 10580 15641 6
|
||||
// 256 27715 20800 16000 13550 11875 11400 11505 14090 18460 6
|
||||
// 512 55100 41250 31740 26570 22030 19830 20760 21380 25215 6
|
||||
// 1024 111520 79000 61080 49720 43080 38320 37600 35040 36750 8
|
||||
// 2048 219480 162680 122120 102080 83760 70360 66600 63920 66160 8
|
||||
// 4096 453320 323080 247240 210200 180040 150240 132440 114920 110560 9
|
||||
|
||||
// 2 4 8 16 32 64 128 256 512 1024 2048 4096
|
||||
// Bos Coster 858 994 1316 1949 3183 5512 9865 17830 33485 63160 124280 246320
|
||||
// Straus 226 341 548 980 1870 3538 7039 14490 29020 57200 118640 233640
|
||||
// Straus/cached 226 315 485 785 1514 2858 5753 11065 22970 45120 98880 194840
|
||||
// Pippenger 555 747 1071 1739 2477 4010 6718 11400 19830 35040 63920 110560
|
||||
|
||||
// Best/cached Straus Straus Straus Straus Straus Straus Straus Straus Pip Pip Pip Pip
|
||||
// Best/uncached Straus Straus Straus Straus Straus Straus Pip Pip Pip Pip Pip Pip
|
||||
|
||||
namespace rct
|
||||
{
|
||||
|
||||
static inline bool operator<(const rct::key &k0, const rct::key&k1)
|
||||
{
|
||||
for (int n = 31; n >= 0; --n)
|
||||
{
|
||||
if (k0.bytes[n] < k1.bytes[n])
|
||||
return true;
|
||||
if (k0.bytes[n] > k1.bytes[n])
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline rct::key div2(const rct::key &k)
|
||||
{
|
||||
rct::key res;
|
||||
int carry = 0;
|
||||
for (int n = 31; n >= 0; --n)
|
||||
{
|
||||
int new_carry = (k.bytes[n] & 1) << 7;
|
||||
res.bytes[n] = k.bytes[n] / 2 + carry;
|
||||
carry = new_carry;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline rct::key pow2(size_t n)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(n < 256, "Invalid pow2 argument");
|
||||
rct::key res = rct::zero();
|
||||
res[n >> 3] |= 1<<(n&7);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int test(const rct::key &k, size_t n)
|
||||
{
|
||||
if (n >= 256) return 0;
|
||||
return k[n >> 3] & (1 << (n & 7));
|
||||
}
|
||||
|
||||
static inline void add(ge_p3 &p3, const ge_cached &other)
|
||||
{
|
||||
ge_p1p1 p1;
|
||||
ge_add(&p1, &p3, &other);
|
||||
ge_p1p1_to_p3(&p3, &p1);
|
||||
}
|
||||
|
||||
static inline void add(ge_p3 &p3, const ge_p3 &other)
|
||||
{
|
||||
ge_cached cached;
|
||||
ge_p3_to_cached(&cached, &other);
|
||||
add(p3, cached);
|
||||
}
|
||||
|
||||
rct::key bos_coster_heap_conv(std::vector<MultiexpData> data)
|
||||
{
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(bos_coster, 1000000));
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(setup, 1000000));
|
||||
size_t points = data.size();
|
||||
CHECK_AND_ASSERT_THROW_MES(points > 1, "Not enough points");
|
||||
std::vector<size_t> heap(points);
|
||||
for (size_t n = 0; n < points; ++n)
|
||||
heap[n] = n;
|
||||
|
||||
auto Comp = [&](size_t e0, size_t e1) { return data[e0].scalar < data[e1].scalar; };
|
||||
std::make_heap(heap.begin(), heap.end(), Comp);
|
||||
// MULTIEXP_PERF(PERF_TIMER_STOP(setup));
|
||||
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(loop, 1000000));
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(pop, 1000000)); MULTIEXP_PERF(PERF_TIMER_PAUSE(pop));
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(add, 1000000)); MULTIEXP_PERF(PERF_TIMER_PAUSE(add));
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(sub, 1000000)); MULTIEXP_PERF(PERF_TIMER_PAUSE(sub));
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(push, 1000000)); MULTIEXP_PERF(PERF_TIMER_PAUSE(push));
|
||||
while (heap.size() > 1)
|
||||
{
|
||||
// MULTIEXP_PERF(PERF_TIMER_RESUME(pop));
|
||||
std::pop_heap(heap.begin(), heap.end(), Comp);
|
||||
size_t index1 = heap.back();
|
||||
heap.pop_back();
|
||||
std::pop_heap(heap.begin(), heap.end(), Comp);
|
||||
size_t index2 = heap.back();
|
||||
heap.pop_back();
|
||||
// MULTIEXP_PERF(PERF_TIMER_PAUSE(pop));
|
||||
|
||||
// MULTIEXP_PERF(PERF_TIMER_RESUME(add));
|
||||
ge_cached cached;
|
||||
ge_p3_to_cached(&cached, &data[index1].point);
|
||||
ge_p1p1 p1;
|
||||
ge_add(&p1, &data[index2].point, &cached);
|
||||
ge_p1p1_to_p3(&data[index2].point, &p1);
|
||||
// MULTIEXP_PERF(PERF_TIMER_PAUSE(add));
|
||||
|
||||
// MULTIEXP_PERF(PERF_TIMER_RESUME(sub));
|
||||
sc_sub(data[index1].scalar.bytes, data[index1].scalar.bytes, data[index2].scalar.bytes);
|
||||
// MULTIEXP_PERF(PERF_TIMER_PAUSE(sub));
|
||||
|
||||
// MULTIEXP_PERF(PERF_TIMER_RESUME(push));
|
||||
if (!(data[index1].scalar == rct::zero()))
|
||||
{
|
||||
heap.push_back(index1);
|
||||
std::push_heap(heap.begin(), heap.end(), Comp);
|
||||
}
|
||||
|
||||
heap.push_back(index2);
|
||||
std::push_heap(heap.begin(), heap.end(), Comp);
|
||||
// MULTIEXP_PERF(PERF_TIMER_PAUSE(push));
|
||||
}
|
||||
// MULTIEXP_PERF(PERF_TIMER_STOP(push));
|
||||
// MULTIEXP_PERF(PERF_TIMER_STOP(sub));
|
||||
// MULTIEXP_PERF(PERF_TIMER_STOP(add));
|
||||
// MULTIEXP_PERF(PERF_TIMER_STOP(pop));
|
||||
// MULTIEXP_PERF(PERF_TIMER_STOP(loop));
|
||||
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(end, 1000000));
|
||||
//return rct::scalarmultKey(data[index1].point, data[index1].scalar);
|
||||
std::pop_heap(heap.begin(), heap.end(), Comp);
|
||||
size_t index1 = heap.back();
|
||||
heap.pop_back();
|
||||
ge_p2 p2;
|
||||
ge_scalarmult(&p2, data[index1].scalar.bytes, &data[index1].point);
|
||||
rct::key res;
|
||||
ge_tobytes(res.bytes, &p2);
|
||||
return res;
|
||||
}
|
||||
|
||||
rct::key bos_coster_heap_conv_robust(std::vector<MultiexpData> data)
|
||||
{
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(bos_coster, 1000000));
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(setup, 1000000));
|
||||
size_t points = data.size();
|
||||
CHECK_AND_ASSERT_THROW_MES(points > 0, "Not enough points");
|
||||
std::vector<size_t> heap;
|
||||
heap.reserve(points);
|
||||
for (size_t n = 0; n < points; ++n)
|
||||
{
|
||||
if (!(data[n].scalar == rct::zero()) && !ge_p3_is_point_at_infinity(&data[n].point))
|
||||
heap.push_back(n);
|
||||
}
|
||||
points = heap.size();
|
||||
if (points == 0)
|
||||
return rct::identity();
|
||||
|
||||
auto Comp = [&](size_t e0, size_t e1) { return data[e0].scalar < data[e1].scalar; };
|
||||
std::make_heap(heap.begin(), heap.end(), Comp);
|
||||
|
||||
if (points < 2)
|
||||
{
|
||||
std::pop_heap(heap.begin(), heap.end(), Comp);
|
||||
size_t index1 = heap.back();
|
||||
ge_p2 p2;
|
||||
ge_scalarmult(&p2, data[index1].scalar.bytes, &data[index1].point);
|
||||
rct::key res;
|
||||
ge_tobytes(res.bytes, &p2);
|
||||
return res;
|
||||
}
|
||||
|
||||
// MULTIEXP_PERF(PERF_TIMER_STOP(setup));
|
||||
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(loop, 1000000));
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(pop, 1000000)); MULTIEXP_PERF(PERF_TIMER_PAUSE(pop));
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(div, 1000000)); MULTIEXP_PERF(PERF_TIMER_PAUSE(div));
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(add, 1000000)); MULTIEXP_PERF(PERF_TIMER_PAUSE(add));
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(sub, 1000000)); MULTIEXP_PERF(PERF_TIMER_PAUSE(sub));
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(push, 1000000)); MULTIEXP_PERF(PERF_TIMER_PAUSE(push));
|
||||
while (heap.size() > 1)
|
||||
{
|
||||
// MULTIEXP_PERF(PERF_TIMER_RESUME(pop));
|
||||
std::pop_heap(heap.begin(), heap.end(), Comp);
|
||||
size_t index1 = heap.back();
|
||||
heap.pop_back();
|
||||
std::pop_heap(heap.begin(), heap.end(), Comp);
|
||||
size_t index2 = heap.back();
|
||||
heap.pop_back();
|
||||
// MULTIEXP_PERF(PERF_TIMER_PAUSE(pop));
|
||||
|
||||
ge_cached cached;
|
||||
ge_p1p1 p1;
|
||||
ge_p2 p2;
|
||||
|
||||
// MULTIEXP_PERF(PERF_TIMER_RESUME(div));
|
||||
while (1)
|
||||
{
|
||||
rct::key s1_2 = div2(data[index1].scalar);
|
||||
if (!(data[index2].scalar < s1_2))
|
||||
break;
|
||||
if (data[index1].scalar.bytes[0] & 1)
|
||||
{
|
||||
data.resize(data.size()+1);
|
||||
data.back().scalar = rct::identity();
|
||||
data.back().point = data[index1].point;
|
||||
heap.push_back(data.size() - 1);
|
||||
std::push_heap(heap.begin(), heap.end(), Comp);
|
||||
}
|
||||
data[index1].scalar = div2(data[index1].scalar);
|
||||
ge_p3_to_p2(&p2, &data[index1].point);
|
||||
ge_p2_dbl(&p1, &p2);
|
||||
ge_p1p1_to_p3(&data[index1].point, &p1);
|
||||
}
|
||||
// MULTIEXP_PERF(PERF_TIMER_PAUSE(div));
|
||||
|
||||
// MULTIEXP_PERF(PERF_TIMER_RESUME(add));
|
||||
ge_p3_to_cached(&cached, &data[index1].point);
|
||||
ge_add(&p1, &data[index2].point, &cached);
|
||||
ge_p1p1_to_p3(&data[index2].point, &p1);
|
||||
// MULTIEXP_PERF(PERF_TIMER_PAUSE(add));
|
||||
|
||||
// MULTIEXP_PERF(PERF_TIMER_RESUME(sub));
|
||||
sc_sub(data[index1].scalar.bytes, data[index1].scalar.bytes, data[index2].scalar.bytes);
|
||||
// MULTIEXP_PERF(PERF_TIMER_PAUSE(sub));
|
||||
|
||||
// MULTIEXP_PERF(PERF_TIMER_RESUME(push));
|
||||
if (!(data[index1].scalar == rct::zero()))
|
||||
{
|
||||
heap.push_back(index1);
|
||||
std::push_heap(heap.begin(), heap.end(), Comp);
|
||||
}
|
||||
|
||||
heap.push_back(index2);
|
||||
std::push_heap(heap.begin(), heap.end(), Comp);
|
||||
// MULTIEXP_PERF(PERF_TIMER_PAUSE(push));
|
||||
}
|
||||
// MULTIEXP_PERF(PERF_TIMER_STOP(push));
|
||||
// MULTIEXP_PERF(PERF_TIMER_STOP(sub));
|
||||
// MULTIEXP_PERF(PERF_TIMER_STOP(add));
|
||||
// MULTIEXP_PERF(PERF_TIMER_STOP(pop));
|
||||
// MULTIEXP_PERF(PERF_TIMER_STOP(loop));
|
||||
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(end, 1000000));
|
||||
//return rct::scalarmultKey(data[index1].point, data[index1].scalar);
|
||||
std::pop_heap(heap.begin(), heap.end(), Comp);
|
||||
size_t index1 = heap.back();
|
||||
heap.pop_back();
|
||||
ge_p2 p2;
|
||||
ge_scalarmult(&p2, data[index1].scalar.bytes, &data[index1].point);
|
||||
rct::key res;
|
||||
ge_tobytes(res.bytes, &p2);
|
||||
return res;
|
||||
}
|
||||
|
||||
static constexpr unsigned int STRAUS_C = 4;
|
||||
|
||||
struct straus_cached_data
|
||||
{
|
||||
#ifdef RAW_MEMORY_BLOCK
|
||||
size_t size;
|
||||
ge_cached *multiples;
|
||||
straus_cached_data(): size(0), multiples(NULL) {}
|
||||
~straus_cached_data() { aligned_free(multiples); }
|
||||
#else
|
||||
std::vector<std::vector<ge_cached>> multiples;
|
||||
#endif
|
||||
};
|
||||
#ifdef RAW_MEMORY_BLOCK
|
||||
#ifdef ALTERNATE_LAYOUT
|
||||
#define CACHE_OFFSET(cache,point,digit) cache->multiples[(point)*((1<<STRAUS_C)-1)+((digit)-1)]
|
||||
#else
|
||||
#define CACHE_OFFSET(cache,point,digit) cache->multiples[(point)+cache->size*((digit)-1)]
|
||||
#endif
|
||||
#else
|
||||
#ifdef ALTERNATE_LAYOUT
|
||||
#define CACHE_OFFSET(cache,point,digit) local_cache->multiples[j][digit-1]
|
||||
#else
|
||||
#define CACHE_OFFSET(cache,point,digit) local_cache->multiples[digit][j]
|
||||
#endif
|
||||
#endif
|
||||
|
||||
std::shared_ptr<straus_cached_data> straus_init_cache(const std::vector<MultiexpData> &data, size_t N)
|
||||
{
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(multiples, 1000000));
|
||||
if (N == 0)
|
||||
N = data.size();
|
||||
CHECK_AND_ASSERT_THROW_MES(N <= data.size(), "Bad cache base data");
|
||||
ge_cached cached;
|
||||
ge_p1p1 p1;
|
||||
ge_p3 p3;
|
||||
std::shared_ptr<straus_cached_data> cache(new straus_cached_data());
|
||||
|
||||
#ifdef RAW_MEMORY_BLOCK
|
||||
const size_t offset = cache->size;
|
||||
cache->multiples = (ge_cached*)aligned_realloc(cache->multiples, sizeof(ge_cached) * ((1<<STRAUS_C)-1) * std::max(offset, N), 4096);
|
||||
CHECK_AND_ASSERT_THROW_MES(cache->multiples, "Out of memory");
|
||||
cache->size = N;
|
||||
for (size_t j=offset;j<N;++j)
|
||||
{
|
||||
ge_p3_to_cached(&CACHE_OFFSET(cache, j, 1), &data[j].point);
|
||||
for (size_t i=2;i<1<<STRAUS_C;++i)
|
||||
{
|
||||
ge_add(&p1, &data[j].point, &CACHE_OFFSET(cache, j, i-1));
|
||||
ge_p1p1_to_p3(&p3, &p1);
|
||||
ge_p3_to_cached(&CACHE_OFFSET(cache, j, i), &p3);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#ifdef ALTERNATE_LAYOUT
|
||||
const size_t offset = cache->multiples.size();
|
||||
cache->multiples.resize(std::max(offset, N));
|
||||
for (size_t i = offset; i < N; ++i)
|
||||
{
|
||||
cache->multiples[i].resize((1<<STRAUS_C)-1);
|
||||
ge_p3_to_cached(&cache->multiples[i][0], &data[i].point);
|
||||
for (size_t j=2;j<1<<STRAUS_C;++j)
|
||||
{
|
||||
ge_add(&p1, &data[i].point, &cache->multiples[i][j-2]);
|
||||
ge_p1p1_to_p3(&p3, &p1);
|
||||
ge_p3_to_cached(&cache->multiples[i][j-1], &p3);
|
||||
}
|
||||
}
|
||||
#else
|
||||
cache->multiples.resize(1<<STRAUS_C);
|
||||
size_t offset = cache->multiples[1].size();
|
||||
cache->multiples[1].resize(std::max(offset, N));
|
||||
for (size_t i = offset; i < N; ++i)
|
||||
ge_p3_to_cached(&cache->multiples[1][i], &data[i].point);
|
||||
for (size_t i=2;i<1<<STRAUS_C;++i)
|
||||
cache->multiples[i].resize(std::max(offset, N));
|
||||
for (size_t j=offset;j<N;++j)
|
||||
{
|
||||
for (size_t i=2;i<1<<STRAUS_C;++i)
|
||||
{
|
||||
ge_add(&p1, &data[j].point, &cache->multiples[i-1][j]);
|
||||
ge_p1p1_to_p3(&p3, &p1);
|
||||
ge_p3_to_cached(&cache->multiples[i][j], &p3);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
// MULTIEXP_PERF(PERF_TIMER_STOP(multiples));
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
size_t straus_get_cache_size(const std::shared_ptr<straus_cached_data> &cache)
|
||||
{
|
||||
size_t sz = 0;
|
||||
#ifdef RAW_MEMORY_BLOCK
|
||||
sz += cache->size * sizeof(ge_cached) * ((1<<STRAUS_C)-1);
|
||||
#else
|
||||
for (const auto &e0: cache->multiples)
|
||||
sz += e0.size() * sizeof(ge_cached);
|
||||
#endif
|
||||
return sz;
|
||||
}
|
||||
|
||||
rct::key straus(const std::vector<MultiexpData> &data, const std::shared_ptr<straus_cached_data> &cache, size_t STEP)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(cache == NULL || cache->size >= data.size(), "Cache is too small");
|
||||
// MULTIEXP_PERF(PERF_TIMER_UNIT(straus, 1000000));
|
||||
bool HiGi = cache != NULL;
|
||||
STEP = STEP ? STEP : 192;
|
||||
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(setup, 1000000));
|
||||
static constexpr unsigned int mask = (1<<STRAUS_C)-1;
|
||||
std::shared_ptr<straus_cached_data> local_cache = cache == NULL ? straus_init_cache(data) : cache;
|
||||
ge_cached cached;
|
||||
ge_p1p1 p1;
|
||||
ge_p3 p3;
|
||||
|
||||
#ifdef TRACK_STRAUS_ZERO_IDENTITY
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(skip, 1000000));
|
||||
std::vector<uint8_t> skip(data.size());
|
||||
for (size_t i = 0; i < data.size(); ++i)
|
||||
skip[i] = data[i].scalar == rct::zero() || ge_p3_is_point_at_infinity(&data[i].point);
|
||||
// MULTIEXP_PERF(PERF_TIMER_STOP(skip));
|
||||
#endif
|
||||
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(digits, 1000000));
|
||||
std::unique_ptr<uint8_t[]> digits{new uint8_t[256 * data.size()]};
|
||||
for (size_t j = 0; j < data.size(); ++j)
|
||||
{
|
||||
unsigned char bytes33[33];
|
||||
memcpy(bytes33, data[j].scalar.bytes, 32);
|
||||
bytes33[32] = 0;
|
||||
const unsigned char *bytes = bytes33;
|
||||
#if 1
|
||||
static_assert(STRAUS_C == 4, "optimized version needs STRAUS_C == 4");
|
||||
unsigned int i;
|
||||
for (i = 0; i < 256; i += 8, bytes++)
|
||||
{
|
||||
digits[j*256+i] = bytes[0] & 0xf;
|
||||
digits[j*256+i+1] = (bytes[0] >> 1) & 0xf;
|
||||
digits[j*256+i+2] = (bytes[0] >> 2) & 0xf;
|
||||
digits[j*256+i+3] = (bytes[0] >> 3) & 0xf;
|
||||
digits[j*256+i+4] = ((bytes[0] >> 4) | (bytes[1]<<4)) & 0xf;
|
||||
digits[j*256+i+5] = ((bytes[0] >> 5) | (bytes[1]<<3)) & 0xf;
|
||||
digits[j*256+i+6] = ((bytes[0] >> 6) | (bytes[1]<<2)) & 0xf;
|
||||
digits[j*256+i+7] = ((bytes[0] >> 7) | (bytes[1]<<1)) & 0xf;
|
||||
}
|
||||
#elif 1
|
||||
for (size_t i = 0; i < 256; ++i)
|
||||
digits[j*256+i] = ((bytes[i>>3] | (bytes[(i>>3)+1]<<8)) >> (i&7)) & mask;
|
||||
#else
|
||||
rct::key shifted = data[j].scalar;
|
||||
for (size_t i = 0; i < 256; ++i)
|
||||
{
|
||||
digits[j*256+i] = shifted.bytes[0] & 0xf;
|
||||
shifted = div2(shifted, (256-i)>>3);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// MULTIEXP_PERF(PERF_TIMER_STOP(digits));
|
||||
|
||||
rct::key maxscalar = rct::zero();
|
||||
for (size_t i = 0; i < data.size(); ++i)
|
||||
if (maxscalar < data[i].scalar)
|
||||
maxscalar = data[i].scalar;
|
||||
size_t start_i = 0;
|
||||
while (start_i < 256 && !(maxscalar < pow2(start_i)))
|
||||
start_i += STRAUS_C;
|
||||
// MULTIEXP_PERF(PERF_TIMER_STOP(setup));
|
||||
|
||||
ge_p3 res_p3 = ge_p3_identity;
|
||||
|
||||
for (size_t start_offset = 0; start_offset < data.size(); start_offset += STEP)
|
||||
{
|
||||
const size_t num_points = std::min(data.size() - start_offset, STEP);
|
||||
|
||||
ge_p3 band_p3 = ge_p3_identity;
|
||||
size_t i = start_i;
|
||||
if (!(i < STRAUS_C))
|
||||
goto skipfirst;
|
||||
while (!(i < STRAUS_C))
|
||||
{
|
||||
ge_p2 p2;
|
||||
ge_p3_to_p2(&p2, &band_p3);
|
||||
for (size_t j = 0; j < STRAUS_C; ++j)
|
||||
{
|
||||
ge_p2_dbl(&p1, &p2);
|
||||
if (j == STRAUS_C - 1)
|
||||
ge_p1p1_to_p3(&band_p3, &p1);
|
||||
else
|
||||
ge_p1p1_to_p2(&p2, &p1);
|
||||
}
|
||||
skipfirst:
|
||||
i -= STRAUS_C;
|
||||
for (size_t j = start_offset; j < start_offset + num_points; ++j)
|
||||
{
|
||||
#ifdef TRACK_STRAUS_ZERO_IDENTITY
|
||||
if (skip[j])
|
||||
continue;
|
||||
#endif
|
||||
const uint8_t digit = digits[j*256+i];
|
||||
if (digit)
|
||||
{
|
||||
ge_add(&p1, &band_p3, &CACHE_OFFSET(local_cache, j, digit));
|
||||
ge_p1p1_to_p3(&band_p3, &p1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ge_p3_to_cached(&cached, &band_p3);
|
||||
ge_add(&p1, &res_p3, &cached);
|
||||
ge_p1p1_to_p3(&res_p3, &p1);
|
||||
}
|
||||
|
||||
rct::key res;
|
||||
ge_p3_tobytes(res.bytes, &res_p3);
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t get_pippenger_c(size_t N)
|
||||
{
|
||||
// uncached: 2:1, 4:2, 8:2, 16:3, 32:4, 64:4, 128:5, 256:6, 512:7, 1024:7, 2048:8, 4096:9
|
||||
// cached: 2:1, 4:2, 8:2, 16:3, 32:4, 64:4, 128:5, 256:6, 512:7, 1024:7, 2048:8, 4096:9
|
||||
if (N <= 2) return 1;
|
||||
if (N <= 8) return 2;
|
||||
if (N <= 16) return 3;
|
||||
if (N <= 64) return 4;
|
||||
if (N <= 128) return 5;
|
||||
if (N <= 256) return 6;
|
||||
if (N <= 1024) return 7;
|
||||
if (N <= 2048) return 8;
|
||||
return 9;
|
||||
}
|
||||
|
||||
struct pippenger_cached_data
|
||||
{
|
||||
size_t size;
|
||||
ge_cached *cached;
|
||||
pippenger_cached_data(): size(0), cached(NULL) {}
|
||||
~pippenger_cached_data() { aligned_free(cached); }
|
||||
};
|
||||
|
||||
std::shared_ptr<pippenger_cached_data> pippenger_init_cache(const std::vector<MultiexpData> &data, size_t N)
|
||||
{
|
||||
// MULTIEXP_PERF(PERF_TIMER_START_UNIT(pippenger_init_cache, 1000000));
|
||||
if (N == 0)
|
||||
N = data.size();
|
||||
CHECK_AND_ASSERT_THROW_MES(N <= data.size(), "Bad cache base data");
|
||||
ge_cached cached;
|
||||
std::shared_ptr<pippenger_cached_data> cache(new pippenger_cached_data());
|
||||
|
||||
cache->size = N;
|
||||
cache->cached = (ge_cached*)aligned_realloc(cache->cached, N * sizeof(ge_cached), 4096);
|
||||
CHECK_AND_ASSERT_THROW_MES(cache->cached, "Out of memory");
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
ge_p3_to_cached(&cache->cached[i], &data[i].point);
|
||||
|
||||
// MULTIEXP_PERF(PERF_TIMER_STOP(pippenger_init_cache));
|
||||
return cache;
|
||||
}
|
||||
|
||||
size_t pippenger_get_cache_size(const std::shared_ptr<pippenger_cached_data> &cache)
|
||||
{
|
||||
return cache->size * sizeof(*cache->cached);
|
||||
}
|
||||
|
||||
rct::key pippenger(const std::vector<MultiexpData> &data, const std::shared_ptr<pippenger_cached_data> &cache, size_t c)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(cache == NULL || cache->size >= data.size(), "Cache is too small");
|
||||
if (c == 0)
|
||||
c = get_pippenger_c(data.size());
|
||||
CHECK_AND_ASSERT_THROW_MES(c <= 9, "c is too large");
|
||||
|
||||
ge_p3 result = ge_p3_identity;
|
||||
std::unique_ptr<ge_p3[]> buckets{new ge_p3[1<<c]};
|
||||
std::shared_ptr<pippenger_cached_data> local_cache = cache == NULL ? pippenger_init_cache(data) : cache;
|
||||
|
||||
rct::key maxscalar = rct::zero();
|
||||
for (size_t i = 0; i < data.size(); ++i)
|
||||
{
|
||||
if (maxscalar < data[i].scalar)
|
||||
maxscalar = data[i].scalar;
|
||||
}
|
||||
size_t groups = 0;
|
||||
while (groups < 256 && !(maxscalar < pow2(groups)))
|
||||
++groups;
|
||||
groups = (groups + c - 1) / c;
|
||||
|
||||
for (size_t k = groups; k-- > 0; )
|
||||
{
|
||||
if (!ge_p3_is_point_at_infinity(&result))
|
||||
{
|
||||
ge_p2 p2;
|
||||
ge_p3_to_p2(&p2, &result);
|
||||
for (size_t i = 0; i < c; ++i)
|
||||
{
|
||||
ge_p1p1 p1;
|
||||
ge_p2_dbl(&p1, &p2);
|
||||
if (i == c - 1)
|
||||
ge_p1p1_to_p3(&result, &p1);
|
||||
else
|
||||
ge_p1p1_to_p2(&p2, &p1);
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < (1u<<c); ++i)
|
||||
buckets[i] = ge_p3_identity;
|
||||
|
||||
// partition scalars into buckets
|
||||
for (size_t i = 0; i < data.size(); ++i)
|
||||
{
|
||||
unsigned int bucket = 0;
|
||||
for (size_t j = 0; j < c; ++j)
|
||||
if (test(data[i].scalar, k*c+j))
|
||||
bucket |= 1<<j;
|
||||
if (bucket == 0)
|
||||
continue;
|
||||
CHECK_AND_ASSERT_THROW_MES(bucket < (1u<<c), "bucket overflow");
|
||||
if (!ge_p3_is_point_at_infinity(&buckets[bucket]))
|
||||
{
|
||||
add(buckets[bucket], local_cache->cached[i]);
|
||||
}
|
||||
else
|
||||
buckets[bucket] = data[i].point;
|
||||
}
|
||||
|
||||
// sum the buckets
|
||||
ge_p3 pail = ge_p3_identity;
|
||||
for (size_t i = (1<<c)-1; i > 0; --i)
|
||||
{
|
||||
if (!ge_p3_is_point_at_infinity(&buckets[i]))
|
||||
add(pail, buckets[i]);
|
||||
if (!ge_p3_is_point_at_infinity(&pail))
|
||||
add(result, pail);
|
||||
}
|
||||
}
|
||||
|
||||
rct::key res;
|
||||
ge_p3_tobytes(res.bytes, &result);
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2017, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// 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.
|
||||
//
|
||||
// Adapted from Python code by Sarang Noether
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef MULTIEXP_H
|
||||
#define MULTIEXP_H
|
||||
|
||||
#include <vector>
|
||||
#include "crypto/crypto.h"
|
||||
#include "rctTypes.h"
|
||||
#include "misc_log_ex.h"
|
||||
|
||||
namespace rct
|
||||
{
|
||||
|
||||
struct MultiexpData {
|
||||
rct::key scalar;
|
||||
ge_p3 point;
|
||||
|
||||
MultiexpData() {}
|
||||
MultiexpData(const rct::key &s, const ge_p3 &p): scalar(s), point(p) {}
|
||||
MultiexpData(const rct::key &s, const rct::key &p): scalar(s)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&point, p.bytes) == 0, "ge_frombytes_vartime failed");
|
||||
}
|
||||
};
|
||||
|
||||
struct straus_cached_data;
|
||||
struct pippenger_cached_data;
|
||||
|
||||
rct::key bos_coster_heap_conv(std::vector<MultiexpData> data);
|
||||
rct::key bos_coster_heap_conv_robust(std::vector<MultiexpData> data);
|
||||
std::shared_ptr<straus_cached_data> straus_init_cache(const std::vector<MultiexpData> &data, size_t N =0);
|
||||
size_t straus_get_cache_size(const std::shared_ptr<straus_cached_data> &cache);
|
||||
rct::key straus(const std::vector<MultiexpData> &data, const std::shared_ptr<straus_cached_data> &cache = NULL, size_t STEP = 0);
|
||||
std::shared_ptr<pippenger_cached_data> pippenger_init_cache(const std::vector<MultiexpData> &data, size_t N =0);
|
||||
size_t pippenger_get_cache_size(const std::shared_ptr<pippenger_cached_data> &cache);
|
||||
size_t get_pippenger_c(size_t N);
|
||||
rct::key pippenger(const std::vector<MultiexpData> &data, const std::shared_ptr<pippenger_cached_data> &cache = NULL, size_t c = 0);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in new issue