Skip to content

Commit

Permalink
jamtis: implement dense/sparse view privacy changes
Browse files Browse the repository at this point in the history
Results of `test_remote_scanner_client_scan_sp` performance test:
```
seraphis_lib (original) run #1
test_remote_scanner_client_scan_sp (23 calls) - OK: 13434 µs/call
test_remote_scanner_client_scan_sp (23 calls) - OK: 13217 µs/call
test_remote_scanner_client_scan_sp (23 calls) - OK: 14304 µs/call

seraphis_lib (original) run #2
test_remote_scanner_client_scan_sp (23 calls) - OK: 13086 µs/call
test_remote_scanner_client_scan_sp (23 calls) - OK: 13130 µs/call
test_remote_scanner_client_scan_sp (23 calls) - OK: 14217 µs/call

jamtis_fix_fr_privacy (new PR) run #1
test_remote_scanner_client_scan_sp (23 calls) - OK: 1738 ms/call
test_remote_scanner_client_scan_sp (23 calls) - OK: 1738 ms/call
test_remote_scanner_client_scan_sp (23 calls) - OK: 1739 ms/call

jamtis_fix_fr_privacy (new PR) run #2
test_remote_scanner_client_scan_sp (23 calls) - OK: 1731 ms/call
test_remote_scanner_client_scan_sp (23 calls) - OK: 1750 ms/call
test_remote_scanner_client_scan_sp (23 calls) - OK: 1734 ms/call
```

Ran on an AMD Ryzen 9 3900X 12-core CPU. Processing basic records from a remote scanner is about 128x slower.
  • Loading branch information
