parent
40db201ddf
commit
050f451b7a
@ -0,0 +1,195 @@
|
||||
// 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 <fstream>
|
||||
|
||||
#include "include_base_utils.h"
|
||||
#include "account.h"
|
||||
#include "warnings.h"
|
||||
#include "crypto/crypto.h"
|
||||
extern "C"
|
||||
{
|
||||
#include "crypto/keccak.h"
|
||||
}
|
||||
#include "cryptonote_basic_impl.h"
|
||||
#include "cryptonote_format_utils.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "account"
|
||||
|
||||
using namespace std;
|
||||
|
||||
DISABLE_VS_WARNINGS(4244 4345)
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
hw::device& account_keys::get_device() const {
|
||||
return *m_device;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
void account_keys::set_device( hw::device &hwdev) {
|
||||
m_device = &hwdev;
|
||||
MCDEBUG("device", "account_keys::set_device device type: "<<typeid(hwdev).name());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
account_base::account_base()
|
||||
{
|
||||
set_null();
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
void account_base::set_null()
|
||||
{
|
||||
m_keys = account_keys();
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
void account_base::forget_spend_key()
|
||||
{
|
||||
m_keys.m_spend_secret_key = crypto::secret_key();
|
||||
m_keys.m_multisig_keys.clear();
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
crypto::secret_key account_base::generate(const crypto::secret_key& recovery_key, bool recover, bool two_random, bool from_legacy16B_lw_seed)
|
||||
{
|
||||
crypto::secret_key first = generate_keys(m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key, recovery_key, recover);
|
||||
|
||||
// rng for generating second set of keys is hash of first rng. means only one set of electrum-style words needed for recovery
|
||||
crypto::secret_key second;
|
||||
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));
|
||||
|
||||
generate_keys(m_keys.m_account_address.m_view_public_key, m_keys.m_view_secret_key, second, two_random ? false : true);
|
||||
|
||||
struct tm timestamp = {0};
|
||||
timestamp.tm_year = 2014 - 1900; // year 2014
|
||||
timestamp.tm_mon = 6 - 1; // month june
|
||||
timestamp.tm_mday = 8; // 8th of june
|
||||
timestamp.tm_hour = 0;
|
||||
timestamp.tm_min = 0;
|
||||
timestamp.tm_sec = 0;
|
||||
|
||||
if (recover)
|
||||
{
|
||||
m_creation_timestamp = mktime(×tamp);
|
||||
if (m_creation_timestamp == (uint64_t)-1) // failure
|
||||
m_creation_timestamp = 0; // lowest value
|
||||
}
|
||||
else
|
||||
{
|
||||
m_creation_timestamp = time(NULL);
|
||||
}
|
||||
return first;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
void account_base::create_from_keys(const cryptonote::account_public_address& address, const crypto::secret_key& spendkey, const crypto::secret_key& viewkey)
|
||||
{
|
||||
m_keys.m_account_address = address;
|
||||
m_keys.m_spend_secret_key = spendkey;
|
||||
m_keys.m_view_secret_key = viewkey;
|
||||
|
||||
struct tm timestamp = {0};
|
||||
timestamp.tm_year = 2014 - 1900; // year 2014
|
||||
timestamp.tm_mon = 4 - 1; // month april
|
||||
timestamp.tm_mday = 15; // 15th of april
|
||||
timestamp.tm_hour = 0;
|
||||
timestamp.tm_min = 0;
|
||||
timestamp.tm_sec = 0;
|
||||
|
||||
m_creation_timestamp = mktime(×tamp);
|
||||
if (m_creation_timestamp == (uint64_t)-1) // failure
|
||||
m_creation_timestamp = 0; // lowest value
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
void account_base::create_from_device(const std::string &device_name)
|
||||
{
|
||||
|
||||
hw::device &hwdev = hw::get_device(device_name);
|
||||
m_keys.set_device(hwdev);
|
||||
hwdev.set_name(device_name);
|
||||
MCDEBUG("ledger", "device type: "<<typeid(hwdev).name());
|
||||
hwdev.init();
|
||||
hwdev.connect();
|
||||
hwdev.get_public_address(m_keys.m_account_address);
|
||||
hwdev.get_secret_keys(m_keys.m_view_secret_key, m_keys.m_spend_secret_key);
|
||||
struct tm timestamp = {0};
|
||||
timestamp.tm_year = 2014 - 1900; // year 2014
|
||||
timestamp.tm_mon = 4 - 1; // month april
|
||||
timestamp.tm_mday = 15; // 15th of april
|
||||
timestamp.tm_hour = 0;
|
||||
timestamp.tm_min = 0;
|
||||
timestamp.tm_sec = 0;
|
||||
|
||||
m_creation_timestamp = mktime(×tamp);
|
||||
if (m_creation_timestamp == (uint64_t)-1) // failure
|
||||
m_creation_timestamp = 0; // lowest value
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
void account_base::create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey)
|
||||
{
|
||||
crypto::secret_key fake;
|
||||
memset(&unwrap(fake), 0, sizeof(fake));
|
||||
create_from_keys(address, fake, viewkey);
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
bool account_base::make_multisig(const crypto::secret_key &view_secret_key, const crypto::secret_key &spend_secret_key, const crypto::public_key &spend_public_key, const std::vector<crypto::secret_key> &multisig_keys)
|
||||
{
|
||||
m_keys.m_account_address.m_spend_public_key = spend_public_key;
|
||||
m_keys.m_view_secret_key = view_secret_key;
|
||||
m_keys.m_spend_secret_key = spend_secret_key;
|
||||
m_keys.m_multisig_keys = multisig_keys;
|
||||
return crypto::secret_key_to_public_key(view_secret_key, m_keys.m_account_address.m_view_public_key);
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
void account_base::finalize_multisig(const crypto::public_key &spend_public_key)
|
||||
{
|
||||
m_keys.m_account_address.m_spend_public_key = spend_public_key;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
const account_keys& account_base::get_keys() const
|
||||
{
|
||||
return m_keys;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
std::string account_base::get_public_address_str(network_type nettype) const
|
||||
{
|
||||
//TODO: change this code into base 58
|
||||
return get_account_address_as_str(nettype, false, m_keys.m_account_address);
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
std::string account_base::get_public_integrated_address_str(const crypto::hash8 &payment_id, network_type nettype) const
|
||||
{
|
||||
//TODO: change this code into base 58
|
||||
return get_account_integrated_address_as_str(nettype, m_keys.m_account_address, payment_id);
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
// 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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cryptonote_basic.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "serialization/keyvalue_serialization.h"
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
struct account_keys
|
||||
{
|
||||
account_public_address m_account_address;
|
||||
crypto::secret_key m_spend_secret_key;
|
||||
crypto::secret_key m_view_secret_key;
|
||||
std::vector<crypto::secret_key> m_multisig_keys;
|
||||
hw::device *m_device = &hw::get_device("default");
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(m_account_address)
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_spend_secret_key)
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_secret_key)
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_multisig_keys)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
|
||||
account_keys& operator=(account_keys const&) = default;
|
||||
|
||||
hw::device& get_device() const ;
|
||||
void set_device( hw::device &hwdev) ;
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
class account_base
|
||||
{
|
||||
public:
|
||||
account_base();
|
||||
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) ;
|
||||
void create_from_keys(const cryptonote::account_public_address& address, const crypto::secret_key& spendkey, const crypto::secret_key& viewkey);
|
||||
void create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey);
|
||||
bool make_multisig(const crypto::secret_key &view_secret_key, const crypto::secret_key &spend_secret_key, const crypto::public_key &spend_public_key, const std::vector<crypto::secret_key> &multisig_keys);
|
||||
void finalize_multisig(const crypto::public_key &spend_public_key);
|
||||
const account_keys& get_keys() const;
|
||||
std::string get_public_address_str(network_type nettype) const;
|
||||
std::string get_public_integrated_address_str(const crypto::hash8 &payment_id, network_type nettype) const;
|
||||
|
||||
hw::device& get_device() const {return m_keys.get_device();}
|
||||
void set_device( hw::device &hwdev) {m_keys.set_device(hwdev);}
|
||||
|
||||
uint64_t get_createtime() const { return m_creation_timestamp; }
|
||||
void set_createtime(uint64_t val) { m_creation_timestamp = val; }
|
||||
|
||||
bool load(const std::string& file_path);
|
||||
bool store(const std::string& file_path);
|
||||
|
||||
void forget_spend_key();
|
||||
const std::vector<crypto::secret_key> &get_multisig_keys() const { return m_keys.m_multisig_keys; }
|
||||
|
||||
template <class t_archive>
|
||||
inline void serialize(t_archive &a, const unsigned int /*ver*/)
|
||||
{
|
||||
a & m_keys;
|
||||
a & m_creation_timestamp;
|
||||
}
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(m_keys)
|
||||
KV_SERIALIZE(m_creation_timestamp)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
|
||||
private:
|
||||
void set_null();
|
||||
account_keys m_keys;
|
||||
uint64_t m_creation_timestamp;
|
||||
};
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,102 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "serialization/keyvalue_serialization.h"
|
||||
#include <boost/serialization/serialization.hpp>
|
||||
#include <boost/serialization/version.hpp>
|
||||
#include <ostream>
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
struct subaddress_index
|
||||
{
|
||||
uint32_t major;
|
||||
uint32_t minor;
|
||||
bool operator==(const subaddress_index& rhs) const { return !memcmp(this, &rhs, sizeof(subaddress_index)); }
|
||||
bool operator!=(const subaddress_index& rhs) const { return !(*this == rhs); }
|
||||
bool is_zero() const { return major == 0 && minor == 0; }
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(major)
|
||||
FIELD(minor)
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(major)
|
||||
KV_SERIALIZE(minor)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
}
|
||||
|
||||
namespace cryptonote {
|
||||
inline std::ostream& operator<<(std::ostream& out, const cryptonote::subaddress_index& subaddr_index)
|
||||
{
|
||||
return out << subaddr_index.major << '/' << subaddr_index.minor;
|
||||
}
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<cryptonote::subaddress_index>
|
||||
{
|
||||
size_t operator()(const cryptonote::subaddress_index& index ) const
|
||||
{
|
||||
size_t res;
|
||||
if (sizeof(size_t) == 8)
|
||||
{
|
||||
res = ((uint64_t)index.major << 32) | index.minor;
|
||||
}
|
||||
else
|
||||
{
|
||||
// https://stackoverflow.com/a/17017281
|
||||
res = 17;
|
||||
res = res * 31 + hash<uint32_t>()(index.major);
|
||||
res = res * 31 + hash<uint32_t>()(index.minor);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
BOOST_CLASS_VERSION(cryptonote::subaddress_index, 0)
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::subaddress_index &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.major;
|
||||
a & x.minor;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,194 @@
|
||||
// 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
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#define TX_EXTRA_PADDING_MAX_COUNT 255
|
||||
#define TX_EXTRA_NONCE_MAX_COUNT 255
|
||||
|
||||
#define TX_EXTRA_TAG_PADDING 0x00
|
||||
#define TX_EXTRA_TAG_PUBKEY 0x01
|
||||
#define TX_EXTRA_NONCE 0x02
|
||||
#define TX_EXTRA_MERGE_MINING_TAG 0x03
|
||||
#define TX_EXTRA_TAG_ADDITIONAL_PUBKEYS 0x04
|
||||
#define TX_EXTRA_MYSTERIOUS_MINERGATE_TAG 0xDE
|
||||
|
||||
#define TX_EXTRA_NONCE_PAYMENT_ID 0x00
|
||||
#define TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID 0x01
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
struct tx_extra_padding
|
||||
{
|
||||
size_t size;
|
||||
|
||||
// load
|
||||
template <template <bool> class Archive>
|
||||
bool do_serialize(Archive<false>& ar)
|
||||
{
|
||||
// size - 1 - because of variant tag
|
||||
for (size = 1; size <= TX_EXTRA_PADDING_MAX_COUNT; ++size)
|
||||
{
|
||||
std::ios_base::iostate state = ar.stream().rdstate();
|
||||
bool eof = EOF == ar.stream().peek();
|
||||
ar.stream().clear(state);
|
||||
|
||||
if (eof)
|
||||
break;
|
||||
|
||||
uint8_t zero;
|
||||
if (!::do_serialize(ar, zero))
|
||||
return false;
|
||||
|
||||
if (0 != zero)
|
||||
return false;
|
||||
}
|
||||
|
||||
return size <= TX_EXTRA_PADDING_MAX_COUNT;
|
||||
}
|
||||
|
||||
// store
|
||||
template <template <bool> class Archive>
|
||||
bool do_serialize(Archive<true>& ar)
|
||||
{
|
||||
if(TX_EXTRA_PADDING_MAX_COUNT < size)
|
||||
return false;
|
||||
|
||||
// i = 1 - because of variant tag
|
||||
for (size_t i = 1; i < size; ++i)
|
||||
{
|
||||
uint8_t zero = 0;
|
||||
if (!::do_serialize(ar, zero))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct tx_extra_pub_key
|
||||
{
|
||||
crypto::public_key pub_key;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(pub_key)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_extra_nonce
|
||||
{
|
||||
std::string nonce;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(nonce)
|
||||
if(TX_EXTRA_NONCE_MAX_COUNT < nonce.size()) return false;
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_extra_merge_mining_tag
|
||||
{
|
||||
struct serialize_helper
|
||||
{
|
||||
tx_extra_merge_mining_tag& mm_tag;
|
||||
|
||||
serialize_helper(tx_extra_merge_mining_tag& mm_tag_) : mm_tag(mm_tag_)
|
||||
{
|
||||
}
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
VARINT_FIELD_N("depth", mm_tag.depth)
|
||||
FIELD_N("merkle_root", mm_tag.merkle_root)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
size_t depth;
|
||||
crypto::hash merkle_root;
|
||||
|
||||
// load
|
||||
template <template <bool> class Archive>
|
||||
bool do_serialize(Archive<false>& ar)
|
||||
{
|
||||
std::string field;
|
||||
if(!::do_serialize(ar, field))
|
||||
return false;
|
||||
|
||||
std::istringstream iss(field);
|
||||
binary_archive<false> iar(iss);
|
||||
serialize_helper helper(*this);
|
||||
return ::serialization::serialize(iar, helper);
|
||||
}
|
||||
|
||||
// store
|
||||
template <template <bool> class Archive>
|
||||
bool do_serialize(Archive<true>& ar)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
binary_archive<true> oar(oss);
|
||||
serialize_helper helper(*this);
|
||||
if(!::do_serialize(oar, helper))
|
||||
return false;
|
||||
|
||||
std::string field = oss.str();
|
||||
return ::serialization::serialize(ar, field);
|
||||
}
|
||||
};
|
||||
|
||||
// per-output additional tx pubkey for multi-destination transfers involving at least one subaddress
|
||||
struct tx_extra_additional_pub_keys
|
||||
{
|
||||
std::vector<crypto::public_key> data;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(data)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_extra_mysterious_minergate
|
||||
{
|
||||
std::string data;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(data)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
// tx_extra_field format, except tx_extra_padding and tx_extra_pub_key:
|
||||
// varint tag;
|
||||
// varint size;
|
||||
// varint data[];
|
||||
typedef boost::variant<tx_extra_padding, tx_extra_pub_key, tx_extra_nonce, tx_extra_merge_mining_tag, tx_extra_additional_pub_keys, tx_extra_mysterious_minergate> tx_extra_field;
|
||||
}
|
||||
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_padding, TX_EXTRA_TAG_PADDING);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_pub_key, TX_EXTRA_TAG_PUBKEY);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_nonce, TX_EXTRA_NONCE);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_merge_mining_tag, TX_EXTRA_MERGE_MINING_TAG);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_additional_pub_keys, TX_EXTRA_TAG_ADDITIONAL_PUBKEYS);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_mysterious_minergate, TX_EXTRA_MYSTERIOUS_MINERGATE_TAG);
|
@ -0,0 +1,70 @@
|
||||
// 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 "device.hpp"
|
||||
#include "device_default.hpp"
|
||||
#ifdef HAVE_PCSC
|
||||
#include "device_ledger.hpp"
|
||||
#endif
|
||||
#include "misc_log_ex.h"
|
||||
|
||||
|
||||
namespace hw {
|
||||
|
||||
/* ======================================================================= */
|
||||
/* SETUP */
|
||||
/* ======================================================================= */
|
||||
device& get_device(const std::string device_descriptor) {
|
||||
|
||||
struct s_devices {
|
||||
std::map<std::string, std::unique_ptr<device>> registry;
|
||||
s_devices() : registry() {
|
||||
hw::core::register_all(registry);
|
||||
#ifdef HAVE_PCSC
|
||||
hw::ledger::register_all(registry);
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
static const s_devices devices;
|
||||
|
||||
auto device = devices.registry.find(device_descriptor);
|
||||
if (device == devices.registry.end()) {
|
||||
MERROR("device not found in registry: '" << device_descriptor << "'\n" <<
|
||||
"known devices:");
|
||||
|
||||
for( const auto& sm_pair : devices.registry ) {
|
||||
MERROR(" - " << sm_pair.first);
|
||||
}
|
||||
throw std::runtime_error("device not found: "+ device_descriptor);
|
||||
}
|
||||
return *device->second;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,207 @@
|
||||
// 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.
|
||||
//
|
||||
|
||||
|
||||
/* Note about debug:
|
||||
* To debug Device you can def the following :
|
||||
* #define DEBUG_HWDEVICE
|
||||
* Activate debug mechanism:
|
||||
* - Add more trace
|
||||
* - All computation done by device are checked by default device.
|
||||
* Required IODUMMYCRYPT_HWDEVICE or IONOCRYPT_HWDEVICE for fully working
|
||||
* #define IODUMMYCRYPT_HWDEVICE 1
|
||||
* - It assumes sensitive data encryption is is off on device side. a XOR with 0x55. This allow Ledger Class to make check on clear value
|
||||
* #define IONOCRYPT_HWDEVICE 1
|
||||
* - It assumes sensitive data encryption is off on device side.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/chacha.h"
|
||||
#include "ringct/rctTypes.h"
|
||||
|
||||
#ifndef USE_DEVICE_LEDGER
|
||||
#define USE_DEVICE_LEDGER 1
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_PCSC)
|
||||
#undef USE_DEVICE_LEDGER
|
||||
#define USE_DEVICE_LEDGER 0
|
||||
#endif
|
||||
|
||||
#if USE_DEVICE_LEDGER
|
||||
#define WITH_DEVICE_LEDGER
|
||||
#endif
|
||||
|
||||
// forward declaration needed because this header is included by headers in libcryptonote_basic which depends on libdevice
|
||||
namespace cryptonote
|
||||
{
|
||||
struct account_public_address;
|
||||
struct account_keys;
|
||||
struct subaddress_index;
|
||||
}
|
||||
|
||||
namespace hw {
|
||||
namespace {
|
||||
//device funcion not supported
|
||||
#define dfns() \
|
||||
throw std::runtime_error(std::string("device function not supported: ")+ std::string(__FUNCTION__) + \
|
||||
std::string(" (device.hpp line ")+std::to_string(__LINE__)+std::string(").")); \
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
class device {
|
||||
protected:
|
||||
std::string name;
|
||||
|
||||
public:
|
||||
|
||||
device() {}
|
||||
device(const device &hwdev) {}
|
||||
virtual ~device() {}
|
||||
|
||||
explicit virtual operator bool() const = 0;
|
||||
enum device_mode {
|
||||
NONE,
|
||||
TRANSACTION_CREATE_REAL,
|
||||
TRANSACTION_CREATE_FAKE,
|
||||
TRANSACTION_PARSE
|
||||
};
|
||||
|
||||
/* ======================================================================= */
|
||||
/* SETUP/TEARDOWN */
|
||||
/* ======================================================================= */
|
||||
virtual bool set_name(const std::string &name) = 0;
|
||||
virtual const std::string get_name() const = 0;
|
||||
|
||||
virtual bool init(void) = 0;
|
||||
virtual bool release() = 0;
|
||||
|
||||
virtual bool connect(void) = 0;
|
||||
virtual bool disconnect(void) = 0;
|
||||
|
||||
virtual bool set_mode(device_mode mode) = 0;
|
||||
|
||||
|
||||
/* ======================================================================= */
|
||||
/* LOCKER */
|
||||
/* ======================================================================= */
|
||||
virtual void lock(void) = 0;
|
||||
virtual void unlock(void) = 0;
|
||||
virtual bool try_lock(void) = 0;
|
||||
|
||||
|
||||
/* ======================================================================= */
|
||||
/* WALLET & ADDRESS */
|
||||
/* ======================================================================= */
|
||||
virtual bool get_public_address(cryptonote::account_public_address &pubkey) = 0;
|
||||
virtual bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) = 0;
|
||||
virtual bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) = 0;
|
||||
|
||||
/* ======================================================================= */
|
||||
/* SUB ADDRESS */
|
||||
/* ======================================================================= */
|
||||
virtual bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_pub) = 0;
|
||||
virtual crypto::public_key get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index) = 0;
|
||||
virtual std::vector<crypto::public_key> get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end) = 0;
|
||||
virtual cryptonote::account_public_address get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) = 0;
|
||||
virtual crypto::secret_key get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index) = 0;
|
||||
|
||||
/* ======================================================================= */
|
||||
/* DERIVATION & KEY */
|
||||
/* ======================================================================= */
|
||||
virtual bool verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) = 0;
|
||||
virtual bool scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) = 0;
|
||||
virtual bool scalarmultBase(rct::key &aG, const rct::key &a) = 0;
|
||||
virtual bool sc_secret_add( crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) = 0;
|
||||
virtual crypto::secret_key generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false) = 0;
|
||||
virtual bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) = 0;
|
||||
virtual bool conceal_derivation(crypto::key_derivation &derivation, const crypto::public_key &tx_pub_key, const std::vector<crypto::public_key> &additional_tx_pub_keys, const crypto::key_derivation &main_derivation, const std::vector<crypto::key_derivation> &additional_derivations) = 0;
|
||||
virtual bool derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) = 0;
|
||||
virtual bool derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) = 0;
|
||||
virtual bool derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub) = 0;
|
||||
virtual bool secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) = 0;
|
||||
virtual bool generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image) = 0;
|
||||
|
||||
// alternative prototypes available in libringct
|
||||
rct::key scalarmultKey(const rct::key &P, const rct::key &a)
|
||||
{
|
||||
rct::key aP;
|
||||
scalarmultKey(aP, P, a);
|
||||
return aP;
|
||||
}
|
||||
|
||||
rct::key scalarmultBase(const rct::key &a)
|
||||
{
|
||||
rct::key aG;
|
||||
scalarmultBase(aG, a);
|
||||
return aG;
|
||||
}
|
||||
|
||||
/* ======================================================================= */
|
||||
/* TRANSACTION */
|
||||
/* ======================================================================= */
|
||||
|
||||
virtual bool open_tx(crypto::secret_key &tx_key) = 0;
|
||||
|
||||
virtual bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) = 0;
|
||||
bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key)
|
||||
{
|
||||
// Encryption and decryption are the same operation (xor with a key)
|
||||
return encrypt_payment_id(payment_id, public_key, secret_key);
|
||||
}
|
||||
|
||||
virtual bool ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec) = 0;
|
||||
virtual bool ecdhDecode(rct::ecdhTuple & masked, const rct::key & sharedSec) = 0;
|
||||
|
||||
virtual bool add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, const bool is_subaddress, const size_t real_output_index,
|
||||
const rct::key &amount_key, const crypto::public_key &out_eph_public_key) = 0;
|
||||
|
||||
|
||||
virtual bool mlsag_prehash(const std::string &blob, size_t inputs_size, size_t outputs_size, const rct::keyV &hashes, const rct::ctkeyV &outPk, rct::key &prehash) = 0;
|
||||
virtual bool mlsag_prepare(const rct::key &H, const rct::key &xx, rct::key &a, rct::key &aG, rct::key &aHP, rct::key &rvII) = 0;
|
||||
virtual bool mlsag_prepare(rct::key &a, rct::key &aG) = 0;
|
||||
virtual bool mlsag_hash(const rct::keyV &long_message, rct::key &c) = 0;
|
||||
virtual bool mlsag_sign(const rct::key &c, const rct::keyV &xx, const rct::keyV &alpha, const size_t rows, const size_t dsRows, rct::keyV &ss) = 0;
|
||||
|
||||
virtual bool close_tx(void) = 0;
|
||||
} ;
|
||||
|
||||
struct reset_mode {
|
||||
device& hwref;
|
||||
reset_mode(hw::device& dev) : hwref(dev) { }
|
||||
~reset_mode() { hwref.set_mode(hw::device::NONE);}
|
||||
};
|
||||
|
||||
device& get_device(const std::string device_descriptor) ;
|
||||
}
|
||||
|
@ -0,0 +1,367 @@
|
||||
// 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 "device_default.hpp"
|
||||
#include "common/int-util.h"
|
||||
#include "cryptonote_basic/account.h"
|
||||
#include "cryptonote_basic/subaddress_index.h"
|
||||
#include "ringct/rctOps.h"
|
||||
|
||||
#define ENCRYPTED_PAYMENT_ID_TAIL 0x8d
|
||||
#define CHACHA8_KEY_TAIL 0x8c
|
||||
|
||||
namespace hw {
|
||||
|
||||
namespace core {
|
||||
|
||||
device_default::device_default() { }
|
||||
|
||||
device_default::~device_default() { }
|
||||
|
||||
/* ===================================================================== */
|
||||
/* === Misc ==== */
|
||||
/* ===================================================================== */
|
||||
static inline unsigned char *operator &(crypto::ec_scalar &scalar) {
|
||||
return &reinterpret_cast<unsigned char &>(scalar);
|
||||
}
|
||||
static inline const unsigned char *operator &(const crypto::ec_scalar &scalar) {
|
||||
return &reinterpret_cast<const unsigned char &>(scalar);
|
||||
}
|
||||
|
||||
/* ======================================================================= */
|
||||
/* SETUP/TEARDOWN */
|
||||
/* ======================================================================= */
|
||||
bool device_default::set_name(const std::string &name) {
|
||||
this->name = name;
|
||||
return true;
|
||||
}
|
||||
const std::string device_default::get_name() const {
|
||||
return this->name;
|
||||
}
|
||||
|
||||
bool device_default::init(void) {
|
||||
dfns();
|
||||
}
|
||||
bool device_default::release() {
|
||||
dfns();
|
||||
}
|
||||
|
||||
bool device_default::connect(void) {
|
||||
dfns();
|
||||
}
|
||||
bool device_default::disconnect() {
|
||||
dfns();
|
||||
}
|
||||
|
||||
bool device_default::set_mode(device_mode mode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ======================================================================= */
|
||||
/* LOCKER */
|
||||
/* ======================================================================= */
|
||||
|
||||
void device_default::lock() { }
|
||||
|
||||
bool device_default::try_lock() { return true; }
|
||||
|
||||
void device_default::unlock() { }
|
||||
|
||||
/* ======================================================================= */
|
||||
/* WALLET & ADDRESS */
|
||||
/* ======================================================================= */
|
||||
|
||||
bool device_default::generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) {
|
||||
const crypto::secret_key &view_key = keys.m_view_secret_key;
|
||||
const crypto::secret_key &spend_key = keys.m_spend_secret_key;
|
||||
tools::scrubbed_arr<char, sizeof(view_key) + sizeof(spend_key) + 1> data;
|
||||
memcpy(data.data(), &view_key, sizeof(view_key));
|
||||
memcpy(data.data() + sizeof(view_key), &spend_key, sizeof(spend_key));
|
||||
data[sizeof(data) - 1] = CHACHA8_KEY_TAIL;
|
||||
crypto::generate_chacha_key(data.data(), sizeof(data), key);
|
||||
return true;
|
||||
}
|
||||
bool device_default::get_public_address(cryptonote::account_public_address &pubkey) {
|
||||
dfns();
|
||||
}
|
||||
bool device_default::get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) {
|
||||
dfns();
|
||||
}
|
||||
/* ======================================================================= */
|
||||
/* SUB ADDRESS */
|
||||
/* ======================================================================= */
|
||||
|
||||
bool device_default::derive_subaddress_public_key(const crypto::public_key &out_key, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_key) {
|
||||
return crypto::derive_subaddress_public_key(out_key, derivation, output_index,derived_key);
|
||||
}
|
||||
|
||||
crypto::public_key device_default::get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) {
|
||||
if (index.is_zero())
|
||||
return keys.m_account_address.m_spend_public_key;
|
||||
|
||||
// m = Hs(a || index_major || index_minor)
|
||||
crypto::secret_key m = get_subaddress_secret_key(keys.m_view_secret_key, index);
|
||||
|
||||
// M = m*G
|
||||
crypto::public_key M;
|
||||
crypto::secret_key_to_public_key(m, M);
|
||||
|
||||
// D = B + M
|
||||
crypto::public_key D = rct::rct2pk(rct::addKeys(rct::pk2rct(keys.m_account_address.m_spend_public_key), rct::pk2rct(M)));
|
||||
return D;
|
||||
}
|
||||
|
||||
std::vector<crypto::public_key> device_default::get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end) {
|
||||
CHECK_AND_ASSERT_THROW_MES(begin <= end, "begin > end");
|
||||
|
||||
std::vector<crypto::public_key> pkeys;
|
||||
pkeys.reserve(end - begin);
|
||||
cryptonote::subaddress_index index = {account, begin};
|
||||
|
||||
ge_p3 p3;
|
||||
ge_cached cached;
|
||||
CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&p3, (const unsigned char*)keys.m_account_address.m_spend_public_key.data) == 0,
|
||||
"ge_frombytes_vartime failed to convert spend public key");
|
||||
ge_p3_to_cached(&cached, &p3);
|
||||
|
||||
for (uint32_t idx = begin; idx < end; ++idx)
|
||||
{
|
||||
index.minor = idx;
|
||||
if (index.is_zero())
|
||||
{
|
||||
pkeys.push_back(keys.m_account_address.m_spend_public_key);
|
||||
continue;
|
||||
}
|
||||
crypto::secret_key m = get_subaddress_secret_key(keys.m_view_secret_key, index);
|
||||
|
||||
// M = m*G
|
||||
ge_scalarmult_base(&p3, (const unsigned char*)m.data);
|
||||
|
||||
// D = B + M
|
||||
crypto::public_key D;
|
||||
ge_p1p1 p1p1;
|
||||
ge_add(&p1p1, &p3, &cached);
|
||||
ge_p1p1_to_p3(&p3, &p1p1);
|
||||
ge_p3_tobytes((unsigned char*)D.data, &p3);
|
||||
|
||||
pkeys.push_back(D);
|
||||
}
|
||||
return pkeys;
|
||||
}
|
||||
|
||||
cryptonote::account_public_address device_default::get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) {
|
||||
if (index.is_zero())
|
||||
return keys.m_account_address;
|
||||
|
||||
crypto::public_key D = get_subaddress_spend_public_key(keys, index);
|
||||
|
||||
// C = a*D
|
||||
crypto::public_key C = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(D), rct::sk2rct(keys.m_view_secret_key)));
|
||||
|
||||
// result: (C, D)
|
||||
cryptonote::account_public_address address;
|
||||
address.m_view_public_key = C;
|
||||
address.m_spend_public_key = D;
|
||||
return address;
|
||||
}
|
||||
|
||||
crypto::secret_key device_default::get_subaddress_secret_key(const crypto::secret_key &a, const cryptonote::subaddress_index &index) {
|
||||
const char prefix[] = "SubAddr";
|
||||
char data[sizeof(prefix) + sizeof(crypto::secret_key) + 2 * sizeof(uint32_t)];
|
||||
memcpy(data, prefix, sizeof(prefix));
|
||||
memcpy(data + sizeof(prefix), &a, sizeof(crypto::secret_key));
|
||||
uint32_t idx = SWAP32LE(index.major);
|
||||
memcpy(data + sizeof(prefix) + sizeof(crypto::secret_key), &idx, sizeof(uint32_t));
|
||||
idx = SWAP32LE(index.minor);
|
||||
memcpy(data + sizeof(prefix) + sizeof(crypto::secret_key) + sizeof(uint32_t), &idx, sizeof(uint32_t));
|
||||
crypto::secret_key m;
|
||||
crypto::hash_to_scalar(data, sizeof(data), m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/* ======================================================================= */
|
||||
/* DERIVATION & KEY */
|
||||
/* ======================================================================= */
|
||||
|
||||
bool device_default::verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) {
|
||||
crypto::public_key calculated_pub;
|
||||
bool r = crypto::secret_key_to_public_key(secret_key, calculated_pub);
|
||||
return r && public_key == calculated_pub;
|
||||
}
|
||||
|
||||
bool device_default::scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) {
|
||||
rct::scalarmultKey(aP, P,a);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool device_default::scalarmultBase(rct::key &aG, const rct::key &a) {
|
||||
rct::scalarmultBase(aG,a);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool device_default::sc_secret_add(crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) {
|
||||
sc_add(&r, &a, &b);
|
||||
return true;
|
||||
}
|
||||
|
||||
crypto::secret_key device_default::generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key, bool recover) {
|
||||
return crypto::generate_keys(pub, sec, recovery_key, recover);
|
||||
}
|
||||
|
||||
bool device_default::generate_key_derivation(const crypto::public_key &key1, const crypto::secret_key &key2, crypto::key_derivation &derivation) {
|
||||
return crypto::generate_key_derivation(key1, key2, derivation);
|
||||
}
|
||||
|
||||
bool device_default::derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res){
|
||||
crypto::derivation_to_scalar(derivation,output_index, res);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool device_default::derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &base, crypto::secret_key &derived_key){
|
||||
crypto::derive_secret_key(derivation, output_index, base, derived_key);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool device_default::derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &base, crypto::public_key &derived_key){
|
||||
return crypto::derive_public_key(derivation, output_index, base, derived_key);
|
||||
}
|
||||
|
||||
bool device_default::secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) {
|
||||
return crypto::secret_key_to_public_key(sec,pub);
|
||||
}
|
||||
|
||||
bool device_default::generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image){
|
||||
crypto::generate_key_image(pub, sec,image);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool device_default::conceal_derivation(crypto::key_derivation &derivation, const crypto::public_key &tx_pub_key, const std::vector<crypto::public_key> &additional_tx_pub_keys, const crypto::key_derivation &main_derivation, const std::vector<crypto::key_derivation> &additional_derivations){
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ======================================================================= */
|
||||
/* TRANSACTION */
|
||||
/* ======================================================================= */
|
||||
|
||||
bool device_default::open_tx(crypto::secret_key &tx_key) {
|
||||
cryptonote::keypair txkey = cryptonote::keypair::generate(*this);
|
||||
tx_key = txkey.sec;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool device_default::add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, const bool is_subaddress, const size_t real_output_index,
|
||||
const rct::key &amount_key, const crypto::public_key &out_eph_public_key) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool device_default::encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) {
|
||||
crypto::key_derivation derivation;
|
||||
crypto::hash hash;
|
||||
char data[33]; /* A hash, and an extra byte */
|
||||
|
||||
if (!generate_key_derivation(public_key, secret_key, derivation))
|
||||
return false;
|
||||
|
||||
memcpy(data, &derivation, 32);
|
||||
data[32] = ENCRYPTED_PAYMENT_ID_TAIL;
|
||||
cn_fast_hash(data, 33, hash);
|
||||
|
||||
for (size_t b = 0; b < 8; ++b)
|
||||
payment_id.data[b] ^= hash.data[b];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool device_default::ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec) {
|
||||
rct::ecdhEncode(unmasked, sharedSec);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool device_default::ecdhDecode(rct::ecdhTuple & masked, const rct::key & sharedSec) {
|
||||
rct::ecdhDecode(masked, sharedSec);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool device_default::mlsag_prepare(const rct::key &H, const rct::key &xx,
|
||||
rct::key &a, rct::key &aG, rct::key &aHP, rct::key &II) {
|
||||
rct::skpkGen(a, aG);
|
||||
rct::scalarmultKey(aHP, H, a);
|
||||
rct::scalarmultKey(II, H, xx);
|
||||
return true;
|
||||
}
|
||||
bool device_default::mlsag_prepare(rct::key &a, rct::key &aG) {
|
||||
rct::skpkGen(a, aG);
|
||||
return true;
|
||||
}
|
||||
bool device_default::mlsag_prehash(const std::string &blob, size_t inputs_size, size_t outputs_size, const rct::keyV &hashes, const rct::ctkeyV &outPk, rct::key &prehash) {
|
||||
prehash = rct::cn_fast_hash(hashes);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool device_default::mlsag_hash(const rct::keyV &toHash, rct::key &c_old) {
|
||||
c_old = rct::hash_to_scalar(toHash);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool device_default::mlsag_sign(const rct::key &c, const rct::keyV &xx, const rct::keyV &alpha, const size_t rows, const size_t dsRows, rct::keyV &ss ) {
|
||||
CHECK_AND_ASSERT_THROW_MES(dsRows<=rows, "dsRows greater than rows");
|
||||
CHECK_AND_ASSERT_THROW_MES(xx.size() == rows, "xx size does not match rows");
|
||||
CHECK_AND_ASSERT_THROW_MES(alpha.size() == rows, "alpha size does not match rows");
|
||||
CHECK_AND_ASSERT_THROW_MES(ss.size() == rows, "ss size does not match rows");
|
||||
for (size_t j = 0; j < rows; j++) {
|
||||
sc_mulsub(ss[j].bytes, c.bytes, xx[j].bytes, alpha[j].bytes);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool device_default::close_tx() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------------- */
|
||||
static device_default *default_core_device = NULL;
|
||||
void register_all(std::map<std::string, std::unique_ptr<device>> ®istry) {
|
||||
if (!default_core_device) {
|
||||
default_core_device = new device_default();
|
||||
default_core_device->set_name("default_core_device");
|
||||
|
||||
}
|
||||
registry.insert(std::make_pair("default", std::unique_ptr<device>(default_core_device)));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
// 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.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "device.hpp"
|
||||
|
||||
namespace hw {
|
||||
|
||||
namespace core {
|
||||
|
||||
void register_all(std::map<std::string, std::unique_ptr<device>> ®istry);
|
||||
|
||||
class device_default : public hw::device {
|
||||
public:
|
||||
device_default();
|
||||
~device_default();
|
||||
|
||||
device_default(const device_default &device) = delete;
|
||||
device_default& operator=(const device_default &device) = delete;
|
||||
|
||||
explicit operator bool() const override { return false; };
|
||||
|
||||
/* ======================================================================= */
|
||||
/* SETUP/TEARDOWN */
|
||||
/* ======================================================================= */
|
||||
bool set_name(const std::string &name) override;
|
||||
const std::string get_name() const override;
|
||||
|
||||
bool init(void) override;
|
||||
bool release() override;
|
||||
|
||||
bool connect(void) override;
|
||||
bool disconnect() override;
|
||||
|
||||
bool set_mode(device_mode mode) override;
|
||||
|
||||
/* ======================================================================= */
|
||||
/* LOCKER */
|
||||
/* ======================================================================= */
|
||||
void lock(void) override;
|
||||
void unlock(void) override;
|
||||
bool try_lock(void) override;
|
||||
|
||||
/* ======================================================================= */
|
||||
/* WALLET & ADDRESS */
|
||||
/* ======================================================================= */
|
||||
bool get_public_address(cryptonote::account_public_address &pubkey) override;
|
||||
bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) override;
|
||||
bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) override;
|
||||
|
||||
/* ======================================================================= */
|
||||
/* SUB ADDRESS */
|
||||
/* ======================================================================= */
|
||||
bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_pub) override;
|
||||
crypto::public_key get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index) override;
|
||||
std::vector<crypto::public_key> get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end) override;
|
||||
cryptonote::account_public_address get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) override;
|
||||
crypto::secret_key get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index) override;
|
||||
|
||||
/* ======================================================================= */
|
||||
/* DERIVATION & KEY */
|
||||
/* ======================================================================= */
|
||||
bool verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) override;
|
||||
bool scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) override;
|
||||
bool scalarmultBase(rct::key &aG, const rct::key &a) override;
|
||||
bool sc_secret_add(crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) override;
|
||||
crypto::secret_key generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false) override;
|
||||
bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) override;
|
||||
bool conceal_derivation(crypto::key_derivation &derivation, const crypto::public_key &tx_pub_key, const std::vector<crypto::public_key> &additional_tx_pub_keys, const crypto::key_derivation &main_derivation, const std::vector<crypto::key_derivation> &additional_derivations) override;
|
||||
bool derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) override;
|
||||
bool derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) override;
|
||||
bool derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub) override;
|
||||
bool secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) override;
|
||||
bool generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image) override;
|
||||
|
||||
|
||||
/* ======================================================================= */
|
||||
/* TRANSACTION */
|
||||
/* ======================================================================= */
|
||||
|
||||
bool open_tx(crypto::secret_key &tx_key) override;
|
||||
|
||||
bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) override;
|
||||
|
||||
bool ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec) override;
|
||||
bool ecdhDecode(rct::ecdhTuple & masked, const rct::key & sharedSec) override;
|
||||
|
||||
bool add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, const bool is_subaddress, const size_t real_output_index,
|
||||
const rct::key &amount_key, const crypto::public_key &out_eph_public_key) override;
|
||||
|
||||
|
||||
bool mlsag_prehash(const std::string &blob, size_t inputs_size, size_t outputs_size, const rct::keyV &hashes, const rct::ctkeyV &outPk, rct::key &prehash) override;
|
||||
bool mlsag_prepare(const rct::key &H, const rct::key &xx, rct::key &a, rct::key &aG, rct::key &aHP, rct::key &rvII) override;
|
||||
bool mlsag_prepare(rct::key &a, rct::key &aG) override;
|
||||
bool mlsag_hash(const rct::keyV &long_message, rct::key &c) override;
|
||||
bool mlsag_sign(const rct::key &c, const rct::keyV &xx, const rct::keyV &alpha, const size_t rows, const size_t dsRows, rct::keyV &ss) override;
|
||||
|
||||
bool close_tx(void) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,166 @@
|
||||
// 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 "misc_log_ex.h"
|
||||
#include "log.hpp"
|
||||
|
||||
namespace hw {
|
||||
|
||||
#ifdef WITH_DEVICE_LEDGER
|
||||
namespace ledger {
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "device.ledger"
|
||||
|
||||
void buffer_to_str(char *to_buff, size_t to_len, const char *buff, size_t len) {
|
||||
CHECK_AND_ASSERT_THROW_MES(to_len > (len*2), "destination buffer too short. At least" << (len*2+1) << " bytes required");
|
||||
for (size_t i=0; i<len; i++) {
|
||||
sprintf(to_buff+2*i, "%.02x", (unsigned char)buff[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void log_hexbuffer(const std::string &msg, const char* buff, size_t len) {
|
||||
char logstr[1025];
|
||||
buffer_to_str(logstr, sizeof(logstr), buff, len);
|
||||
MDEBUG(msg<< ": " << logstr);
|
||||
}
|
||||
|
||||
void log_message(const std::string &msg, const std::string &info ) {
|
||||
MDEBUG(msg << ": " << info);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_HWDEVICE
|
||||
extern crypto::secret_key dbg_viewkey;
|
||||
extern crypto::secret_key dbg_spendkey;
|
||||
|
||||
|
||||
void decrypt(char* buf, size_t len) {
|
||||
#ifdef IODUMMYCRYPT_HWDEVICE
|
||||
size_t i;
|
||||
if (len == 32) {
|
||||
//view key?
|
||||
for (i = 0; i<32; i++) {
|
||||
if (buf[i] != 0) break;
|
||||
}
|
||||
if (i == 32) {
|
||||
memmove(buf, hw::ledger::dbg_viewkey.data, 32);
|
||||
return;
|
||||
}
|
||||
//spend key?
|
||||
for (i = 0; i<32; i++) {
|
||||
if (buf[i] != (char)0xff) break;
|
||||
}
|
||||
if (i == 32) {
|
||||
memmove(buf, hw::ledger::dbg_spendkey.data, 32);
|
||||
return;
|
||||
}
|
||||
}
|
||||
//std decrypt: XOR.55h
|
||||
for (i = 0; i<len;i++) {
|
||||
buf[i] ^= 0x55;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
crypto::key_derivation decrypt(const crypto::key_derivation &derivation) {
|
||||
crypto::key_derivation x = derivation;
|
||||
decrypt(x.data, 32);
|
||||
return x;
|
||||
}
|
||||
|
||||
cryptonote::account_keys decrypt(const cryptonote::account_keys& keys) {
|
||||
cryptonote::account_keys x = keys;
|
||||
decrypt(x.m_view_secret_key.data, 32);
|
||||
decrypt(x.m_spend_secret_key.data, 32);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
crypto::secret_key decrypt(const crypto::secret_key &sec) {
|
||||
crypto::secret_key x = sec;
|
||||
decrypt(x.data, 32);
|
||||
return x;
|
||||
}
|
||||
|
||||
rct::key decrypt(const rct::key &sec) {
|
||||
rct::key x = sec;
|
||||
decrypt((char*)x.bytes, 32);
|
||||
return x;
|
||||
}
|
||||
|
||||
crypto::ec_scalar decrypt(const crypto::ec_scalar &res) {
|
||||
crypto::ec_scalar x = res;
|
||||
decrypt((char*)x.data, 32);
|
||||
return x;
|
||||
}
|
||||
|
||||
rct::keyV decrypt(const rct::keyV &keys) {
|
||||
rct::keyV x ;
|
||||
x.reserve(keys.size());
|
||||
for (unsigned int j = 0; j<keys.size(); j++) {
|
||||
x.push_back(decrypt(keys[j]));
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static void check(const std::string &msg, const std::string &info, const char *h, const char *d, size_t len, bool crypted) {
|
||||
char dd[32];
|
||||
char logstr[128];
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(len <= sizeof(dd), "invalid len");
|
||||
memmove(dd,d,len);
|
||||
if (crypted) {
|
||||
CHECK_AND_ASSERT_THROW_MES(len<=32, "encrypted data greater than 32");
|
||||
decrypt(dd,len);
|
||||
}
|
||||
|
||||
if (memcmp(h,dd,len)) {
|
||||
log_message("ASSERT EQ FAIL", msg + ": "+ info );
|
||||
log_hexbuffer(" host ", h, len);
|
||||
log_hexbuffer(" device", dd, len);
|
||||
|
||||
} else {
|
||||
buffer_to_str(logstr, 128, dd, len);
|
||||
log_message("ASSERT EQ OK", msg + ": "+ info + ": "+ std::string(logstr) );
|
||||
}
|
||||
}
|
||||
|
||||
void check32(const std::string &msg, const std::string &info, const char *h, const char *d, bool crypted) {
|
||||
check(msg, info, h, d, 32, crypted);
|
||||
}
|
||||
|
||||
void check8(const std::string &msg, const std::string &info, const char *h, const char *d, bool crypted) {
|
||||
check(msg, info, h, d, 8, crypted);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
#endif //WITH_DEVICE_LEDGER
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
// 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.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
#include "ringct/rctOps.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "cryptonote_basic/account.h"
|
||||
|
||||
#include "device.hpp"
|
||||
|
||||
namespace hw {
|
||||
|
||||
#ifdef WITH_DEVICE_LEDGER
|
||||
namespace ledger {
|
||||
|
||||
void buffer_to_str(char *to_buff, size_t to_len, const char *buff, size_t len) ;
|
||||
void log_hexbuffer(const std::string &msg, const char* buff, size_t len);
|
||||
void log_message(const std::string &msg, const std::string &info );
|
||||
#ifdef DEBUG_HWDEVICE
|
||||
#define TRACK printf("file %s:%d\n",__FILE__, __LINE__)
|
||||
//#define TRACK MCDEBUG("ledger"," At file " << __FILE__ << ":" << __LINE__)
|
||||
//#define TRACK while(0);
|
||||
|
||||
void decrypt(char* buf, size_t len) ;
|
||||
crypto::key_derivation decrypt(const crypto::key_derivation &derivation) ;
|
||||
cryptonote::account_keys decrypt(const cryptonote::account_keys& keys) ;
|
||||
crypto::secret_key decrypt(const crypto::secret_key &sec) ;
|
||||
rct::key decrypt(const rct::key &sec);
|
||||
crypto::ec_scalar decrypt(const crypto::ec_scalar &res);
|
||||
rct::keyV decrypt(const rct::keyV &keys);
|
||||
|
||||
void check32(const std::string &msg, const std::string &info, const char *h, const char *d, bool crypted=false);
|
||||
void check8(const std::string &msg, const std::string &info, const char *h, const char *d, bool crypted=false);
|
||||
|
||||
void set_check_verbose(bool verbose);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * 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.
|
||||
// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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
|
||||
|
||||
#define BOOST_FILESYSTEM_VERSION 3
|
||||
#define ENABLE_RELEASE_LOGGING
|
||||
|
||||
#include "misc_log_ex.h"
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,532 @@
|
||||
// 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.
|
||||
|
||||
/*!
|
||||
* \file electrum-words.cpp
|
||||
*
|
||||
* \brief Mnemonic seed generation and wallet restoration from them.
|
||||
*
|
||||
* This file and its header file are for translating Electrum-style word lists
|
||||
* into their equivalent byte representations for cross-compatibility with
|
||||
* that method of "backing up" one's wallet keys.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include "crypto/crypto.h" // for declaration of crypto::secret_key
|
||||
#include <fstream>
|
||||
#include "mnemonics/electrum-words.h"
|
||||
#include <stdexcept>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/crc.hpp>
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
|
||||
#include "chinese_simplified.h"
|
||||
#include "english.h"
|
||||
#include "dutch.h"
|
||||
#include "french.h"
|
||||
#include "italian.h"
|
||||
#include "german.h"
|
||||
#include "spanish.h"
|
||||
#include "portuguese.h"
|
||||
#include "japanese.h"
|
||||
#include "russian.h"
|
||||
#include "esperanto.h"
|
||||
#include "lojban.h"
|
||||
#include "english_old.h"
|
||||
#include "language_base.h"
|
||||
#include "singleton.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "mnemonic"
|
||||
|
||||
namespace
|
||||
{
|
||||
uint32_t create_checksum_index(const std::vector<std::string> &word_list,
|
||||
uint32_t unique_prefix_length);
|
||||
bool checksum_test(std::vector<std::string> seed, uint32_t unique_prefix_length);
|
||||
|
||||
/*!
|
||||
* \brief Finds the word list that contains the seed words and puts the indices
|
||||
* where matches occured in matched_indices.
|
||||
* \param seed List of words to match.
|
||||
* \param has_checksum The seed has a checksum word (maybe not checked).
|
||||
* \param matched_indices The indices where the seed words were found are added to this.
|
||||
* \param language Language instance pointer to write to after it is found.
|
||||
* \return true if all the words were present in some language false if not.
|
||||
*/
|
||||
bool find_seed_language(const std::vector<std::string> &seed,
|
||||
bool has_checksum, std::vector<uint32_t> &matched_indices, Language::Base **language)
|
||||
{
|
||||
// If there's a new language added, add an instance of it here.
|
||||
std::vector<Language::Base*> language_instances({
|
||||
Language::Singleton<Language::Chinese_Simplified>::instance(),
|
||||
Language::Singleton<Language::English>::instance(),
|
||||
Language::Singleton<Language::Dutch>::instance(),
|
||||
Language::Singleton<Language::French>::instance(),
|
||||
Language::Singleton<Language::Spanish>::instance(),
|
||||
Language::Singleton<Language::German>::instance(),
|
||||
Language::Singleton<Language::Italian>::instance(),
|
||||
Language::Singleton<Language::Portuguese>::instance(),
|
||||
Language::Singleton<Language::Japanese>::instance(),
|
||||
Language::Singleton<Language::Russian>::instance(),
|
||||
Language::Singleton<Language::Esperanto>::instance(),
|
||||
Language::Singleton<Language::Lojban>::instance(),
|
||||
Language::Singleton<Language::EnglishOld>::instance()
|
||||
});
|
||||
Language::Base *fallback = NULL;
|
||||
|
||||
// Iterate through all the languages and find a match
|
||||
for (std::vector<Language::Base*>::iterator it1 = language_instances.begin();
|
||||
it1 != language_instances.end(); it1++)
|
||||
{
|
||||
const std::unordered_map<std::string, uint32_t> &word_map = (*it1)->get_word_map();
|
||||
const std::unordered_map<std::string, uint32_t> &trimmed_word_map = (*it1)->get_trimmed_word_map();
|
||||
// To iterate through seed words
|
||||
std::vector<std::string>::const_iterator it2;
|
||||
bool full_match = true;
|
||||
|
||||
std::string trimmed_word;
|
||||
// Iterate through all the words and see if they're all present
|
||||
for (it2 = seed.begin(); it2 != seed.end(); it2++)
|
||||
{
|
||||
if (has_checksum)
|
||||
{
|
||||
trimmed_word = Language::utf8prefix(*it2, (*it1)->get_unique_prefix_length());
|
||||
// Use the trimmed words and map
|
||||
if (trimmed_word_map.count(trimmed_word) == 0)
|
||||
{
|
||||
full_match = false;
|
||||
break;
|
||||
}
|
||||
matched_indices.push_back(trimmed_word_map.at(trimmed_word));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (word_map.count(*it2) == 0)
|
||||
{
|
||||
full_match = false;
|
||||
break;
|
||||
}
|
||||
matched_indices.push_back(word_map.at(*it2));
|
||||
}
|
||||
}
|
||||
if (full_match)
|
||||
{
|
||||
// if we were using prefix only, and we have a checksum, check it now
|
||||
// to avoid false positives due to prefix set being too common
|
||||
if (has_checksum)
|
||||
if (!checksum_test(seed, (*it1)->get_unique_prefix_length()))
|
||||
{
|
||||
fallback = *it1;
|
||||
full_match = false;
|
||||
}
|
||||
}
|
||||
if (full_match)
|
||||
{
|
||||
*language = *it1;
|
||||
MINFO("Full match for language " << (*language)->get_english_language_name());
|
||||
return true;
|
||||
}
|
||||
// Some didn't match. Clear the index array.
|
||||
matched_indices.clear();
|
||||
}
|
||||
|
||||
// if we get there, we've not found a good match, but we might have a fallback,
|
||||
// if we detected a match which did not fit the checksum, which might be a badly
|
||||
// typed/transcribed seed in the right language
|
||||
if (fallback)
|
||||
{
|
||||
*language = fallback;
|
||||
MINFO("Fallback match for language " << (*language)->get_english_language_name());
|
||||
return true;
|
||||
}
|
||||
|
||||
MINFO("No match found");
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Creates a checksum index in the word list array on the list of words.
|
||||
* \param word_list Vector of words
|
||||
* \param unique_prefix_length the prefix length of each word to use for checksum
|
||||
* \return Checksum index
|
||||
*/
|
||||
uint32_t create_checksum_index(const std::vector<std::string> &word_list,
|
||||
uint32_t unique_prefix_length)
|
||||
{
|
||||
std::string trimmed_words = "";
|
||||
|
||||
for (std::vector<std::string>::const_iterator it = word_list.begin(); it != word_list.end(); it++)
|
||||
{
|
||||
if (it->length() > unique_prefix_length)
|
||||
{
|
||||
trimmed_words += Language::utf8prefix(*it, unique_prefix_length);
|
||||
}
|
||||
else
|
||||
{
|
||||
trimmed_words += *it;
|
||||
}
|
||||
}
|
||||
boost::crc_32_type result;
|
||||
result.process_bytes(trimmed_words.data(), trimmed_words.length());
|
||||
return result.checksum() % word_list.size();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Does the checksum test on the seed passed.
|
||||
* \param seed Vector of seed words
|
||||
* \param unique_prefix_length the prefix length of each word to use for checksum
|
||||
* \return True if the test passed false if not.
|
||||
*/
|
||||
bool checksum_test(std::vector<std::string> seed, uint32_t unique_prefix_length)
|
||||
{
|
||||
if (seed.empty())
|
||||
return false;
|
||||
// The last word is the checksum.
|
||||
std::string last_word = seed.back();
|
||||
seed.pop_back();
|
||||
|
||||
std::string checksum = seed[create_checksum_index(seed, unique_prefix_length)];
|
||||
|
||||
std::string trimmed_checksum = checksum.length() > unique_prefix_length ? Language::utf8prefix(checksum, unique_prefix_length) :
|
||||
checksum;
|
||||
std::string trimmed_last_word = last_word.length() > unique_prefix_length ? Language::utf8prefix(last_word, unique_prefix_length) :
|
||||
last_word;
|
||||
bool ret = trimmed_checksum == trimmed_last_word;
|
||||
MINFO("Checksum is %s" << (ret ? "valid" : "invalid"));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \namespace crypto
|
||||
*
|
||||
* \brief crypto namespace.
|
||||
*/
|
||||
namespace crypto
|
||||
{
|
||||
/*!
|
||||
* \namespace crypto::ElectrumWords
|
||||
*
|
||||
* \brief Mnemonic seed word generation and wallet restoration helper functions.
|
||||
*/
|
||||
namespace ElectrumWords
|
||||
{
|
||||
/*!
|
||||
* \brief Converts seed words to bytes (secret key).
|
||||
* \param words String containing the words separated by spaces.
|
||||
* \param dst To put the secret data restored from the words.
|
||||
* \param len The number of bytes to expect, 0 if unknown
|
||||
* \param duplicate If true and len is not zero, we accept half the data, and duplicate it
|
||||
* \param language_name Language of the seed as found gets written here.
|
||||
* \return false if not a multiple of 3 words, or if word is not in the words list
|
||||
*/
|
||||
bool words_to_bytes(std::string words, std::string& dst, size_t len, bool duplicate,
|
||||
std::string &language_name)
|
||||
{
|
||||
std::vector<std::string> seed;
|
||||
|
||||
boost::algorithm::trim(words);
|
||||
boost::split(seed, words, boost::is_any_of(" "), boost::token_compress_on);
|
||||
|
||||
if (len % 4)
|
||||
{
|
||||
MERROR("Invalid seed: not a multiple of 4");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool has_checksum = true;
|
||||
if (len)
|
||||
{
|
||||
// error on non-compliant word list
|
||||
const size_t expected = len * 8 * 3 / 32;
|
||||
if (seed.size() != expected/2 && seed.size() != expected &&
|
||||
seed.size() != expected + 1)
|
||||
{
|
||||
MERROR("Invalid seed: unexpected number of words");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If it is seed with a checksum.
|
||||
has_checksum = seed.size() == (expected + 1);
|
||||
}
|
||||
|
||||
std::vector<uint32_t> matched_indices;
|
||||
Language::Base *language;
|
||||
if (!find_seed_language(seed, has_checksum, matched_indices, &language))
|
||||
{
|
||||
MERROR("Invalid seed: language not found");
|
||||
return false;
|
||||
}
|
||||
language_name = language->get_language_name();
|
||||
uint32_t word_list_length = language->get_word_list().size();
|
||||
|
||||
if (has_checksum)
|
||||
{
|
||||
if (!checksum_test(seed, language->get_unique_prefix_length()))
|
||||
{
|
||||
// Checksum fail
|
||||
MERROR("Invalid seed: invalid checksum");
|
||||
return false;
|
||||
}
|
||||
seed.pop_back();
|
||||
}
|
||||
|
||||
for (unsigned int i=0; i < seed.size() / 3; i++)
|
||||
{
|
||||
uint32_t val;
|
||||
uint32_t w1, w2, w3;
|
||||
w1 = matched_indices[i*3];
|
||||
w2 = matched_indices[i*3 + 1];
|
||||
w3 = matched_indices[i*3 + 2];
|
||||
|
||||
val = w1 + word_list_length * (((word_list_length - w1) + w2) % word_list_length) +
|
||||
word_list_length * word_list_length * (((word_list_length - w2) + w3) % word_list_length);
|
||||
|
||||
if (!(val % word_list_length == w1))
|
||||
{
|
||||
MERROR("Invalid seed: mumble mumble");
|
||||
return false;
|
||||
}
|
||||
|
||||
dst.append((const char*)&val, 4); // copy 4 bytes to position
|
||||
}
|
||||
|
||||
if (len > 0 && duplicate)
|
||||
{
|
||||
const size_t expected = len * 3 / 32;
|
||||
std::string wlist_copy = words;
|
||||
if (seed.size() == expected/2)
|
||||
{
|
||||
dst.append(dst); // if electrum 12-word seed, duplicate
|
||||
wlist_copy += ' ';
|
||||
wlist_copy += words;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Converts seed words to bytes (secret key).
|
||||
* \param words String containing the words separated by spaces.
|
||||
* \param dst To put the secret key restored from the words.
|
||||
* \param language_name Language of the seed as found gets written here.
|
||||
* \return false if not a multiple of 3 words, or if word is not in the words list
|
||||
*/
|
||||
bool words_to_bytes(std::string words, crypto::secret_key& dst,
|
||||
std::string &language_name)
|
||||
{
|
||||
std::string s;
|
||||
if (!words_to_bytes(words, s, sizeof(dst), true, language_name))
|
||||
{
|
||||
MERROR("Invalid seed: failed to convert words to bytes");
|
||||
return false;
|
||||
}
|
||||
if (s.size() != sizeof(dst))
|
||||
{
|
||||
MERROR("Invalid seed: wrong output size");
|
||||
return false;
|
||||
}
|
||||
memcpy(dst.data, s.data(), sizeof(dst.data));
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Converts bytes (secret key) to seed words.
|
||||
* \param src Secret key
|
||||
* \param words Space delimited concatenated words get written here.
|
||||
* \param language_name Seed language name
|
||||
* \return true if successful false if not. Unsuccessful if wrong key size.
|
||||
*/
|
||||
bool bytes_to_words(const char *src, size_t len, std::string& words,
|
||||
const std::string &language_name)
|
||||
{
|
||||
|
||||
if (len % 4 != 0 || len == 0) return false;
|
||||
|
||||
Language::Base *language;
|
||||
if (language_name == "English")
|
||||
{
|
||||
language = Language::Singleton<Language::English>::instance();
|
||||
}
|
||||
else if (language_name == "Nederlands")
|
||||
{
|
||||
language = Language::Singleton<Language::Dutch>::instance();
|
||||
}
|
||||
else if (language_name == "Français")
|
||||
{
|
||||
language = Language::Singleton<Language::French>::instance();
|
||||
}
|
||||
else if (language_name == "Español")
|
||||
{
|
||||
language = Language::Singleton<Language::Spanish>::instance();
|
||||
}
|
||||
else if (language_name == "Português")
|
||||
{
|
||||
language = Language::Singleton<Language::Portuguese>::instance();
|
||||
}
|
||||
else if (language_name == "日本語")
|
||||
{
|
||||
language = Language::Singleton<Language::Japanese>::instance();
|
||||
}
|
||||
else if (language_name == "Italiano")
|
||||
{
|
||||
language = Language::Singleton<Language::Italian>::instance();
|
||||
}
|
||||
else if (language_name == "Deutsch")
|
||||
{
|
||||
language = Language::Singleton<Language::German>::instance();
|
||||
}
|
||||
else if (language_name == "русский язык")
|
||||
{
|
||||
language = Language::Singleton<Language::Russian>::instance();
|
||||
}
|
||||
else if (language_name == "简体中文 (中国)")
|
||||
{
|
||||
language = Language::Singleton<Language::Chinese_Simplified>::instance();
|
||||
}
|
||||
else if (language_name == "Esperanto")
|
||||
{
|
||||
language = Language::Singleton<Language::Esperanto>::instance();
|
||||
}
|
||||
else if (language_name == "Lojban")
|
||||
{
|
||||
language = Language::Singleton<Language::Lojban>::instance();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const std::vector<std::string> &word_list = language->get_word_list();
|
||||
// To store the words for random access to add the checksum word later.
|
||||
std::vector<std::string> words_store;
|
||||
|
||||
uint32_t word_list_length = word_list.size();
|
||||
// 4 bytes -> 3 words. 8 digits base 16 -> 3 digits base 1626
|
||||
for (unsigned int i=0; i < len/4; i++, words += ' ')
|
||||
{
|
||||
uint32_t w1, w2, w3;
|
||||
|
||||
uint32_t val;
|
||||
|
||||
memcpy(&val, src + (i * 4), 4);
|
||||
|
||||
w1 = val % word_list_length;
|
||||
w2 = ((val / word_list_length) + w1) % word_list_length;
|
||||
w3 = (((val / word_list_length) / word_list_length) + w2) % word_list_length;
|
||||
|
||||
words += word_list[w1];
|
||||
words += ' ';
|
||||
words += word_list[w2];
|
||||
words += ' ';
|
||||
words += word_list[w3];
|
||||
|
||||
words_store.push_back(word_list[w1]);
|
||||
words_store.push_back(word_list[w2]);
|
||||
words_store.push_back(word_list[w3]);
|
||||
}
|
||||
|
||||
words.pop_back();
|
||||
words += (' ' + words_store[create_checksum_index(words_store, language->get_unique_prefix_length())]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bytes_to_words(const crypto::secret_key& src, std::string& words,
|
||||
const std::string &language_name)
|
||||
{
|
||||
return bytes_to_words(src.data, sizeof(src), words, language_name);
|
||||
}
|
||||
|
||||
std::vector<const Language::Base*> get_language_list()
|
||||
{
|
||||
static const std::vector<const Language::Base*> language_instances({
|
||||
Language::Singleton<Language::German>::instance(),
|
||||
Language::Singleton<Language::English>::instance(),
|
||||
Language::Singleton<Language::Spanish>::instance(),
|
||||
Language::Singleton<Language::French>::instance(),
|
||||
Language::Singleton<Language::Italian>::instance(),
|
||||
Language::Singleton<Language::Dutch>::instance(),
|
||||
Language::Singleton<Language::Portuguese>::instance(),
|
||||
Language::Singleton<Language::Russian>::instance(),
|
||||
Language::Singleton<Language::Japanese>::instance(),
|
||||
Language::Singleton<Language::Chinese_Simplified>::instance(),
|
||||
Language::Singleton<Language::Esperanto>::instance(),
|
||||
Language::Singleton<Language::Lojban>::instance()
|
||||
});
|
||||
return language_instances;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets a list of seed languages that are supported.
|
||||
* \param languages The vector is set to the list of languages.
|
||||
*/
|
||||
void get_language_list(std::vector<std::string> &languages, bool english)
|
||||
{
|
||||
const std::vector<const Language::Base*> language_instances = get_language_list();
|
||||
for (std::vector<const Language::Base*>::const_iterator it = language_instances.begin();
|
||||
it != language_instances.end(); it++)
|
||||
{
|
||||
languages.push_back(english ? (*it)->get_english_language_name() : (*it)->get_language_name());
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Tells if the seed passed is an old style seed or not.
|
||||
* \param seed The seed to check (a space delimited concatenated word list)
|
||||
* \return true if the seed passed is a old style seed false if not.
|
||||
*/
|
||||
bool get_is_old_style_seed(std::string seed)
|
||||
{
|
||||
std::vector<std::string> word_list;
|
||||
boost::algorithm::trim(seed);
|
||||
boost::split(word_list, seed, boost::is_any_of(" "), boost::token_compress_on);
|
||||
return word_list.size() != (seed_length + 1);
|
||||
}
|
||||
|
||||
std::string get_english_name_for(const std::string &name)
|
||||
{
|
||||
const std::vector<const Language::Base*> language_instances = get_language_list();
|
||||
for (std::vector<const Language::Base*>::const_iterator it = language_instances.begin();
|
||||
it != language_instances.end(); it++)
|
||||
{
|
||||
if ((*it)->get_language_name() == name)
|
||||
return (*it)->get_english_language_name();
|
||||
}
|
||||
return "<language not found>";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
// 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.
|
||||
|
||||
/*!
|
||||
* \file electrum-words.h
|
||||
*
|
||||
* \brief Mnemonic seed generation and wallet restoration from them.
|
||||
*
|
||||
* This file and its cpp file are for translating Electrum-style word lists
|
||||
* into their equivalent byte representations for cross-compatibility with
|
||||
* that method of "backing up" one's wallet keys.
|
||||
*/
|
||||
|
||||
#ifndef ELECTRUM_WORDS_H
|
||||
#define ELECTRUM_WORDS_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include "crypto/crypto.h" // for declaration of crypto::secret_key
|
||||
|
||||
/*!
|
||||
* \namespace crypto
|
||||
*
|
||||
* \brief crypto namespace.
|
||||
*/
|
||||
namespace crypto
|
||||
{
|
||||
/*!
|
||||
* \namespace crypto::ElectrumWords
|
||||
*
|
||||
* \brief Mnemonic seed word generation and wallet restoration helper functions.
|
||||
*/
|
||||
namespace ElectrumWords
|
||||
{
|
||||
|
||||
const int seed_length = 24;
|
||||
const std::string old_language_name = "EnglishOld";
|
||||
/*!
|
||||
* \brief Converts seed words to bytes (secret key).
|
||||
* \param words String containing the words separated by spaces.
|
||||
* \param dst To put the secret data restored from the words.
|
||||
* \param len The number of bytes to expect, 0 if unknown
|
||||
* \param duplicate If true and len is not zero, we accept half the data, and duplicate it
|
||||
* \param language_name Language of the seed as found gets written here.
|
||||
* \return false if not a multiple of 3 words, or if word is not in the words list
|
||||
*/
|
||||
bool words_to_bytes(std::string words, std::string& dst, size_t len, bool duplicate,
|
||||
std::string &language_name);
|
||||
/*!
|
||||
* \brief Converts seed words to bytes (secret key).
|
||||
* \param words String containing the words separated by spaces.
|
||||
* \param dst To put the secret key restored from the words.
|
||||
* \param language_name Language of the seed as found gets written here.
|
||||
* \return false if not a multiple of 3 words, or if word is not in the words list
|
||||
*/
|
||||
bool words_to_bytes(std::string words, crypto::secret_key& dst,
|
||||
std::string &language_name);
|
||||
|
||||
/*!
|
||||
* \brief Converts bytes to seed words.
|
||||
* \param src Secret data
|
||||
* \param len Secret data length in bytes (positive multiples of 4 only)
|
||||
* \param words Space delimited concatenated words get written here.
|
||||
* \param language_name Seed language name
|
||||
* \return true if successful false if not. Unsuccessful if wrong key size.
|
||||
*/
|
||||
bool bytes_to_words(const char *src, size_t len, std::string& words,
|
||||
const std::string &language_name);
|
||||
|
||||
/*!
|
||||
* \brief Converts bytes (secret key) to seed words.
|
||||
* \param src Secret key
|
||||
* \param words Space delimited concatenated words get written here.
|
||||
* \param language_name Seed language name
|
||||
* \return true if successful false if not. Unsuccessful if wrong key size.
|
||||
*/
|
||||
bool bytes_to_words(const crypto::secret_key& src, std::string& words,
|
||||
const std::string &language_name);
|
||||
|
||||
/*!
|
||||
* \brief Gets a list of seed languages that are supported.
|
||||
* \param languages A vector is set to the list of languages.
|
||||
* \param english whether to get the names in English or the language language
|
||||
*/
|
||||
void get_language_list(std::vector<std::string> &languages, bool english = false);
|
||||
|
||||
/*!
|
||||
* \brief Tells if the seed passed is an old style seed or not.
|
||||
* \param seed The seed to check (a space delimited concatenated word list)
|
||||
* \return true if the seed passed is a old style seed false if not.
|
||||
*/
|
||||
bool get_is_old_style_seed(std::string seed);
|
||||
|
||||
/*!
|
||||
* \brief Returns the name of a language in English
|
||||
* \param name the name of the language in its own language
|
||||
* \return the name of the language in English
|
||||
*/
|
||||
std::string get_english_name_for(const std::string &name);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,187 @@
|
||||
// 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.
|
||||
|
||||
/*!
|
||||
* \file language_base.h
|
||||
*
|
||||
* \brief Language Base class for Polymorphism.
|
||||
*/
|
||||
|
||||
#ifndef LANGUAGE_BASE_H
|
||||
#define LANGUAGE_BASE_H
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include "misc_log_ex.h"
|
||||
|
||||
/*!
|
||||
* \namespace Language
|
||||
* \brief Mnemonic language related namespace.
|
||||
*/
|
||||
namespace Language
|
||||
{
|
||||
/*!
|
||||
* \brief Returns a string made of (at most) the first count characters in s.
|
||||
* Assumes well formedness. No check is made for this.
|
||||
* \param s The string from which to return the first count characters.
|
||||
* \param count How many characters to return.
|
||||
* \return A string consisting of the first count characters in s.
|
||||
*/
|
||||
inline std::string utf8prefix(const std::string &s, size_t count)
|
||||
{
|
||||
std::string prefix = "";
|
||||
const char *ptr = s.c_str();
|
||||
while (count-- && *ptr)
|
||||
{
|
||||
prefix += *ptr++;
|
||||
while (((*ptr) & 0xc0) == 0x80)
|
||||
prefix += *ptr++;
|
||||
}
|
||||
return prefix;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \class Base
|
||||
* \brief A base language class which all languages have to inherit from for
|
||||
* Polymorphism.
|
||||
*/
|
||||
class Base
|
||||
{
|
||||
protected:
|
||||
enum {
|
||||
ALLOW_SHORT_WORDS = 1<<0,
|
||||
ALLOW_DUPLICATE_PREFIXES = 1<<1,
|
||||
};
|
||||
const std::vector<std::string> word_list; /*!< A pointer to the array of words */
|
||||
std::unordered_map<std::string, uint32_t> word_map; /*!< hash table to find word's index */
|
||||
std::unordered_map<std::string, uint32_t> trimmed_word_map; /*!< hash table to find word's trimmed index */
|
||||
std::string language_name; /*!< Name of language */
|
||||
std::string english_language_name; /*!< Name of language */
|
||||
uint32_t unique_prefix_length; /*!< Number of unique starting characters to trim the wordlist to when matching */
|
||||
/*!
|
||||
* \brief Populates the word maps after the list is ready.
|
||||
*/
|
||||
void populate_maps(uint32_t flags = 0)
|
||||
{
|
||||
int ii;
|
||||
std::vector<std::string>::const_iterator it;
|
||||
if (word_list.size () != 1626)
|
||||
throw std::runtime_error("Wrong word list length for " + language_name);
|
||||
for (it = word_list.begin(), ii = 0; it != word_list.end(); it++, ii++)
|
||||
{
|
||||
word_map[*it] = ii;
|
||||
if ((*it).size() < unique_prefix_length)
|
||||
{
|
||||
if (flags & ALLOW_SHORT_WORDS)
|
||||
MWARNING(language_name << " word '" << *it << "' is shorter than its prefix length, " << unique_prefix_length);
|
||||
else
|
||||
throw std::runtime_error("Too short word in " + language_name + " word list: " + *it);
|
||||
}
|
||||
std::string trimmed;
|
||||
if (it->length() > unique_prefix_length)
|
||||
{
|
||||
trimmed = utf8prefix(*it, unique_prefix_length);
|
||||
}
|
||||
else
|
||||
{
|
||||
trimmed = *it;
|
||||
}
|
||||
if (trimmed_word_map.find(trimmed) != trimmed_word_map.end())
|
||||
{
|
||||
if (flags & ALLOW_DUPLICATE_PREFIXES)
|
||||
MWARNING("Duplicate prefix in " << language_name << " word list: " << trimmed);
|
||||
else
|
||||
throw std::runtime_error("Duplicate prefix in " + language_name + " word list: " + trimmed);
|
||||
}
|
||||
trimmed_word_map[trimmed] = ii;
|
||||
}
|
||||
}
|
||||
public:
|
||||
Base(const char *language_name, const char *english_language_name, const std::vector<std::string> &words, uint32_t prefix_length):
|
||||
word_list(words),
|
||||
unique_prefix_length(prefix_length),
|
||||
language_name(language_name),
|
||||
english_language_name(english_language_name)
|
||||
{
|
||||
}
|
||||
virtual ~Base()
|
||||
{
|
||||
}
|
||||
/*!
|
||||
* \brief Returns a pointer to the word list.
|
||||
* \return A pointer to the word list.
|
||||
*/
|
||||
const std::vector<std::string>& get_word_list() const
|
||||
{
|
||||
return word_list;
|
||||
}
|
||||
/*!
|
||||
* \brief Returns a pointer to the word map.
|
||||
* \return A pointer to the word map.
|
||||
*/
|
||||
const std::unordered_map<std::string, uint32_t>& get_word_map() const
|
||||
{
|
||||
return word_map;
|
||||
}
|
||||
/*!
|
||||
* \brief Returns a pointer to the trimmed word map.
|
||||
* \return A pointer to the trimmed word map.
|
||||
*/
|
||||
const std::unordered_map<std::string, uint32_t>& get_trimmed_word_map() const
|
||||
{
|
||||
return trimmed_word_map;
|
||||
}
|
||||
/*!
|
||||
* \brief Returns the name of the language.
|
||||
* \return Name of the language.
|
||||
*/
|
||||
const std::string &get_language_name() const
|
||||
{
|
||||
return language_name;
|
||||
}
|
||||
/*!
|
||||
* \brief Returns the name of the language in English.
|
||||
* \return Name of the language.
|
||||
*/
|
||||
const std::string &get_english_language_name() const
|
||||
{
|
||||
return english_language_name;
|
||||
}
|
||||
/*!
|
||||
* \brief Returns the number of unique starting characters to be used for matching.
|
||||
* \return Number of unique starting characters.
|
||||
*/
|
||||
uint32_t get_unique_prefix_length() const
|
||||
{
|
||||
return unique_prefix_length;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,62 @@
|
||||
// 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.
|
||||
|
||||
/*!
|
||||
* \file singleton.h
|
||||
*
|
||||
* \brief A singleton helper class based on template.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \namespace Language
|
||||
* \brief Mnemonic language related namespace.
|
||||
*/
|
||||
namespace Language
|
||||
{
|
||||
/*!
|
||||
* \class Singleton
|
||||
*
|
||||
* \brief Single helper class.
|
||||
*
|
||||
* Do Language::Singleton<YourClass>::instance() to create a singleton instance
|
||||
* of `YourClass`.
|
||||
*/
|
||||
template <class T>
|
||||
class Singleton
|
||||
{
|
||||
Singleton() {}
|
||||
Singleton(Singleton &s) {}
|
||||
Singleton& operator=(const Singleton&) {}
|
||||
public:
|
||||
static T* instance()
|
||||
{
|
||||
static T* obj = new T;
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,77 @@
|
||||
# Copyright (c) 2016-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.
|
||||
|
||||
set(ringct_basic_sources
|
||||
rctOps.cpp
|
||||
rctTypes.cpp
|
||||
rctCryptoOps.c
|
||||
bulletproofs.cc)
|
||||
|
||||
set(ringct_basic_private_headers
|
||||
rctOps.h
|
||||
rctTypes.h
|
||||
bulletproofs.h)
|
||||
|
||||
monero_private_headers(ringct_basic
|
||||
${crypto_private_headers})
|
||||
monero_add_library(ringct_basic
|
||||
${ringct_basic_sources}
|
||||
${ringct_basic_private_headers})
|
||||
target_link_libraries(ringct_basic
|
||||
PUBLIC
|
||||
common
|
||||
cncrypto
|
||||
PRIVATE
|
||||
${OPENSSL_LIBRARIES}
|
||||
${EXTRA_LIBRARIES})
|
||||
|
||||
set(ringct_sources
|
||||
rctSigs.cpp
|
||||
)
|
||||
|
||||
set(ringct_headers)
|
||||
|
||||
set(ringct_private_headers
|
||||
rctSigs.h
|
||||
)
|
||||
|
||||
monero_private_headers(ringct
|
||||
${crypto_private_headers})
|
||||
monero_add_library(ringct
|
||||
${ringct_sources}
|
||||
${ringct_headers}
|
||||
${ringct_private_headers})
|
||||
target_link_libraries(ringct
|
||||
PUBLIC
|
||||
common
|
||||
cncrypto
|
||||
cryptonote_basic
|
||||
device
|
||||
PRIVATE
|
||||
${OPENSSL_LIBRARIES}
|
||||
${EXTRA_LIBRARIES})
|
@ -0,0 +1,752 @@
|
||||
// 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.
|
||||
//
|
||||
// Adapted from Java code by Sarang Noether
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include "misc_log_ex.h"
|
||||
#include "common/perf_timer.h"
|
||||
extern "C"
|
||||
{
|
||||
#include "crypto/crypto-ops.h"
|
||||
}
|
||||
#include "rctOps.h"
|
||||
#include "bulletproofs.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "bulletproofs"
|
||||
|
||||
//#define DEBUG_BP
|
||||
|
||||
#define PERF_TIMER_START_BP(x) PERF_TIMER_START_UNIT(x, 1000000)
|
||||
|
||||
namespace rct
|
||||
{
|
||||
|
||||
static rct::key vector_exponent(const rct::keyV &a, const rct::keyV &b);
|
||||
static rct::keyV vector_powers(rct::key x, size_t n);
|
||||
static rct::key inner_product(const rct::keyV &a, const rct::keyV &b);
|
||||
|
||||
static constexpr size_t maxN = 64;
|
||||
static rct::key Hi[maxN], Gi[maxN];
|
||||
static ge_dsmp Gprecomp[64], Hprecomp[64];
|
||||
static const rct::key TWO = { {0x02, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 } };
|
||||
static const rct::keyV oneN = vector_powers(rct::identity(), maxN);
|
||||
static const rct::keyV twoN = vector_powers(TWO, maxN);
|
||||
static const rct::key ip12 = inner_product(oneN, twoN);
|
||||
static boost::mutex init_mutex;
|
||||
|
||||
static rct::key get_exponent(const rct::key &base, size_t idx)
|
||||
{
|
||||
static const std::string salt("bulletproof");
|
||||
std::string hashed = std::string((const char*)base.bytes, sizeof(base)) + salt + tools::get_varint_data(idx);
|
||||
return rct::hashToPoint(rct::hash2rct(crypto::cn_fast_hash(hashed.data(), hashed.size())));
|
||||
}
|
||||
|
||||
static void init_exponents()
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(init_mutex);
|
||||
|
||||
static bool init_done = false;
|
||||
if (init_done)
|
||||
return;
|
||||
for (size_t i = 0; i < maxN; ++i)
|
||||
{
|
||||
Hi[i] = get_exponent(rct::H, i * 2);
|
||||
rct::precomp(Hprecomp[i], Hi[i]);
|
||||
Gi[i] = get_exponent(rct::H, i * 2 + 1);
|
||||
rct::precomp(Gprecomp[i], Gi[i]);
|
||||
}
|
||||
init_done = true;
|
||||
}
|
||||
|
||||
/* Given two scalar arrays, construct a vector commitment */
|
||||
static rct::key vector_exponent(const rct::keyV &a, const rct::keyV &b)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(a.size() == b.size(), "Incompatible sizes of a and b");
|
||||
CHECK_AND_ASSERT_THROW_MES(a.size() <= maxN, "Incompatible sizes of a and maxN");
|
||||
rct::key res = rct::identity();
|
||||
for (size_t i = 0; i < a.size(); ++i)
|
||||
{
|
||||
rct::key term;
|
||||
rct::addKeys3(term, a[i], Gprecomp[i], b[i], Hprecomp[i]);
|
||||
rct::addKeys(res, res, term);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Compute a custom vector-scalar commitment */
|
||||
static rct::key vector_exponent_custom(const rct::keyV &A, const rct::keyV &B, const rct::keyV &a, const rct::keyV &b)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(A.size() == B.size(), "Incompatible sizes of A and B");
|
||||
CHECK_AND_ASSERT_THROW_MES(a.size() == b.size(), "Incompatible sizes of a and b");
|
||||
CHECK_AND_ASSERT_THROW_MES(a.size() == A.size(), "Incompatible sizes of a and A");
|
||||
CHECK_AND_ASSERT_THROW_MES(a.size() <= maxN, "Incompatible sizes of a and maxN");
|
||||
rct::key res = rct::identity();
|
||||
for (size_t i = 0; i < a.size(); ++i)
|
||||
{
|
||||
rct::key term;
|
||||
#if 0
|
||||
// we happen to know where A and B might fall, so don't bother checking the rest
|
||||
ge_dsmp *Acache = NULL, *Bcache = NULL;
|
||||
ge_dsmp Acache_custom[1], Bcache_custom[1];
|
||||
if (Gi[i] == A[i])
|
||||
Acache = Gprecomp + i;
|
||||
else if (i<32 && Gi[i+32] == A[i])
|
||||
Acache = Gprecomp + i + 32;
|
||||
else
|
||||
{
|
||||
rct::precomp(Acache_custom[0], A[i]);
|
||||
Acache = Acache_custom;
|
||||
}
|
||||
if (i == 0 && B[i] == Hi[0])
|
||||
Bcache = Hprecomp;
|
||||
else
|
||||
{
|
||||
rct::precomp(Bcache_custom[0], B[i]);
|
||||
Bcache = Bcache_custom;
|
||||
}
|
||||
rct::addKeys3(term, a[i], *Acache, b[i], *Bcache);
|
||||
#else
|
||||
ge_dsmp Acache, Bcache;
|
||||
rct::precomp(Bcache, B[i]);
|
||||
rct::addKeys3(term, a[i], A[i], b[i], Bcache);
|
||||
#endif
|
||||
rct::addKeys(res, res, term);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Given a scalar, construct a vector of powers */
|
||||
static rct::keyV vector_powers(rct::key x, size_t n)
|
||||
{
|
||||
rct::keyV res(n);
|
||||
if (n == 0)
|
||||
return res;
|
||||
res[0] = rct::identity();
|
||||
if (n == 1)
|
||||
return res;
|
||||
res[1] = x;
|
||||
for (size_t i = 2; i < n; ++i)
|
||||
{
|
||||
sc_mul(res[i].bytes, res[i-1].bytes, x.bytes);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Given two scalar arrays, construct the inner product */
|
||||
static rct::key inner_product(const rct::keyV &a, const rct::keyV &b)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(a.size() == b.size(), "Incompatible sizes of a and b");
|
||||
rct::key res = rct::zero();
|
||||
for (size_t i = 0; i < a.size(); ++i)
|
||||
{
|
||||
sc_muladd(res.bytes, a[i].bytes, b[i].bytes, res.bytes);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Given two scalar arrays, construct the Hadamard product */
|
||||
static rct::keyV hadamard(const rct::keyV &a, const rct::keyV &b)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(a.size() == b.size(), "Incompatible sizes of a and b");
|
||||
rct::keyV res(a.size());
|
||||
for (size_t i = 0; i < a.size(); ++i)
|
||||
{
|
||||
sc_mul(res[i].bytes, a[i].bytes, b[i].bytes);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Given two curvepoint arrays, construct the Hadamard product */
|
||||
static rct::keyV hadamard2(const rct::keyV &a, const rct::keyV &b)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(a.size() == b.size(), "Incompatible sizes of a and b");
|
||||
rct::keyV res(a.size());
|
||||
for (size_t i = 0; i < a.size(); ++i)
|
||||
{
|
||||
rct::addKeys(res[i], a[i], b[i]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Add two vectors */
|
||||
static rct::keyV vector_add(const rct::keyV &a, const rct::keyV &b)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(a.size() == b.size(), "Incompatible sizes of a and b");
|
||||
rct::keyV res(a.size());
|
||||
for (size_t i = 0; i < a.size(); ++i)
|
||||
{
|
||||
sc_add(res[i].bytes, a[i].bytes, b[i].bytes);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Subtract two vectors */
|
||||
static rct::keyV vector_subtract(const rct::keyV &a, const rct::keyV &b)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(a.size() == b.size(), "Incompatible sizes of a and b");
|
||||
rct::keyV res(a.size());
|
||||
for (size_t i = 0; i < a.size(); ++i)
|
||||
{
|
||||
sc_sub(res[i].bytes, a[i].bytes, b[i].bytes);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Multiply a scalar and a vector */
|
||||
static rct::keyV vector_scalar(const rct::keyV &a, const rct::key &x)
|
||||
{
|
||||
rct::keyV res(a.size());
|
||||
for (size_t i = 0; i < a.size(); ++i)
|
||||
{
|
||||
sc_mul(res[i].bytes, a[i].bytes, x.bytes);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Exponentiate a curve vector by a scalar */
|
||||
static rct::keyV vector_scalar2(const rct::keyV &a, const rct::key &x)
|
||||
{
|
||||
rct::keyV res(a.size());
|
||||
for (size_t i = 0; i < a.size(); ++i)
|
||||
{
|
||||
rct::scalarmultKey(res[i], a[i], x);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static rct::key switch_endianness(rct::key k)
|
||||
{
|
||||
std::reverse(k.bytes, k.bytes + sizeof(k));
|
||||
return k;
|
||||
}
|
||||
|
||||
/* Compute the inverse of a scalar, the stupid way */
|
||||
static rct::key invert(const rct::key &x)
|
||||
{
|
||||
rct::key inv;
|
||||
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BIGNUM *X = BN_new();
|
||||
BIGNUM *L = BN_new();
|
||||
BIGNUM *I = BN_new();
|
||||
|
||||
BN_bin2bn(switch_endianness(x).bytes, sizeof(rct::key), X);
|
||||
BN_bin2bn(switch_endianness(rct::curveOrder()).bytes, sizeof(rct::key), L);
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(BN_mod_inverse(I, X, L, ctx), "Failed to invert");
|
||||
|
||||
const int len = BN_num_bytes(I);
|
||||
CHECK_AND_ASSERT_THROW_MES((size_t)len <= sizeof(rct::key), "Invalid number length");
|
||||
inv = rct::zero();
|
||||
BN_bn2bin(I, inv.bytes);
|
||||
std::reverse(inv.bytes, inv.bytes + len);
|
||||
|
||||
BN_free(I);
|
||||
BN_free(L);
|
||||
BN_free(X);
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
#ifdef DEBUG_BP
|
||||
rct::key tmp;
|
||||
sc_mul(tmp.bytes, inv.bytes, x.bytes);
|
||||
CHECK_AND_ASSERT_THROW_MES(tmp == rct::identity(), "invert failed");
|
||||
#endif
|
||||
return inv;
|
||||
}
|
||||
|
||||
/* Compute the slice of a vector */
|
||||
static rct::keyV slice(const rct::keyV &a, size_t start, size_t stop)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(start < a.size(), "Invalid start index");
|
||||
CHECK_AND_ASSERT_THROW_MES(stop <= a.size(), "Invalid stop index");
|
||||
CHECK_AND_ASSERT_THROW_MES(start < stop, "Invalid start/stop indices");
|
||||
rct::keyV res(stop - start);
|
||||
for (size_t i = start; i < stop; ++i)
|
||||
{
|
||||
res[i - start] = a[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static rct::key hash_cache_mash(rct::key &hash_cache, const rct::key &mash0, const rct::key &mash1)
|
||||
{
|
||||
rct::keyV data;
|
||||
data.reserve(3);
|
||||
data.push_back(hash_cache);
|
||||
data.push_back(mash0);
|
||||
data.push_back(mash1);
|
||||
return hash_cache = rct::hash_to_scalar(data);
|
||||
}
|
||||
|
||||
static rct::key hash_cache_mash(rct::key &hash_cache, const rct::key &mash0, const rct::key &mash1, const rct::key &mash2)
|
||||
{
|
||||
rct::keyV data;
|
||||
data.reserve(4);
|
||||
data.push_back(hash_cache);
|
||||
data.push_back(mash0);
|
||||
data.push_back(mash1);
|
||||
data.push_back(mash2);
|
||||
return hash_cache = rct::hash_to_scalar(data);
|
||||
}
|
||||
|
||||
static rct::key hash_cache_mash(rct::key &hash_cache, const rct::key &mash0, const rct::key &mash1, const rct::key &mash2, const rct::key &mash3)
|
||||
{
|
||||
rct::keyV data;
|
||||
data.reserve(5);
|
||||
data.push_back(hash_cache);
|
||||
data.push_back(mash0);
|
||||
data.push_back(mash1);
|
||||
data.push_back(mash2);
|
||||
data.push_back(mash3);
|
||||
return hash_cache = rct::hash_to_scalar(data);
|
||||
}
|
||||
|
||||
/* Given a value v (0..2^N-1) and a mask gamma, construct a range proof */
|
||||
Bulletproof bulletproof_PROVE(const rct::key &sv, const rct::key &gamma)
|
||||
{
|
||||
init_exponents();
|
||||
|
||||
PERF_TIMER_UNIT(PROVE, 1000000);
|
||||
|
||||
constexpr size_t logN = 6; // log2(64)
|
||||
constexpr size_t N = 1<<logN;
|
||||
|
||||
rct::key V;
|
||||
rct::keyV aL(N), aR(N);
|
||||
|
||||
PERF_TIMER_START_BP(PROVE_v);
|
||||
rct::addKeys2(V, gamma, sv, rct::H);
|
||||
PERF_TIMER_STOP(PROVE_v);
|
||||
|
||||
PERF_TIMER_START_BP(PROVE_aLaR);
|
||||
for (size_t i = N; i-- > 0; )
|
||||
{
|
||||
if (sv[i/8] & (((uint64_t)1)<<(i%8)))
|
||||
{
|
||||
aL[i] = rct::identity();
|
||||
}
|
||||
else
|
||||
{
|
||||
aL[i] = rct::zero();
|
||||
}
|
||||
sc_sub(aR[i].bytes, aL[i].bytes, rct::identity().bytes);
|
||||
}
|
||||
PERF_TIMER_STOP(PROVE_aLaR);
|
||||
|
||||
rct::key hash_cache = rct::hash_to_scalar(V);
|
||||
|
||||
// DEBUG: Test to ensure this recovers the value
|
||||
#ifdef DEBUG_BP
|
||||
uint64_t test_aL = 0, test_aR = 0;
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
{
|
||||
if (aL[i] == rct::identity())
|
||||
test_aL += ((uint64_t)1)<<i;
|
||||
if (aR[i] == rct::zero())
|
||||
test_aR += ((uint64_t)1)<<i;
|
||||
}
|
||||
uint64_t v_test = 0;
|
||||
for (int n = 0; n < 8; ++n) v_test |= (((uint64_t)sv[n]) << (8*n));
|
||||
CHECK_AND_ASSERT_THROW_MES(test_aL == v_test, "test_aL failed");
|
||||
CHECK_AND_ASSERT_THROW_MES(test_aR == v_test, "test_aR failed");
|
||||
#endif
|
||||
|
||||
PERF_TIMER_START_BP(PROVE_step1);
|
||||
// PAPER LINES 38-39
|
||||
rct::key alpha = rct::skGen();
|
||||
rct::key ve = vector_exponent(aL, aR);
|
||||
rct::key A;
|
||||
rct::addKeys(A, ve, rct::scalarmultBase(alpha));
|
||||
|
||||
// PAPER LINES 40-42
|
||||
rct::keyV sL = rct::skvGen(N), sR = rct::skvGen(N);
|
||||
rct::key rho = rct::skGen();
|
||||
ve = vector_exponent(sL, sR);
|
||||
rct::key S;
|
||||
rct::addKeys(S, ve, rct::scalarmultBase(rho));
|
||||
|
||||
// PAPER LINES 43-45
|
||||
rct::key y = hash_cache_mash(hash_cache, A, S);
|
||||
rct::key z = hash_cache = rct::hash_to_scalar(y);
|
||||
|
||||
// Polynomial construction before PAPER LINE 46
|
||||
rct::key t0 = rct::zero();
|
||||
rct::key t1 = rct::zero();
|
||||
rct::key t2 = rct::zero();
|
||||
|
||||
const auto yN = vector_powers(y, N);
|
||||
|
||||
rct::key ip1y = inner_product(oneN, yN);
|
||||
rct::key tmp;
|
||||
sc_muladd(t0.bytes, z.bytes, ip1y.bytes, t0.bytes);
|
||||
|
||||
rct::key zsq;
|
||||
sc_mul(zsq.bytes, z.bytes, z.bytes);
|
||||
sc_muladd(t0.bytes, zsq.bytes, sv.bytes, t0.bytes);
|
||||
|
||||
rct::key k = rct::zero();
|
||||
sc_mulsub(k.bytes, zsq.bytes, ip1y.bytes, k.bytes);
|
||||
|
||||
rct::key zcu;
|
||||
sc_mul(zcu.bytes, zsq.bytes, z.bytes);
|
||||
sc_mulsub(k.bytes, zcu.bytes, ip12.bytes, k.bytes);
|
||||
sc_add(t0.bytes, t0.bytes, k.bytes);
|
||||
|
||||
// DEBUG: Test the value of t0 has the correct form
|
||||
#ifdef DEBUG_BP
|
||||
rct::key test_t0 = rct::zero();
|
||||
rct::key iph = inner_product(aL, hadamard(aR, yN));
|
||||
sc_add(test_t0.bytes, test_t0.bytes, iph.bytes);
|
||||
rct::key ips = inner_product(vector_subtract(aL, aR), yN);
|
||||
sc_muladd(test_t0.bytes, z.bytes, ips.bytes, test_t0.bytes);
|
||||
rct::key ipt = inner_product(twoN, aL);
|
||||
sc_muladd(test_t0.bytes, zsq.bytes, ipt.bytes, test_t0.bytes);
|
||||
sc_add(test_t0.bytes, test_t0.bytes, k.bytes);
|
||||
CHECK_AND_ASSERT_THROW_MES(t0 == test_t0, "t0 check failed");
|
||||
#endif
|
||||
PERF_TIMER_STOP(PROVE_step1);
|
||||
|
||||
PERF_TIMER_START_BP(PROVE_step2);
|
||||
const auto HyNsR = hadamard(yN, sR);
|
||||
const auto vpIz = vector_scalar(oneN, z);
|
||||
const auto vp2zsq = vector_scalar(twoN, zsq);
|
||||
const auto aL_vpIz = vector_subtract(aL, vpIz);
|
||||
const auto aR_vpIz = vector_add(aR, vpIz);
|
||||
|
||||
rct::key ip1 = inner_product(aL_vpIz, HyNsR);
|
||||
sc_add(t1.bytes, t1.bytes, ip1.bytes);
|
||||
|
||||
rct::key ip2 = inner_product(sL, vector_add(hadamard(yN, aR_vpIz), vp2zsq));
|
||||
sc_add(t1.bytes, t1.bytes, ip2.bytes);
|
||||
|
||||
rct::key ip3 = inner_product(sL, HyNsR);
|
||||
sc_add(t2.bytes, t2.bytes, ip3.bytes);
|
||||
|
||||
// PAPER LINES 47-48
|
||||
rct::key tau1 = rct::skGen(), tau2 = rct::skGen();
|
||||
|
||||
rct::key T1 = rct::addKeys(rct::scalarmultKey(rct::H, t1), rct::scalarmultBase(tau1));
|
||||
rct::key T2 = rct::addKeys(rct::scalarmultKey(rct::H, t2), rct::scalarmultBase(tau2));
|
||||
|
||||
// PAPER LINES 49-51
|
||||
rct::key x = hash_cache_mash(hash_cache, z, T1, T2);
|
||||
|
||||
// PAPER LINES 52-53
|
||||
rct::key taux = rct::zero();
|
||||
sc_mul(taux.bytes, tau1.bytes, x.bytes);
|
||||
rct::key xsq;
|
||||
sc_mul(xsq.bytes, x.bytes, x.bytes);
|
||||
sc_muladd(taux.bytes, tau2.bytes, xsq.bytes, taux.bytes);
|
||||
sc_muladd(taux.bytes, gamma.bytes, zsq.bytes, taux.bytes);
|
||||
rct::key mu;
|
||||
sc_muladd(mu.bytes, x.bytes, rho.bytes, alpha.bytes);
|
||||
|
||||
// PAPER LINES 54-57
|
||||
rct::keyV l = vector_add(aL_vpIz, vector_scalar(sL, x));
|
||||
rct::keyV r = vector_add(hadamard(yN, vector_add(aR_vpIz, vector_scalar(sR, x))), vp2zsq);
|
||||
PERF_TIMER_STOP(PROVE_step2);
|
||||
|
||||
PERF_TIMER_START_BP(PROVE_step3);
|
||||
rct::key t = inner_product(l, r);
|
||||
|
||||
// DEBUG: Test if the l and r vectors match the polynomial forms
|
||||
#ifdef DEBUG_BP
|
||||
rct::key test_t;
|
||||
sc_muladd(test_t.bytes, t1.bytes, x.bytes, t0.bytes);
|
||||
sc_muladd(test_t.bytes, t2.bytes, xsq.bytes, test_t.bytes);
|
||||
CHECK_AND_ASSERT_THROW_MES(test_t == t, "test_t check failed");
|
||||
#endif
|
||||
|
||||
// PAPER LINES 32-33
|
||||
rct::key x_ip = hash_cache_mash(hash_cache, x, taux, mu, t);
|
||||
|
||||
// These are used in the inner product rounds
|
||||
size_t nprime = N;
|
||||
rct::keyV Gprime(N);
|
||||
rct::keyV Hprime(N);
|
||||
rct::keyV aprime(N);
|
||||
rct::keyV bprime(N);
|
||||
const rct::key yinv = invert(y);
|
||||
rct::key yinvpow = rct::identity();
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
{
|
||||
Gprime[i] = Gi[i];
|
||||
Hprime[i] = scalarmultKey(Hi[i], yinvpow);
|
||||
sc_mul(yinvpow.bytes, yinvpow.bytes, yinv.bytes);
|
||||
aprime[i] = l[i];
|
||||
bprime[i] = r[i];
|
||||
}
|
||||
rct::keyV L(logN);
|
||||
rct::keyV R(logN);
|
||||
int round = 0;
|
||||
rct::keyV w(logN); // this is the challenge x in the inner product protocol
|
||||
PERF_TIMER_STOP(PROVE_step3);
|
||||
|
||||
PERF_TIMER_START_BP(PROVE_step4);
|
||||
// PAPER LINE 13
|
||||
while (nprime > 1)
|
||||
{
|
||||
// PAPER LINE 15
|
||||
nprime /= 2;
|
||||
|
||||
// PAPER LINES 16-17
|
||||
rct::key cL = inner_product(slice(aprime, 0, nprime), slice(bprime, nprime, bprime.size()));
|
||||
rct::key cR = inner_product(slice(aprime, nprime, aprime.size()), slice(bprime, 0, nprime));
|
||||
|
||||
// PAPER LINES 18-19
|
||||
L[round] = vector_exponent_custom(slice(Gprime, nprime, Gprime.size()), slice(Hprime, 0, nprime), slice(aprime, 0, nprime), slice(bprime, nprime, bprime.size()));
|
||||
sc_mul(tmp.bytes, cL.bytes, x_ip.bytes);
|
||||
rct::addKeys(L[round], L[round], rct::scalarmultKey(rct::H, tmp));
|
||||
R[round] = vector_exponent_custom(slice(Gprime, 0, nprime), slice(Hprime, nprime, Hprime.size()), slice(aprime, nprime, aprime.size()), slice(bprime, 0, nprime));
|
||||
sc_mul(tmp.bytes, cR.bytes, x_ip.bytes);
|
||||
rct::addKeys(R[round], R[round], rct::scalarmultKey(rct::H, tmp));
|
||||
|
||||
// PAPER LINES 21-22
|
||||
w[round] = hash_cache_mash(hash_cache, L[round], R[round]);
|
||||
|
||||
// PAPER LINES 24-25
|
||||
const rct::key winv = invert(w[round]);
|
||||
Gprime = hadamard2(vector_scalar2(slice(Gprime, 0, nprime), winv), vector_scalar2(slice(Gprime, nprime, Gprime.size()), w[round]));
|
||||
Hprime = hadamard2(vector_scalar2(slice(Hprime, 0, nprime), w[round]), vector_scalar2(slice(Hprime, nprime, Hprime.size()), winv));
|
||||
|
||||
// PAPER LINES 28-29
|
||||
aprime = vector_add(vector_scalar(slice(aprime, 0, nprime), w[round]), vector_scalar(slice(aprime, nprime, aprime.size()), winv));
|
||||
bprime = vector_add(vector_scalar(slice(bprime, 0, nprime), winv), vector_scalar(slice(bprime, nprime, bprime.size()), w[round]));
|
||||
|
||||
++round;
|
||||
}
|
||||
PERF_TIMER_STOP(PROVE_step4);
|
||||
|
||||
// PAPER LINE 58 (with inclusions from PAPER LINE 8 and PAPER LINE 20)
|
||||
return Bulletproof(V, A, S, T1, T2, taux, mu, L, R, aprime[0], bprime[0], t);
|
||||
}
|
||||
|
||||
Bulletproof bulletproof_PROVE(uint64_t v, const rct::key &gamma)
|
||||
{
|
||||
// vG + gammaH
|
||||
PERF_TIMER_START_BP(PROVE_v);
|
||||
rct::key sv = rct::zero();
|
||||
sv.bytes[0] = v & 255;
|
||||
sv.bytes[1] = (v >> 8) & 255;
|
||||
sv.bytes[2] = (v >> 16) & 255;
|
||||
sv.bytes[3] = (v >> 24) & 255;
|
||||
sv.bytes[4] = (v >> 32) & 255;
|
||||
sv.bytes[5] = (v >> 40) & 255;
|
||||
sv.bytes[6] = (v >> 48) & 255;
|
||||
sv.bytes[7] = (v >> 56) & 255;
|
||||
PERF_TIMER_STOP(PROVE_v);
|
||||
return bulletproof_PROVE(sv, gamma);
|
||||
}
|
||||
|
||||
/* Given a range proof, determine if it is valid */
|
||||
bool bulletproof_VERIFY(const Bulletproof &proof)
|
||||
{
|
||||
init_exponents();
|
||||
|
||||
CHECK_AND_ASSERT_MES(proof.V.size() == 1, false, "V does not have exactly one element");
|
||||
CHECK_AND_ASSERT_MES(proof.L.size() == proof.R.size(), false, "Mismatched L and R sizes");
|
||||
CHECK_AND_ASSERT_MES(proof.L.size() > 0, false, "Empty proof");
|
||||
CHECK_AND_ASSERT_MES(proof.L.size() == 6, false, "Proof is not for 64 bits");
|
||||
|
||||
const size_t logN = proof.L.size();
|
||||
const size_t N = 1 << logN;
|
||||
|
||||
// Reconstruct the challenges
|
||||
PERF_TIMER_START_BP(VERIFY);
|
||||
PERF_TIMER_START_BP(VERIFY_start);
|
||||
rct::key hash_cache = rct::hash_to_scalar(proof.V[0]);
|
||||
rct::key y = hash_cache_mash(hash_cache, proof.A, proof.S);
|
||||
rct::key z = hash_cache = rct::hash_to_scalar(y);
|
||||
rct::key x = hash_cache_mash(hash_cache, z, proof.T1, proof.T2);
|
||||
PERF_TIMER_STOP(VERIFY_start);
|
||||
|
||||
PERF_TIMER_START_BP(VERIFY_line_60);
|
||||
// Reconstruct the challenges
|
||||
rct::key x_ip = hash_cache_mash(hash_cache, x, proof.taux, proof.mu, proof.t);
|
||||
PERF_TIMER_STOP(VERIFY_line_60);
|
||||
|
||||
PERF_TIMER_START_BP(VERIFY_line_61);
|
||||
// PAPER LINE 61
|
||||
rct::key L61Left = rct::addKeys(rct::scalarmultBase(proof.taux), rct::scalarmultKey(rct::H, proof.t));
|
||||
|
||||
rct::key k = rct::zero();
|
||||
const auto yN = vector_powers(y, N);
|
||||
rct::key ip1y = inner_product(oneN, yN);
|
||||
rct::key zsq;
|
||||
sc_mul(zsq.bytes, z.bytes, z.bytes);
|
||||
rct::key tmp, tmp2;
|
||||
sc_mulsub(k.bytes, zsq.bytes, ip1y.bytes, k.bytes);
|
||||
rct::key zcu;
|
||||
sc_mul(zcu.bytes, zsq.bytes, z.bytes);
|
||||
sc_mulsub(k.bytes, zcu.bytes, ip12.bytes, k.bytes);
|
||||
PERF_TIMER_STOP(VERIFY_line_61);
|
||||
|
||||
PERF_TIMER_START_BP(VERIFY_line_61rl);
|
||||
sc_muladd(tmp.bytes, z.bytes, ip1y.bytes, k.bytes);
|
||||
rct::key L61Right = rct::scalarmultKey(rct::H, tmp);
|
||||
|
||||
CHECK_AND_ASSERT_MES(proof.V.size() == 1, false, "proof.V does not have exactly one element");
|
||||
tmp = rct::scalarmultKey(proof.V[0], zsq);
|
||||
rct::addKeys(L61Right, L61Right, tmp);
|
||||
|
||||
tmp = rct::scalarmultKey(proof.T1, x);
|
||||
rct::addKeys(L61Right, L61Right, tmp);
|
||||
|
||||
rct::key xsq;
|
||||
sc_mul(xsq.bytes, x.bytes, x.bytes);
|
||||
tmp = rct::scalarmultKey(proof.T2, xsq);
|
||||
rct::addKeys(L61Right, L61Right, tmp);
|
||||
PERF_TIMER_STOP(VERIFY_line_61rl);
|
||||
|
||||
if (!(L61Right == L61Left))
|
||||
{
|
||||
MERROR("Verification failure at step 1");
|
||||
return false;
|
||||
}
|
||||
|
||||
PERF_TIMER_START_BP(VERIFY_line_62);
|
||||
// PAPER LINE 62
|
||||
rct::key P = rct::addKeys(proof.A, rct::scalarmultKey(proof.S, x));
|
||||
PERF_TIMER_STOP(VERIFY_line_62);
|
||||
|
||||
// Compute the number of rounds for the inner product
|
||||
const size_t rounds = proof.L.size();
|
||||
CHECK_AND_ASSERT_MES(rounds > 0, false, "Zero rounds");
|
||||
|
||||
PERF_TIMER_START_BP(VERIFY_line_21_22);
|
||||
// PAPER LINES 21-22
|
||||
// The inner product challenges are computed per round
|
||||
rct::keyV w(rounds);
|
||||
for (size_t i = 0; i < rounds; ++i)
|
||||
{
|
||||
w[i] = hash_cache_mash(hash_cache, proof.L[i], proof.R[i]);
|
||||
}
|
||||
PERF_TIMER_STOP(VERIFY_line_21_22);
|
||||
|
||||
PERF_TIMER_START_BP(VERIFY_line_24_25);
|
||||
// Basically PAPER LINES 24-25
|
||||
// Compute the curvepoints from G[i] and H[i]
|
||||
rct::key inner_prod = rct::identity();
|
||||
rct::key yinvpow = rct::identity();
|
||||
rct::key ypow = rct::identity();
|
||||
|
||||
PERF_TIMER_START_BP(VERIFY_line_24_25_invert);
|
||||
const rct::key yinv = invert(y);
|
||||
rct::keyV winv(rounds);
|
||||
for (size_t i = 0; i < rounds; ++i)
|
||||
winv[i] = invert(w[i]);
|
||||
PERF_TIMER_STOP(VERIFY_line_24_25_invert);
|
||||
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
{
|
||||
// Convert the index to binary IN REVERSE and construct the scalar exponent
|
||||
rct::key g_scalar = proof.a;
|
||||
rct::key h_scalar;
|
||||
sc_mul(h_scalar.bytes, proof.b.bytes, yinvpow.bytes);
|
||||
|
||||
for (size_t j = rounds; j-- > 0; )
|
||||
{
|
||||
size_t J = w.size() - j - 1;
|
||||
|
||||
if ((i & (((size_t)1)<<j)) == 0)
|
||||
{
|
||||
sc_mul(g_scalar.bytes, g_scalar.bytes, winv[J].bytes);
|
||||
sc_mul(h_scalar.bytes, h_scalar.bytes, w[J].bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc_mul(g_scalar.bytes, g_scalar.bytes, w[J].bytes);
|
||||
sc_mul(h_scalar.bytes, h_scalar.bytes, winv[J].bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust the scalars using the exponents from PAPER LINE 62
|
||||
sc_add(g_scalar.bytes, g_scalar.bytes, z.bytes);
|
||||
sc_mul(tmp.bytes, zsq.bytes, twoN[i].bytes);
|
||||
sc_muladd(tmp.bytes, z.bytes, ypow.bytes, tmp.bytes);
|
||||
sc_mulsub(h_scalar.bytes, tmp.bytes, yinvpow.bytes, h_scalar.bytes);
|
||||
|
||||
// Now compute the basepoint's scalar multiplication
|
||||
// Each of these could be written as a multiexp operation instead
|
||||
rct::addKeys3(tmp, g_scalar, Gprecomp[i], h_scalar, Hprecomp[i]);
|
||||
rct::addKeys(inner_prod, inner_prod, tmp);
|
||||
|
||||
if (i != N-1)
|
||||
{
|
||||
sc_mul(yinvpow.bytes, yinvpow.bytes, yinv.bytes);
|
||||
sc_mul(ypow.bytes, ypow.bytes, y.bytes);
|
||||
}
|
||||
}
|
||||
PERF_TIMER_STOP(VERIFY_line_24_25);
|
||||
|
||||
PERF_TIMER_START_BP(VERIFY_line_26);
|
||||
// PAPER LINE 26
|
||||
rct::key pprime;
|
||||
sc_sub(tmp.bytes, rct::zero().bytes, proof.mu.bytes);
|
||||
rct::addKeys(pprime, P, rct::scalarmultBase(tmp));
|
||||
|
||||
for (size_t i = 0; i < rounds; ++i)
|
||||
{
|
||||
sc_mul(tmp.bytes, w[i].bytes, w[i].bytes);
|
||||
sc_mul(tmp2.bytes, winv[i].bytes, winv[i].bytes);
|
||||
#if 1
|
||||
ge_dsmp cacheL, cacheR;
|
||||
rct::precomp(cacheL, proof.L[i]);
|
||||
rct::precomp(cacheR, proof.R[i]);
|
||||
rct::addKeys3(tmp, tmp, cacheL, tmp2, cacheR);
|
||||
rct::addKeys(pprime, pprime, tmp);
|
||||
#else
|
||||
rct::addKeys(pprime, pprime, rct::scalarmultKey(proof.L[i], tmp));
|
||||
rct::addKeys(pprime, pprime, rct::scalarmultKey(proof.R[i], tmp2));
|
||||
#endif
|
||||
}
|
||||
sc_mul(tmp.bytes, proof.t.bytes, x_ip.bytes);
|
||||
rct::addKeys(pprime, pprime, rct::scalarmultKey(rct::H, tmp));
|
||||
PERF_TIMER_STOP(VERIFY_line_26);
|
||||
|
||||
PERF_TIMER_START_BP(VERIFY_step2_check);
|
||||
sc_mul(tmp.bytes, proof.a.bytes, proof.b.bytes);
|
||||
sc_mul(tmp.bytes, tmp.bytes, x_ip.bytes);
|
||||
tmp = rct::scalarmultKey(rct::H, tmp);
|
||||
rct::addKeys(tmp, tmp, inner_prod);
|
||||
PERF_TIMER_STOP(VERIFY_step2_check);
|
||||
if (!(pprime == tmp))
|
||||
{
|
||||
MERROR("Verification failure at step 2");
|
||||
return false;
|
||||
}
|
||||
|
||||
PERF_TIMER_STOP(VERIFY);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
// 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.
|
||||
//
|
||||
// Adapted from Java code by Sarang Noether
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef BULLETPROOFS_H
|
||||
#define BULLETPROOFS_H
|
||||
|
||||
#include "rctTypes.h"
|
||||
|
||||
namespace rct
|
||||
{
|
||||
|
||||
Bulletproof bulletproof_PROVE(const rct::key &v, const rct::key &gamma);
|
||||
Bulletproof bulletproof_PROVE(uint64_t v, const rct::key &gamma);
|
||||
bool bulletproof_VERIFY(const Bulletproof &proof);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,221 @@
|
||||
// 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 <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "crypto/crypto-ops.h"
|
||||
|
||||
//DISABLE_VS_WARNINGS(4146 4244)
|
||||
|
||||
void sc_reduce32copy(unsigned char * scopy, const unsigned char *s) {
|
||||
int64_t s0 = 2097151 & load_3(s);
|
||||
int64_t s1 = 2097151 & (load_4(s + 2) >> 5);
|
||||
int64_t s2 = 2097151 & (load_3(s + 5) >> 2);
|
||||
int64_t s3 = 2097151 & (load_4(s + 7) >> 7);
|
||||
int64_t s4 = 2097151 & (load_4(s + 10) >> 4);
|
||||
int64_t s5 = 2097151 & (load_3(s + 13) >> 1);
|
||||
int64_t s6 = 2097151 & (load_4(s + 15) >> 6);
|
||||
int64_t s7 = 2097151 & (load_3(s + 18) >> 3);
|
||||
int64_t s8 = 2097151 & load_3(s + 21);
|
||||
int64_t s9 = 2097151 & (load_4(s + 23) >> 5);
|
||||
int64_t s10 = 2097151 & (load_3(s + 26) >> 2);
|
||||
int64_t s11 = (load_4(s + 28) >> 7);
|
||||
int64_t s12 = 0;
|
||||
int64_t carry0;
|
||||
int64_t carry1;
|
||||
int64_t carry2;
|
||||
int64_t carry3;
|
||||
int64_t carry4;
|
||||
int64_t carry5;
|
||||
int64_t carry6;
|
||||
int64_t carry7;
|
||||
int64_t carry8;
|
||||
int64_t carry9;
|
||||
int64_t carry10;
|
||||
int64_t carry11;
|
||||
|
||||
carry0 = (s0 + (1<<20)) >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1<<20)) >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1<<20)) >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1<<20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1<<20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1<<20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
|
||||
carry1 = (s1 + (1<<20)) >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1<<20)) >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1<<20)) >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1<<20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1<<20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1<<20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry11 = s11 >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
|
||||
scopy[0] = s0 >> 0;
|
||||
scopy[1] = s0 >> 8;
|
||||
scopy[2] = (s0 >> 16) | (s1 << 5);
|
||||
scopy[3] = s1 >> 3;
|
||||
scopy[4] = s1 >> 11;
|
||||
scopy[5] = (s1 >> 19) | (s2 << 2);
|
||||
scopy[6] = s2 >> 6;
|
||||
scopy[7] = (s2 >> 14) | (s3 << 7);
|
||||
scopy[8] = s3 >> 1;
|
||||
scopy[9] = s3 >> 9;
|
||||
scopy[10] = (s3 >> 17) | (s4 << 4);
|
||||
scopy[11] = s4 >> 4;
|
||||
scopy[12] = s4 >> 12;
|
||||
scopy[13] = (s4 >> 20) | (s5 << 1);
|
||||
scopy[14] = s5 >> 7;
|
||||
scopy[15] = (s5 >> 15) | (s6 << 6);
|
||||
scopy[16] = s6 >> 2;
|
||||
scopy[17] = s6 >> 10;
|
||||
scopy[18] = (s6 >> 18) | (s7 << 3);
|
||||
scopy[19] = s7 >> 5;
|
||||
scopy[20] = s7 >> 13;
|
||||
scopy[21] = s8 >> 0;
|
||||
scopy[22] = s8 >> 8;
|
||||
scopy[23] = (s8 >> 16) | (s9 << 5);
|
||||
scopy[24] = s9 >> 3;
|
||||
scopy[25] = s9 >> 11;
|
||||
scopy[26] = (s9 >> 19) | (s10 << 2);
|
||||
scopy[27] = s10 >> 6;
|
||||
scopy[28] = (s10 >> 14) | (s11 << 7);
|
||||
scopy[29] = s11 >> 1;
|
||||
scopy[30] = s11 >> 9;
|
||||
scopy[31] = s11 >> 17;
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
// 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
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include "crypto/crypto-ops.h"
|
||||
}
|
||||
|
||||
void sc_reduce32copy(unsigned char * scopy, const unsigned char *s);
|
@ -0,0 +1,458 @@
|
||||
// Copyright (c) 2016, Monero Research Labs
|
||||
//
|
||||
// Author: Shen Noether <shen.noether@gmx.com>
|
||||
//
|
||||
// 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 <boost/lexical_cast.hpp>
|
||||
#include "misc_log_ex.h"
|
||||
#include "rctOps.h"
|
||||
using namespace crypto;
|
||||
using namespace std;
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "ringct"
|
||||
|
||||
#define CHECK_AND_ASSERT_THROW_MES_L1(expr, message) {if(!(expr)) {MWARNING(message); throw std::runtime_error(message);}}
|
||||
|
||||
namespace rct {
|
||||
|
||||
//Various key initialization functions
|
||||
|
||||
//initializes a key matrix;
|
||||
//first parameter is rows,
|
||||
//second is columns
|
||||
keyM keyMInit(size_t rows, size_t cols) {
|
||||
keyM rv(cols);
|
||||
size_t i = 0;
|
||||
for (i = 0 ; i < cols ; i++) {
|
||||
rv[i] = keyV(rows);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//Various key generation functions
|
||||
|
||||
//generates a random scalar which can be used as a secret key or mask
|
||||
void skGen(key &sk) {
|
||||
sk = crypto::rand<key>();
|
||||
sc_reduce32(sk.bytes);
|
||||
}
|
||||
|
||||
//generates a random scalar which can be used as a secret key or mask
|
||||
key skGen() {
|
||||
key sk = crypto::rand<key>();
|
||||
sc_reduce32(sk.bytes);
|
||||
return sk;
|
||||
}
|
||||
|
||||
//Generates a vector of secret key
|
||||
//Mainly used in testing
|
||||
keyV skvGen(size_t rows ) {
|
||||
CHECK_AND_ASSERT_THROW_MES(rows > 0, "0 keys requested");
|
||||
keyV rv(rows);
|
||||
size_t i = 0;
|
||||
crypto::rand(rows * sizeof(key), (uint8_t*)&rv[0]);
|
||||
for (i = 0 ; i < rows ; i++) {
|
||||
sc_reduce32(rv[i].bytes);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
//generates a random curve point (for testing)
|
||||
key pkGen() {
|
||||
key sk = skGen();
|
||||
key pk = scalarmultBase(sk);
|
||||
return pk;
|
||||
}
|
||||
|
||||
//generates a random secret and corresponding public key
|
||||
void skpkGen(key &sk, key &pk) {
|
||||
skGen(sk);
|
||||
scalarmultBase(pk, sk);
|
||||
}
|
||||
|
||||
//generates a random secret and corresponding public key
|
||||
tuple<key, key> skpkGen() {
|
||||
key sk = skGen();
|
||||
key pk = scalarmultBase(sk);
|
||||
return make_tuple(sk, pk);
|
||||
}
|
||||
|
||||
//generates C =aG + bH from b, a is given..
|
||||
void genC(key & C, const key & a, xmr_amount amount) {
|
||||
key bH = scalarmultH(d2h(amount));
|
||||
addKeys1(C, a, bH);
|
||||
}
|
||||
|
||||
//generates a <secret , public> / Pedersen commitment to the amount
|
||||
tuple<ctkey, ctkey> ctskpkGen(xmr_amount amount) {
|
||||
ctkey sk, pk;
|
||||
skpkGen(sk.dest, pk.dest);
|
||||
skpkGen(sk.mask, pk.mask);
|
||||
key am = d2h(amount);
|
||||
key bH = scalarmultH(am);
|
||||
addKeys(pk.mask, pk.mask, bH);
|
||||
return make_tuple(sk, pk);
|
||||
}
|
||||
|
||||
|
||||
//generates a <secret , public> / Pedersen commitment but takes bH as input
|
||||
tuple<ctkey, ctkey> ctskpkGen(const key &bH) {
|
||||
ctkey sk, pk;
|
||||
skpkGen(sk.dest, pk.dest);
|
||||
skpkGen(sk.mask, pk.mask);
|
||||
addKeys(pk.mask, pk.mask, bH);
|
||||
return make_tuple(sk, pk);
|
||||
}
|
||||
|
||||
key zeroCommit(xmr_amount amount) {
|
||||
key am = d2h(amount);
|
||||
key bH = scalarmultH(am);
|
||||
return addKeys(G, bH);
|
||||
}
|
||||
|
||||
key commit(xmr_amount amount, const key &mask) {
|
||||
key c = scalarmultBase(mask);
|
||||
key am = d2h(amount);
|
||||
key bH = scalarmultH(am);
|
||||
addKeys(c, c, bH);
|
||||
return c;
|
||||
}
|
||||
|
||||
//generates a random uint long long (for testing)
|
||||
xmr_amount randXmrAmount(xmr_amount upperlimit) {
|
||||
return h2d(skGen()) % (upperlimit);
|
||||
}
|
||||
|
||||
//Scalar multiplications of curve points
|
||||
|
||||
//does a * G where a is a scalar and G is the curve basepoint
|
||||
void scalarmultBase(key &aG,const key &a) {
|
||||
ge_p3 point;
|
||||
sc_reduce32copy(aG.bytes, a.bytes); //do this beforehand!
|
||||
ge_scalarmult_base(&point, aG.bytes);
|
||||
ge_p3_tobytes(aG.bytes, &point);
|
||||
}
|
||||
|
||||
//does a * G where a is a scalar and G is the curve basepoint
|
||||
key scalarmultBase(const key & a) {
|
||||
ge_p3 point;
|
||||
key aG;
|
||||
sc_reduce32copy(aG.bytes, a.bytes); //do this beforehand
|
||||
ge_scalarmult_base(&point, aG.bytes);
|
||||
ge_p3_tobytes(aG.bytes, &point);
|
||||
return aG;
|
||||
}
|
||||
|
||||
//does a * P where a is a scalar and P is an arbitrary point
|
||||
void scalarmultKey(key & aP, const key &P, const key &a) {
|
||||
ge_p3 A;
|
||||
ge_p2 R;
|
||||
CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&A, P.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
|
||||
ge_scalarmult(&R, a.bytes, &A);
|
||||
ge_tobytes(aP.bytes, &R);
|
||||
}
|
||||
|
||||
//does a * P where a is a scalar and P is an arbitrary point
|
||||
key scalarmultKey(const key & P, const key & a) {
|
||||
ge_p3 A;
|
||||
ge_p2 R;
|
||||
CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&A, P.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
|
||||
ge_scalarmult(&R, a.bytes, &A);
|
||||
key aP;
|
||||
ge_tobytes(aP.bytes, &R);
|
||||
return aP;
|
||||
}
|
||||
|
||||
|
||||
//Computes aH where H= toPoint(cn_fast_hash(G)), G the basepoint
|
||||
key scalarmultH(const key & a) {
|
||||
ge_p3 A;
|
||||
ge_p2 R;
|
||||
CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&A, H.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
|
||||
ge_scalarmult(&R, a.bytes, &A);
|
||||
key aP;
|
||||
ge_tobytes(aP.bytes, &R);
|
||||
return aP;
|
||||
}
|
||||
|
||||
//Curve addition / subtractions
|
||||
|
||||
//for curve points: AB = A + B
|
||||
void addKeys(key &AB, const key &A, const key &B) {
|
||||
ge_p3 B2, A2;
|
||||
CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&B2, B.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
|
||||
CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&A2, A.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
|
||||
ge_cached tmp2;
|
||||
ge_p3_to_cached(&tmp2, &B2);
|
||||
ge_p1p1 tmp3;
|
||||
ge_add(&tmp3, &A2, &tmp2);
|
||||
ge_p1p1_to_p3(&A2, &tmp3);
|
||||
ge_p3_tobytes(AB.bytes, &A2);
|
||||
}
|
||||
|
||||
rct::key addKeys(const key &A, const key &B) {
|
||||
key k;
|
||||
addKeys(k, A, B);
|
||||
return k;
|
||||
}
|
||||
|
||||
//addKeys1
|
||||
//aGB = aG + B where a is a scalar, G is the basepoint, and B is a point
|
||||
void addKeys1(key &aGB, const key &a, const key & B) {
|
||||
key aG = scalarmultBase(a);
|
||||
addKeys(aGB, aG, B);
|
||||
}
|
||||
|
||||
//addKeys2
|
||||
//aGbB = aG + bB where a, b are scalars, G is the basepoint and B is a point
|
||||
void addKeys2(key &aGbB, const key &a, const key &b, const key & B) {
|
||||
ge_p2 rv;
|
||||
ge_p3 B2;
|
||||
CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&B2, B.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
|
||||
ge_double_scalarmult_base_vartime(&rv, b.bytes, &B2, a.bytes);
|
||||
ge_tobytes(aGbB.bytes, &rv);
|
||||
}
|
||||
|
||||
//Does some precomputation to make addKeys3 more efficient
|
||||
// input B a curve point and output a ge_dsmp which has precomputation applied
|
||||
void precomp(ge_dsmp rv, const key & B) {
|
||||
ge_p3 B2;
|
||||
CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&B2, B.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
|
||||
ge_dsm_precomp(rv, &B2);
|
||||
}
|
||||
|
||||
//addKeys3
|
||||
//aAbB = a*A + b*B where a, b are scalars, A, B are curve points
|
||||
//B must be input after applying "precomp"
|
||||
void addKeys3(key &aAbB, const key &a, const key &A, const key &b, const ge_dsmp B) {
|
||||
ge_p2 rv;
|
||||
ge_p3 A2;
|
||||
CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&A2, A.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
|
||||
ge_double_scalarmult_precomp_vartime(&rv, a.bytes, &A2, b.bytes, B);
|
||||
ge_tobytes(aAbB.bytes, &rv);
|
||||
}
|
||||
|
||||
//addKeys3
|
||||
//aAbB = a*A + b*B where a, b are scalars, A, B are curve points
|
||||
//A and B must be input after applying "precomp"
|
||||
void addKeys3(key &aAbB, const key &a, const ge_dsmp A, const key &b, const ge_dsmp B) {
|
||||
ge_p2 rv;
|
||||
ge_double_scalarmult_precomp_vartime2(&rv, a.bytes, A, b.bytes, B);
|
||||
ge_tobytes(aAbB.bytes, &rv);
|
||||
}
|
||||
|
||||
|
||||
//subtract Keys (subtracts curve points)
|
||||
//AB = A - B where A, B are curve points
|
||||
void subKeys(key & AB, const key &A, const key &B) {
|
||||
ge_p3 B2, A2;
|
||||
CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&B2, B.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
|
||||
CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&A2, A.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
|
||||
ge_cached tmp2;
|
||||
ge_p3_to_cached(&tmp2, &B2);
|
||||
ge_p1p1 tmp3;
|
||||
ge_sub(&tmp3, &A2, &tmp2);
|
||||
ge_p1p1_to_p3(&A2, &tmp3);
|
||||
ge_p3_tobytes(AB.bytes, &A2);
|
||||
}
|
||||
|
||||
//checks if A, B are equal in terms of bytes (may say no if one is a non-reduced scalar)
|
||||
//without doing curve operations
|
||||
bool equalKeys(const key & a, const key & b) {
|
||||
bool rv = true;
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
if (a.bytes[i] != b.bytes[i]) {
|
||||
rv = false;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
//Hashing - cn_fast_hash
|
||||
//be careful these are also in crypto namespace
|
||||
//cn_fast_hash for arbitrary multiples of 32 bytes
|
||||
void cn_fast_hash(key &hash, const void * data, const std::size_t l) {
|
||||
keccak((const uint8_t *)data, l, hash.bytes, 32);
|
||||
}
|
||||
|
||||
void hash_to_scalar(key &hash, const void * data, const std::size_t l) {
|
||||
cn_fast_hash(hash, data, l);
|
||||
sc_reduce32(hash.bytes);
|
||||
}
|
||||
|
||||
//cn_fast_hash for a 32 byte key
|
||||
void cn_fast_hash(key & hash, const key & in) {
|
||||
keccak((const uint8_t *)in.bytes, 32, hash.bytes, 32);
|
||||
}
|
||||
|
||||
void hash_to_scalar(key & hash, const key & in) {
|
||||
cn_fast_hash(hash, in);
|
||||
sc_reduce32(hash.bytes);
|
||||
}
|
||||
|
||||
//cn_fast_hash for a 32 byte key
|
||||
key cn_fast_hash(const key & in) {
|
||||
key hash;
|
||||
keccak((const uint8_t *)in.bytes, 32, hash.bytes, 32);
|
||||
return hash;
|
||||
}
|
||||
|
||||
key hash_to_scalar(const key & in) {
|
||||
key hash = cn_fast_hash(in);
|
||||
sc_reduce32(hash.bytes);
|
||||
return hash;
|
||||
}
|
||||
|
||||
//cn_fast_hash for a 128 byte unsigned char
|
||||
key cn_fast_hash128(const void * in) {
|
||||
key hash;
|
||||
keccak((const uint8_t *)in, 128, hash.bytes, 32);
|
||||
return hash;
|
||||
}
|
||||
|
||||
key hash_to_scalar128(const void * in) {
|
||||
key hash = cn_fast_hash128(in);
|
||||
sc_reduce32(hash.bytes);
|
||||
return hash;
|
||||
}
|
||||
|
||||
//cn_fast_hash for multisig purpose
|
||||
//This takes the outputs and commitments
|
||||
//and hashes them into a 32 byte sized key
|
||||
key cn_fast_hash(const ctkeyV &PC) {
|
||||
if (PC.empty()) return rct::hash2rct(crypto::cn_fast_hash("", 0));
|
||||
key rv;
|
||||
cn_fast_hash(rv, &PC[0], 64*PC.size());
|
||||
return rv;
|
||||
}
|
||||
|
||||
key hash_to_scalar(const ctkeyV &PC) {
|
||||
key rv = cn_fast_hash(PC);
|
||||
sc_reduce32(rv.bytes);
|
||||
return rv;
|
||||
}
|
||||
|
||||
//cn_fast_hash for a key-vector of arbitrary length
|
||||
//this is useful since you take a number of keys
|
||||
//put them in the key vector and it concatenates them
|
||||
//and then hashes them
|
||||
key cn_fast_hash(const keyV &keys) {
|
||||
if (keys.empty()) return rct::hash2rct(crypto::cn_fast_hash("", 0));
|
||||
key rv;
|
||||
cn_fast_hash(rv, &keys[0], keys.size() * sizeof(keys[0]));
|
||||
//dp(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
key hash_to_scalar(const keyV &keys) {
|
||||
key rv = cn_fast_hash(keys);
|
||||
sc_reduce32(rv.bytes);
|
||||
return rv;
|
||||
}
|
||||
|
||||
key cn_fast_hash(const key64 keys) {
|
||||
key rv;
|
||||
cn_fast_hash(rv, &keys[0], 64 * sizeof(keys[0]));
|
||||
//dp(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
key hash_to_scalar(const key64 keys) {
|
||||
key rv = cn_fast_hash(keys);
|
||||
sc_reduce32(rv.bytes);
|
||||
return rv;
|
||||
}
|
||||
|
||||
key hashToPointSimple(const key & hh) {
|
||||
key pointk;
|
||||
ge_p1p1 point2;
|
||||
ge_p2 point;
|
||||
ge_p3 res;
|
||||
key h = cn_fast_hash(hh);
|
||||
CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&res, h.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
|
||||
ge_p3_to_p2(&point, &res);
|
||||
ge_mul8(&point2, &point);
|
||||
ge_p1p1_to_p3(&res, &point2);
|
||||
ge_p3_tobytes(pointk.bytes, &res);
|
||||
return pointk;
|
||||
}
|
||||
|
||||
key hashToPoint(const key & hh) {
|
||||
key pointk;
|
||||
ge_p2 point;
|
||||
ge_p1p1 point2;
|
||||
ge_p3 res;
|
||||
key h = cn_fast_hash(hh);
|
||||
ge_fromfe_frombytes_vartime(&point, h.bytes);
|
||||
ge_mul8(&point2, &point);
|
||||
ge_p1p1_to_p3(&res, &point2);
|
||||
ge_p3_tobytes(pointk.bytes, &res);
|
||||
return pointk;
|
||||
}
|
||||
|
||||
void hashToPoint(key & pointk, const key & hh) {
|
||||
ge_p2 point;
|
||||
ge_p1p1 point2;
|
||||
ge_p3 res;
|
||||
key h = cn_fast_hash(hh);
|
||||
ge_fromfe_frombytes_vartime(&point, h.bytes);
|
||||
ge_mul8(&point2, &point);
|
||||
ge_p1p1_to_p3(&res, &point2);
|
||||
ge_p3_tobytes(pointk.bytes, &res);
|
||||
}
|
||||
|
||||
//sums a vector of curve points (for scalars use sc_add)
|
||||
void sumKeys(key & Csum, const keyV & Cis) {
|
||||
identity(Csum);
|
||||
size_t i = 0;
|
||||
for (i = 0; i < Cis.size(); i++) {
|
||||
addKeys(Csum, Csum, Cis[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//Elliptic Curve Diffie Helman: encodes and decodes the amount b and mask a
|
||||
// where C= aG + bH
|
||||
void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec) {
|
||||
key sharedSec1 = hash_to_scalar(sharedSec);
|
||||
key sharedSec2 = hash_to_scalar(sharedSec1);
|
||||
//encode
|
||||
sc_add(unmasked.mask.bytes, unmasked.mask.bytes, sharedSec1.bytes);
|
||||
sc_add(unmasked.amount.bytes, unmasked.amount.bytes, sharedSec2.bytes);
|
||||
}
|
||||
void ecdhDecode(ecdhTuple & masked, const key & sharedSec) {
|
||||
key sharedSec1 = hash_to_scalar(sharedSec);
|
||||
key sharedSec2 = hash_to_scalar(sharedSec1);
|
||||
//decode
|
||||
sc_sub(masked.mask.bytes, masked.mask.bytes, sharedSec1.bytes);
|
||||
sc_sub(masked.amount.bytes, masked.amount.bytes, sharedSec2.bytes);
|
||||
}
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
//#define DBG
|
||||
// Copyright (c) 2016, Monero Research Labs
|
||||
//
|
||||
// Author: Shen Noether <shen.noether@gmx.com>
|
||||
//
|
||||
// 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
|
||||
|
||||
#ifndef RCTOPS_H
|
||||
#define RCTOPS_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <tuple>
|
||||
|
||||
#include "crypto/generic-ops.h"
|
||||
|
||||
extern "C" {
|
||||
#include "crypto/random.h"
|
||||
#include "crypto/keccak.h"
|
||||
#include "rctCryptoOps.h"
|
||||
}
|
||||
#include "crypto/crypto.h"
|
||||
|
||||
#include "rctTypes.h"
|
||||
|
||||
//Define this flag when debugging to get additional info on the console
|
||||
#ifdef DBG
|
||||
#define DP(x) dp(x)
|
||||
#else
|
||||
#define DP(x)
|
||||
#endif
|
||||
|
||||
namespace rct {
|
||||
|
||||
//Various key initialization functions
|
||||
|
||||
static const key Z = { {0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 } };
|
||||
static const key I = { {0x01, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 } };
|
||||
static const key L = { {0xed, 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 } };
|
||||
static const key G = { {0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 } };
|
||||
|
||||
//Creates a zero scalar
|
||||
inline key zero() { return Z; }
|
||||
inline void zero(key &z) { memset(&z, 0, 32); }
|
||||
//Creates a zero elliptic curve point
|
||||
inline key identity() { return I; }
|
||||
inline void identity(key &Id) { memcpy(&Id, &I, 32); }
|
||||
//Creates a key equal to the curve order
|
||||
inline key curveOrder() { return L; }
|
||||
inline void curveOrder(key &l) { l = L; }
|
||||
//copies a scalar or point
|
||||
inline void copy(key &AA, const key &A) { memcpy(&AA, &A, 32); }
|
||||
inline key copy(const key & A) { key AA; memcpy(&AA, &A, 32); return AA; }
|
||||
|
||||
//initializes a key matrix;
|
||||
//first parameter is rows,
|
||||
//second is columns
|
||||
keyM keyMInit(size_t rows, size_t cols);
|
||||
|
||||
//Various key generation functions
|
||||
|
||||
//generates a random scalar which can be used as a secret key or mask
|
||||
key skGen();
|
||||
void skGen(key &);
|
||||
|
||||
//generates a vector of secret keys of size "int"
|
||||
keyV skvGen(size_t rows );
|
||||
|
||||
//generates a random curve point (for testing)
|
||||
key pkGen();
|
||||
//generates a random secret and corresponding public key
|
||||
void skpkGen(key &sk, key &pk);
|
||||
std::tuple<key, key> skpkGen();
|
||||
//generates a <secret , public> / Pedersen commitment to the amount
|
||||
std::tuple<ctkey, ctkey> ctskpkGen(xmr_amount amount);
|
||||
//generates C =aG + bH from b, a is random
|
||||
void genC(key & C, const key & a, xmr_amount amount);
|
||||
//this one is mainly for testing, can take arbitrary amounts..
|
||||
std::tuple<ctkey, ctkey> ctskpkGen(const key &bH);
|
||||
// make a pedersen commitment with given key
|
||||
key commit(xmr_amount amount, const key &mask);
|
||||
// make a pedersen commitment with zero key
|
||||
key zeroCommit(xmr_amount amount);
|
||||
//generates a random uint long long
|
||||
xmr_amount randXmrAmount(xmr_amount upperlimit);
|
||||
|
||||
//Scalar multiplications of curve points
|
||||
|
||||
//does a * G where a is a scalar and G is the curve basepoint
|
||||
void scalarmultBase(key & aG, const key &a);
|
||||
key scalarmultBase(const key & a);
|
||||
//does a * P where a is a scalar and P is an arbitrary point
|
||||
void scalarmultKey(key &aP, const key &P, const key &a);
|
||||
key scalarmultKey(const key &P, const key &a);
|
||||
//Computes aH where H= toPoint(cn_fast_hash(G)), G the basepoint
|
||||
key scalarmultH(const key & a);
|
||||
|
||||
//Curve addition / subtractions
|
||||
|
||||
//for curve points: AB = A + B
|
||||
void addKeys(key &AB, const key &A, const key &B);
|
||||
rct::key addKeys(const key &A, const key &B);
|
||||
//aGB = aG + B where a is a scalar, G is the basepoint, and B is a point
|
||||
void addKeys1(key &aGB, const key &a, const key & B);
|
||||
//aGbB = aG + bB where a, b are scalars, G is the basepoint and B is a point
|
||||
void addKeys2(key &aGbB, const key &a, const key &b, const key &B);
|
||||
//Does some precomputation to make addKeys3 more efficient
|
||||
// input B a curve point and output a ge_dsmp which has precomputation applied
|
||||
void precomp(ge_dsmp rv, const key &B);
|
||||
//aAbB = a*A + b*B where a, b are scalars, A, B are curve points
|
||||
//B must be input after applying "precomp"
|
||||
void addKeys3(key &aAbB, const key &a, const key &A, const key &b, const ge_dsmp B);
|
||||
void addKeys3(key &aAbB, const key &a, const ge_dsmp A, const key &b, const ge_dsmp B);
|
||||
//AB = A - B where A, B are curve points
|
||||
void subKeys(key &AB, const key &A, const key &B);
|
||||
//checks if A, B are equal as curve points
|
||||
bool equalKeys(const key & A, const key & B);
|
||||
|
||||
//Hashing - cn_fast_hash
|
||||
//be careful these are also in crypto namespace
|
||||
//cn_fast_hash for arbitrary l multiples of 32 bytes
|
||||
void cn_fast_hash(key &hash, const void * data, const size_t l);
|
||||
void hash_to_scalar(key &hash, const void * data, const size_t l);
|
||||
//cn_fast_hash for a 32 byte key
|
||||
void cn_fast_hash(key &hash, const key &in);
|
||||
void hash_to_scalar(key &hash, const key &in);
|
||||
//cn_fast_hash for a 32 byte key
|
||||
key cn_fast_hash(const key &in);
|
||||
key hash_to_scalar(const key &in);
|
||||
//for mg sigs
|
||||
key cn_fast_hash128(const void * in);
|
||||
key hash_to_scalar128(const void * in);
|
||||
key cn_fast_hash(const ctkeyV &PC);
|
||||
key hash_to_scalar(const ctkeyV &PC);
|
||||
//for mg sigs
|
||||
key cn_fast_hash(const keyV &keys);
|
||||
key hash_to_scalar(const keyV &keys);
|
||||
//for ANSL
|
||||
key cn_fast_hash(const key64 keys);
|
||||
key hash_to_scalar(const key64 keys);
|
||||
|
||||
//returns hashToPoint as described in https://github.com/ShenNoether/ge_fromfe_writeup
|
||||
key hashToPointSimple(const key &in);
|
||||
key hashToPoint(const key &in);
|
||||
void hashToPoint(key &out, const key &in);
|
||||
|
||||
//sums a vector of curve points (for scalars use sc_add)
|
||||
void sumKeys(key & Csum, const key &Cis);
|
||||
|
||||
//Elliptic Curve Diffie Helman: encodes and decodes the amount b and mask a
|
||||
// where C= aG + bH
|
||||
void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec);
|
||||
void ecdhDecode(ecdhTuple & masked, const key & sharedSec);
|
||||
}
|
||||
#endif /* RCTOPS_H */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,138 @@
|
||||
// Copyright (c) 2016, Monero Research Labs
|
||||
//
|
||||
// Author: Shen Noether <shen.noether@gmx.com>
|
||||
//
|
||||
// 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
|
||||
|
||||
//#define DBG
|
||||
|
||||
#ifndef RCTSIGS_H
|
||||
#define RCTSIGS_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
#include "crypto/generic-ops.h"
|
||||
|
||||
extern "C" {
|
||||
#include "crypto/random.h"
|
||||
#include "crypto/keccak.h"
|
||||
}
|
||||
#include "crypto/crypto.h"
|
||||
|
||||
|
||||
#include "rctTypes.h"
|
||||
#include "rctOps.h"
|
||||
|
||||
//Define this flag when debugging to get additional info on the console
|
||||
#ifdef DBG
|
||||
#define DP(x) dp(x)
|
||||
#else
|
||||
#define DP(x)
|
||||
#endif
|
||||
|
||||
namespace hw {
|
||||
class device;
|
||||
}
|
||||
|
||||
|
||||
namespace rct {
|
||||
|
||||
boroSig genBorromean(const key64 x, const key64 P1, const key64 P2, const bits indices);
|
||||
bool verifyBorromean(const boroSig &bb, const key64 P1, const key64 P2);
|
||||
|
||||
//Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures)
|
||||
//These are aka MG signatutes in earlier drafts of the ring ct paper
|
||||
// c.f. https://eprint.iacr.org/2015/1098 section 2.
|
||||
// Gen creates a signature which proves that for some column in the keymatrix "pk"
|
||||
// the signer knows a secret key for each row in that column
|
||||
// Ver verifies that the MG sig was created correctly
|
||||
mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const multisig_kLRki *kLRki, key *mscout, const unsigned int index, size_t dsRows, hw::device &hwdev);
|
||||
bool MLSAG_Ver(const key &message, const keyM &pk, const mgSig &sig, size_t dsRows);
|
||||
//mgSig MLSAG_Gen_Old(const keyM & pk, const keyV & xx, const int index);
|
||||
|
||||
//proveRange and verRange
|
||||
//proveRange gives C, and mask such that \sumCi = C
|
||||
// c.f. https://eprint.iacr.org/2015/1098 section 5.1
|
||||
// and Ci is a commitment to either 0 or 2^i, i=0,...,63
|
||||
// thus this proves that "amount" is in [0, 2^64]
|
||||
// mask is a such that C = aG + bH, and b = amount
|
||||
//verRange verifies that \sum Ci = C and that each Ci is a commitment to 0 or 2^i
|
||||
rangeSig proveRange(key & C, key & mask, const xmr_amount & amount);
|
||||
bool verRange(const key & C, const rangeSig & as);
|
||||
|
||||
//Ring-ct MG sigs
|
||||
//Prove:
|
||||
// c.f. https://eprint.iacr.org/2015/1098 section 4. definition 10.
|
||||
// This does the MG sig on the "dest" part of the given key matrix, and
|
||||
// the last row is the sum of input commitments from that column - sum output commitments
|
||||
// this shows that sum inputs = sum outputs
|
||||
//Ver:
|
||||
// verifies the above sig is created corretly
|
||||
mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const keyV &outMasks, const ctkeyV & outPk, const multisig_kLRki *kLRki, key *mscout, unsigned int index, key txnFee, const key &message, hw::device &hwdev);
|
||||
mgSig proveRctMGSimple(const key & message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, const multisig_kLRki *kLRki, key *mscout, unsigned int index, hw::device &hwdev);
|
||||
bool verRctMG(const mgSig &mg, const ctkeyM & pubs, const ctkeyV & outPk, key txnFee, const key &message);
|
||||
bool verRctMGSimple(const key &message, const mgSig &mg, const ctkeyV & pubs, const key & C);
|
||||
|
||||
//These functions get keys from blockchain
|
||||
//replace these when connecting blockchain
|
||||
//getKeyFromBlockchain grabs a key from the blockchain at "reference_index" to mix with
|
||||
//populateFromBlockchain creates a keymatrix with "mixin" columns and one of the columns is inPk
|
||||
// the return value are the key matrix, and the index where inPk was put (random).
|
||||
void getKeyFromBlockchain(ctkey & a, size_t reference_index);
|
||||
std::tuple<ctkeyM, xmr_amount> populateFromBlockchain(ctkeyV inPk, int mixin);
|
||||
|
||||
//RingCT protocol
|
||||
//genRct:
|
||||
// creates an rctSig with all data necessary to verify the rangeProofs and that the signer owns one of the
|
||||
// columns that are claimed as inputs, and that the sum of inputs = sum of outputs.
|
||||
// Also contains masked "amount" and "mask" so the receiver can see how much they received
|
||||
//verRct:
|
||||
// verifies that all signatures (rangeProogs, MG sig, sum inputs = outputs) are correct
|
||||
//decodeRct: (c.f. https://eprint.iacr.org/2015/1098 section 5.1.1)
|
||||
// uses the attached ecdh info to find the amounts represented by each output commitment
|
||||
// must know the destination private key to find the correct amount, else will return a random number
|
||||
rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, bool bulletproof, hw::device &hwdev);
|
||||
rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, const int mixin, hw::device &hwdev);
|
||||
rctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector<xmr_amount> & inamounts, const std::vector<xmr_amount> & outamounts, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, xmr_amount txnFee, unsigned int mixin, hw::device &hwdev);
|
||||
rctSig genRctSimple(const key & message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & inamounts, const std::vector<xmr_amount> & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, bool bulletproof, hw::device &hwdev);
|
||||
bool verRct(const rctSig & rv, bool semantics);
|
||||
static inline bool verRct(const rctSig & rv) { return verRct(rv, true) && verRct(rv, false); }
|
||||
bool verRctSimple(const rctSig & rv, bool semantics);
|
||||
static inline bool verRctSimple(const rctSig & rv) { return verRctSimple(rv, true) && verRctSimple(rv, false); }
|
||||
xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask, hw::device &hwdev);
|
||||
xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, hw::device &hwdev);
|
||||
xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key & mask, hw::device &hwdev);
|
||||
xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, hw::device &hwdev);
|
||||
|
||||
bool signMultisig(rctSig &rv, const std::vector<unsigned int> &indices, const keyV &k, const multisig_out &msout, const key &secret_key);
|
||||
}
|
||||
#endif /* RCTSIGS_H */
|
||||
|
@ -0,0 +1,212 @@
|
||||
// Copyright (c) 2016, Monero Research Labs
|
||||
//
|
||||
// Author: Shen Noether <shen.noether@gmx.com>
|
||||
//
|
||||
// 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 "rctTypes.h"
|
||||
using namespace crypto;
|
||||
using namespace std;
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "ringct"
|
||||
|
||||
namespace rct {
|
||||
|
||||
//dp
|
||||
//Debug printing for the above types
|
||||
//Actually use DP(value) and #define DBG
|
||||
|
||||
void dp(key a) {
|
||||
int j = 0;
|
||||
printf("\"");
|
||||
for (j = 0; j < 32; j++) {
|
||||
printf("%02x", (unsigned char)a.bytes[j]);
|
||||
}
|
||||
printf("\"");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void dp(bool a) {
|
||||
printf(" ... %s ... ", a ? "true" : "false");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void dp(const char * a, int l) {
|
||||
int j = 0;
|
||||
printf("\"");
|
||||
for (j = 0; j < l; j++) {
|
||||
printf("%02x", (unsigned char)a[j]);
|
||||
}
|
||||
printf("\"");
|
||||
printf("\n");
|
||||
}
|
||||
void dp(keyV a) {
|
||||
size_t j = 0;
|
||||
printf("[");
|
||||
for (j = 0; j < a.size(); j++) {
|
||||
dp(a[j]);
|
||||
if (j < a.size() - 1) {
|
||||
printf(",");
|
||||
}
|
||||
}
|
||||
printf("]");
|
||||
printf("\n");
|
||||
}
|
||||
void dp(keyM a) {
|
||||
size_t j = 0;
|
||||
printf("[");
|
||||
for (j = 0; j < a.size(); j++) {
|
||||
dp(a[j]);
|
||||
if (j < a.size() - 1) {
|
||||
printf(",");
|
||||
}
|
||||
}
|
||||
printf("]");
|
||||
printf("\n");
|
||||
}
|
||||
void dp(xmr_amount vali) {
|
||||
printf("x: ");
|
||||
std::cout << vali;
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
void dp(int vali) {
|
||||
printf("x: %d\n", vali);
|
||||
printf("\n");
|
||||
}
|
||||
void dp(bits amountb) {
|
||||
for (int i = 0; i < 64; i++) {
|
||||
printf("%d", amountb[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
}
|
||||
|
||||
void dp(const char * st) {
|
||||
printf("%s\n", st);
|
||||
}
|
||||
|
||||
//Various Conversions
|
||||
|
||||
//uint long long to 32 byte key
|
||||
void d2h(key & amounth, const xmr_amount in) {
|
||||
sc_0(amounth.bytes);
|
||||
xmr_amount val = in;
|
||||
int i = 0;
|
||||
while (val != 0) {
|
||||
amounth[i] = (unsigned char)(val & 0xFF);
|
||||
i++;
|
||||
val /= (xmr_amount)256;
|
||||
}
|
||||
}
|
||||
|
||||
//uint long long to 32 byte key
|
||||
key d2h(const xmr_amount in) {
|
||||
key amounth;
|
||||
sc_0(amounth.bytes);
|
||||
xmr_amount val = in;
|
||||
int i = 0;
|
||||
while (val != 0) {
|
||||
amounth[i] = (unsigned char)(val & 0xFF);
|
||||
i++;
|
||||
val /= (xmr_amount)256;
|
||||
}
|
||||
return amounth;
|
||||
}
|
||||
|
||||
//uint long long to int[64]
|
||||
void d2b(bits amountb, xmr_amount val) {
|
||||
int i = 0;
|
||||
while (val != 0) {
|
||||
amountb[i] = val & 1;
|
||||
i++;
|
||||
val >>= 1;
|
||||
}
|
||||
while (i < 64) {
|
||||
amountb[i] = 0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
//32 byte key to uint long long
|
||||
// if the key holds a value > 2^64
|
||||
// then the value in the first 8 bytes is returned
|
||||
xmr_amount h2d(const key & test) {
|
||||
xmr_amount vali = 0;
|
||||
int j = 0;
|
||||
for (j = 7; j >= 0; j--) {
|
||||
vali = (xmr_amount)(vali * 256 + (unsigned char)test.bytes[j]);
|
||||
}
|
||||
return vali;
|
||||
}
|
||||
|
||||
//32 byte key to int[64]
|
||||
void h2b(bits amountb2, const key & test) {
|
||||
int val = 0, i = 0, j = 0;
|
||||
for (j = 0; j < 8; j++) {
|
||||
val = (unsigned char)test.bytes[j];
|
||||
i = 8 * j;
|
||||
while (val != 0) {
|
||||
amountb2[i] = val & 1;
|
||||
i++;
|
||||
val >>= 1;
|
||||
}
|
||||
while (i < 8 * (j + 1)) {
|
||||
amountb2[i] = 0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//int[64] to 32 byte key
|
||||
void b2h(key & amountdh, const bits amountb2) {
|
||||
int byte, i, j;
|
||||
for (j = 0; j < 8; j++) {
|
||||
byte = 0;
|
||||
i = 8 * j;
|
||||
for (i = 7; i > -1; i--) {
|
||||
byte = byte * 2 + amountb2[8 * j + i];
|
||||
}
|
||||
amountdh[j] = (unsigned char)byte;
|
||||
}
|
||||
for (j = 8; j < 32; j++) {
|
||||
amountdh[j] = (unsigned char)(0x00);
|
||||
}
|
||||
}
|
||||
|
||||
//int[64] to uint long long
|
||||
xmr_amount b2d(bits amountb) {
|
||||
xmr_amount vali = 0;
|
||||
int j = 0;
|
||||
for (j = 63; j >= 0; j--) {
|
||||
vali = (xmr_amount)(vali * 2 + amountb[j]);
|
||||
}
|
||||
return vali;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,595 @@
|
||||
// Copyright (c) 2016, Monero Research Labs
|
||||
//
|
||||
// Author: Shen Noether <shen.noether@gmx.com>
|
||||
//
|
||||
// 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
|
||||
#ifndef RCT_TYPES_H
|
||||
#define RCT_TYPES_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <cinttypes>
|
||||
|
||||
extern "C" {
|
||||
#include "crypto/crypto-ops.h"
|
||||
#include "crypto/random.h"
|
||||
#include "crypto/keccak.h"
|
||||
}
|
||||
#include "crypto/generic-ops.h"
|
||||
#include "crypto/crypto.h"
|
||||
|
||||
#include "hex.h"
|
||||
#include "span.h"
|
||||
#include "serialization/vector.h"
|
||||
#include "serialization/debug_archive.h"
|
||||
#include "serialization/binary_archive.h"
|
||||
#include "serialization/json_archive.h"
|
||||
|
||||
|
||||
//Define this flag when debugging to get additional info on the console
|
||||
#ifdef DBG
|
||||
#define DP(x) dp(x)
|
||||
#else
|
||||
#define DP(x)
|
||||
#endif
|
||||
|
||||
//atomic units of moneros
|
||||
#define ATOMS 64
|
||||
|
||||
//for printing large ints
|
||||
|
||||
//Namespace specifically for ring ct code
|
||||
namespace rct {
|
||||
//basic ops containers
|
||||
typedef unsigned char * Bytes;
|
||||
|
||||
// Can contain a secret or public key
|
||||
// similar to secret_key / public_key of crypto-ops,
|
||||
// but uses unsigned chars,
|
||||
// also includes an operator for accessing the i'th byte.
|
||||
struct key {
|
||||
unsigned char & operator[](int i) {
|
||||
return bytes[i];
|
||||
}
|
||||
unsigned char operator[](int i) const {
|
||||
return bytes[i];
|
||||
}
|
||||
bool operator==(const key &k) const { return !memcmp(bytes, k.bytes, sizeof(bytes)); }
|
||||
unsigned char bytes[32];
|
||||
};
|
||||
typedef std::vector<key> keyV; //vector of keys
|
||||
typedef std::vector<keyV> keyM; //matrix of keys (indexed by column first)
|
||||
|
||||
//containers For CT operations
|
||||
//if it's representing a private ctkey then "dest" contains the secret key of the address
|
||||
// while "mask" contains a where C = aG + bH is CT pedersen commitment and b is the amount
|
||||
// (store b, the amount, separately
|
||||
//if it's representing a public ctkey, then "dest" = P the address, mask = C the commitment
|
||||
struct ctkey {
|
||||
key dest;
|
||||
key mask; //C here if public
|
||||
};
|
||||
typedef std::vector<ctkey> ctkeyV;
|
||||
typedef std::vector<ctkeyV> ctkeyM;
|
||||
|
||||
//used for multisig data
|
||||
struct multisig_kLRki {
|
||||
key k;
|
||||
key L;
|
||||
key R;
|
||||
key ki;
|
||||
};
|
||||
|
||||
struct multisig_out {
|
||||
std::vector<key> c; // for all inputs
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(c)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
//data for passing the amount to the receiver secretly
|
||||
// If the pedersen commitment to an amount is C = aG + bH,
|
||||
// "mask" contains a 32 byte key a
|
||||
// "amount" contains a hex representation (in 32 bytes) of a 64 bit number
|
||||
// "senderPk" is not the senders actual public key, but a one-time public key generated for
|
||||
// the purpose of the ECDH exchange
|
||||
struct ecdhTuple {
|
||||
key mask;
|
||||
key amount;
|
||||
key senderPk;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(mask)
|
||||
FIELD(amount)
|
||||
// FIELD(senderPk) // not serialized, as we do not use it in monero currently
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
//containers for representing amounts
|
||||
typedef uint64_t xmr_amount;
|
||||
typedef unsigned int bits[ATOMS];
|
||||
typedef key key64[64];
|
||||
|
||||
struct boroSig {
|
||||
key64 s0;
|
||||
key64 s1;
|
||||
key ee;
|
||||
};
|
||||
|
||||
//Container for precomp
|
||||
struct geDsmp {
|
||||
ge_dsmp k;
|
||||
};
|
||||
|
||||
//just contains the necessary keys to represent MLSAG sigs
|
||||
//c.f. https://eprint.iacr.org/2015/1098
|
||||
struct mgSig {
|
||||
keyM ss;
|
||||
key cc;
|
||||
keyV II;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(ss)
|
||||
FIELD(cc)
|
||||
// FIELD(II) - not serialized, it can be reconstructed
|
||||
END_SERIALIZE()
|
||||
};
|
||||
//contains the data for an Borromean sig
|
||||
// also contains the "Ci" values such that
|
||||
// \sum Ci = C
|
||||
// and the signature proves that each Ci is either
|
||||
// a Pedersen commitment to 0 or to 2^i
|
||||
//thus proving that C is in the range of [0, 2^64]
|
||||
struct rangeSig {
|
||||
boroSig asig;
|
||||
key64 Ci;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(asig)
|
||||
FIELD(Ci)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct Bulletproof
|
||||
{
|
||||
rct::keyV V;
|
||||
rct::key A, S, T1, T2;
|
||||
rct::key taux, mu;
|
||||
rct::keyV L, R;
|
||||
rct::key a, b, t;
|
||||
|
||||
Bulletproof() {}
|
||||
Bulletproof(const rct::key &V, const rct::key &A, const rct::key &S, const rct::key &T1, const rct::key &T2, const rct::key &taux, const rct::key &mu, const rct::keyV &L, const rct::keyV &R, const rct::key &a, const rct::key &b, const rct::key &t):
|
||||
V({V}), A(A), S(S), T1(T1), T2(T2), taux(taux), mu(mu), L(L), R(R), a(a), b(b), t(t) {}
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
// Commitments aren't saved, they're restored via outPk
|
||||
// FIELD(V)
|
||||
FIELD(A)
|
||||
FIELD(S)
|
||||
FIELD(T1)
|
||||
FIELD(T2)
|
||||
FIELD(taux)
|
||||
FIELD(mu)
|
||||
FIELD(L)
|
||||
FIELD(R)
|
||||
FIELD(a)
|
||||
FIELD(b)
|
||||
FIELD(t)
|
||||
|
||||
if (L.empty() || L.size() != R.size())
|
||||
return false;
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
//A container to hold all signatures necessary for RingCT
|
||||
// rangeSigs holds all the rangeproof data of a transaction
|
||||
// MG holds the MLSAG signature of a transaction
|
||||
// mixRing holds all the public keypairs (P, C) for a transaction
|
||||
// ecdhInfo holds an encoded mask / amount to be passed to each receiver
|
||||
// outPk contains public keypairs which are destinations (P, C),
|
||||
// P = address, C = commitment to amount
|
||||
enum {
|
||||
RCTTypeNull = 0,
|
||||
RCTTypeFull = 1,
|
||||
RCTTypeSimple = 2,
|
||||
RCTTypeFullBulletproof = 3,
|
||||
RCTTypeSimpleBulletproof = 4,
|
||||
};
|
||||
struct rctSigBase {
|
||||
uint8_t type;
|
||||
key message;
|
||||
ctkeyM mixRing; //the set of all pubkeys / copy
|
||||
//pairs that you mix with
|
||||
keyV pseudoOuts; //C - for simple rct
|
||||
std::vector<ecdhTuple> ecdhInfo;
|
||||
ctkeyV outPk;
|
||||
xmr_amount txnFee; // contains b
|
||||
|
||||
template<bool W, template <bool> class Archive>
|
||||
bool serialize_rctsig_base(Archive<W> &ar, size_t inputs, size_t outputs)
|
||||
{
|
||||
FIELD(type)
|
||||
if (type == RCTTypeNull)
|
||||
return true;
|
||||
if (type != RCTTypeFull && type != RCTTypeFullBulletproof && type != RCTTypeSimple && type != RCTTypeSimpleBulletproof)
|
||||
return false;
|
||||
VARINT_FIELD(txnFee)
|
||||
// inputs/outputs not saved, only here for serialization help
|
||||
// FIELD(message) - not serialized, it can be reconstructed
|
||||
// FIELD(mixRing) - not serialized, it can be reconstructed
|
||||
if (type == RCTTypeSimple) // moved to prunable with bulletproofs
|
||||
{
|
||||
ar.tag("pseudoOuts");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, pseudoOuts);
|
||||
if (pseudoOuts.size() != inputs)
|
||||
return false;
|
||||
for (size_t i = 0; i < inputs; ++i)
|
||||
{
|
||||
FIELDS(pseudoOuts[i])
|
||||
if (inputs - i > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
}
|
||||
|
||||
ar.tag("ecdhInfo");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, ecdhInfo);
|
||||
if (ecdhInfo.size() != outputs)
|
||||
return false;
|
||||
for (size_t i = 0; i < outputs; ++i)
|
||||
{
|
||||
FIELDS(ecdhInfo[i])
|
||||
if (outputs - i > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
|
||||
ar.tag("outPk");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, outPk);
|
||||
if (outPk.size() != outputs)
|
||||
return false;
|
||||
for (size_t i = 0; i < outputs; ++i)
|
||||
{
|
||||
FIELDS(outPk[i].mask)
|
||||
if (outputs - i > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
struct rctSigPrunable {
|
||||
std::vector<rangeSig> rangeSigs;
|
||||
std::vector<Bulletproof> bulletproofs;
|
||||
std::vector<mgSig> MGs; // simple rct has N, full has 1
|
||||
keyV pseudoOuts; //C - for simple rct
|
||||
|
||||
template<bool W, template <bool> class Archive>
|
||||
bool serialize_rctsig_prunable(Archive<W> &ar, uint8_t type, size_t inputs, size_t outputs, size_t mixin)
|
||||
{
|
||||
if (type == RCTTypeNull)
|
||||
return true;
|
||||
if (type != RCTTypeFull && type != RCTTypeFullBulletproof && type != RCTTypeSimple && type != RCTTypeSimpleBulletproof)
|
||||
return false;
|
||||
if (type == RCTTypeSimpleBulletproof || type == RCTTypeFullBulletproof)
|
||||
{
|
||||
ar.tag("bp");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, bulletproofs);
|
||||
if (bulletproofs.size() != outputs)
|
||||
return false;
|
||||
for (size_t i = 0; i < outputs; ++i)
|
||||
{
|
||||
FIELDS(bulletproofs[i])
|
||||
if (outputs - i > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
}
|
||||
else
|
||||
{
|
||||
ar.tag("rangeSigs");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, rangeSigs);
|
||||
if (rangeSigs.size() != outputs)
|
||||
return false;
|
||||
for (size_t i = 0; i < outputs; ++i)
|
||||
{
|
||||
FIELDS(rangeSigs[i])
|
||||
if (outputs - i > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
}
|
||||
|
||||
ar.tag("MGs");
|
||||
ar.begin_array();
|
||||
// we keep a byte for size of MGs, because we don't know whether this is
|
||||
// a simple or full rct signature, and it's starting to annoy the hell out of me
|
||||
size_t mg_elements = (type == RCTTypeSimple || type == RCTTypeSimpleBulletproof) ? inputs : 1;
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_elements, MGs);
|
||||
if (MGs.size() != mg_elements)
|
||||
return false;
|
||||
for (size_t i = 0; i < mg_elements; ++i)
|
||||
{
|
||||
// we save the MGs contents directly, because we want it to save its
|
||||
// arrays and matrices without the size prefixes, and the load can't
|
||||
// know what size to expect if it's not in the data
|
||||
ar.begin_object();
|
||||
ar.tag("ss");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mixin + 1, MGs[i].ss);
|
||||
if (MGs[i].ss.size() != mixin + 1)
|
||||
return false;
|
||||
for (size_t j = 0; j < mixin + 1; ++j)
|
||||
{
|
||||
ar.begin_array();
|
||||
size_t mg_ss2_elements = ((type == RCTTypeSimple || type == RCTTypeSimpleBulletproof) ? 1 : inputs) + 1;
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_ss2_elements, MGs[i].ss[j]);
|
||||
if (MGs[i].ss[j].size() != mg_ss2_elements)
|
||||
return false;
|
||||
for (size_t k = 0; k < mg_ss2_elements; ++k)
|
||||
{
|
||||
FIELDS(MGs[i].ss[j][k])
|
||||
if (mg_ss2_elements - k > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
|
||||
if (mixin + 1 - j > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
|
||||
ar.tag("cc");
|
||||
FIELDS(MGs[i].cc)
|
||||
// MGs[i].II not saved, it can be reconstructed
|
||||
ar.end_object();
|
||||
|
||||
if (mg_elements - i > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
if (type == RCTTypeSimpleBulletproof)
|
||||
{
|
||||
ar.tag("pseudoOuts");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, pseudoOuts);
|
||||
if (pseudoOuts.size() != inputs)
|
||||
return false;
|
||||
for (size_t i = 0; i < inputs; ++i)
|
||||
{
|
||||
FIELDS(pseudoOuts[i])
|
||||
if (inputs - i > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
struct rctSig: public rctSigBase {
|
||||
rctSigPrunable p;
|
||||
};
|
||||
|
||||
//other basepoint H = toPoint(cn_fast_hash(G)), G the basepoint
|
||||
static const key H = { {0x8b, 0x65, 0x59, 0x70, 0x15, 0x37, 0x99, 0xaf, 0x2a, 0xea, 0xdc, 0x9f, 0xf1, 0xad, 0xd0, 0xea, 0x6c, 0x72, 0x51, 0xd5, 0x41, 0x54, 0xcf, 0xa9, 0x2c, 0x17, 0x3a, 0x0d, 0xd3, 0x9c, 0x1f, 0x94} };
|
||||
|
||||
//H2 contains 2^i H in each index, i.e. H, 2H, 4H, 8H, ...
|
||||
//This is used for the range proofG
|
||||
//You can regenerate this by running python2 Test.py HPow2 in the MiniNero repo
|
||||
static const key64 H2 = {{{0x8b, 0x65, 0x59, 0x70, 0x15, 0x37, 0x99, 0xaf, 0x2a, 0xea, 0xdc, 0x9f, 0xf1, 0xad, 0xd0, 0xea, 0x6c, 0x72, 0x51, 0xd5, 0x41, 0x54, 0xcf, 0xa9, 0x2c, 0x17, 0x3a, 0x0d, 0xd3, 0x9c, 0x1f, 0x94}},
|
||||
{{0x8f, 0xaa, 0x44, 0x8a, 0xe4, 0xb3, 0xe2, 0xbb, 0x3d, 0x4d, 0x13, 0x09, 0x09, 0xf5, 0x5f, 0xcd, 0x79, 0x71, 0x1c, 0x1c, 0x83, 0xcd, 0xbc, 0xca, 0xdd, 0x42, 0xcb, 0xe1, 0x51, 0x5e, 0x87, 0x12}},
|
||||
{{0x12, 0xa7, 0xd6, 0x2c, 0x77, 0x91, 0x65, 0x4a, 0x57, 0xf3, 0xe6, 0x76, 0x94, 0xed, 0x50, 0xb4, 0x9a, 0x7d, 0x9e, 0x3f, 0xc1, 0xe4, 0xc7, 0xa0, 0xbd, 0xe2, 0x9d, 0x18, 0x7e, 0x9c, 0xc7, 0x1d}},
|
||||
{{0x78, 0x9a, 0xb9, 0x93, 0x4b, 0x49, 0xc4, 0xf9, 0xe6, 0x78, 0x5c, 0x6d, 0x57, 0xa4, 0x98, 0xb3, 0xea, 0xd4, 0x43, 0xf0, 0x4f, 0x13, 0xdf, 0x11, 0x0c, 0x54, 0x27, 0xb4, 0xf2, 0x14, 0xc7, 0x39}},
|
||||
{{0x77, 0x1e, 0x92, 0x99, 0xd9, 0x4f, 0x02, 0xac, 0x72, 0xe3, 0x8e, 0x44, 0xde, 0x56, 0x8a, 0xc1, 0xdc, 0xb2, 0xed, 0xc6, 0xed, 0xb6, 0x1f, 0x83, 0xca, 0x41, 0x8e, 0x10, 0x77, 0xce, 0x3d, 0xe8}},
|
||||
{{0x73, 0xb9, 0x6d, 0xb4, 0x30, 0x39, 0x81, 0x9b, 0xda, 0xf5, 0x68, 0x0e, 0x5c, 0x32, 0xd7, 0x41, 0x48, 0x88, 0x84, 0xd1, 0x8d, 0x93, 0x86, 0x6d, 0x40, 0x74, 0xa8, 0x49, 0x18, 0x2a, 0x8a, 0x64}},
|
||||
{{0x8d, 0x45, 0x8e, 0x1c, 0x2f, 0x68, 0xeb, 0xeb, 0xcc, 0xd2, 0xfd, 0x5d, 0x37, 0x9f, 0x5e, 0x58, 0xf8, 0x13, 0x4d, 0xf3, 0xe0, 0xe8, 0x8c, 0xad, 0x3d, 0x46, 0x70, 0x10, 0x63, 0xa8, 0xd4, 0x12}},
|
||||
{{0x09, 0x55, 0x1e, 0xdb, 0xe4, 0x94, 0x41, 0x8e, 0x81, 0x28, 0x44, 0x55, 0xd6, 0x4b, 0x35, 0xee, 0x8a, 0xc0, 0x93, 0x06, 0x8a, 0x5f, 0x16, 0x1f, 0xa6, 0x63, 0x75, 0x59, 0x17, 0x7e, 0xf4, 0x04}},
|
||||
{{0xd0, 0x5a, 0x88, 0x66, 0xf4, 0xdf, 0x8c, 0xee, 0x1e, 0x26, 0x8b, 0x1d, 0x23, 0xa4, 0xc5, 0x8c, 0x92, 0xe7, 0x60, 0x30, 0x97, 0x86, 0xcd, 0xac, 0x0f, 0xed, 0xa1, 0xd2, 0x47, 0xa9, 0xc9, 0xa7}},
|
||||
{{0x55, 0xcd, 0xaa, 0xd5, 0x18, 0xbd, 0x87, 0x1d, 0xd1, 0xeb, 0x7b, 0xc7, 0x02, 0x3e, 0x1d, 0xc0, 0xfd, 0xf3, 0x33, 0x98, 0x64, 0xf8, 0x8f, 0xdd, 0x2d, 0xe2, 0x69, 0xfe, 0x9e, 0xe1, 0x83, 0x2d}},
|
||||
{{0xe7, 0x69, 0x7e, 0x95, 0x1a, 0x98, 0xcf, 0xd5, 0x71, 0x2b, 0x84, 0xbb, 0xe5, 0xf3, 0x4e, 0xd7, 0x33, 0xe9, 0x47, 0x3f, 0xcb, 0x68, 0xed, 0xa6, 0x6e, 0x37, 0x88, 0xdf, 0x19, 0x58, 0xc3, 0x06}},
|
||||
{{0xf9, 0x2a, 0x97, 0x0b, 0xae, 0x72, 0x78, 0x29, 0x89, 0xbf, 0xc8, 0x3a, 0xdf, 0xaa, 0x92, 0xa4, 0xf4, 0x9c, 0x7e, 0x95, 0x91, 0x8b, 0x3b, 0xba, 0x3c, 0xdc, 0x7f, 0xe8, 0x8a, 0xcc, 0x8d, 0x47}},
|
||||
{{0x1f, 0x66, 0xc2, 0xd4, 0x91, 0xd7, 0x5a, 0xf9, 0x15, 0xc8, 0xdb, 0x6a, 0x6d, 0x1c, 0xb0, 0xcd, 0x4f, 0x7d, 0xdc, 0xd5, 0xe6, 0x3d, 0x3b, 0xa9, 0xb8, 0x3c, 0x86, 0x6c, 0x39, 0xef, 0x3a, 0x2b}},
|
||||
{{0x3e, 0xec, 0x98, 0x84, 0xb4, 0x3f, 0x58, 0xe9, 0x3e, 0xf8, 0xde, 0xea, 0x26, 0x00, 0x04, 0xef, 0xea, 0x2a, 0x46, 0x34, 0x4f, 0xc5, 0x96, 0x5b, 0x1a, 0x7d, 0xd5, 0xd1, 0x89, 0x97, 0xef, 0xa7}},
|
||||
{{0xb2, 0x9f, 0x8f, 0x0c, 0xcb, 0x96, 0x97, 0x7f, 0xe7, 0x77, 0xd4, 0x89, 0xd6, 0xbe, 0x9e, 0x7e, 0xbc, 0x19, 0xc4, 0x09, 0xb5, 0x10, 0x35, 0x68, 0xf2, 0x77, 0x61, 0x1d, 0x7e, 0xa8, 0x48, 0x94}},
|
||||
{{0x56, 0xb1, 0xf5, 0x12, 0x65, 0xb9, 0x55, 0x98, 0x76, 0xd5, 0x8d, 0x24, 0x9d, 0x0c, 0x14, 0x6d, 0x69, 0xa1, 0x03, 0x63, 0x66, 0x99, 0x87, 0x4d, 0x3f, 0x90, 0x47, 0x35, 0x50, 0xfe, 0x3f, 0x2c}},
|
||||
{{0x1d, 0x7a, 0x36, 0x57, 0x5e, 0x22, 0xf5, 0xd1, 0x39, 0xff, 0x9c, 0xc5, 0x10, 0xfa, 0x13, 0x85, 0x05, 0x57, 0x6b, 0x63, 0x81, 0x5a, 0x94, 0xe4, 0xb0, 0x12, 0xbf, 0xd4, 0x57, 0xca, 0xaa, 0xda}},
|
||||
{{0xd0, 0xac, 0x50, 0x7a, 0x86, 0x4e, 0xcd, 0x05, 0x93, 0xfa, 0x67, 0xbe, 0x7d, 0x23, 0x13, 0x43, 0x92, 0xd0, 0x0e, 0x40, 0x07, 0xe2, 0x53, 0x48, 0x78, 0xd9, 0xb2, 0x42, 0xe1, 0x0d, 0x76, 0x20}},
|
||||
{{0xf6, 0xc6, 0x84, 0x0b, 0x9c, 0xf1, 0x45, 0xbb, 0x2d, 0xcc, 0xf8, 0x6e, 0x94, 0x0b, 0xe0, 0xfc, 0x09, 0x8e, 0x32, 0xe3, 0x10, 0x99, 0xd5, 0x6f, 0x7f, 0xe0, 0x87, 0xbd, 0x5d, 0xeb, 0x50, 0x94}},
|
||||
{{0x28, 0x83, 0x1a, 0x33, 0x40, 0x07, 0x0e, 0xb1, 0xdb, 0x87, 0xc1, 0x2e, 0x05, 0x98, 0x0d, 0x5f, 0x33, 0xe9, 0xef, 0x90, 0xf8, 0x3a, 0x48, 0x17, 0xc9, 0xf4, 0xa0, 0xa3, 0x32, 0x27, 0xe1, 0x97}},
|
||||
{{0x87, 0x63, 0x22, 0x73, 0xd6, 0x29, 0xcc, 0xb7, 0xe1, 0xed, 0x1a, 0x76, 0x8f, 0xa2, 0xeb, 0xd5, 0x17, 0x60, 0xf3, 0x2e, 0x1c, 0x0b, 0x86, 0x7a, 0x5d, 0x36, 0x8d, 0x52, 0x71, 0x05, 0x5c, 0x6e}},
|
||||
{{0x5c, 0x7b, 0x29, 0x42, 0x43, 0x47, 0x96, 0x4d, 0x04, 0x27, 0x55, 0x17, 0xc5, 0xae, 0x14, 0xb6, 0xb5, 0xea, 0x27, 0x98, 0xb5, 0x73, 0xfc, 0x94, 0xe6, 0xe4, 0x4a, 0x53, 0x21, 0x60, 0x0c, 0xfb}},
|
||||
{{0xe6, 0x94, 0x50, 0x42, 0xd7, 0x8b, 0xc2, 0xc3, 0xbd, 0x6e, 0xc5, 0x8c, 0x51, 0x1a, 0x9f, 0xe8, 0x59, 0xc0, 0xad, 0x63, 0xfd, 0xe4, 0x94, 0xf5, 0x03, 0x9e, 0x0e, 0x82, 0x32, 0x61, 0x2b, 0xd5}},
|
||||
{{0x36, 0xd5, 0x69, 0x07, 0xe2, 0xec, 0x74, 0x5d, 0xb6, 0xe5, 0x4f, 0x0b, 0x2e, 0x1b, 0x23, 0x00, 0xab, 0xcb, 0x42, 0x2e, 0x71, 0x2d, 0xa5, 0x88, 0xa4, 0x0d, 0x3f, 0x1e, 0xbb, 0xbe, 0x02, 0xf6}},
|
||||
{{0x34, 0xdb, 0x6e, 0xe4, 0xd0, 0x60, 0x8e, 0x5f, 0x78, 0x36, 0x50, 0x49, 0x5a, 0x3b, 0x2f, 0x52, 0x73, 0xc5, 0x13, 0x4e, 0x52, 0x84, 0xe4, 0xfd, 0xf9, 0x66, 0x27, 0xbb, 0x16, 0xe3, 0x1e, 0x6b}},
|
||||
{{0x8e, 0x76, 0x59, 0xfb, 0x45, 0xa3, 0x78, 0x7d, 0x67, 0x4a, 0xe8, 0x67, 0x31, 0xfa, 0xa2, 0x53, 0x8e, 0xc0, 0xfd, 0xf4, 0x42, 0xab, 0x26, 0xe9, 0xc7, 0x91, 0xfa, 0xda, 0x08, 0x94, 0x67, 0xe9}},
|
||||
{{0x30, 0x06, 0xcf, 0x19, 0x8b, 0x24, 0xf3, 0x1b, 0xb4, 0xc7, 0xe6, 0x34, 0x60, 0x00, 0xab, 0xc7, 0x01, 0xe8, 0x27, 0xcf, 0xbb, 0x5d, 0xf5, 0x2d, 0xcf, 0xa4, 0x2e, 0x9c, 0xa9, 0xff, 0x08, 0x02}},
|
||||
{{0xf5, 0xfd, 0x40, 0x3c, 0xb6, 0xe8, 0xbe, 0x21, 0x47, 0x2e, 0x37, 0x7f, 0xfd, 0x80, 0x5a, 0x8c, 0x60, 0x83, 0xea, 0x48, 0x03, 0xb8, 0x48, 0x53, 0x89, 0xcc, 0x3e, 0xbc, 0x21, 0x5f, 0x00, 0x2a}},
|
||||
{{0x37, 0x31, 0xb2, 0x60, 0xeb, 0x3f, 0x94, 0x82, 0xe4, 0x5f, 0x1c, 0x3f, 0x3b, 0x9d, 0xcf, 0x83, 0x4b, 0x75, 0xe6, 0xee, 0xf8, 0xc4, 0x0f, 0x46, 0x1e, 0xa2, 0x7e, 0x8b, 0x6e, 0xd9, 0x47, 0x3d}},
|
||||
{{0x9f, 0x9d, 0xab, 0x09, 0xc3, 0xf5, 0xe4, 0x28, 0x55, 0xc2, 0xde, 0x97, 0x1b, 0x65, 0x93, 0x28, 0xa2, 0xdb, 0xc4, 0x54, 0x84, 0x5f, 0x39, 0x6f, 0xfc, 0x05, 0x3f, 0x0b, 0xb1, 0x92, 0xf8, 0xc3}},
|
||||
{{0x5e, 0x05, 0x5d, 0x25, 0xf8, 0x5f, 0xdb, 0x98, 0xf2, 0x73, 0xe4, 0xaf, 0xe0, 0x84, 0x64, 0xc0, 0x03, 0xb7, 0x0f, 0x1e, 0xf0, 0x67, 0x7b, 0xb5, 0xe2, 0x57, 0x06, 0x40, 0x0b, 0xe6, 0x20, 0xa5}},
|
||||
{{0x86, 0x8b, 0xcf, 0x36, 0x79, 0xcb, 0x6b, 0x50, 0x0b, 0x94, 0x41, 0x8c, 0x0b, 0x89, 0x25, 0xf9, 0x86, 0x55, 0x30, 0x30, 0x3a, 0xe4, 0xe4, 0xb2, 0x62, 0x59, 0x18, 0x65, 0x66, 0x6a, 0x45, 0x90}},
|
||||
{{0xb3, 0xdb, 0x6b, 0xd3, 0x89, 0x7a, 0xfb, 0xd1, 0xdf, 0x3f, 0x96, 0x44, 0xab, 0x21, 0xc8, 0x05, 0x0e, 0x1f, 0x00, 0x38, 0xa5, 0x2f, 0x7c, 0xa9, 0x5a, 0xc0, 0xc3, 0xde, 0x75, 0x58, 0xcb, 0x7a}},
|
||||
{{0x81, 0x19, 0xb3, 0xa0, 0x59, 0xff, 0x2c, 0xac, 0x48, 0x3e, 0x69, 0xbc, 0xd4, 0x1d, 0x6d, 0x27, 0x14, 0x94, 0x47, 0x91, 0x42, 0x88, 0xbb, 0xea, 0xee, 0x34, 0x13, 0xe6, 0xdc, 0xc6, 0xd1, 0xeb}},
|
||||
{{0x10, 0xfc, 0x58, 0xf3, 0x5f, 0xc7, 0xfe, 0x7a, 0xe8, 0x75, 0x52, 0x4b, 0xb5, 0x85, 0x00, 0x03, 0x00, 0x5b, 0x7f, 0x97, 0x8c, 0x0c, 0x65, 0xe2, 0xa9, 0x65, 0x46, 0x4b, 0x6d, 0x00, 0x81, 0x9c}},
|
||||
{{0x5a, 0xcd, 0x94, 0xeb, 0x3c, 0x57, 0x83, 0x79, 0xc1, 0xea, 0x58, 0xa3, 0x43, 0xec, 0x4f, 0xcf, 0xf9, 0x62, 0x77, 0x6f, 0xe3, 0x55, 0x21, 0xe4, 0x75, 0xa0, 0xe0, 0x6d, 0x88, 0x7b, 0x2d, 0xb9}},
|
||||
{{0x33, 0xda, 0xf3, 0xa2, 0x14, 0xd6, 0xe0, 0xd4, 0x2d, 0x23, 0x00, 0xa7, 0xb4, 0x4b, 0x39, 0x29, 0x0d, 0xb8, 0x98, 0x9b, 0x42, 0x79, 0x74, 0xcd, 0x86, 0x5d, 0xb0, 0x11, 0x05, 0x5a, 0x29, 0x01}},
|
||||
{{0xcf, 0xc6, 0x57, 0x2f, 0x29, 0xaf, 0xd1, 0x64, 0xa4, 0x94, 0xe6, 0x4e, 0x6f, 0x1a, 0xeb, 0x82, 0x0c, 0x3e, 0x7d, 0xa3, 0x55, 0x14, 0x4e, 0x51, 0x24, 0xa3, 0x91, 0xd0, 0x6e, 0x9f, 0x95, 0xea}},
|
||||
{{0xd5, 0x31, 0x2a, 0x4b, 0x0e, 0xf6, 0x15, 0xa3, 0x31, 0xf6, 0x35, 0x2c, 0x2e, 0xd2, 0x1d, 0xac, 0x9e, 0x7c, 0x36, 0x39, 0x8b, 0x93, 0x9a, 0xec, 0x90, 0x1c, 0x25, 0x7f, 0x6c, 0xbc, 0x9e, 0x8e}},
|
||||
{{0x55, 0x1d, 0x67, 0xfe, 0xfc, 0x7b, 0x5b, 0x9f, 0x9f, 0xdb, 0xf6, 0xaf, 0x57, 0xc9, 0x6c, 0x8a, 0x74, 0xd7, 0xe4, 0x5a, 0x00, 0x20, 0x78, 0xa7, 0xb5, 0xba, 0x45, 0xc6, 0xfd, 0xe9, 0x3e, 0x33}},
|
||||
{{0xd5, 0x0a, 0xc7, 0xbd, 0x5c, 0xa5, 0x93, 0xc6, 0x56, 0x92, 0x8f, 0x38, 0x42, 0x80, 0x17, 0xfc, 0x7b, 0xa5, 0x02, 0x85, 0x4c, 0x43, 0xd8, 0x41, 0x49, 0x50, 0xe9, 0x6e, 0xcb, 0x40, 0x5d, 0xc3}},
|
||||
{{0x07, 0x73, 0xe1, 0x8e, 0xa1, 0xbe, 0x44, 0xfe, 0x1a, 0x97, 0xe2, 0x39, 0x57, 0x3c, 0xfa, 0xe3, 0xe4, 0xe9, 0x5e, 0xf9, 0xaa, 0x9f, 0xaa, 0xbe, 0xac, 0x12, 0x74, 0xd3, 0xad, 0x26, 0x16, 0x04}},
|
||||
{{0xe9, 0xaf, 0x0e, 0x7c, 0xa8, 0x93, 0x30, 0xd2, 0xb8, 0x61, 0x5d, 0x1b, 0x41, 0x37, 0xca, 0x61, 0x7e, 0x21, 0x29, 0x7f, 0x2f, 0x0d, 0xed, 0x8e, 0x31, 0xb7, 0xd2, 0xea, 0xd8, 0x71, 0x46, 0x60}},
|
||||
{{0x7b, 0x12, 0x45, 0x83, 0x09, 0x7f, 0x10, 0x29, 0xa0, 0xc7, 0x41, 0x91, 0xfe, 0x73, 0x78, 0xc9, 0x10, 0x5a, 0xcc, 0x70, 0x66, 0x95, 0xed, 0x14, 0x93, 0xbb, 0x76, 0x03, 0x42, 0x26, 0xa5, 0x7b}},
|
||||
{{0xec, 0x40, 0x05, 0x7b, 0x99, 0x54, 0x76, 0x65, 0x0b, 0x3d, 0xb9, 0x8e, 0x9d, 0xb7, 0x57, 0x38, 0xa8, 0xcd, 0x2f, 0x94, 0xd8, 0x63, 0xb9, 0x06, 0x15, 0x0c, 0x56, 0xaa, 0xc1, 0x9c, 0xaa, 0x6b}},
|
||||
{{0x01, 0xd9, 0xff, 0x72, 0x9e, 0xfd, 0x39, 0xd8, 0x37, 0x84, 0xc0, 0xfe, 0x59, 0xc4, 0xae, 0x81, 0xa6, 0x70, 0x34, 0xcb, 0x53, 0xc9, 0x43, 0xfb, 0x81, 0x8b, 0x9d, 0x8a, 0xe7, 0xfc, 0x33, 0xe5}},
|
||||
{{0x00, 0xdf, 0xb3, 0xc6, 0x96, 0x32, 0x8c, 0x76, 0x42, 0x45, 0x19, 0xa7, 0xbe, 0xfe, 0x8e, 0x0f, 0x6c, 0x76, 0xf9, 0x47, 0xb5, 0x27, 0x67, 0x91, 0x6d, 0x24, 0x82, 0x3f, 0x73, 0x5b, 0xaf, 0x2e}},
|
||||
{{0x46, 0x1b, 0x79, 0x9b, 0x4d, 0x9c, 0xee, 0xa8, 0xd5, 0x80, 0xdc, 0xb7, 0x6d, 0x11, 0x15, 0x0d, 0x53, 0x5e, 0x16, 0x39, 0xd1, 0x60, 0x03, 0xc3, 0xfb, 0x7e, 0x9d, 0x1f, 0xd1, 0x30, 0x83, 0xa8}},
|
||||
{{0xee, 0x03, 0x03, 0x94, 0x79, 0xe5, 0x22, 0x8f, 0xdc, 0x55, 0x1c, 0xbd, 0xe7, 0x07, 0x9d, 0x34, 0x12, 0xea, 0x18, 0x6a, 0x51, 0x7c, 0xcc, 0x63, 0xe4, 0x6e, 0x9f, 0xcc, 0xe4, 0xfe, 0x3a, 0x6c}},
|
||||
{{0xa8, 0xcf, 0xb5, 0x43, 0x52, 0x4e, 0x7f, 0x02, 0xb9, 0xf0, 0x45, 0xac, 0xd5, 0x43, 0xc2, 0x1c, 0x37, 0x3b, 0x4c, 0x9b, 0x98, 0xac, 0x20, 0xce, 0xc4, 0x17, 0xa6, 0xdd, 0xb5, 0x74, 0x4e, 0x94}},
|
||||
{{0x93, 0x2b, 0x79, 0x4b, 0xf8, 0x9c, 0x6e, 0xda, 0xf5, 0xd0, 0x65, 0x0c, 0x7c, 0x4b, 0xad, 0x92, 0x42, 0xb2, 0x56, 0x26, 0xe3, 0x7e, 0xad, 0x5a, 0xa7, 0x5e, 0xc8, 0xc6, 0x4e, 0x09, 0xdd, 0x4f}},
|
||||
{{0x16, 0xb1, 0x0c, 0x77, 0x9c, 0xe5, 0xcf, 0xef, 0x59, 0xc7, 0x71, 0x0d, 0x2e, 0x68, 0x44, 0x1e, 0xa6, 0xfa, 0xcb, 0x68, 0xe9, 0xb5, 0xf7, 0xd5, 0x33, 0xae, 0x0b, 0xb7, 0x8e, 0x28, 0xbf, 0x57}},
|
||||
{{0x0f, 0x77, 0xc7, 0x67, 0x43, 0xe7, 0x39, 0x6f, 0x99, 0x10, 0x13, 0x9f, 0x49, 0x37, 0xd8, 0x37, 0xae, 0x54, 0xe2, 0x10, 0x38, 0xac, 0x5c, 0x0b, 0x3f, 0xd6, 0xef, 0x17, 0x1a, 0x28, 0xa7, 0xe4}},
|
||||
{{0xd7, 0xe5, 0x74, 0xb7, 0xb9, 0x52, 0xf2, 0x93, 0xe8, 0x0d, 0xde, 0x90, 0x5e, 0xb5, 0x09, 0x37, 0x3f, 0x3f, 0x6c, 0xd1, 0x09, 0xa0, 0x22, 0x08, 0xb3, 0xc1, 0xe9, 0x24, 0x08, 0x0a, 0x20, 0xca}},
|
||||
{{0x45, 0x66, 0x6f, 0x8c, 0x38, 0x1e, 0x3d, 0xa6, 0x75, 0x56, 0x3f, 0xf8, 0xba, 0x23, 0xf8, 0x3b, 0xfa, 0xc3, 0x0c, 0x34, 0xab, 0xdd, 0xe6, 0xe5, 0xc0, 0x97, 0x5e, 0xf9, 0xfd, 0x70, 0x0c, 0xb9}},
|
||||
{{0xb2, 0x46, 0x12, 0xe4, 0x54, 0x60, 0x7e, 0xb1, 0xab, 0xa4, 0x47, 0xf8, 0x16, 0xd1, 0xa4, 0x55, 0x1e, 0xf9, 0x5f, 0xa7, 0x24, 0x7f, 0xb7, 0xc1, 0xf5, 0x03, 0x02, 0x0a, 0x71, 0x77, 0xf0, 0xdd}},
|
||||
{{0x7e, 0x20, 0x88, 0x61, 0x85, 0x6d, 0xa4, 0x2c, 0x8b, 0xb4, 0x6a, 0x75, 0x67, 0xf8, 0x12, 0x13, 0x62, 0xd9, 0xfb, 0x24, 0x96, 0xf1, 0x31, 0xa4, 0xaa, 0x90, 0x17, 0xcf, 0x36, 0x6c, 0xdf, 0xce}},
|
||||
{{0x5b, 0x64, 0x6b, 0xff, 0x6a, 0xd1, 0x10, 0x01, 0x65, 0x03, 0x7a, 0x05, 0x56, 0x01, 0xea, 0x02, 0x35, 0x8c, 0x0f, 0x41, 0x05, 0x0f, 0x9d, 0xfe, 0x3c, 0x95, 0xdc, 0xcb, 0xd3, 0x08, 0x7b, 0xe0}},
|
||||
{{0x74, 0x6d, 0x1d, 0xcc, 0xfe, 0xd2, 0xf0, 0xff, 0x1e, 0x13, 0xc5, 0x1e, 0x2d, 0x50, 0xd5, 0x32, 0x43, 0x75, 0xfb, 0xd5, 0xbf, 0x7c, 0xa8, 0x2a, 0x89, 0x31, 0x82, 0x8d, 0x80, 0x1d, 0x43, 0xab}},
|
||||
{{0xcb, 0x98, 0x11, 0x0d, 0x4a, 0x6b, 0xb9, 0x7d, 0x22, 0xfe, 0xad, 0xbc, 0x6c, 0x0d, 0x89, 0x30, 0xc5, 0xf8, 0xfc, 0x50, 0x8b, 0x2f, 0xc5, 0xb3, 0x53, 0x28, 0xd2, 0x6b, 0x88, 0xdb, 0x19, 0xae}},
|
||||
{{0x60, 0xb6, 0x26, 0xa0, 0x33, 0xb5, 0x5f, 0x27, 0xd7, 0x67, 0x6c, 0x40, 0x95, 0xea, 0xba, 0xbc, 0x7a, 0x2c, 0x7e, 0xde, 0x26, 0x24, 0xb4, 0x72, 0xe9, 0x7f, 0x64, 0xf9, 0x6b, 0x8c, 0xfc, 0x0e}},
|
||||
{{0xe5, 0xb5, 0x2b, 0xc9, 0x27, 0x46, 0x8d, 0xf7, 0x18, 0x93, 0xeb, 0x81, 0x97, 0xef, 0x82, 0x0c, 0xf7, 0x6c, 0xb0, 0xaa, 0xf6, 0xe8, 0xe4, 0xfe, 0x93, 0xad, 0x62, 0xd8, 0x03, 0x98, 0x31, 0x04}},
|
||||
{{0x05, 0x65, 0x41, 0xae, 0x5d, 0xa9, 0x96, 0x1b, 0xe2, 0xb0, 0xa5, 0xe8, 0x95, 0xe5, 0xc5, 0xba, 0x15, 0x3c, 0xbb, 0x62, 0xdd, 0x56, 0x1a, 0x42, 0x7b, 0xad, 0x0f, 0xfd, 0x41, 0x92, 0x31, 0x99}},
|
||||
{{0xf8, 0xfe, 0xf0, 0x5a, 0x3f, 0xa5, 0xc9, 0xf3, 0xeb, 0xa4, 0x16, 0x38, 0xb2, 0x47, 0xb7, 0x11, 0xa9, 0x9f, 0x96, 0x0f, 0xe7, 0x3a, 0xa2, 0xf9, 0x01, 0x36, 0xae, 0xb2, 0x03, 0x29, 0xb8, 0x88}}};
|
||||
|
||||
//Debug printing for the above types
|
||||
//Actually use DP(value) and #define DBG
|
||||
void dp(key a);
|
||||
void dp(bool a);
|
||||
void dp(const char * a, int l);
|
||||
void dp(keyV a);
|
||||
void dp(keyM a);
|
||||
void dp(xmr_amount vali);
|
||||
void dp(int vali);
|
||||
void dp(bits amountb);
|
||||
void dp(const char * st);
|
||||
|
||||
//various conversions
|
||||
|
||||
//uint long long to 32 byte key
|
||||
void d2h(key & amounth, xmr_amount val);
|
||||
key d2h(xmr_amount val);
|
||||
//uint long long to int[64]
|
||||
void d2b(bits amountb, xmr_amount val);
|
||||
//32 byte key to uint long long
|
||||
// if the key holds a value > 2^64
|
||||
// then the value in the first 8 bytes is returned
|
||||
xmr_amount h2d(const key &test);
|
||||
//32 byte key to int[64]
|
||||
void h2b(bits amountb2, const key & test);
|
||||
//int[64] to 32 byte key
|
||||
void b2h(key & amountdh, bits amountb2);
|
||||
//int[64] to uint long long
|
||||
xmr_amount b2d(bits amountb);
|
||||
|
||||
static inline const rct::key pk2rct(const crypto::public_key &pk) { return (const rct::key&)pk; }
|
||||
static inline const rct::key sk2rct(const crypto::secret_key &sk) { return (const rct::key&)sk; }
|
||||
static inline const rct::key ki2rct(const crypto::key_image &ki) { return (const rct::key&)ki; }
|
||||
static inline const rct::key hash2rct(const crypto::hash &h) { return (const rct::key&)h; }
|
||||
static inline const crypto::public_key rct2pk(const rct::key &k) { return (const crypto::public_key&)k; }
|
||||
static inline const crypto::secret_key rct2sk(const rct::key &k) { return (const crypto::secret_key&)k; }
|
||||
static inline const crypto::key_image rct2ki(const rct::key &k) { return (const crypto::key_image&)k; }
|
||||
static inline const crypto::hash rct2hash(const rct::key &k) { return (const crypto::hash&)k; }
|
||||
static inline bool operator==(const rct::key &k0, const crypto::public_key &k1) { return !memcmp(&k0, &k1, 32); }
|
||||
static inline bool operator!=(const rct::key &k0, const crypto::public_key &k1) { return memcmp(&k0, &k1, 32); }
|
||||
}
|
||||
|
||||
|
||||
namespace cryptonote {
|
||||
static inline bool operator==(const crypto::public_key &k0, const rct::key &k1) { return !memcmp(&k0, &k1, 32); }
|
||||
static inline bool operator!=(const crypto::public_key &k0, const rct::key &k1) { return memcmp(&k0, &k1, 32); }
|
||||
static inline bool operator==(const crypto::secret_key &k0, const rct::key &k1) { return !memcmp(&k0, &k1, 32); }
|
||||
static inline bool operator!=(const crypto::secret_key &k0, const rct::key &k1) { return memcmp(&k0, &k1, 32); }
|
||||
}
|
||||
|
||||
namespace rct {
|
||||
inline std::ostream &operator <<(std::ostream &o, const rct::key &v) {
|
||||
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<> struct hash<rct::key> { std::size_t operator()(const rct::key &k) const { return reinterpret_cast<const std::size_t&>(k); } };
|
||||
}
|
||||
|
||||
BLOB_SERIALIZER(rct::key);
|
||||
BLOB_SERIALIZER(rct::key64);
|
||||
BLOB_SERIALIZER(rct::ctkey);
|
||||
BLOB_SERIALIZER(rct::multisig_kLRki);
|
||||
BLOB_SERIALIZER(rct::boroSig);
|
||||
|
||||
VARIANT_TAG(debug_archive, rct::key, "rct::key");
|
||||
VARIANT_TAG(debug_archive, rct::key64, "rct::key64");
|
||||
VARIANT_TAG(debug_archive, rct::keyV, "rct::keyV");
|
||||
VARIANT_TAG(debug_archive, rct::keyM, "rct::keyM");
|
||||
VARIANT_TAG(debug_archive, rct::ctkey, "rct::ctkey");
|
||||
VARIANT_TAG(debug_archive, rct::ctkeyV, "rct::ctkeyV");
|
||||
VARIANT_TAG(debug_archive, rct::ctkeyM, "rct::ctkeyM");
|
||||
VARIANT_TAG(debug_archive, rct::ecdhTuple, "rct::ecdhTuple");
|
||||
VARIANT_TAG(debug_archive, rct::mgSig, "rct::mgSig");
|
||||
VARIANT_TAG(debug_archive, rct::rangeSig, "rct::rangeSig");
|
||||
VARIANT_TAG(debug_archive, rct::boroSig, "rct::boroSig");
|
||||
VARIANT_TAG(debug_archive, rct::rctSig, "rct::rctSig");
|
||||
VARIANT_TAG(debug_archive, rct::Bulletproof, "rct::bulletproof");
|
||||
VARIANT_TAG(debug_archive, rct::multisig_kLRki, "rct::multisig_kLRki");
|
||||
VARIANT_TAG(debug_archive, rct::multisig_out, "rct::multisig_out");
|
||||
|
||||
VARIANT_TAG(binary_archive, rct::key, 0x90);
|
||||
VARIANT_TAG(binary_archive, rct::key64, 0x91);
|
||||
VARIANT_TAG(binary_archive, rct::keyV, 0x92);
|
||||
VARIANT_TAG(binary_archive, rct::keyM, 0x93);
|
||||
VARIANT_TAG(binary_archive, rct::ctkey, 0x94);
|
||||
VARIANT_TAG(binary_archive, rct::ctkeyV, 0x95);
|
||||
VARIANT_TAG(binary_archive, rct::ctkeyM, 0x96);
|
||||
VARIANT_TAG(binary_archive, rct::ecdhTuple, 0x97);
|
||||
VARIANT_TAG(binary_archive, rct::mgSig, 0x98);
|
||||
VARIANT_TAG(binary_archive, rct::rangeSig, 0x99);
|
||||
VARIANT_TAG(binary_archive, rct::boroSig, 0x9a);
|
||||
VARIANT_TAG(binary_archive, rct::rctSig, 0x9b);
|
||||
VARIANT_TAG(binary_archive, rct::Bulletproof, 0x9c);
|
||||
VARIANT_TAG(binary_archive, rct::multisig_kLRki, 0x9d);
|
||||
VARIANT_TAG(binary_archive, rct::multisig_out, 0x9e);
|
||||
|
||||
VARIANT_TAG(json_archive, rct::key, "rct_key");
|
||||
VARIANT_TAG(json_archive, rct::key64, "rct_key64");
|
||||
VARIANT_TAG(json_archive, rct::keyV, "rct_keyV");
|
||||
VARIANT_TAG(json_archive, rct::keyM, "rct_keyM");
|
||||
VARIANT_TAG(json_archive, rct::ctkey, "rct_ctkey");
|
||||
VARIANT_TAG(json_archive, rct::ctkeyV, "rct_ctkeyV");
|
||||
VARIANT_TAG(json_archive, rct::ctkeyM, "rct_ctkeyM");
|
||||
VARIANT_TAG(json_archive, rct::ecdhTuple, "rct_ecdhTuple");
|
||||
VARIANT_TAG(json_archive, rct::mgSig, "rct_mgSig");
|
||||
VARIANT_TAG(json_archive, rct::rangeSig, "rct_rangeSig");
|
||||
VARIANT_TAG(json_archive, rct::boroSig, "rct_boroSig");
|
||||
VARIANT_TAG(json_archive, rct::rctSig, "rct_rctSig");
|
||||
VARIANT_TAG(json_archive, rct::Bulletproof, "rct_bulletproof");
|
||||
VARIANT_TAG(json_archive, rct::multisig_kLRki, "rct_multisig_kLR");
|
||||
VARIANT_TAG(json_archive, rct::multisig_out, "rct_multisig_out");
|
||||
|
||||
#endif /* RCTTYPES_H */
|
Loading…
Reference in new issue