Encrypt mapping values via libsodium, using the name as secret

This commit is contained in:
Doyle 2020-02-14 11:07:00 +11:00
parent 79ad110ba7
commit 1ba657d3b5
10 changed files with 298 additions and 202 deletions

View File

@ -401,28 +401,28 @@ namespace cryptonote
crypto::ed25519_public_key owner; // only serialized if command == tx_command_t::buy
crypto::ed25519_signature signature; // only serialized if command == tx_command_t::update
crypto::hash name_hash;
std::string value; // binary format of the name->value mapping
std::string encrypted_value; // encrypted binary format of the value in the name->value mapping
crypto::hash prev_txid = crypto::null_hash; // previous txid that purchased the mapping
static tx_extra_loki_name_system make_buy(crypto::ed25519_public_key const &owner, lns::mapping_type type, crypto::hash const &name_hash, std::string const &value, crypto::hash const &prev_txid)
static tx_extra_loki_name_system make_buy(crypto::ed25519_public_key const &owner, lns::mapping_type type, crypto::hash const &name_hash, std::string const &encrypted_value, crypto::hash const &prev_txid)
{
tx_extra_loki_name_system result = {};
result.owner = owner;
result.type = type;
result.name_hash = name_hash;
result.value = value;
result.encrypted_value = encrypted_value;
result.prev_txid = prev_txid;
result.command = lns::tx_command_t::buy;
return result;
}
static tx_extra_loki_name_system make_update(crypto::ed25519_signature const &signature, lns::mapping_type type, crypto::hash const &name_hash, std::string const &value, crypto::hash const &prev_txid)
static tx_extra_loki_name_system make_update(crypto::ed25519_signature const &signature, lns::mapping_type type, crypto::hash const &name_hash, std::string const &encrypted_value, crypto::hash const &prev_txid)
{
tx_extra_loki_name_system result = {};
result.signature = signature;
result.type = type;
result.name_hash = name_hash;
result.value = value;
result.encrypted_value = encrypted_value;
result.prev_txid = prev_txid;
result.command = lns::tx_command_t::update;
return result;
@ -437,7 +437,7 @@ namespace cryptonote
else
FIELD(signature)
FIELD(name_hash)
FIELD(value)
FIELD(encrypted_value)
FIELD(prev_txid)
END_SERIALIZE()
};

View File