jeffro256 committed Sep 9, 2023
1 parent ea9fa07 commit 3aa169b
Show file tree
Hide file tree
Showing 56 changed files with 1,637 additions and 1,011 deletions.
6 changes: 4 additions & 2 deletions src/cryptonote_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,15 +307,17 @@ namespace config
const constexpr char HASH_KEY_JAMTIS_UNLOCKAMOUNTS_KEY[] = "jamtis_unlock_amounts_key";
const constexpr char HASH_KEY_JAMTIS_GENERATEADDRESS_SECRET[] = "jamtis_generate_address_secret";
const constexpr char HASH_KEY_JAMTIS_CIPHERTAG_SECRET[] = "jamtis_cipher_tag_secret";
const constexpr char HASH_KEY_JAMTIS_FINDRECEIVED_KEY[] = "jamtis_find_received_key";
const constexpr char HASH_KEY_JAMTIS_DENSEVIEW_KEY[] = "jamtis_dense_view_key";
const constexpr char HASH_KEY_JAMTIS_SPARSEVIEW_KEY[] = "jamtis_sparse_view_key";
const constexpr char HASH_KEY_JAMTIS_INDEX_EXTENSION_GENERATOR[] = "jamtis_index_extension_generator";
const constexpr char HASH_KEY_JAMTIS_ADDRESS_PRIVKEY[] = "jamtis_address_privkey";
const constexpr char HASH_KEY_JAMTIS_SPENDKEY_EXTENSION_G[] = "jamtis_spendkey_extension_g";
const constexpr char HASH_KEY_JAMTIS_SPENDKEY_EXTENSION_X[] = "jamtis_spendkey_extension_x";
const constexpr char HASH_KEY_JAMTIS_SPENDKEY_EXTENSION_U[] = "jamtis_spendkey_extension_u";
const constexpr char HASH_KEY_JAMTIS_ADDRESS_TAG_HINT[] = "jamtis_address_tag_hint";
const constexpr char HASH_KEY_JAMTIS_ENCRYPTED_ADDRESS_TAG[] = "jamtis_encrypted_address_tag";
const constexpr char HASH_KEY_JAMTIS_VIEW_TAG[] = "jamtis_view_tag";
const constexpr char HASH_KEY_JAMTIS_DENSE_VIEW_TAG[] = "jamtis_dense_view_tag";
const constexpr char HASH_KEY_JAMTIS_SPARSE_VIEW_TAG[] = "jamtis_sparse_view_tag";
const constexpr char HASH_KEY_JAMTIS_SENDER_RECEIVER_SECRET_PLAIN[] = "jamtis_sr_secret_plain";
const constexpr char HASH_KEY_JAMTIS_SENDER_RECEIVER_SECRET_SELFSEND_DUMMY[] = "jamtis_selfsend_dummy";
const constexpr char HASH_KEY_JAMTIS_SENDER_RECEIVER_SECRET_SELFSEND_CHANGE[] = "jamtis_selfsend_change";
Expand Down
1 change: 1 addition & 0 deletions src/ringct/rctTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ namespace rct {
return bytes[i];
}
bool operator==(const key &k) const { return !crypto_verify_32(bytes, k.bytes); }
bool operator!=(const key &k) const { return !(*this == k); }
unsigned char bytes[32];
};
typedef std::vector<key> keyV; //vector of keys
Expand Down
2 changes: 1 addition & 1 deletion src/seraphis_core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ set(seraphis_core_sources
discretized_fee.cpp
jamtis_address_tag_utils.cpp
jamtis_address_utils.cpp
jamtis_core_utils.cpp
jamtis_destination.cpp
jamtis_enote_utils.cpp
jamtis_payment_proposal.cpp
jamtis_secret_utils.cpp
jamtis_support_types.cpp
legacy_core_utils.cpp
legacy_decoy_selector_flat.cpp
Expand Down
74 changes: 20 additions & 54 deletions src/seraphis_core/jamtis_address_tag_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ extern "C"
#include "crypto/blake2b.h"
#include "crypto/twofish.h"
}
#include "jamtis_secret_utils.h"
#include "jamtis_support_types.h"
#include "memwipe.h"
#include "misc_language.h"
Expand Down Expand Up @@ -87,43 +88,6 @@ static encrypted_address_tag_secret_t get_encrypted_address_tag_secret(const rct
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
static address_tag_hint_t get_address_tag_hint(const crypto::secret_key &cipher_key,
const address_index_t &encrypted_address_index)
{
static_assert(sizeof(address_tag_hint_t) == 2, "");
static_assert(sizeof(config::TRANSCRIPT_PREFIX) != 0, "");
static_assert(sizeof(config::HASH_KEY_JAMTIS_ADDRESS_TAG_HINT) != 0, "");

// assemble hash contents: prefix || 'domain-sep' || k || cipher[k](j)
// note: use a raw C-style struct here instead of SpKDFTranscript for maximal performance (the string produced is
// equivalent to what you'd get from SpKDFTranscript)
// note2: '-1' removes the null terminator
struct hash_context_t {
unsigned char prefix[sizeof(config::TRANSCRIPT_PREFIX) - 1];
unsigned char domain_separator[sizeof(config::HASH_KEY_JAMTIS_ADDRESS_TAG_HINT) - 1];
rct::key cipher_key; //not crypto::secret_key, which has significant construction cost
address_index_t enc_j;
} hash_context;
static_assert(!epee::has_padding<hash_context_t>(), "");

memcpy(hash_context.prefix, config::TRANSCRIPT_PREFIX, sizeof(config::TRANSCRIPT_PREFIX) - 1);
memcpy(hash_context.domain_separator,
config::HASH_KEY_JAMTIS_ADDRESS_TAG_HINT,
sizeof(config::HASH_KEY_JAMTIS_ADDRESS_TAG_HINT) - 1);
hash_context.cipher_key = rct::sk2rct(cipher_key);
hash_context.enc_j = encrypted_address_index;

// address_tag_hint = H_2(k, cipher[k](j))
address_tag_hint_t address_tag_hint;
sp_hash_to_2(&hash_context, sizeof(hash_context), address_tag_hint.bytes);

// clean up cipher key bytes
memwipe(hash_context.cipher_key.bytes, 32);

return address_tag_hint;
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
jamtis_address_tag_cipher_context::jamtis_address_tag_cipher_context(const crypto::secret_key &cipher_key)
{
// cache the cipher key
Expand All @@ -136,45 +100,47 @@ jamtis_address_tag_cipher_context::jamtis_address_tag_cipher_context(const crypt
//-------------------------------------------------------------------------------------------------------------------
jamtis_address_tag_cipher_context::~jamtis_address_tag_cipher_context()
{
memwipe(&m_cipher_key, sizeof(crypto::secret_key));
memwipe(&m_twofish_key, sizeof(Twofish_key));
}
//-------------------------------------------------------------------------------------------------------------------
address_tag_t jamtis_address_tag_cipher_context::cipher(const address_index_t &j) const
{
// address tag = cipher[k](j) || H_2(k, cipher[k](j))
// address tag = cipher[k](j)

// expect address index to fit in one Twofish block (16 bytes)
static_assert(sizeof(address_index_t) == TWOFISH_BLOCK_SIZE, "");
static_assert(sizeof(address_index_t) == sizeof(address_tag_t), "");

// prepare ciphered index
address_index_t encrypted_j{j};

// encrypt the address index
Twofish_encrypt_block(&m_twofish_key, encrypted_j.bytes, encrypted_j.bytes);

// make the address tag hint and complete the address tag
return make_address_tag(encrypted_j, get_address_tag_hint(m_cipher_key, encrypted_j));
// make the address tag
return make_address_tag(encrypted_j);
}
//-------------------------------------------------------------------------------------------------------------------
bool jamtis_address_tag_cipher_context::try_decipher(const address_tag_t &addr_tag, address_index_t &j_out) const
void jamtis_address_tag_cipher_context::decipher(const address_tag_t &addr_tag, address_index_t &j_out) const
{
static_assert(sizeof(address_index_t) == TWOFISH_BLOCK_SIZE, "");
static_assert(sizeof(address_index_t) + sizeof(address_tag_hint_t) == sizeof(address_tag_t), "");
static_assert(sizeof(address_index_t) == sizeof(address_tag_t), "");

// extract the encrypted index
memcpy(j_out.bytes, addr_tag.bytes, sizeof(address_index_t));

// recover the address tag hint
const address_tag_hint_t address_tag_hint{get_address_tag_hint(m_cipher_key, j_out)};

// check the address tag hint
if (memcmp(addr_tag.bytes + sizeof(address_index_t), address_tag_hint.bytes, sizeof(address_tag_hint_t)) != 0)
return false;

// decrypt the address index
Twofish_decrypt_block(&m_twofish_key, j_out.bytes, j_out.bytes);
}
//-------------------------------------------------------------------------------------------------------------------
jamtis_address_tag_cipher_context jamtis_address_tag_cipher_context::from_generateaddress_secret(const crypto::secret_key &s_ga)
{
// derive s_ct from s_ga
crypto::secret_key cipher_tag_secret;
jamtis::make_jamtis_ciphertag_secret(s_ga, cipher_tag_secret);

return true;
return jamtis_address_tag_cipher_context(cipher_tag_secret);
}
//-------------------------------------------------------------------------------------------------------------------
address_tag_t cipher_address_index(const jamtis_address_tag_cipher_context &cipher_context, const address_index_t &j)
Expand All @@ -191,22 +157,22 @@ address_tag_t cipher_address_index(const crypto::secret_key &cipher_key, const a
return cipher_address_index(cipher_context, j);
}
//-------------------------------------------------------------------------------------------------------------------
bool try_decipher_address_index(const jamtis_address_tag_cipher_context &cipher_context,
void decipher_address_index(const jamtis_address_tag_cipher_context &cipher_context,
const address_tag_t &addr_tag,
address_index_t &j_out)
{
return cipher_context.try_decipher(addr_tag, j_out);
cipher_context.decipher(addr_tag, j_out);
}
//-------------------------------------------------------------------------------------------------------------------
bool try_decipher_address_index(const crypto::secret_key &cipher_key,
void decipher_address_index(const crypto::secret_key &cipher_key,
const address_tag_t &addr_tag,
address_index_t &j_out)
{
// prepare to decipher the tag
const jamtis_address_tag_cipher_context cipher_context{cipher_key};

// decipher it
return try_decipher_address_index(cipher_context, addr_tag, j_out);
decipher_address_index(cipher_context, addr_tag, j_out);
}
//-------------------------------------------------------------------------------------------------------------------
encrypted_address_tag_t encrypt_address_tag(const rct::key &sender_receiver_secret,
Expand Down
21 changes: 14 additions & 7 deletions src/seraphis_core/jamtis_address_tag_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,32 +58,39 @@ struct jamtis_address_tag_cipher_context final
/// normal constructor
jamtis_address_tag_cipher_context(const crypto::secret_key &cipher_key);

/// copy/move construction
jamtis_address_tag_cipher_context(const jamtis_address_tag_cipher_context&) = default;
jamtis_address_tag_cipher_context(jamtis_address_tag_cipher_context&&) = default;

//destructor
~jamtis_address_tag_cipher_context();

//overloaded operators
/// disable copy/move (this is a scoped manager)
jamtis_address_tag_cipher_context& operator=(jamtis_address_tag_cipher_context&&) = delete;
// copy/move assignment
jamtis_address_tag_cipher_context& operator=(const jamtis_address_tag_cipher_context&) = default;
jamtis_address_tag_cipher_context& operator=(jamtis_address_tag_cipher_context&&) = default;

//member functions
address_tag_t cipher(const address_index_t &j) const;
bool try_decipher(const address_tag_t &addr_tag, address_index_t &j_out) const;
void decipher(const address_tag_t &addr_tag, address_index_t &j_out) const;

static jamtis_address_tag_cipher_context from_generateaddress_secret(const crypto::secret_key &s_ga);

//member variables
private:
crypto::secret_key m_cipher_key;
Twofish_key m_twofish_key;
};

/// addr_tag = cipher[k](j) || H_2(k, cipher[k](j))
/// addr_tag = cipher[k](j)
address_tag_t cipher_address_index(const jamtis_address_tag_cipher_context &cipher_context, const address_index_t &j);
address_tag_t cipher_address_index(const crypto::secret_key &cipher_key, const address_index_t &j);

/// try to get j from an address tag
bool try_decipher_address_index(const jamtis_address_tag_cipher_context &cipher_context,
/// get j from an address tag
void decipher_address_index(const jamtis_address_tag_cipher_context &cipher_context,
const address_tag_t &addr_tag,
address_index_t &j_out);
bool try_decipher_address_index(const crypto::secret_key &cipher_key,
void decipher_address_index(const crypto::secret_key &cipher_key,
const address_tag_t &addr_tag,
address_index_t &j_out);

Expand Down
Loading

0 comments on commit 3aa169b

Please sign in to comment.