Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Subaddresses #2056

Merged
merged 1 commit into from
Oct 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ namespace epee
typename stl_container::value_type exchange_val;
typename t_storage::harray hval_array = stg.get_first_value(pname, exchange_val, hparent_section);
if(!hval_array) return false;
container.push_back(std::move(exchange_val));
container.insert(container.end(), std::move(exchange_val));
while(stg.get_next_value(hval_array, exchange_val))
container.push_back(std::move(exchange_val));
container.insert(container.end(), std::move(exchange_val));
return true;
}//--------------------------------------------------------------------------------------------------------------------
template<class stl_container, class t_storage>
Expand Down Expand Up @@ -152,7 +152,7 @@ namespace epee
"size in blob " << loaded_size << " not have not zero modulo for sizeof(value_type) = " << sizeof(typename stl_container::value_type));
size_t count = (loaded_size/sizeof(typename stl_container::value_type));
for(size_t i = 0; i < count; i++)
container.push_back(*(pelem++));
container.insert(container.end(), *(pelem++));
}
return res;
}
Expand Down Expand Up @@ -186,12 +186,12 @@ namespace epee
typename t_storage::harray hsec_array = stg.get_first_section(pname, hchild_section, hparent_section);
if(!hsec_array || !hchild_section) return false;
res = val._load(stg, hchild_section);
container.push_back(val);
container.insert(container.end(), val);
while(stg.get_next_section(hsec_array, hchild_section))
{
typename stl_container::value_type val_l = typename stl_container::value_type();
res |= val_l._load(stg, hchild_section);
container.push_back(std::move(val_l));
container.insert(container.end(), std::move(val_l));
}
return res;
}
Expand Down Expand Up @@ -250,6 +250,18 @@ namespace epee
return unserialize_stl_container_t_val(d, stg, hparent_section, pname);
}
//-------------------------------------------------------------------------------------------------------------------
template<class t_type, class t_storage>
static bool kv_serialize(const std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
{
return serialize_stl_container_t_val(d, stg, hparent_section, pname);
}
//-------------------------------------------------------------------------------------------------------------------
template<class t_type, class t_storage>
static bool kv_unserialize(std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
{
return unserialize_stl_container_t_val(d, stg, hparent_section, pname);
}
//-------------------------------------------------------------------------------------------------------------------
};
template<>
struct kv_serialization_overloads_impl_is_base_serializable_types<false>
Expand Down Expand Up @@ -302,6 +314,18 @@ namespace epee
{
return unserialize_stl_container_t_obj(d, stg, hparent_section, pname);
}
//-------------------------------------------------------------------------------------------------------------------
template<class t_type, class t_storage>
static bool kv_serialize(const std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
{
return serialize_stl_container_t_obj(d, stg, hparent_section, pname);
}
//-------------------------------------------------------------------------------------------------------------------
template<class t_type, class t_storage>
static bool kv_unserialize(std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
{
return unserialize_stl_container_t_obj(d, stg, hparent_section, pname);
}
};
template<class t_storage>
struct base_serializable_types: public boost::mpl::vector<uint64_t, uint32_t, uint16_t, uint8_t, int64_t, int32_t, int16_t, int8_t, double, bool, std::string, typename t_storage::meta_entry>::type
Expand Down Expand Up @@ -399,5 +423,17 @@ namespace epee
{
return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_unserialize(d, stg, hparent_section, pname);
}
//-------------------------------------------------------------------------------------------------------------------
template<class t_type, class t_storage>
bool kv_serialize(const std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
{
return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_serialize(d, stg, hparent_section, pname);
}
//-------------------------------------------------------------------------------------------------------------------
template<class t_type, class t_storage>
bool kv_unserialize(std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
{
return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_unserialize(d, stg, hparent_section, pname);
}
}
}
125 changes: 92 additions & 33 deletions src/crypto/crypto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ namespace crypto {
random_scalar_not_thread_safe(res);
}

static inline void hash_to_scalar(const void *data, size_t length, ec_scalar &res) {
void hash_to_scalar(const void *data, size_t length, ec_scalar &res) {
cn_fast_hash(data, length, reinterpret_cast<hash &>(res));
sc_reduce32(&res);
}
Expand Down Expand Up @@ -189,6 +189,25 @@ namespace crypto {
sc_add(&derived_key, &base, &scalar);
}

bool crypto_ops::derive_subaddress_public_key(const public_key &out_key, const key_derivation &derivation, std::size_t output_index, public_key &derived_key) {
ec_scalar scalar;
ge_p3 point1;
ge_p3 point2;
ge_cached point3;
ge_p1p1 point4;
ge_p2 point5;
if (ge_frombytes_vartime(&point1, &out_key) != 0) {
return false;
}
derivation_to_scalar(derivation, output_index, scalar);
ge_scalarmult_base(&point2, &scalar);
ge_p3_to_cached(&point3, &point2);
ge_sub(&point4, &point1, &point3);
ge_p1p1_to_p2(&point5, &point4);
ge_tobytes(&derived_key, &point5);
return true;
}

struct s_comm {
hash h;
ec_point key;
Expand Down Expand Up @@ -246,22 +265,33 @@ namespace crypto {
return sc_isnonzero(&c) == 0;
}

void crypto_ops::generate_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const public_key &D, const secret_key &r, signature &sig) {
void crypto_ops::generate_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const secret_key &r, signature &sig) {
// sanity check
ge_p3 R_p3;
ge_p3 A_p3;
ge_p3 B_p3;
ge_p3 D_p3;
if (ge_frombytes_vartime(&R_p3, &R) != 0) throw std::runtime_error("tx pubkey is invalid");
if (ge_frombytes_vartime(&A_p3, &A) != 0) throw std::runtime_error("recipient view pubkey is invalid");
if (B && ge_frombytes_vartime(&B_p3, &*B) != 0) throw std::runtime_error("recipient spend pubkey is invalid");
if (ge_frombytes_vartime(&D_p3, &D) != 0) throw std::runtime_error("key derivation is invalid");
#if !defined(NDEBUG)
{
assert(sc_check(&r) == 0);
// check R == r*G
ge_p3 dbg_R_p3;
ge_scalarmult_base(&dbg_R_p3, &r);
// check R == r*G or R == r*B
public_key dbg_R;
ge_p3_tobytes(&dbg_R, &dbg_R_p3);
if (B)
{
ge_p2 dbg_R_p2;
ge_scalarmult(&dbg_R_p2, &r, &B_p3);
ge_tobytes(&dbg_R, &dbg_R_p2);
}
else
{
ge_p3 dbg_R_p3;
ge_scalarmult_base(&dbg_R_p3, &r);
ge_p3_tobytes(&dbg_R, &dbg_R_p3);
}
assert(R == dbg_R);
// check D == r*A
ge_p2 dbg_D_p2;
Expand All @@ -276,43 +306,84 @@ namespace crypto {
ec_scalar k;
random_scalar(k);

// compute X = k*G
ge_p3 X_p3;
ge_scalarmult_base(&X_p3, &k);
s_comm_2 buf;
buf.msg = prefix_hash;
buf.D = D;

if (B)
{
// compute X = k*B
ge_p2 X_p2;
ge_scalarmult(&X_p2, &k, &B_p3);
ge_tobytes(&buf.X, &X_p2);
}
else
{
// compute X = k*G
ge_p3 X_p3;
ge_scalarmult_base(&X_p3, &k);
ge_p3_tobytes(&buf.X, &X_p3);
}

// compute Y = k*A
ge_p2 Y_p2;
ge_scalarmult(&Y_p2, &k, &A_p3);
ge_tobytes(&buf.Y, &Y_p2);

// sig.c = Hs(Msg || D || X || Y)
s_comm_2 buf;
buf.msg = prefix_hash;
buf.D = D;
ge_p3_tobytes(&buf.X, &X_p3);
ge_tobytes(&buf.Y, &Y_p2);
hash_to_scalar(&buf, sizeof(s_comm_2), sig.c);
hash_to_scalar(&buf, sizeof(buf), sig.c);

// sig.r = k - sig.c*r
sc_mulsub(&sig.r, &sig.c, &r, &k);
}

bool crypto_ops::check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const public_key &D, const signature &sig) {
bool crypto_ops::check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const signature &sig) {
// sanity check
ge_p3 R_p3;
ge_p3 A_p3;
ge_p3 B_p3;
ge_p3 D_p3;
if (ge_frombytes_vartime(&R_p3, &R) != 0) return false;
if (ge_frombytes_vartime(&A_p3, &A) != 0) return false;
if (B && ge_frombytes_vartime(&B_p3, &*B) != 0) return false;
if (ge_frombytes_vartime(&D_p3, &D) != 0) return false;
if (sc_check(&sig.c) != 0 || sc_check(&sig.r) != 0) return false;

// compute sig.c*R
ge_p2 cR_p2;
ge_scalarmult(&cR_p2, &sig.c, &R_p3);
ge_p3 cR_p3;
{
ge_p2 cR_p2;
ge_scalarmult(&cR_p2, &sig.c, &R_p3);
public_key cR;
ge_tobytes(&cR, &cR_p2);
if (ge_frombytes_vartime(&cR_p3, &cR) != 0) return false;
}

// compute sig.r*G
ge_p3 rG_p3;
ge_scalarmult_base(&rG_p3, &sig.r);
ge_p1p1 X_p1p1;
if (B)
{
// compute X = sig.c*R + sig.r*B
ge_p2 rB_p2;
ge_scalarmult(&rB_p2, &sig.r, &B_p3);
public_key rB;
ge_tobytes(&rB, &rB_p2);
ge_p3 rB_p3;
if (ge_frombytes_vartime(&rB_p3, &rB) != 0) return false;
ge_cached rB_cached;
ge_p3_to_cached(&rB_cached, &rB_p3);
ge_add(&X_p1p1, &cR_p3, &rB_cached);
}
else
{
// compute X = sig.c*R + sig.r*G
ge_p3 rG_p3;
ge_scalarmult_base(&rG_p3, &sig.r);
ge_cached rG_cached;
ge_p3_to_cached(&rG_cached, &rG_p3);
ge_add(&X_p1p1, &cR_p3, &rG_cached);
}
ge_p2 X_p2;
ge_p1p1_to_p2(&X_p2, &X_p1p1);

// compute sig.c*D
ge_p2 cD_p2;
Expand All @@ -322,18 +393,6 @@ namespace crypto {
ge_p2 rA_p2;
ge_scalarmult(&rA_p2, &sig.r, &A_p3);

// compute X = sig.c*R + sig.r*G
public_key cR;
ge_tobytes(&cR, &cR_p2);
ge_p3 cR_p3;
if (ge_frombytes_vartime(&cR_p3, &cR) != 0) return false;
ge_cached rG_cached;
ge_p3_to_cached(&rG_cached, &rG_p3);
ge_p1p1 X_p1p1;
ge_add(&X_p1p1, &cR_p3, &rG_cached);
ge_p2 X_p2;
ge_p1p1_to_p2(&X_p2, &X_p1p1);

// compute Y = sig.c*D + sig.r*A
public_key cD;
public_key rA;
Expand Down
27 changes: 19 additions & 8 deletions src/crypto/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <boost/thread/mutex.hpp>
#include <boost/thread/lock_guard.hpp>
#include <boost/utility/value_init.hpp>
#include <boost/optional.hpp>
#include <vector>

#include "common/pod-class.h"
Expand Down Expand Up @@ -98,6 +99,8 @@ namespace crypto {
};
#pragma pack(pop)

void hash_to_scalar(const void *data, size_t length, ec_scalar &res);

static_assert(sizeof(ec_point) == 32 && sizeof(ec_scalar) == 32 &&
sizeof(public_key) == 32 && sizeof(secret_key) == 32 &&
sizeof(key_derivation) == 32 && sizeof(key_image) == 32 &&
Expand All @@ -123,14 +126,16 @@ namespace crypto {
friend bool derive_public_key(const key_derivation &, std::size_t, const public_key &, public_key &);
static void derive_secret_key(const key_derivation &, std::size_t, const secret_key &, secret_key &);
friend void derive_secret_key(const key_derivation &, std::size_t, const secret_key &, secret_key &);
static bool derive_subaddress_public_key(const public_key &, const key_derivation &, std::size_t, public_key &);
friend bool derive_subaddress_public_key(const public_key &, const key_derivation &, std::size_t, public_key &);
static void generate_signature(const hash &, const public_key &, const secret_key &, signature &);
friend void generate_signature(const hash &, const public_key &, const secret_key &, signature &);
static bool check_signature(const hash &, const public_key &, const signature &);
friend bool check_signature(const hash &, const public_key &, const signature &);
static void generate_tx_proof(const hash &, const public_key &, const public_key &, const public_key &, const secret_key &, signature &);
friend void generate_tx_proof(const hash &, const public_key &, const public_key &, const public_key &, const secret_key &, signature &);
static bool check_tx_proof(const hash &, const public_key &, const public_key &, const public_key &, const signature &);
friend bool check_tx_proof(const hash &, const public_key &, const public_key &, const public_key &, const signature &);
static void generate_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
friend void generate_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
static bool check_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const signature &);
friend bool check_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const signature &);
static void generate_key_image(const public_key &, const secret_key &, key_image &);
friend void generate_key_image(const public_key &, const secret_key &, key_image &);
static void generate_ring_signature(const hash &, const key_image &,
Expand Down Expand Up @@ -198,6 +203,9 @@ namespace crypto {
const secret_key &base, secret_key &derived_key) {
crypto_ops::derive_secret_key(derivation, output_index, base, derived_key);
}
inline bool derive_subaddress_public_key(const public_key &out_key, const key_derivation &derivation, std::size_t output_index, public_key &result) {
return crypto_ops::derive_subaddress_public_key(out_key, derivation, output_index, result);
}

/* Generation and checking of a standard signature.
*/
Expand All @@ -210,12 +218,13 @@ namespace crypto {

/* Generation and checking of a tx proof; given a tx pubkey R, the recipient's view pubkey A, and the key
* derivation D, the signature proves the knowledge of the tx secret key r such that R=r*G and D=r*A
* When the recipient's address is a subaddress, the tx pubkey R is defined as R=r*B where B is the recipient's spend pubkey
*/
inline void generate_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const public_key &D, const secret_key &r, signature &sig) {
crypto_ops::generate_tx_proof(prefix_hash, R, A, D, r, sig);
inline void generate_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const secret_key &r, signature &sig) {
crypto_ops::generate_tx_proof(prefix_hash, R, A, B, D, r, sig);
}
inline bool check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const public_key &D, const signature &sig) {
return crypto_ops::check_tx_proof(prefix_hash, R, A, D, sig);
inline bool check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const signature &sig) {
return crypto_ops::check_tx_proof(prefix_hash, R, A, B, D, sig);
}

/* To send money to a key:
Expand Down Expand Up @@ -270,8 +279,10 @@ namespace crypto {
}

const static crypto::public_key null_pkey = boost::value_initialized<crypto::public_key>();
const static crypto::secret_key null_skey = boost::value_initialized<crypto::secret_key>();
}

CRYPTO_MAKE_HASHABLE(public_key)
CRYPTO_MAKE_HASHABLE(secret_key)
CRYPTO_MAKE_HASHABLE(key_image)
CRYPTO_MAKE_COMPARABLE(signature)
2 changes: 1 addition & 1 deletion src/cryptonote_basic/account.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ DISABLE_VS_WARNINGS(4244 4345)
std::string account_base::get_public_address_str(bool testnet) const
{
//TODO: change this code into base 58
return get_account_address_as_str(testnet, m_keys.m_account_address);
return get_account_address_as_str(testnet, false, m_keys.m_account_address);
}
//-----------------------------------------------------------------
std::string account_base::get_public_integrated_address_str(const crypto::hash8 &payment_id, bool testnet) const
Expand Down
Loading