@ -18,7 +18,7 @@
extern "C"
{
#include "sodium.h"
#include <sodium.h>
}
#undef LOKI_DEFAULT_LOG_CATEGORY
@ -63,7 +63,7 @@ enum struct mapping_record_row
id,
type,
name_hash,
value,
encrypted_value,
txid,
prev_txid,
register_height,
@ -142,9 +142,18 @@ static bool sql_run_statement(cryptonote::network_type nettype, lns_sql_type typ
tmp_entry.register_height = static_cast<uint16_t>(sqlite3_column_int(statement, static_cast<int>(mapping_record_row::register_height)));
tmp_entry.owner_id = sqlite3_column_int(statement, static_cast<int>(mapping_record_row::owner_id));
size_t value_len = static_cast<size_t>(sqlite3_column_bytes(statement, static_cast<int>(mapping_record_row::value)));
auto *value = reinterpret_cast<char const *>(sqlite3_column_text(statement, static_cast<int>(mapping_record_row::value)));
tmp_entry.value = std::string(value, value_len);
// Copy encrypted_value
{
size_t value_len = static_cast<size_t>(sqlite3_column_bytes(statement, static_cast<int>(mapping_record_row::encrypted_value)));
auto *value = reinterpret_cast<char const *>(sqlite3_column_text(statement, static_cast<int>(mapping_record_row::encrypted_value)));
if (value_len > tmp_entry.encrypted_value.buffer.size())
{
MERROR("Unexpected encrypted value blob with size=" << value_len << ", in LNS db larger than the available size=" << tmp_entry.encrypted_value.buffer.size());
return false;
}
tmp_entry.encrypted_value.len = value_len;
memcpy(&tmp_entry.encrypted_value.buffer[0], value, value_len);
}
if (!sql_copy_blob(statement, static_cast<int>(mapping_record_row::name_hash), tmp_entry.name_hash.data, sizeof(tmp_entry.name_hash)))
return false;
@ -273,9 +282,9 @@ crypto::hash tx_extra_signature_hash(epee::span<const uint8_t> blob, crypto::has
{
static_assert(sizeof(crypto::hash) == crypto_generichash_BYTES, "Using libsodium generichash for signature hash, require we fit into crypto::hash");
crypto::hash result = {};
if (blob.size() <= lns_value::BUFFER_SIZE)
if (blob.size() <= mapping_value::BUFFER_SIZE)
{
unsigned char buffer[lns_value::BUFFER_SIZE + sizeof(prev_txid)] = {};
unsigned char buffer[mapping_value::BUFFER_SIZE + sizeof(prev_txid)] = {};
size_t buffer_len = blob.size() + sizeof(prev_txid);
memcpy(buffer, blob.data(), blob.size());
memcpy(buffer + blob.size(), prev_txid.data, sizeof(prev_txid));
@ -283,7 +292,7 @@ crypto::hash tx_extra_signature_hash(epee::span<const uint8_t> blob, crypto::has
}
else
{
MERROR("Unexpected blob len=" << blob.size() << " greater than the blob backing buffer capacity=" << lns_value::BUFFER_SIZE);
MERROR("Unexpected blob len=" << blob.size() << " greater than the blob backing buffer capacity=" << mapping_value::BUFFER_SIZE);
}
return result;
@ -409,7 +418,7 @@ static bool check_lengths(mapping_type type, std::string const &value, size_t ma
if (reason)
{
std::stringstream err_stream;
err_stream << "LNS type=" << type << ", specifies mapping from name_hash->value where the value's length=" << value.size() << ", does not equal the required length=" << max << ", given value=" << value;
err_stream << "LNS type=" << type << ", specifies mapping from name_hash->encrypted_value where the value's length=" << value.size() << ", does not equal the required length=" << max << ", given value=" << value;
*reason = err_stream.str();
}
}
@ -417,16 +426,16 @@ static bool check_lengths(mapping_type type, std::string const &value, size_t ma
return result;
}
bool validate_lns_value(cryptonote::network_type nettype, mapping_type type, std::string const &value, lns_value *blob, std::string *reason)
bool validate_mapping_value(cryptonote::network_type nettype, mapping_type type, std::string const &value, mapping_value *blob, std::string *reason)
{
if (blob) *blob = {};
std::stringstream err_stream;
cryptonote::address_parse_info addr_info = {};
static_assert(lns_value::BUFFER_SIZE >= SESSION_PUBLIC_KEY_BINARY_LENGTH, "Value blob assumes the largest size required, all other values should be able to fit into this buffer");
static_assert(lns_value::BUFFER_SIZE >= LOKINET_ADDRESS_BINARY_LENGTH, "Value blob assumes the largest size required, all other values should be able to fit into this buffer");
static_assert(lns_value::BUFFER_SIZE >= sizeof(addr_info.address), "Value blob assumes the largest size required, all other values should be able to fit into this buffer");
static_assert(mapping_value::BUFFER_SIZE >= SESSION_PUBLIC_KEY_BINARY_LENGTH, "Value blob assumes the largest size required, all other values should be able to fit into this buffer");
static_assert(mapping_value::BUFFER_SIZE >= LOKINET_ADDRESS_BINARY_LENGTH, "Value blob assumes the largest size required, all other values should be able to fit into this buffer");
static_assert(mapping_value::BUFFER_SIZE >= sizeof(addr_info.address), "Value blob assumes the largest size required, all other values should be able to fit into this buffer");
if (type == mapping_type::wallet)
{
if (value.empty() || !get_account_address_from_str(addr_info, nettype, value))
@ -547,13 +556,13 @@ bool validate_lns_value(cryptonote::network_type nettype, mapping_type type, std
return true;
}
bool validate_lns_value_binary(mapping_type type, std::string const &value, std::string *reason)
bool validate_encrypted_mapping_value(mapping_type type, std::string const &value, std::string *reason)
{
std::stringstream err_stream;
int max_value_len = 0;
if (is_lokinet_type(type)) max_value_len = LOKINET_ADDRESS_BINARY_LENGTH;
else if (type == mapping_type::session) max_value_len = SESSION_PUBLIC_KEY_BINARY_LENGTH;
else if (type == mapping_type::wallet) max_value_len = sizeof(cryptonote::account_public_address);
int max_value_len = crypto_secretbox_MACBYTES;
if (is_lokinet_type(type)) max_value_len += LOKINET_ADDRESS_BINARY_LENGTH;
else if (type == mapping_type::session) max_value_len += SESSION_PUBLIC_KEY_BINARY_LENGTH;
else if (type == mapping_type::wallet) max_value_len += sizeof(cryptonote::account_public_address);
else
{
if (reason)
@ -628,7 +637,7 @@ static bool validate_against_previous_mapping(lns::name_system_db const &lns_db,
return false;
}
if (data.value == mapping.value)
if (mapping.encrypted_value == data.encrypted_value)
{
if (reason)
{
@ -640,7 +649,7 @@ static bool validate_against_previous_mapping(lns::name_system_db const &lns_db,
// Validate signature
{
crypto::hash hash = tx_extra_signature_hash(epee::span<const uint8_t>(reinterpret_cast<const uint8_t *>(data.value.data()), data.value.size()), expected_prev_txid);
crypto::hash hash = tx_extra_signature_hash(epee::span<const uint8_t>(reinterpret_cast<const uint8_t *>(data.encrypted_value.data()), data.encrypted_value.size()), expected_prev_txid);
if (crypto_sign_verify_detached(data.signature.data, reinterpret_cast<unsigned char *>(hash.data), sizeof(hash.data), mapping.owner.data) != 0)
{
if (reason)
@ -778,7 +787,7 @@ bool name_system_db::validate_lns_tx(uint8_t hf_version, uint64_t blockchain_hei
return false;
}
if (!validate_lns_value_binary(entry->type, entry->value, reason))
if (!validate_encrypted_mapping_value(entry->type, entry->encrypted_value, reason))
return false;
if (!validate_against_previous_mapping(*this, blockchain_height, tx, *entry, reason))
@ -852,6 +861,56 @@ crypto::hash name_to_hash(std::string const &name)
return result;
}
struct alignas(size_t) secretbox_secret_key_ { unsigned char data[crypto_secretbox_KEYBYTES]; };
using secretbox_secret_key = epee::mlocked<tools::scrubbed<secretbox_secret_key_>>;
static bool name_to_encryption_key(std::string const &name, secretbox_secret_key &out)
{
static_assert(sizeof(out) >= crypto_secretbox_KEYBYTES, "Encrypting key needs to have sufficient space for running encryption functions via libsodium");
static unsigned char constexpr SALT[crypto_pwhash_SALTBYTES] = {};
bool result = (crypto_pwhash(out.data, sizeof(out), name.data(), name.size(), SALT, crypto_pwhash_OPSLIMIT_MODERATE, crypto_pwhash_MEMLIMIT_MODERATE, crypto_pwhash_ALG_ARGON2ID13) == 0);
return result;
}
static unsigned char const ENCRYPTION_NONCE[crypto_secretbox_NONCEBYTES] = {}; // NOTE: Not meant to be secure
bool encrypt_mapping_value(std::string const &name, mapping_value const &value, mapping_value &encrypted_value)
{
bool result = false;
size_t const encryption_len = value.len + crypto_secretbox_MACBYTES;
if (encryption_len > encrypted_value.buffer.size())
{
MERROR("Encrypted value pre-allocated buffer too small=" << encrypted_value.buffer.size() << ", required=" << encryption_len);
return result;
}
encrypted_value = {};
encrypted_value.len = encryption_len;
secretbox_secret_key skey;
if (name_to_encryption_key(name, skey))
result = (crypto_secretbox_easy(encrypted_value.buffer.data(), value.buffer.data(), value.len, ENCRYPTION_NONCE, reinterpret_cast<unsigned char *>(&skey)) == 0);
return result;
}
bool decrypt_mapping_value(std::string const &name, mapping_value const &encrypted_value, mapping_value &value)
{
bool result = false;
if (encrypted_value.len <= crypto_secretbox_MACBYTES)
{
MERROR("Encrypted value is too short=" << encrypted_value.len << ", at least required=" << crypto_secretbox_MACBYTES + 1);
return result;
}
value = {};
value.len = encrypted_value.len - crypto_secretbox_MACBYTES;
secretbox_secret_key skey;
if (name_to_encryption_key(name, skey))
result = crypto_secretbox_open_easy(value.buffer.data(), encrypted_value.buffer.data(), encrypted_value.len, ENCRYPTION_NONCE, reinterpret_cast<unsigned char *>(&skey)) == 0;
return result;
}
static bool build_default_tables(sqlite3 *db)
{
constexpr char BUILD_TABLE_SQL[] = R"(
@ -871,7 +930,7 @@ CREATE TABLE IF NOT EXISTS "mappings" (
"id" INTEGER PRIMARY KEY NOT NULL,
"type" INTEGER NOT NULL,
"name_hash" BLOB NOT NULL,
"value" BLOB NOT NULL,
"encrypted_value" BLOB NOT NULL,
"txid" BLOB NOT NULL,
"prev_txid" BLOB NOT NULL,
"register_height" INTEGER NOT NULL,
@ -908,7 +967,7 @@ bool name_system_db::init(cryptonote::network_type nettype, sqlite3 *db, uint64_
char constexpr GET_SETTINGS_SQL[] = R"(SELECT * FROM "settings" WHERE "id" = 1)";
char constexpr PRUNE_MAPPINGS_SQL[] = R"(DELETE FROM "mappings" WHERE "register_height" >= ?)";
char constexpr PRUNE_OWNERS_SQL[] = R"(DELETE FROM "owner" WHERE "id" NOT IN (SELECT "owner_id" FROM "mappings"))";
char constexpr SAVE_MAPPING_SQL[] = R"(INSERT OR REPLACE INTO "mappings" ("type", "name_hash", "value", "txid", "prev_txid", "register_height", "owner_id") VALUES (?,?,?,?,?,?,?))";
char constexpr SAVE_MAPPING_SQL[] = R"(INSERT OR REPLACE INTO "mappings" ("type", "name_hash", "encrypted_value", "txid", "prev_txid", "register_height", "owner_id") VALUES (?,?,?,?,?,?,?))";
char constexpr SAVE_OWNER_SQL[] = R"(INSERT INTO "owner" ("public_key") VALUES (?);)";
char constexpr SAVE_SETTINGS_SQL[] = R"(INSERT OR REPLACE INTO "settings" ("id", "top_height", "top_hash", "version") VALUES (1,?,?,?))";
@ -1178,7 +1237,7 @@ bool name_system_db::save_mapping(crypto::hash const &tx_hash, cryptonote::tx_ex
sqlite3_stmt *statement = save_mapping_sql;
sqlite3_bind_int (statement, static_cast<int>(mapping_record_row::type), static_cast<uint16_t>(src.type));
sqlite3_bind_blob (statement, static_cast<int>(mapping_record_row::name_hash), src.name_hash.data, sizeof(src.name_hash), nullptr /*destructor*/);
sqlite3_bind_blob (statement, static_cast<int>(mapping_record_row::value), src.value.data(), src.value.size(), nullptr /*destructor*/);
sqlite3_bind_blob (statement, static_cast<int>(mapping_record_row::encrypted_value), src.encrypted_value.data(), src.encrypted_value.size(), nullptr /*destructor*/);
sqlite3_bind_blob (statement, static_cast<int>(mapping_record_row::txid), tx_hash.data, sizeof(tx_hash), nullptr /*destructor*/);
sqlite3_bind_blob (statement, static_cast<int>(mapping_record_row::prev_txid), src.prev_txid.data, sizeof(src.prev_txid), nullptr /*destructor*/);
sqlite3_bind_int64(statement, static_cast<int>(mapping_record_row::register_height), static_cast<int64_t>(height));

View File

@ -5,6 +5,7 @@
#include "cryptonote_config.h"
#include "span.h"
#include "cryptonote_basic/tx_extra.h"
#include "common/hex.h"
#include <string>
@ -29,27 +30,33 @@ constexpr size_t LOKINET_ADDRESS_BINARY_LENGTH = sizeof(crypto::ed25519_publi
constexpr size_t SESSION_DISPLAY_NAME_MAX = 64;
constexpr size_t SESSION_PUBLIC_KEY_BINARY_LENGTH = 1 + sizeof(crypto::ed25519_public_key); // Session keys at prefixed with 0x05 + ed25519 key
struct lns_value
struct mapping_value
{
static size_t constexpr BUFFER_SIZE = 255;
std::array<uint8_t, BUFFER_SIZE> buffer;
size_t len;
};
inline std::ostream &operator<<(std::ostream &os, mapping_type type)
std::string to_string() const { return std::string(reinterpret_cast<char const *>(buffer.data()), len); }
epee::span<const uint8_t> to_span() const { return epee::span<const uint8_t>(reinterpret_cast<const uint8_t *>(buffer.data()), len); }
bool operator==(mapping_value const &other) const { return other.len == len && memcmp(buffer.data(), other.buffer.data(), len) == 0; }
bool operator==(std::string const &other) const { return other.size() == len && memcmp(buffer.data(), other.data(), len) == 0; }
};
inline std::ostream &operator<<(std::ostream &os, mapping_value const &v) { return os << hex::from_hex(v.buffer.begin(), v.buffer.begin() + v.len); }
inline char const *mapping_type_str(mapping_type type)
{
switch(type)
{
case mapping_type::lokinet_1year: os << "lokinet_1year"; break;
case mapping_type::lokinet_2years: os << "lokinet_2years"; break;
case mapping_type::lokinet_5years: os << "lokinet_5years"; break;
case mapping_type::lokinet_10years: os << "lokinet_10years"; break;
case mapping_type::session: os << "session"; break;
case mapping_type::wallet: os << "wallet"; break;
default: assert(false); os << "xx_unhandled_type"; break;
case mapping_type::lokinet_1year: return "lokinet_1year";
case mapping_type::lokinet_2years: return "lokinet_2years";
case mapping_type::lokinet_5years: return "lokinet_5years";
case mapping_type::lokinet_10years: return "lokinet_10years";
case mapping_type::session: return "session";
case mapping_type::wallet: return "wallet";
default: assert(false); return "xx_unhandled_type";
}
return os;
}
inline std::ostream &operator<<(std::ostream &os, mapping_type type) { return os << mapping_type_str(type); }
constexpr bool mapping_type_allowed(uint8_t hf_version, mapping_type type) { return type == mapping_type::session; }
constexpr bool is_lokinet_type (lns::mapping_type type) { return type >= mapping_type::lokinet_1year && type <= mapping_type::lokinet_10years; }
@ -62,11 +69,16 @@ crypto::hash tx_extra_signature_hash(epee::span<const uint8_t> blob, crypto::has
bool validate_lns_name(mapping_type type, std::string const &name, std::string *reason = nullptr);
// blob: if set, validate_lns_value will convert the value into the binary format suitable for storing into the LNS DB.
bool validate_lns_value(cryptonote::network_type nettype, mapping_type type, std::string const &value, lns_value *blob = nullptr, std::string *reason = nullptr);
bool validate_lns_value_binary(mapping_type type, std::string const &value, std::string *reason = nullptr);
bool validate_mapping_value(cryptonote::network_type nettype, mapping_type type, std::string const &value, mapping_value *blob = nullptr, std::string *reason = nullptr);
bool validate_encrypted_mapping_value(mapping_type type, std::string const &value, std::string *reason = nullptr);
bool validate_mapping_type(std::string const &type, lns::mapping_type *mapping_type, std::string *reason);
crypto::hash name_to_hash(std::string const &name);
// Takes a binary value and encrypts it using 'name' as a secret key or vice versa, suitable for storing into the LNS DB.
// Only basic overflow validation is attempted, values should be pre-validated in the validate* functions
bool encrypt_mapping_value(std::string const &name, mapping_value const &value, mapping_value &encrypted_value);
bool decrypt_mapping_value(std::string const &name, mapping_value const &encrypted_value, mapping_value &value);
struct owner_record
{
operator bool() const { return loaded; }
@ -99,7 +111,7 @@ struct mapping_record
bool loaded;
mapping_type type;
crypto::hash name_hash;
std::string value;
mapping_value encrypted_value;
uint64_t register_height;
int64_t owner_id;
crypto::ed25519_public_key owner;

View File

@ -3374,22 +3374,6 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
static std::string extract_lns_mapping_value(lns::mapping_record const &record)
{
std::string result;
if (lns::is_lokinet_type(record.type))
{
char buf[64] = {};
base32z::encode(record.value, buf);
result = std::string(buf) + ".loki";
}
else
{
result = epee::to_hex::string(epee::span<const uint8_t>(reinterpret_cast<const uint8_t *>(record.value.data()), record.value.size()));
}
return result;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_lns_names_to_owners(const COMMAND_RPC_GET_LNS_NAMES_TO_OWNERS::request &req, COMMAND_RPC_GET_LNS_NAMES_TO_OWNERS::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx)
{
if (exceeds_quantity_limit(ctx, error_resp, m_restricted, req.entries.size(), COMMAND_RPC_GET_LNS_NAMES_TO_OWNERS::MAX_REQUEST_ENTRIES))
@ -3412,7 +3396,7 @@ namespace cryptonote
entry.entry_index = request_index;
entry.type = static_cast<uint16_t>(record.type);
entry.owner = epee::string_tools::pod_to_hex(record.owner);
entry.value = extract_lns_mapping_value(record);
entry.encrypted_value = epee::to_hex::string(epee::span<const uint8_t>(record.encrypted_value.buffer.data(), record.encrypted_value.len));
entry.register_height = record.register_height;
entry.txid = epee::string_tools::pod_to_hex(record.txid);
entry.prev_txid = epee::string_tools::pod_to_hex(record.prev_txid);
@ -3448,27 +3432,27 @@ namespace cryptonote
}
lns::name_system_db const &db = m_core.get_blockchain_storage().name_system_db();
std::vector<lns::mapping_record> db_mappings = db.get_mappings_by_owners(keys);
for (lns::mapping_record const &mapping : db_mappings)
std::vector<lns::mapping_record> records = db.get_mappings_by_owners(keys);
for (auto const &record : records)
{
res.entries.emplace_back();
COMMAND_RPC_GET_LNS_OWNERS_TO_NAMES::response_entry &entry = res.entries.back();
auto it = key_to_request_index.find(mapping.owner);
auto it = key_to_request_index.find(record.owner);
if (it == key_to_request_index.end())
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
error_resp.message = "Public key=" + epee::string_tools::pod_to_hex(mapping.owner) + ", could not be mapped back a index in the request 'entries' array";
error_resp.message = "Public key=" + epee::string_tools::pod_to_hex(record.owner) + ", could not be mapped back a index in the request 'entries' array";
return false;
}
entry.request_index = it->second;
entry.type = static_cast<uint16_t>(mapping.type);
entry.name_hash = epee::string_tools::pod_to_hex(mapping.name_hash);
entry.value = extract_lns_mapping_value(mapping);
entry.register_height = mapping.register_height;
entry.txid = epee::string_tools::pod_to_hex(mapping.txid);
entry.prev_txid = epee::string_tools::pod_to_hex(mapping.prev_txid);
entry.type = static_cast<uint16_t>(record.type);
entry.name_hash = epee::string_tools::pod_to_hex(record.name_hash);
entry.encrypted_value = epee::to_hex::string(epee::span<const uint8_t>(record.encrypted_value.buffer.data(), record.encrypted_value.len));
entry.register_height = record.register_height;
entry.txid = epee::string_tools::pod_to_hex(record.txid);
entry.prev_txid = epee::string_tools::pod_to_hex(record.prev_txid);
}
res.status = CORE_RPC_STATUS_OK;

View File

@ -3482,7 +3482,7 @@ constexpr char const CORE_RPC_STATUS_TX_LONG_POLL_MAX_CONNECTIONS[] = "Daemon ma
uint64_t entry_index; // The index in request_entry's `entries` array that was resolved via Loki Name Service.
uint16_t type; // The type of Loki Name Service entry that the owner owns.
std::string owner; // The ed25519 public key that purchased the Loki Name Service entry.
std::string value; // The value that the name maps to.
std::string encrypted_value; // The encrypted value that the name maps to. This value is encrypted using the name (not the hash) as the secret.
uint64_t register_height; // The height that this Loki Name Service entry was purchased on the Blockchain.
std::string txid; // The txid of who purchased the mapping, null hash if not applicable.
std::string prev_txid; // The previous txid that purchased the mapping, null hash if not applicable.
@ -3490,7 +3490,7 @@ constexpr char const CORE_RPC_STATUS_TX_LONG_POLL_MAX_CONNECTIONS[] = "Daemon ma
KV_SERIALIZE(entry_index)
KV_SERIALIZE(type)
KV_SERIALIZE(owner)
KV_SERIALIZE(value)
KV_SERIALIZE(encrypted_value)
KV_SERIALIZE(register_height)
KV_SERIALIZE(txid)
KV_SERIALIZE(prev_txid)
@ -3528,14 +3528,15 @@ constexpr char const CORE_RPC_STATUS_TX_LONG_POLL_MAX_CONNECTIONS[] = "Daemon ma
uint64_t request_index; // The index in request's `entries` array that was resolved via Loki Name Service.
uint16_t type; // The category the Loki Name Service entry belongs to, currently only Session whose value is 0.
std::string name_hash; // The hash of the name that the owner purchased via Loki Name Service.
std::string value; // The value that the name maps to.
std::string encrypted_value; // The encrypted value that the name maps to. This value is encrypted using the name (not the hash) as the secret.
uint64_t register_height; // The height that this Loki Name Service entry was purchased on the Blockchain.
std::string txid; // The txid of who purchases the mapping, null hash if not applicable
std::string prev_txid; // The previous txid that purchased the mapping, null hash if not applicable.
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(request_index)
KV_SERIALIZE(type)
KV_SERIALIZE(name_hash)
KV_SERIALIZE(value)
KV_SERIALIZE(encrypted_value)
KV_SERIALIZE(register_height)
KV_SERIALIZE(txid)
KV_SERIALIZE(prev_txid)

View File

@ -6675,7 +6675,7 @@ bool simple_wallet::print_lns_owners_to_name_hashes(const std::vector<std::strin
}
}
tools::msg_writer() << "owner=" << *owner << ", type=" << entry.type << ", height=" << entry.register_height << ", name_hash=\"" << entry.name_hash << "\", value=" << entry.value << ", prev_txid=" << entry.prev_txid;
tools::msg_writer() << "owner=" << *owner << ", type=" << entry.type << ", height=" << entry.register_height << ", name_hash=\"" << entry.name_hash << "\", encrypted_value=" << entry.encrypted_value << ", prev_txid=" << entry.prev_txid;
}
return true;
}

View File

@ -8434,7 +8434,7 @@ static bool prepare_tx_extra_loki_name_system_values(cryptonote::network_type ne
std::string const &value,
wallet2 const &wallet,
crypto::hash &prev_txid,
lns::lns_value &value_blob,
lns::mapping_value &encrypted_value,
std::string *reason)
{
if (priority == tools::tx_priority_blink)
@ -8443,11 +8443,38 @@ static bool prepare_tx_extra_loki_name_system_values(cryptonote::network_type ne
return false;
}
if (!lns::validate_lns_name(type, name, reason))
boost::optional<uint8_t> hf_version = wallet.get_hard_fork_version();
if (!hf_version)
{
if (reason) *reason = ERR_MSG_NETWORK_VERSION_QUERY_FAILED;
return false;
}
if (!lns::validate_lns_value(nettype, type, value, &value_blob, reason))
return false;
// Make encrypted value
{
if (!lns::validate_lns_name(type, name, reason))
return false;
if (!lns::mapping_type_allowed(*hf_version, type))
{
if (reason)
{
*reason = "Mapping type not allowed=";
reason->append(lns::mapping_type_str(type));
}
return false;
}
lns::mapping_value blob = {};
if (!lns::validate_mapping_value(nettype, type, value, &blob, reason))
return false;
if (!lns::encrypt_mapping_value(name, blob, encrypted_value))
{
if (reason) *reason = "Failed to encrypt LNS value=" + value;
return false;
}
}
prev_txid = crypto::null_hash;
{
@ -8509,13 +8536,13 @@ std::vector<wallet2::pending_tx> wallet2::create_buy_lns_mapping_tx(lns::mapping
crypto_sign_ed25519_seed_keypair(pkey.data, skey.data, reinterpret_cast<const unsigned char *>(&m_account.get_keys().m_spend_secret_key));
}
lns::lns_value value_blob;
lns::mapping_value encrypted_value;
crypto::hash prev_txid;
if (!prepare_tx_extra_loki_name_system_values(nettype(), type, priority, name, value, *this, prev_txid, value_blob, reason))
if (!prepare_tx_extra_loki_name_system_values(nettype(), type, priority, name, value, *this, prev_txid, encrypted_value, reason))
return {};
std::vector<uint8_t> extra;
auto entry = cryptonote::tx_extra_loki_name_system::make_buy(pkey, type, lns::name_to_hash(name), std::string(reinterpret_cast<char const *>(value_blob.buffer.data()), value_blob.len), prev_txid);
auto entry = cryptonote::tx_extra_loki_name_system::make_buy(pkey, type, lns::name_to_hash(name), encrypted_value.to_string(), prev_txid);
add_loki_name_system_to_tx_extra(extra, entry);
boost::optional<uint8_t> hf_version = get_hard_fork_version();
@ -8564,7 +8591,7 @@ std::vector<wallet2::pending_tx> wallet2::create_update_lns_mapping_tx(lns::mapp
std::set<uint32_t> subaddr_indices)
{
crypto::hash prev_txid;
lns::lns_value value_blob;
lns::mapping_value value_blob;
if (!prepare_tx_extra_loki_name_system_values(nettype(), type, priority, name, value, *this, prev_txid, value_blob, reason))
return {};

View File

@ -284,22 +284,23 @@ void loki_chain_generator::add_tx(cryptonote::transaction const &tx, bool can_be
cryptonote::transaction
loki_chain_generator::create_and_add_loki_name_system_tx(cryptonote::account_base const &src,
lns::mapping_type type,
std::string const &value,
std::string const &name,
crypto::ed25519_public_key const *owner,
bool kept_by_block)
lns::mapping_type type,
lns::mapping_value const &value,
std::string const &name,
crypto::ed25519_public_key const *owner,
bool kept_by_block)
{
cryptonote::transaction t = create_loki_name_system_tx(src, type, value, name, owner);
add_tx(t, true /*can_be_added_to_blockchain*/, ""/*fail_msg*/, kept_by_block);
return t;
}
cryptonote::transaction loki_chain_generator::create_and_add_loki_name_system_tx_update(cryptonote::account_base const &src,
lns::mapping_type type,
std::string const &value,
std::string const &name,
bool kept_by_block)
cryptonote::transaction
loki_chain_generator::create_and_add_loki_name_system_tx_update(cryptonote::account_base const &src,
lns::mapping_type type,
lns::mapping_value const &value,
std::string const &name,
bool kept_by_block)
{
cryptonote::transaction t = create_loki_name_system_tx_update(src, type, value, name);
add_tx(t, true /*can_be_added_to_blockchain*/, ""/*fail_msg*/, kept_by_block);
@ -514,7 +515,7 @@ cryptonote::checkpoint_t loki_chain_generator::create_service_node_checkpoint(ui
cryptonote::transaction loki_chain_generator::create_loki_name_system_tx(cryptonote::account_base const &src,
lns::mapping_type type,
std::string const &value,
lns::mapping_value const &value,
std::string const &name,
crypto::ed25519_public_key const *owner,
uint64_t burn) const
@ -541,8 +542,12 @@ cryptonote::transaction loki_chain_generator::create_loki_name_system_tx(crypton
if (lns::mapping_record mapping = lns_db_.get_mapping(type, name_hash))
prev_txid = mapping.txid;
lns::mapping_value encrypted_value = {};
bool encrypted = lns::encrypt_mapping_value(name, value, encrypted_value);
assert(encrypted);
std::vector<uint8_t> extra;
cryptonote::tx_extra_loki_name_system data = cryptonote::tx_extra_loki_name_system::make_buy(pkey, type, name_hash, value, prev_txid);
cryptonote::tx_extra_loki_name_system data = cryptonote::tx_extra_loki_name_system::make_buy(pkey, type, name_hash, encrypted_value.to_string(), prev_txid);
cryptonote::add_loki_name_system_to_tx_extra(extra, data);
cryptonote::add_burned_amount_to_tx_extra(extra, burn);
cryptonote::transaction result = {};
@ -557,7 +562,7 @@ cryptonote::transaction loki_chain_generator::create_loki_name_system_tx(crypton
cryptonote::transaction loki_chain_generator::create_loki_name_system_tx_update(cryptonote::account_base const &src,
lns::mapping_type type,
std::string const &value,
lns::mapping_value const &value,
std::string const &name,
crypto::ed25519_signature *signature,
bool use_asserts) const
@ -571,16 +576,20 @@ cryptonote::transaction loki_chain_generator::create_loki_name_system_tx_update(
crypto::ed25519_secret_key skey;
crypto_sign_ed25519_seed_keypair(pkey.data, skey.data, reinterpret_cast<const unsigned char *>(&src.get_keys().m_spend_secret_key));
lns::mapping_value encrypted_value = {};
bool encrypted = lns::encrypt_mapping_value(name, value, encrypted_value);
if (use_asserts) assert(encrypted);
crypto::ed25519_signature signature_ = {};
if (!signature)
{
signature = &signature_;
crypto::hash hash = lns::tx_extra_signature_hash(epee::span<const uint8_t>(reinterpret_cast<const uint8_t *>(value.data()), value.size()), prev_txid);
crypto::hash hash = lns::tx_extra_signature_hash(epee::span<const uint8_t>(reinterpret_cast<const uint8_t *>(encrypted_value.buffer.data()), encrypted_value.len), prev_txid);
crypto_sign_detached(signature->data, NULL, reinterpret_cast<unsigned char *>(hash.data), sizeof(hash.data), skey.data);
}
std::vector<uint8_t> extra;
cryptonote::tx_extra_loki_name_system data = cryptonote::tx_extra_loki_name_system::make_update(*signature, type, name_hash, value, prev_txid);
cryptonote::tx_extra_loki_name_system data = cryptonote::tx_extra_loki_name_system::make_update(*signature, type, name_hash, encrypted_value.to_string(), prev_txid);
cryptonote::add_loki_name_system_to_tx_extra(extra, data);
cryptonote::block const &head = top().block;

View File

@ -1421,8 +1421,9 @@ struct loki_chain_generator
// NOTE: Add constructed TX to events_ and assume that it is valid to add to the blockchain. If the TX is meant to be unaddable to the blockchain use the individual create + add functions to
// be able to mark the add TX event as something that should trigger a failure.
cryptonote::transaction create_and_add_loki_name_system_tx(cryptonote::account_base const &src, lns::mapping_type type, std::string const &value, std::string const &name, crypto::ed25519_public_key const *owner = nullptr, bool kept_by_block = false);
cryptonote::transaction create_and_add_loki_name_system_tx_update(cryptonote::account_base const &src, lns::mapping_type type, std::string const &value, std::string const &name, bool kept_by_block = false);
// value: The binary representation of the value part in the name->value mapping
cryptonote::transaction create_and_add_loki_name_system_tx(cryptonote::account_base const &src, lns::mapping_type type, lns::mapping_value const &value, std::string const &name, crypto::ed25519_public_key const *owner = nullptr, bool kept_by_block = false);
cryptonote::transaction create_and_add_loki_name_system_tx_update(cryptonote::account_base const &src, lns::mapping_type type, lns::mapping_value const &value, std::string const &name, bool kept_by_block = false);
cryptonote::transaction create_and_add_tx (const cryptonote::account_base& src, const cryptonote::account_public_address& dest, uint64_t amount, uint64_t fee = TESTS_DEFAULT_FEE, bool kept_by_block = false);
cryptonote::transaction create_and_add_state_change_tx(service_nodes::new_state state, const crypto::public_key& pub_key, uint64_t height = -1, const std::vector<uint64_t>& voters = {}, uint64_t fee = 0, bool kept_by_block = false);
cryptonote::transaction create_and_add_registration_tx(const cryptonote::account_base& src, const cryptonote::keypair& sn_keys = cryptonote::keypair::generate(hw::get_device("default")), bool kept_by_block = false);
@ -1443,8 +1444,8 @@ struct loki_chain_generator
// value: Takes the binary value NOT the human readable version, of the name->value mapping
static const uint64_t LNS_AUTO_BURN = static_cast<uint64_t>(-1);
cryptonote::transaction create_loki_name_system_tx (cryptonote::account_base const &src, lns::mapping_type type, std::string const &value, std::string const &name, crypto::ed25519_public_key const *owner = nullptr, uint64_t burn = LNS_AUTO_BURN) const;
cryptonote::transaction create_loki_name_system_tx_update(cryptonote::account_base const &src, lns::mapping_type type, std::string const &value, std::string const &name, crypto::ed25519_signature *signature = nullptr, bool use_asserts = false) const;
cryptonote::transaction create_loki_name_system_tx (cryptonote::account_base const &src, lns::mapping_type type, lns::mapping_value const &value, std::string const &name, crypto::ed25519_public_key const *owner = nullptr, uint64_t burn = LNS_AUTO_BURN) const;
cryptonote::transaction create_loki_name_system_tx_update(cryptonote::account_base const &src, lns::mapping_type type, lns::mapping_value const &value, std::string const &name, crypto::ed25519_signature *signature = nullptr, bool use_asserts = false) const;
cryptonote::transaction create_loki_name_system_tx_update_w_extra(cryptonote::account_base const &src, cryptonote::tx_extra_loki_name_system const &lns_extra) const;
loki_blockchain_entry create_genesis_block(const cryptonote::account_base &miner, uint64_t timestamp);

View File

@ -1002,7 +1002,8 @@ bool loki_name_system_disallow_reserved_type::generate(std::vector<test_event_en
gen.add_n_blocks(10); /// generate some outputs and unlock them
gen.add_mined_money_unlock_blocks();
std::string mapping_value = "asdf";
lns::mapping_value mapping_value = {};
mapping_value.len = 20;
auto unusable_type = static_cast<lns::mapping_type>(-1);
assert(!lns::mapping_type_allowed(gen.hardfork(), unusable_type));
@ -1015,13 +1016,9 @@ struct lns_keys_t
{
crypto::ed25519_public_key ed_key;
crypto::ed25519_secret_key ed_skey;
std::string wallet_value; // NOTE: this field is the binary (value) part of the name -> (value) mapping
std::string lokinet_value;
std::string session_value;
std::string session_value_hex; // NOTE: likewise, but represented in hex, except, for blockchain, which is the cryptonote account address
std::string wallet_value_hex;
std::string lokinet_value_hex;
lns::mapping_value wallet_value; // NOTE: this field is the binary (value) part of the name -> (value) mapping
lns::mapping_value lokinet_value;
lns::mapping_value session_value;
};
static lns_keys_t make_lns_keys(cryptonote::account_base const &src)
@ -1029,20 +1026,25 @@ static lns_keys_t make_lns_keys(cryptonote::account_base const &src)
lns_keys_t result = {};
crypto_sign_ed25519_seed_keypair(result.ed_key.data, result.ed_skey.data, reinterpret_cast<const unsigned char *>(src.get_keys().m_spend_secret_key.data));
char session_value[lns::SESSION_PUBLIC_KEY_BINARY_LENGTH] = {};
session_value[0] = 5; // prefix with 0x05
memcpy(session_value + 1, &result.ed_key, sizeof(result.ed_key));
result.session_value.len = lns::SESSION_PUBLIC_KEY_BINARY_LENGTH;
result.wallet_value.len = sizeof(src.get_keys().m_account_address);
result.lokinet_value.len = sizeof(result.ed_key.data);
result.session_value = std::string(session_value, sizeof(session_value));
result.wallet_value = std::string((char *)&src.get_keys().m_account_address, sizeof(src.get_keys().m_account_address));
result.lokinet_value = std::string((char *)result.ed_key.data, sizeof(result.ed_key.data));
memcpy(&result.session_value.buffer[0], &result.ed_key, sizeof(result.ed_key));
memcpy(&result.wallet_value.buffer[0], (char *)&src.get_keys().m_account_address, result.wallet_value.len);
memcpy(&result.lokinet_value.buffer[0], (char *)result.ed_key.data, result.lokinet_value.len);
result.session_value_hex = epee::string_tools::pod_to_hex(session_value);
result.wallet_value_hex = cryptonote::get_account_address_as_str(cryptonote::FAKECHAIN, false /*subaddress*/, src.get_keys().m_account_address);
result.lokinet_value_hex = epee::string_tools::pod_to_hex(result.ed_key);
result.session_value.buffer[0] = 5; // prefix with 0x05
return result;
}
static lns::mapping_value helper_encrypt_lns_value(std::string const &name, lns::mapping_value const &value)
{
lns::mapping_value result;
bool encrypted = lns::encrypt_mapping_value(name, value, result);
assert(encrypted);
return result;
}
bool loki_name_system_expiration::generate(std::vector<test_event_entry> &events)
{
@ -1083,7 +1085,7 @@ bool loki_name_system_expiration::generate(std::vector<test_event_entry> &events
CHECK_EQ(mappings.loaded, true);
CHECK_EQ(mappings.type, mapping_type);
CHECK_EQ(mappings.name_hash, name_hash);
CHECK_EQ(mappings.value, miner_key.lokinet_value);
CHECK_EQ(mappings.encrypted_value, helper_encrypt_lns_value(name, miner_key.lokinet_value));
CHECK_EQ(mappings.register_height, height_of_lns_entry);
CHECK_EQ(mappings.owner_id, owner.id);
return true;
@ -1109,7 +1111,7 @@ bool loki_name_system_expiration::generate(std::vector<test_event_entry> &events
CHECK_EQ(mappings.active(cryptonote::FAKECHAIN, blockchain_height), false);
CHECK_EQ(mappings.type, mapping_type);
CHECK_EQ(mappings.name_hash, name_hash);
CHECK_EQ(mappings.value, miner_key.lokinet_value);
CHECK_EQ(mappings.encrypted_value, helper_encrypt_lns_value(name, miner_key.lokinet_value));
CHECK_EQ(mappings.register_height, height_of_lns_entry);
CHECK_EQ(mappings.owner_id, owner.id);
return true;
@ -1197,8 +1199,8 @@ bool loki_name_system_get_mappings_by_owner::generate(std::vector<test_event_ent
CHECK_EQ(records[1].name_hash, lns::name_to_hash(session_name2));
CHECK_EQ(records[0].register_height, session_height);
CHECK_EQ(records[1].register_height, session_height);
CHECK_EQ(records[0].value, bob_key.session_value);
CHECK_EQ(records[1].value, bob_key.session_value);
CHECK_EQ(records[0].encrypted_value, helper_encrypt_lns_value(session_name1, bob_key.session_value));
CHECK_EQ(records[1].encrypted_value, helper_encrypt_lns_value(session_name2, bob_key.session_value));
CHECK_EQ(records[0].type, lns::mapping_type::session);
CHECK_EQ(records[1].type, lns::mapping_type::session);
}
@ -1209,8 +1211,8 @@ bool loki_name_system_get_mappings_by_owner::generate(std::vector<test_event_ent
CHECK_EQ(records[3].name_hash, lns::name_to_hash(lokinet_name2));
CHECK_EQ(records[2].register_height, lokinet_height);
CHECK_EQ(records[3].register_height, lokinet_height);
CHECK_EQ(records[2].value, bob_key.lokinet_value);
CHECK_EQ(records[3].value, bob_key.lokinet_value);
CHECK_EQ(records[2].encrypted_value, helper_encrypt_lns_value(lokinet_name1, bob_key.lokinet_value));
CHECK_EQ(records[3].encrypted_value, helper_encrypt_lns_value(lokinet_name2, bob_key.lokinet_value));
CHECK_EQ(records[2].type, lns::mapping_type::lokinet_1year);
CHECK_EQ(records[3].type, lns::mapping_type::lokinet_1year);
}
@ -1221,8 +1223,8 @@ bool loki_name_system_get_mappings_by_owner::generate(std::vector<test_event_ent
CHECK_EQ(records[5].name_hash, lns::name_to_hash(wallet_name2));
CHECK_EQ(records[4].register_height, wallet_height);
CHECK_EQ(records[5].register_height, wallet_height);
CHECK_EQ(records[4].value, bob_key.wallet_value);
CHECK_EQ(records[5].value, bob_key.wallet_value);
CHECK_EQ(records[4].encrypted_value, helper_encrypt_lns_value(wallet_name1, bob_key.wallet_value));
CHECK_EQ(records[5].encrypted_value, helper_encrypt_lns_value(wallet_name2, bob_key.wallet_value));
CHECK_EQ(records[4].type, lns::mapping_type::wallet);
CHECK_EQ(records[5].type, lns::mapping_type::wallet);
}
@ -1295,7 +1297,7 @@ bool loki_name_system_get_mappings_by_owners::generate(std::vector<test_event_en
});
CHECK_EQ(records[0].type, lns::mapping_type::session);
CHECK_EQ(records[0].name_hash, lns::name_to_hash(session_name1));
CHECK_EQ(records[0].value, bob_key.session_value);
CHECK_EQ(records[0].encrypted_value, helper_encrypt_lns_value(session_name1, bob_key.session_value));
CHECK_EQ(records[0].register_height, session_height1);
CHECK_EQ(records[0].prev_txid, crypto::null_hash);
CHECK_EQ(records[0].txid, session_tx_hash1);
@ -1303,7 +1305,7 @@ bool loki_name_system_get_mappings_by_owners::generate(std::vector<test_event_en
CHECK_EQ(records[1].type, lns::mapping_type::session);
CHECK_EQ(records[1].name_hash, lns::name_to_hash(session_name2));
CHECK_EQ(records[1].value, bob_key.session_value);
CHECK_EQ(records[1].encrypted_value, helper_encrypt_lns_value(session_name2, bob_key.session_value));
CHECK_EQ(records[1].register_height, session_height2);
CHECK_EQ(records[1].prev_txid, crypto::null_hash);
CHECK_EQ(records[1].txid, session_tx_hash2);
@ -1311,7 +1313,7 @@ bool loki_name_system_get_mappings_by_owners::generate(std::vector<test_event_en
CHECK_EQ(records[2].type, lns::mapping_type::session);
CHECK_EQ(records[2].name_hash, lns::name_to_hash(session_name3));
CHECK_EQ(records[2].value, miner_key.session_value);
CHECK_EQ(records[2].encrypted_value, helper_encrypt_lns_value(session_name3, miner_key.session_value));
CHECK_EQ(records[2].register_height, session_height3);
CHECK_EQ(records[2].prev_txid, crypto::null_hash);
CHECK_EQ(records[2].txid, session_tx_hash3);
@ -1361,7 +1363,7 @@ bool loki_name_system_get_mappings::generate(std::vector<test_event_entry> &even
CHECK_EQ(records.size(), 1);
CHECK_EQ(records[0].type, lns::mapping_type::session);
CHECK_EQ(records[0].name_hash, session_name_hash);
CHECK_EQ(records[0].value, bob_key.session_value);
CHECK_EQ(records[0].encrypted_value, helper_encrypt_lns_value(session_name1, bob_key.session_value));
CHECK_EQ(records[0].register_height, session_height);
CHECK_EQ(records[0].prev_txid, crypto::null_hash);
CHECK_EQ(records[0].txid, session_tx_hash);
@ -1435,7 +1437,7 @@ bool loki_name_system_handles_duplicate_in_lns_db::generate(std::vector<test_eve
CHECK_EQ(mappings.loaded, true);
CHECK_EQ(mappings.type, lns::mapping_type::session);
CHECK_EQ(mappings.name_hash, session_name_hash);
CHECK_EQ(mappings.value, bob_key.session_value);
CHECK_EQ(mappings.encrypted_value, helper_encrypt_lns_value(session_name, bob_key.session_value));
CHECK_EQ(mappings.register_height, height_of_lns_entry);
CHECK_EQ(mappings.owner_id, owner.id);
@ -1445,7 +1447,7 @@ bool loki_name_system_handles_duplicate_in_lns_db::generate(std::vector<test_eve
CHECK_EQ(mappings2.loaded, true);
CHECK_EQ(mappings2.type, lns::mapping_type::lokinet_1year);
CHECK_EQ(mappings2.name_hash, session_name_hash);
CHECK_EQ(mappings2.value, miner_key.lokinet_value);
CHECK_EQ(mappings2.encrypted_value, helper_encrypt_lns_value(session_name, miner_key.lokinet_value));
CHECK_EQ(mappings2.register_height, height_of_lns_entry);
CHECK_EQ(mappings2.owner_id, owner.id);
}
@ -1456,7 +1458,7 @@ bool loki_name_system_handles_duplicate_in_lns_db::generate(std::vector<test_eve
CHECK_EQ(mappings3.loaded, true);
CHECK_EQ(mappings3.type, custom_type);
CHECK_EQ(mappings3.name_hash, session_name_hash);
CHECK_EQ(mappings3.value, bob_key.session_value);
CHECK_EQ(mappings3.encrypted_value, helper_encrypt_lns_value(session_name, bob_key.session_value));
CHECK_EQ(mappings3.register_height, height_of_lns_entry);
CHECK_EQ(mappings3.owner_id, owner.id);
}
@ -1541,10 +1543,11 @@ bool loki_name_system_invalid_tx_extra_params::generate(std::vector<test_event_e
gen.add_tx(tx, valid /*can_be_added_to_blockchain*/, reason, false /*kept_by_block*/);
};
std::string name = "my_lns_name";
cryptonote::tx_extra_loki_name_system valid_data = {};
valid_data.owner = miner_key.ed_key;
valid_data.type = lns::mapping_type::wallet;
valid_data.value = miner_key.wallet_value;
valid_data.encrypted_value = helper_encrypt_lns_value(name, miner_key.wallet_value).to_string();
valid_data.name_hash = lns::name_to_hash("my_lns_name");
if (lns::mapping_type_allowed(gen.hardfork(), lns::mapping_type::wallet))
@ -1553,13 +1556,17 @@ bool loki_name_system_invalid_tx_extra_params::generate(std::vector<test_event_e
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.name_hash = {};
data.encrypted_value = helper_encrypt_lns_value("", miner_key.wallet_value).to_string();
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Blockchain) Empty wallet name in LNS is invalid");
}
// Blockchain value (wallet address) is invalid, clearly too short
{
lns::mapping_value value = {};
value.len = miner_key.wallet_value.len - 1;
cryptonote::tx_extra_loki_name_system data = valid_data;
data.value = std::string(32, 'A');
data.encrypted_value = helper_encrypt_lns_value(name, value).to_string();
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Blockchain) Wallet value in LNS too long");
}
}
@ -1567,68 +1574,53 @@ bool loki_name_system_invalid_tx_extra_params::generate(std::vector<test_event_e
if (lns::mapping_type_allowed(gen.hardfork(), lns::mapping_type::lokinet_1year))
{
valid_data.type = lns::mapping_type::lokinet_1year;
// Lokinet domain name empty
// Lokinet name empty
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.name_hash = {};
data.encrypted_value = helper_encrypt_lns_value("", miner_key.lokinet_value).to_string();
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Lokinet) Empty domain name in LNS is invalid");
}
// Lokinet domain value too long
// Lokinet value too short
{
lns::mapping_value value = {};
value.len = miner_key.lokinet_value.len - 1;
cryptonote::tx_extra_loki_name_system data = valid_data;
data.value = std::string(lns::LOKINET_ADDRESS_BINARY_LENGTH * 2 + 1, 'A');
data.encrypted_value = helper_encrypt_lns_value(name, value).to_string();
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Lokinet) Domain value in LNS too long");
}
// Lokinet domain value too long
// Lokinet value too long
{
lns::mapping_value value = {};
value.len = miner_key.lokinet_value.len + 1;
cryptonote::tx_extra_loki_name_system data = valid_data;
data.value = std::string(lns::LOKINET_ADDRESS_BINARY_LENGTH * 2 - 1, 'A');
size_t index = 0;
data.value[data.value.size() - ++index] = 'i';
data.value[data.value.size() - ++index] = 'k';
data.value[data.value.size() - ++index] = 'o';
data.value[data.value.size() - ++index] = 'l';
data.value[data.value.size() - ++index] = '.';
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Lokinet) Domain value in LNS too short");
data.encrypted_value = helper_encrypt_lns_value(name, value).to_string();
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Lokinet) Domain value in LNS too long");
}
}
// Session value invalid, session keys require a 33 byte key where the first byte is a 0x05
std::stringstream stream;
valid_data.type = lns::mapping_type::session;
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.value[0] = 'a';
stream << "(Session) Key invalid, not prefixed with 0x05";
make_lns_tx_with_custom_extra(gen, events, miner, data, false, stream.str().c_str());
stream.clear();
}
// Session should be valid with this key with a 0x05 prefix
valid_data.value = miner_key.session_value;
{
cryptonote::tx_extra_loki_name_system data = valid_data;
stream << "(Session) Key should be valid, prefixed with 0x05: " << miner_key.session_value_hex;
make_lns_tx_with_custom_extra(gen, events, miner, data, true, stream.str().c_str());
stream.clear();
}
// Session value too short
// We added valid tx prior, we should update name to avoid conflict names in session land and test other invalid params
valid_data.name_hash = lns::name_to_hash("new_friendly_name");
name = "new_friendly_name";
valid_data.name_hash = lns::name_to_hash(name);
{
lns::mapping_value value = {};
value.len = miner_key.session_value.len - 1;
cryptonote::tx_extra_loki_name_system data = valid_data;
data.value = std::string(lns::SESSION_PUBLIC_KEY_BINARY_LENGTH * 2 - 1, 'A');
data.encrypted_value = helper_encrypt_lns_value(name, value).to_string();
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Session) User id, value too short");
}
// Session value too long
{
lns::mapping_value value = {};
value.len = miner_key.session_value.len - 1;
cryptonote::tx_extra_loki_name_system data = valid_data;
data.value = std::string(lns::SESSION_PUBLIC_KEY_BINARY_LENGTH * 2 + 1, 'A');
data.encrypted_value = helper_encrypt_lns_value(name, value).to_string();
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Session) User id, value too long");
}
@ -1636,6 +1628,7 @@ bool loki_name_system_invalid_tx_extra_params::generate(std::vector<test_event_e
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.name_hash = {};
data.encrypted_value = helper_encrypt_lns_value("", miner_key.session_value).to_string();
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Session) Name empty");
}
}
@ -1714,19 +1707,19 @@ bool loki_name_system_large_reorg::generate(std::vector<test_event_entry> &event
{
CHECK_EQ(record.name_hash, lns::name_to_hash(miner_session_name1));
CHECK_EQ(record.register_height, first_lns_height);
CHECK_EQ(record.value, miner_key.session_value);
CHECK_EQ(record.encrypted_value, helper_encrypt_lns_value(miner_session_name1, miner_key.session_value));
}
else if (record.type == lns::mapping_type::lokinet_1year)
{
CHECK_EQ(record.name_hash, lns::name_to_hash(miner_lokinet_domain1));
CHECK_EQ(record.register_height, first_lns_height);
CHECK_EQ(record.value, miner_key.lokinet_value);
CHECK_EQ(record.encrypted_value, helper_encrypt_lns_value(miner_lokinet_domain1, miner_key.lokinet_value));
}
else if (record.type == lns::mapping_type::wallet)
{
CHECK_EQ(record.name_hash, lns::name_to_hash(miner_wallet_name1));
CHECK_EQ(record.register_height, first_lns_height);
CHECK_EQ(record.value, miner_key.wallet_value);
CHECK_EQ(record.encrypted_value, helper_encrypt_lns_value(miner_wallet_name1, miner_key.wallet_value));
}
else
{
@ -1772,19 +1765,19 @@ bool loki_name_system_large_reorg::generate(std::vector<test_event_entry> &event
{
CHECK_EQ(record.name_hash, lns::name_to_hash(miner_session_name1));
CHECK_EQ(record.register_height, first_lns_height);
CHECK_EQ(record.value, miner_key.session_value);
CHECK_EQ(record.encrypted_value, helper_encrypt_lns_value(miner_session_name1, miner_key.session_value));
}
else if (record.type == lns::mapping_type::lokinet_1year)
{
CHECK_EQ(record.name_hash, lns::name_to_hash(miner_lokinet_domain1));
CHECK_EQ(record.register_height, second_lns_height);
CHECK_EQ(record.value, miner_key.lokinet_value);
CHECK_EQ(record.encrypted_value, helper_encrypt_lns_value(miner_lokinet_domain1, miner_key.lokinet_value));
}
else if (record.type == lns::mapping_type::wallet)
{
CHECK_EQ(record.name_hash, lns::name_to_hash(miner_wallet_name1));
CHECK_EQ(record.register_height, first_lns_height);
CHECK_EQ(record.value, miner_key.wallet_value);
CHECK_EQ(record.encrypted_value, helper_encrypt_lns_value(miner_wallet_name1, miner_key.wallet_value));
}
else
{
@ -1799,7 +1792,7 @@ bool loki_name_system_large_reorg::generate(std::vector<test_event_entry> &event
CHECK_EQ(records.size(), 1);
CHECK_EQ(records[0].name_hash, lns::name_to_hash(bob_session_name1));
CHECK_EQ(records[0].register_height, second_lns_height);
CHECK_EQ(records[0].value, bob_key.session_value);
CHECK_EQ(records[0].encrypted_value, helper_encrypt_lns_value(bob_session_name1, bob_key.session_value));
CHECK_EQ(records[0].type, lns::mapping_type::session);
}
@ -1841,19 +1834,19 @@ bool loki_name_system_large_reorg::generate(std::vector<test_event_entry> &event
{
CHECK_EQ(record.name_hash, lns::name_to_hash(miner_session_name1));
CHECK_EQ(record.register_height, first_lns_height);
CHECK_EQ(record.value, miner_key.session_value);
CHECK_EQ(record.encrypted_value, helper_encrypt_lns_value(miner_session_name1, miner_key.session_value));
}
else if (record.type == lns::mapping_type::lokinet_1year)
{
CHECK_EQ(record.name_hash, lns::name_to_hash(miner_lokinet_domain1));
CHECK_EQ(record.register_height, first_lns_height);
CHECK_EQ(record.value, miner_key.lokinet_value);
CHECK_EQ(record.encrypted_value, helper_encrypt_lns_value(miner_lokinet_domain1, miner_key.lokinet_value));
}
else if (record.type == lns::mapping_type::wallet)
{
CHECK_EQ(record.name_hash, lns::name_to_hash(miner_wallet_name1));
CHECK_EQ(record.register_height, first_lns_height);
CHECK_EQ(record.value, miner_key.wallet_value);
CHECK_EQ(record.encrypted_value, helper_encrypt_lns_value(miner_wallet_name1, miner_key.wallet_value));
}
else
{
@ -1931,7 +1924,7 @@ bool loki_name_system_name_renewal::generate(std::vector<test_event_entry> &even
CHECK_EQ(mappings.loaded, true);
CHECK_EQ(mappings.type, lns::mapping_type::lokinet_1year);
CHECK_EQ(mappings.name_hash, name_hash);
CHECK_EQ(mappings.value, miner_key.lokinet_value);
CHECK_EQ(mappings.encrypted_value, helper_encrypt_lns_value(name, miner_key.lokinet_value));
CHECK_EQ(mappings.register_height, height_of_lns_entry);
CHECK_EQ(mappings.prev_txid, crypto::null_hash);
CHECK_EQ(mappings.owner_id, owner.id);
@ -1961,7 +1954,7 @@ bool loki_name_system_name_renewal::generate(std::vector<test_event_entry> &even
CHECK_EQ(mappings.loaded, true);
CHECK_EQ(mappings.type, lns::mapping_type::lokinet_1year);
CHECK_EQ(mappings.name_hash, name_hash);
CHECK_EQ(mappings.value, miner_key.lokinet_value);
CHECK_EQ(mappings.encrypted_value, helper_encrypt_lns_value(name, miner_key.lokinet_value));
CHECK_EQ(mappings.register_height, renewal_height);
CHECK_EQ(mappings.prev_txid, prev_txid);
CHECK_EQ(mappings.owner_id, owner.id);
@ -2007,31 +2000,39 @@ bool loki_name_system_name_value_max_lengths::generate(std::vector<test_event_en
cryptonote::tx_extra_loki_name_system data = {};
data.owner = miner_key.ed_key;
// Blockchain
// Wallet
if (lns::mapping_type_allowed(gen.hardfork(), lns::mapping_type::wallet))
{
std::string name(lns::WALLET_NAME_MAX, 'A');
data.type = lns::mapping_type::wallet;
data.name_hash = lns::name_to_hash(std::string(lns::WALLET_NAME_MAX, 'A'));
data.value = miner_key.wallet_value;
data.name_hash = lns::name_to_hash(name);
data.encrypted_value = helper_encrypt_lns_value(name, miner_key.wallet_value).to_string();
make_lns_tx_with_custom_extra(gen, events, miner, data);
}
// Lokinet
if (lns::mapping_type_allowed(gen.hardfork(), lns::mapping_type::lokinet_1year))
{
data.type = lns::mapping_type::lokinet_1year;
data.name_hash = lns::name_to_hash("doyle.loki");
data.value = std::string(lns::LOKINET_ADDRESS_BINARY_LENGTH, 'a');
std::string name(lns::LOKINET_DOMAIN_NAME_MAX, 'A');
size_t last_index = name.size() - 1;
name[last_index--] = 'i';
name[last_index--] = 'k';
name[last_index--] = 'o';
name[last_index--] = 'l';
name[last_index--] = '.';
data.type = lns::mapping_type::lokinet_1year;
data.name_hash = lns::name_to_hash(name);
data.encrypted_value = helper_encrypt_lns_value(name, miner_key.lokinet_value).to_string();
make_lns_tx_with_custom_extra(gen, events, miner, data);
}
// Session
{
data.type = lns::mapping_type::session;
data.name_hash = lns::name_to_hash(std::string(lns::SESSION_DISPLAY_NAME_MAX, 'A'));
data.value = std::string(lns::SESSION_PUBLIC_KEY_BINARY_LENGTH, 'a');
data.value[0] = '0';
data.value[1] = '5';
std::string name(lns::SESSION_DISPLAY_NAME_MAX, 'A');
data.type = lns::mapping_type::session;
data.name_hash = lns::name_to_hash(name);
data.encrypted_value = helper_encrypt_lns_value(name, miner_key.session_value).to_string();
make_lns_tx_with_custom_extra(gen, events, miner, data);
}
@ -2075,12 +2076,12 @@ bool loki_name_system_update_mapping_after_expiry_fails::generate(std::vector<te
CHECK_EQ(owner.id, 1);
CHECK_EQ(miner_key.ed_key, owner.key);
crypto::hash name_hash = lns::name_to_hash(name);
crypto::hash name_hash = lns::name_to_hash(name);
lns::mapping_record mappings = lns_db.get_mapping(lns::mapping_type::lokinet_1year, name_hash);
CHECK_EQ(mappings.loaded, true);
CHECK_EQ(mappings.type, lns::mapping_type::lokinet_1year);
CHECK_EQ(mappings.name_hash, name_hash);
CHECK_EQ(mappings.value, miner_key.lokinet_value);
CHECK_EQ(mappings.encrypted_value, helper_encrypt_lns_value(name, miner_key.lokinet_value));
CHECK_EQ(mappings.register_height, height_of_lns_entry);
CHECK_EQ(mappings.owner_id, owner.id);
return true;
@ -2132,10 +2133,11 @@ bool loki_name_system_update_mapping::generate(std::vector<test_event_entry> &ev
crypto::hash name_hash = lns::name_to_hash(session_name1);
std::vector<lns::mapping_record> records = lns_db.get_mappings({static_cast<uint16_t>(lns::mapping_type::session)}, name_hash);
CHECK_EQ(records.size(), 1);
CHECK_EQ(records[0].type, lns::mapping_type::session);
CHECK_EQ(records[0].name_hash, name_hash);
CHECK_EQ(records[0].value, bob_key.session_value);
CHECK_EQ(records[0].encrypted_value, helper_encrypt_lns_value(session_name1, bob_key.session_value));
CHECK_EQ(records[0].register_height, session_height2);
CHECK_EQ(records[0].prev_txid, session_tx_hash1);
CHECK_EQ(records[0].txid, session_tx_hash2);
@ -2254,7 +2256,7 @@ bool loki_name_system_wrong_burn::generate(std::vector<test_event_entry> &events
{
if (lns::mapping_type_allowed(gen.hardfork(), type))
{
std::string value;
lns::mapping_value value = {};
std::string name;
if (type == lns::mapping_type::session)
@ -2299,13 +2301,14 @@ bool loki_name_system_wrong_version::generate(std::vector<test_event_entry> &eve
gen.add_n_blocks(10); /// generate some outputs and unlock them
gen.add_mined_money_unlock_blocks();
std::string name = "lns_name";
lns_keys_t miner_key = make_lns_keys(miner);
cryptonote::tx_extra_loki_name_system data = {};
data.version = 0xFF;
data.owner = miner_key.ed_key;
data.type = lns::mapping_type::session;
data.value = miner_key.session_value;
data.name_hash = lns::name_to_hash("my_lns_name");
data.name_hash = lns::name_to_hash(name);
data.encrypted_value = helper_encrypt_lns_value(name, miner_key.session_value).to_string();
uint64_t new_height = cryptonote::get_block_height(gen.top().block) + 1;
uint8_t new_hf_version = gen.get_hf_version_at(new_height);