aboutsummaryrefslogtreecommitdiff
path: root/src/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto')
-rw-r--r--src/crypto/CMakeLists.txt24
-rw-r--r--src/crypto/blake256.c2
-rw-r--r--src/crypto/blake256.h2
-rw-r--r--src/crypto/c_threads.h2
-rw-r--r--src/crypto/chacha.h2
-rw-r--r--src/crypto/crypto-ops-data.c2
-rw-r--r--src/crypto/crypto-ops.c52
-rw-r--r--src/crypto/crypto-ops.h4
-rw-r--r--src/crypto/crypto.cpp26
-rw-r--r--src/crypto/crypto.h33
-rw-r--r--src/crypto/crypto_ops_builder/README.md2
-rw-r--r--src/crypto/crypto_ops_builder/crypto-ops-data.c2
-rw-r--r--src/crypto/crypto_ops_builder/crypto-ops-old.c2
-rw-r--r--src/crypto/crypto_ops_builder/crypto-ops.h2
-rw-r--r--src/crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py2
-rw-r--r--src/crypto/crypto_ops_builder/ref10CommentedCombined/crypto-ops.h2
-rw-r--r--src/crypto/duration.h3
-rw-r--r--src/crypto/generic-ops.h2
-rw-r--r--src/crypto/groestl.h2
-rw-r--r--src/crypto/groestl_tables.h2
-rw-r--r--src/crypto/hash-extra-blake.c2
-rw-r--r--src/crypto/hash-extra-groestl.c2
-rw-r--r--src/crypto/hash-extra-jh.c2
-rw-r--r--src/crypto/hash-extra-skein.c2
-rw-r--r--src/crypto/hash-ops.h2
-rw-r--r--src/crypto/hash.c2
-rw-r--r--src/crypto/hash.h2
-rw-r--r--src/crypto/hmac-keccak.c2
-rw-r--r--src/crypto/hmac-keccak.h2
-rw-r--r--src/crypto/initializer.h2
-rw-r--r--src/crypto/keccak.c95
-rw-r--r--src/crypto/random.c2
-rw-r--r--src/crypto/random.h2
-rw-r--r--src/crypto/rx-slow-hash.c7
-rw-r--r--src/crypto/skein_port.h2
-rw-r--r--src/crypto/slow-hash.c212
-rw-r--r--src/crypto/tree-hash.c2
-rw-r--r--src/crypto/wallet/CMakeLists.txt3
-rw-r--r--src/crypto/wallet/crypto.h3
-rw-r--r--src/crypto/wallet/empty.h.in3
40 files changed, 366 insertions, 155 deletions
diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt
index 3f0f7d34b..595c7f966 100644
--- a/src/crypto/CMakeLists.txt
+++ b/src/crypto/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2020, The Monero Project
+# Copyright (c) 2014-2022, The Monero Project
#
# All rights reserved.
#
@@ -58,27 +58,7 @@ include_directories(${RANDOMX_INCLUDE})
set(crypto_headers)
-set(crypto_private_headers
- blake256.h
- chacha.h
- crypto-ops.h
- crypto.h
- generic-ops.h
- groestl.h
- groestl_tables.h
- hash-ops.h
- hash.h
- hmac-keccak.h
- initializer.h
- jh.h
- keccak.h
- oaes_config.h
- oaes_lib.h
- random.h
- skein.h
- skein_port.h
- CryptonightR_JIT.h
- CryptonightR_template.h)
+monero_find_all_headers(crypto_private_headers "${CMAKE_CURRENT_SOURCE_DIR}")
monero_private_headers(cncrypto
${crypto_private_headers})
diff --git a/src/crypto/blake256.c b/src/crypto/blake256.c
index 831a90302..7e302bcad 100644
--- a/src/crypto/blake256.c
+++ b/src/crypto/blake256.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/blake256.h b/src/crypto/blake256.h
index 5abdb79b9..f727bddee 100644
--- a/src/crypto/blake256.h
+++ b/src/crypto/blake256.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/c_threads.h b/src/crypto/c_threads.h
index 5b2fcddd3..c5431cb8d 100644
--- a/src/crypto/c_threads.h
+++ b/src/crypto/c_threads.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2020, The Monero Project
+// Copyright (c) 2019-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/chacha.h b/src/crypto/chacha.h
index a1158be7e..74f05cbe8 100644
--- a/src/crypto/chacha.h
+++ b/src/crypto/chacha.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/crypto-ops-data.c b/src/crypto/crypto-ops-data.c
index d16fd9429..1a85de60d 100644
--- a/src/crypto/crypto-ops-data.c
+++ b/src/crypto/crypto-ops-data.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/crypto-ops.c b/src/crypto/crypto-ops.c
index 508709280..4b392d472 100644
--- a/src/crypto/crypto-ops.c
+++ b/src/crypto/crypto-ops.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
@@ -3830,15 +3830,51 @@ int sc_isnonzero(const unsigned char *s) {
s[27] | s[28] | s[29] | s[30] | s[31]) - 1) >> 8) + 1;
}
-int ge_p3_is_point_at_infinity(const ge_p3 *p) {
- // X = 0 and Y == Z
- int n;
- for (n = 0; n < 10; ++n)
+int ge_p3_is_point_at_infinity_vartime(const ge_p3 *p) {
+ // https://eprint.iacr.org/2008/522
+ // X == T == 0 and Y/Z == 1
+ // note: convert all pieces to canonical bytes in case rounding is required (i.e. an element is > q)
+ // note2: even though T = XY/Z is true for valid point representations (implying it isn't necessary to
+ // test T == 0), the input to this function might NOT be valid, so we must test T == 0
+ char result_X_bytes[32];
+ fe_tobytes((unsigned char*)&result_X_bytes, p->X);
+
+ // X != 0
+ for (int i = 0; i < 32; ++i)
{
- if (p->X[n] | p->T[n])
+ if (result_X_bytes[i])
return 0;
- if (p->Y[n] != p->Z[n])
+ }
+
+ char result_T_bytes[32];
+ fe_tobytes((unsigned char*)&result_T_bytes, p->T);
+
+ // T != 0
+ for (int i = 0; i < 32; ++i)
+ {
+ if (result_T_bytes[i])
return 0;
}
- return 1;
+
+ char result_Y_bytes[32];
+ char result_Z_bytes[32];
+ fe_tobytes((unsigned char*)&result_Y_bytes, p->Y);
+ fe_tobytes((unsigned char*)&result_Z_bytes, p->Z);
+
+ // Y != Z
+ for (int i = 0; i < 32; ++i)
+ {
+ if (result_Y_bytes[i] != result_Z_bytes[i])
+ return 0;
+ }
+
+ // is Y nonzero? then Y/Z == 1
+ for (int i = 0; i < 32; ++i)
+ {
+ if (result_Y_bytes[i] != 0)
+ return 1;
+ }
+
+ // Y/Z = 0/0
+ return 0;
}
diff --git a/src/crypto/crypto-ops.h b/src/crypto/crypto-ops.h
index 22f76974b..e4901e080 100644
--- a/src/crypto/crypto-ops.h
+++ b/src/crypto/crypto-ops.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
@@ -162,4 +162,4 @@ void fe_add(fe h, const fe f, const fe g);
void fe_tobytes(unsigned char *, const fe);
void fe_invert(fe out, const fe z);
-int ge_p3_is_point_at_infinity(const ge_p3 *p);
+int ge_p3_is_point_at_infinity_vartime(const ge_p3 *p);
diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp
index 0059dd7f5..77a36069a 100644
--- a/src/crypto/crypto.cpp
+++ b/src/crypto/crypto.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
@@ -749,4 +749,28 @@ POP_WARNINGS
sc_sub(&h, &h, &sum);
return sc_isnonzero(&h) == 0;
}
+
+ void crypto_ops::derive_view_tag(const key_derivation &derivation, size_t output_index, view_tag &view_tag) {
+ #pragma pack(push, 1)
+ struct {
+ char salt[8]; // view tag domain-separator
+ key_derivation derivation;
+ char output_index[(sizeof(size_t) * 8 + 6) / 7];
+ } buf;
+ #pragma pack(pop)
+
+ char *end = buf.output_index;
+ memcpy(buf.salt, "view_tag", 8); // leave off null terminator
+ buf.derivation = derivation;
+ tools::write_varint(end, output_index);
+ assert(end <= buf.output_index + sizeof buf.output_index);
+
+ // view_tag_full = H[salt|derivation|output_index]
+ hash view_tag_full;
+ cn_fast_hash(&buf, end - reinterpret_cast<char *>(&buf), view_tag_full);
+
+ // only need a slice of view_tag_full to realize optimal perf/space efficiency
+ static_assert(sizeof(crypto::view_tag) <= sizeof(view_tag_full), "view tag should not be larger than hash result");
+ memcpy(&view_tag, &view_tag_full, sizeof(crypto::view_tag));
+ }
}
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 7ddc0150f..d8cd6c6a0 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
@@ -64,6 +64,11 @@ namespace crypto {
friend class crypto_ops;
};
+ POD_CLASS public_key_memsafe : epee::mlocked<tools::scrubbed<public_key>> {
+ public_key_memsafe() = default;
+ public_key_memsafe(const public_key &original) { memcpy(this->data, original.data, 32); }
+ };
+
using secret_key = epee::mlocked<tools::scrubbed<ec_scalar>>;
POD_CLASS public_keyV {
@@ -94,15 +99,19 @@ namespace crypto {
ec_scalar c, r;
friend class crypto_ops;
};
+
+ POD_CLASS view_tag {
+ char data;
+ };
#pragma pack(pop)
void hash_to_scalar(const void *data, size_t length, ec_scalar &res);
void random32_unbiased(unsigned char *bytes);
static_assert(sizeof(ec_point) == 32 && sizeof(ec_scalar) == 32 &&
- sizeof(public_key) == 32 && sizeof(secret_key) == 32 &&
+ sizeof(public_key) == 32 && sizeof(public_key_memsafe) == 32 && sizeof(secret_key) == 32 &&
sizeof(key_derivation) == 32 && sizeof(key_image) == 32 &&
- sizeof(signature) == 64, "Invalid structure size");
+ sizeof(signature) == 64 && sizeof(view_tag) == 1, "Invalid structure size");
class crypto_ops {
crypto_ops();
@@ -146,6 +155,8 @@ namespace crypto {
const public_key *const *, std::size_t, const signature *);
friend bool check_ring_signature(const hash &, const key_image &,
const public_key *const *, std::size_t, const signature *);
+ static void derive_view_tag(const key_derivation &, std::size_t, view_tag &);
+ friend void derive_view_tag(const key_derivation &, std::size_t, view_tag &);
};
void generate_random_bytes_thread_safe(size_t N, uint8_t *bytes);
@@ -292,6 +303,14 @@ namespace crypto {
return check_ring_signature(prefix_hash, image, pubs.data(), pubs.size(), sig);
}
+ /* Derive a 1-byte view tag from the sender-receiver shared secret to reduce scanning time.
+ * When scanning outputs that were not sent to the user, checking the view tag for a match removes the need to proceed with expensive EC operations
+ * for an expected 99.6% of outputs (expected false positive rate = 1/2^8 = 1/256 = 0.4% = 100% - 99.6%).
+ */
+ inline void derive_view_tag(const key_derivation &derivation, std::size_t output_index, view_tag &vt) {
+ crypto_ops::derive_view_tag(derivation, output_index, vt);
+ }
+
inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) {
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
}
@@ -307,12 +326,20 @@ namespace crypto {
inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) {
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
}
+ inline std::ostream &operator <<(std::ostream &o, const crypto::view_tag &v) {
+ epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+ }
const extern crypto::public_key null_pkey;
const extern crypto::secret_key null_skey;
+
+ inline bool operator<(const public_key &p1, const public_key &p2) { return memcmp(&p1, &p2, sizeof(public_key)) < 0; }
+ inline bool operator>(const public_key &p1, const public_key &p2) { return p2 < p1; }
}
CRYPTO_MAKE_HASHABLE(public_key)
CRYPTO_MAKE_HASHABLE_CONSTANT_TIME(secret_key)
+CRYPTO_MAKE_HASHABLE_CONSTANT_TIME(public_key_memsafe)
CRYPTO_MAKE_HASHABLE(key_image)
CRYPTO_MAKE_COMPARABLE(signature)
+CRYPTO_MAKE_COMPARABLE(view_tag)
diff --git a/src/crypto/crypto_ops_builder/README.md b/src/crypto/crypto_ops_builder/README.md
index a3acb11e8..831c6a63c 100644
--- a/src/crypto/crypto_ops_builder/README.md
+++ b/src/crypto/crypto_ops_builder/README.md
@@ -1,6 +1,6 @@
# Monero
-Copyright (c) 2014-2020, The Monero Project
+Copyright (c) 2014-2022, The Monero Project
## Crypto Ops Builder
diff --git a/src/crypto/crypto_ops_builder/crypto-ops-data.c b/src/crypto/crypto_ops_builder/crypto-ops-data.c
index 64fd15070..4785f975f 100644
--- a/src/crypto/crypto_ops_builder/crypto-ops-data.c
+++ b/src/crypto/crypto_ops_builder/crypto-ops-data.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/crypto_ops_builder/crypto-ops-old.c b/src/crypto/crypto_ops_builder/crypto-ops-old.c
index da85ee534..5d632809e 100644
--- a/src/crypto/crypto_ops_builder/crypto-ops-old.c
+++ b/src/crypto/crypto_ops_builder/crypto-ops-old.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/crypto_ops_builder/crypto-ops.h b/src/crypto/crypto_ops_builder/crypto-ops.h
index d719743c4..568bf2a37 100644
--- a/src/crypto/crypto_ops_builder/crypto-ops.h
+++ b/src/crypto/crypto_ops_builder/crypto-ops.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py b/src/crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py
index 08cead175..16b6c0ba9 100644
--- a/src/crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py
+++ b/src/crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py
@@ -15,7 +15,7 @@ print("maybe someone smart can replace the sed with perl..")
a = ""
license = textwrap.dedent("""\
- // Copyright (c) 2014-2020, The Monero Project
+ // Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/crypto_ops_builder/ref10CommentedCombined/crypto-ops.h b/src/crypto/crypto_ops_builder/ref10CommentedCombined/crypto-ops.h
index 613b718f5..8c0cbcda1 100644
--- a/src/crypto/crypto_ops_builder/ref10CommentedCombined/crypto-ops.h
+++ b/src/crypto/crypto_ops_builder/ref10CommentedCombined/crypto-ops.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/duration.h b/src/crypto/duration.h
index 493874288..25d1c0b8c 100644
--- a/src/crypto/duration.h
+++ b/src/crypto/duration.h
@@ -1,4 +1,5 @@
-// Copyright (c) 2020, The Monero Project
+// Copyright (c) 2020-2022, The Monero Project
+
//
// All rights reserved.
//
diff --git a/src/crypto/generic-ops.h b/src/crypto/generic-ops.h
index 9aa7b065a..5a5e09f9b 100644
--- a/src/crypto/generic-ops.h
+++ b/src/crypto/generic-ops.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/groestl.h b/src/crypto/groestl.h
index 7483db9b6..899660cb1 100644
--- a/src/crypto/groestl.h
+++ b/src/crypto/groestl.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/groestl_tables.h b/src/crypto/groestl_tables.h
index 7bf03afd7..556354c47 100644
--- a/src/crypto/groestl_tables.h
+++ b/src/crypto/groestl_tables.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/hash-extra-blake.c b/src/crypto/hash-extra-blake.c
index 4cc915cdd..1557269e6 100644
--- a/src/crypto/hash-extra-blake.c
+++ b/src/crypto/hash-extra-blake.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/hash-extra-groestl.c b/src/crypto/hash-extra-groestl.c
index dec21310d..96230aed7 100644
--- a/src/crypto/hash-extra-groestl.c
+++ b/src/crypto/hash-extra-groestl.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/hash-extra-jh.c b/src/crypto/hash-extra-jh.c
index 0604003bd..4d7481c07 100644
--- a/src/crypto/hash-extra-jh.c
+++ b/src/crypto/hash-extra-jh.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/hash-extra-skein.c b/src/crypto/hash-extra-skein.c
index 55bd4ddec..9ea9c4faa 100644
--- a/src/crypto/hash-extra-skein.c
+++ b/src/crypto/hash-extra-skein.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/hash-ops.h b/src/crypto/hash-ops.h
index 1cd502994..b7ec80d7c 100644
--- a/src/crypto/hash-ops.h
+++ b/src/crypto/hash-ops.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/hash.c b/src/crypto/hash.c
index a917115fe..7c761a1b9 100644
--- a/src/crypto/hash.c
+++ b/src/crypto/hash.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/hash.h b/src/crypto/hash.h
index 4b99bebaa..2812422e0 100644
--- a/src/crypto/hash.h
+++ b/src/crypto/hash.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/hmac-keccak.c b/src/crypto/hmac-keccak.c
index edcb2065e..771fcc27e 100644
--- a/src/crypto/hmac-keccak.c
+++ b/src/crypto/hmac-keccak.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/hmac-keccak.h b/src/crypto/hmac-keccak.h
index c450860d4..6b3633617 100644
--- a/src/crypto/hmac-keccak.h
+++ b/src/crypto/hmac-keccak.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/initializer.h b/src/crypto/initializer.h
index e9a7d97e2..90c09a087 100644
--- a/src/crypto/initializer.h
+++ b/src/crypto/initializer.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/keccak.c b/src/crypto/keccak.c
index 72d472d8a..f098cbdf0 100644
--- a/src/crypto/keccak.c
+++ b/src/crypto/keccak.c
@@ -31,54 +31,83 @@ const uint64_t keccakf_rndc[24] =
0x8000000000008080, 0x0000000080000001, 0x8000000080008008
};
-const int keccakf_rotc[24] =
-{
- 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
- 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44
-};
-
-const int keccakf_piln[24] =
-{
- 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
- 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1
-};
-
// update the state with given number of rounds
void keccakf(uint64_t st[25], int rounds)
{
- int i, j, round;
+ int round;
uint64_t t, bc[5];
- for (round = 0; round < rounds; round++) {
-
+ for (round = 0; round < rounds; ++round) {
// Theta
- for (i = 0; i < 5; i++)
- bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20];
-
- for (i = 0; i < 5; i++) {
- t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1);
- for (j = 0; j < 25; j += 5)
- st[j + i] ^= t;
+ bc[0] = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20];
+ bc[1] = st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21];
+ bc[2] = st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22];
+ bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23];
+ bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24];
+
+#define THETA(i) { \
+ t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); \
+ st[i ] ^= t; \
+ st[i + 5] ^= t; \
+ st[i + 10] ^= t; \
+ st[i + 15] ^= t; \
+ st[i + 20] ^= t; \
}
+ THETA(0);
+ THETA(1);
+ THETA(2);
+ THETA(3);
+ THETA(4);
+
// Rho Pi
t = st[1];
- for (i = 0; i < 24; i++) {
- j = keccakf_piln[i];
- bc[0] = st[j];
- st[j] = ROTL64(t, keccakf_rotc[i]);
- t = bc[0];
- }
+ st[ 1] = ROTL64(st[ 6], 44);
+ st[ 6] = ROTL64(st[ 9], 20);
+ st[ 9] = ROTL64(st[22], 61);
+ st[22] = ROTL64(st[14], 39);
+ st[14] = ROTL64(st[20], 18);
+ st[20] = ROTL64(st[ 2], 62);
+ st[ 2] = ROTL64(st[12], 43);
+ st[12] = ROTL64(st[13], 25);
+ st[13] = ROTL64(st[19], 8);
+ st[19] = ROTL64(st[23], 56);
+ st[23] = ROTL64(st[15], 41);
+ st[15] = ROTL64(st[ 4], 27);
+ st[ 4] = ROTL64(st[24], 14);
+ st[24] = ROTL64(st[21], 2);
+ st[21] = ROTL64(st[ 8], 55);
+ st[ 8] = ROTL64(st[16], 45);
+ st[16] = ROTL64(st[ 5], 36);
+ st[ 5] = ROTL64(st[ 3], 28);
+ st[ 3] = ROTL64(st[18], 21);
+ st[18] = ROTL64(st[17], 15);
+ st[17] = ROTL64(st[11], 10);
+ st[11] = ROTL64(st[ 7], 6);
+ st[ 7] = ROTL64(st[10], 3);
+ st[10] = ROTL64(t, 1);
// Chi
- for (j = 0; j < 25; j += 5) {
- for (i = 0; i < 5; i++)
- bc[i] = st[j + i];
- for (i = 0; i < 5; i++)
- st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5];
+#define CHI(j) { \
+ const uint64_t st0 = st[j ]; \
+ const uint64_t st1 = st[j + 1]; \
+ const uint64_t st2 = st[j + 2]; \
+ const uint64_t st3 = st[j + 3]; \
+ const uint64_t st4 = st[j + 4]; \
+ st[j ] ^= ~st1 & st2; \
+ st[j + 1] ^= ~st2 & st3; \
+ st[j + 2] ^= ~st3 & st4; \
+ st[j + 3] ^= ~st4 & st0; \
+ st[j + 4] ^= ~st0 & st1; \
}
+ CHI( 0);
+ CHI( 5);
+ CHI(10);
+ CHI(15);
+ CHI(20);
+
// Iota
st[0] ^= keccakf_rndc[round];
}
diff --git a/src/crypto/random.c b/src/crypto/random.c
index 1e3d9beff..cfb637fb4 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/random.h b/src/crypto/random.h
index 8b81e7a66..d50f29430 100644
--- a/src/crypto/random.h
+++ b/src/crypto/random.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/rx-slow-hash.c b/src/crypto/rx-slow-hash.c
index 801987e37..40ef96ac9 100644
--- a/src/crypto/rx-slow-hash.c
+++ b/src/crypto/rx-slow-hash.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2020, The Monero Project
+// Copyright (c) 2019-2022, The Monero Project
//
// All rights reserved.
//
@@ -63,6 +63,7 @@ static rx_state rx_s[2] = {{CTHR_MUTEX_INIT,{0},0,0},{CTHR_MUTEX_INIT,{0},0,0}};
static randomx_dataset *rx_dataset;
static int rx_dataset_nomem;
+static int rx_dataset_nolp;
static uint64_t rx_dataset_height;
static THREADV randomx_vm *rx_vm = NULL;
@@ -316,10 +317,11 @@ void rx_slow_hash(const uint64_t mainheight, const uint64_t seedheight, const ch
}
CTHR_MUTEX_UNLOCK(rx_dataset_mutex);
}
- if (!(disabled_flags() & RANDOMX_FLAG_LARGE_PAGES)) {
+ if (!(disabled_flags() & RANDOMX_FLAG_LARGE_PAGES) && !rx_dataset_nolp) {
rx_vm = randomx_create_vm(flags | RANDOMX_FLAG_LARGE_PAGES, rx_sp->rs_cache, rx_dataset);
if(rx_vm == NULL) { //large pages failed
mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX VM");
+ rx_dataset_nolp = 1;
}
}
if (rx_vm == NULL)
@@ -370,5 +372,6 @@ void rx_stop_mining(void) {
randomx_release_dataset(rd);
}
rx_dataset_nomem = 0;
+ rx_dataset_nolp = 0;
CTHR_MUTEX_UNLOCK(rx_dataset_mutex);
}
diff --git a/src/crypto/skein_port.h b/src/crypto/skein_port.h
index 94fd44035..2b701e8cc 100644
--- a/src/crypto/skein_port.h
+++ b/src/crypto/skein_port.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/slow-hash.c b/src/crypto/slow-hash.c
index 5a773f3cf..0de7db505 100644
--- a/src/crypto/slow-hash.c
+++ b/src/crypto/slow-hash.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
@@ -51,6 +51,12 @@
#define INIT_SIZE_BLK 8
#define INIT_SIZE_BYTE (INIT_SIZE_BLK * AES_BLOCK_SIZE)
+#if defined(_MSC_VER)
+#define THREADV __declspec(thread)
+#else
+#define THREADV __thread
+#endif
+
extern void aesb_single_round(const uint8_t *in, uint8_t *out, const uint8_t *expandedKey);
extern void aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *expandedKey);
@@ -89,6 +95,28 @@ static inline int use_v4_jit(void)
#endif
}
+#if defined(__x86_64__) || defined(__aarch64__)
+static inline int force_software_aes(void)
+{
+ static int use = -1;
+
+ if (use != -1)
+ return use;
+
+ const char *env = getenv("MONERO_USE_SOFTWARE_AES");
+ if (!env) {
+ use = 0;
+ }
+ else if (!strcmp(env, "0") || !strcmp(env, "no")) {
+ use = 0;
+ }
+ else {
+ use = 1;
+ }
+ return use;
+}
+#endif
+
#define VARIANT1_1(p) \
do if (variant == 1) \
{ \
@@ -437,12 +465,6 @@ static inline int use_v4_jit(void)
_b1 = _b; \
_b = _c; \
-#if defined(_MSC_VER)
-#define THREADV __declspec(thread)
-#else
-#define THREADV __thread
-#endif
-
#pragma pack(push, 1)
union cn_slow_hash_state
{
@@ -498,25 +520,6 @@ STATIC INLINE void xor64(uint64_t *a, const uint64_t b)
* @return true if the CPU supports AES, false otherwise
*/
-STATIC INLINE int force_software_aes(void)
-{
- static int use = -1;
-
- if (use != -1)
- return use;
-
- const char *env = getenv("MONERO_USE_SOFTWARE_AES");
- if (!env) {
- use = 0;
- }
- else if (!strcmp(env, "0") || !strcmp(env, "no")) {
- use = 0;
- }
- else {
- use = 1;
- }
- return use;
-}
STATIC INLINE int check_aes_hw(void)
{
@@ -1009,6 +1012,44 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
}
#elif !defined NO_AES && (defined(__arm__) || defined(__aarch64__))
+#ifdef __aarch64__
+#include <sys/mman.h>
+THREADV uint8_t *hp_state = NULL;
+THREADV int hp_malloced = 0;
+
+void cn_slow_hash_allocate_state(void)
+{
+ if(hp_state != NULL)
+ return;
+
+#ifndef MAP_HUGETLB
+#define MAP_HUGETLB 0
+#endif
+ hp_state = mmap(0, MEMORY, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON | MAP_HUGETLB, -1, 0);
+
+ if(hp_state == MAP_FAILED)
+ hp_state = NULL;
+ if(hp_state == NULL)
+ {
+ hp_malloced = 1;
+ hp_state = (uint8_t *) malloc(MEMORY);
+ }
+}
+
+void cn_slow_hash_free_state(void)
+{
+ if(hp_state == NULL)
+ return;
+
+ if (hp_malloced)
+ free(hp_state);
+ else
+ munmap(hp_state, MEMORY);
+ hp_state = NULL;
+ hp_malloced = 0;
+}
+#else
void cn_slow_hash_allocate_state(void)
{
// Do nothing, this is just to maintain compatibility with the upgraded slow-hash.c
@@ -1020,6 +1061,7 @@ void cn_slow_hash_free_state(void)
// As above
return;
}
+#endif
#if defined(__GNUC__)
#define RDATA_ALIGN16 __attribute__ ((aligned(16)))
@@ -1060,6 +1102,23 @@ union cn_slow_hash_state
* and moving between vector and regular registers stalls the pipeline.
*/
#include <arm_neon.h>
+#ifndef __APPLE__
+#include <sys/auxv.h>
+#include <asm/hwcap.h>
+#endif
+
+STATIC INLINE int check_aes_hw(void)
+{
+#ifdef __APPLE__
+ return 1;
+#else
+ static int supported = -1;
+
+ if(supported < 0)
+ supported = (getauxval(AT_HWCAP) & HWCAP_AES) != 0;
+ return supported;
+#endif
+}
#define TOTALBLOCKS (MEMORY / AES_BLOCK_SIZE)
@@ -1156,7 +1215,6 @@ __asm__(
STATIC INLINE void aes_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *expandedKey, int nblocks)
{
const uint8x16_t *k = (const uint8x16_t *)expandedKey, zero = {0};
- uint8x16_t tmp;
int i;
for (i=0; i<nblocks; i++)
@@ -1191,7 +1249,6 @@ STATIC INLINE void aes_pseudo_round_xor(const uint8_t *in, uint8_t *out, const u
{
const uint8x16_t *k = (const uint8x16_t *)expandedKey;
const uint8x16_t *x = (const uint8x16_t *)xor;
- uint8x16_t tmp;
int i;
for (i=0; i<nblocks; i++)
@@ -1244,16 +1301,17 @@ STATIC INLINE void aligned_free(void *ptr)
}
#endif /* FORCE_USE_HEAP */
+STATIC INLINE void xor_blocks(uint8_t* a, const uint8_t* b)
+{
+ U64(a)[0] ^= U64(b)[0];
+ U64(a)[1] ^= U64(b)[1];
+}
+
void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed, uint64_t height)
{
RDATA_ALIGN16 uint8_t expandedKey[240];
-#ifndef FORCE_USE_HEAP
- RDATA_ALIGN16 uint8_t local_hp_state[MEMORY];
-#else
- uint8_t *local_hp_state = (uint8_t *)aligned_malloc(MEMORY,16);
-#endif
-
+ uint8_t *local_hp_state;
uint8_t text[INIT_SIZE_BYTE];
RDATA_ALIGN16 uint64_t a[2];
RDATA_ALIGN16 uint64_t b[4];
@@ -1264,12 +1322,22 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
size_t i, j;
uint64_t *p = NULL;
+ oaes_ctx *aes_ctx = NULL;
+ int useAes = !force_software_aes() && check_aes_hw();
static void (*const extra_hashes[4])(const void *, size_t, char *) =
{
hash_extra_blake, hash_extra_groestl, hash_extra_jh, hash_extra_skein
};
+ // this isn't supposed to happen, but guard against it for now.
+ if(hp_state == NULL)
+ cn_slow_hash_allocate_state();
+
+ // locals to avoid constant TLS dereferencing
+ local_hp_state = hp_state;
+
+ // locals to avoid constant TLS dereferencing
/* CryptoNight Step 1: Use Keccak1600 to initialize the 'state' (and 'text') buffers from the data. */
if (prehashed) {
@@ -1287,11 +1355,26 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
* the 2MB large random access buffer.
*/
- aes_expand_key(state.hs.b, expandedKey);
- for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++)
+ if(useAes)
{
- aes_pseudo_round(text, text, expandedKey, INIT_SIZE_BLK);
- memcpy(&local_hp_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE);
+ aes_expand_key(state.hs.b, expandedKey);
+ for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++)
+ {
+ aes_pseudo_round(text, text, expandedKey, INIT_SIZE_BLK);
+ memcpy(&local_hp_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE);
+ }
+ }
+ else
+ {
+ aes_ctx = (oaes_ctx *) oaes_alloc();
+ oaes_key_import_data(aes_ctx, state.hs.b, AES_KEY_SIZE);
+ for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++)
+ {
+ for(j = 0; j < INIT_SIZE_BLK; j++)
+ aesb_pseudo_round(&text[AES_BLOCK_SIZE * j], &text[AES_BLOCK_SIZE * j], aes_ctx->key->exp_data);
+
+ memcpy(&local_hp_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE);
+ }
}
U64(a)[0] = U64(&state.k[0])[0] ^ U64(&state.k[32])[0];
@@ -1307,13 +1390,26 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
_b = vld1q_u8((const uint8_t *)b);
_b1 = vld1q_u8(((const uint8_t *)b) + AES_BLOCK_SIZE);
- for(i = 0; i < ITER / 2; i++)
+ if(useAes)
{
- pre_aes();
- _c = vaeseq_u8(_c, zero);
- _c = vaesmcq_u8(_c);
- _c = veorq_u8(_c, _a);
- post_aes();
+ for(i = 0; i < ITER / 2; i++)
+ {
+ pre_aes();
+ _c = vaeseq_u8(_c, zero);
+ _c = vaesmcq_u8(_c);
+ _c = veorq_u8(_c, _a);
+ post_aes();
+ }
+ }
+ else
+ {
+ for(i = 0; i < ITER / 2; i++)
+ {
+ pre_aes();
+ aesb_single_round((uint8_t *) &_c, (uint8_t *) &_c, (uint8_t *) &_a);
+ post_aes();
+ }
+
}
/* CryptoNight Step 4: Sequentially pass through the mixing buffer and use 10 rounds
@@ -1322,11 +1418,27 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
memcpy(text, state.init, INIT_SIZE_BYTE);
- aes_expand_key(&state.hs.b[32], expandedKey);
- for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++)
+ if(useAes)
+ {
+ aes_expand_key(&state.hs.b[32], expandedKey);
+ for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++)
+ {
+ // add the xor to the pseudo round
+ aes_pseudo_round_xor(text, text, expandedKey, &local_hp_state[i * INIT_SIZE_BYTE], INIT_SIZE_BLK);
+ }
+ }
+ else
{
- // add the xor to the pseudo round
- aes_pseudo_round_xor(text, text, expandedKey, &local_hp_state[i * INIT_SIZE_BYTE], INIT_SIZE_BLK);
+ oaes_key_import_data(aes_ctx, &state.hs.b[32], AES_KEY_SIZE);
+ for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++)
+ {
+ for(j = 0; j < INIT_SIZE_BLK; j++)
+ {
+ xor_blocks(&text[j * AES_BLOCK_SIZE], &local_hp_state[i * INIT_SIZE_BYTE + j * AES_BLOCK_SIZE]);
+ aesb_pseudo_round(&text[AES_BLOCK_SIZE * j], &text[AES_BLOCK_SIZE * j], aes_ctx->key->exp_data);
+ }
+ }
+ oaes_free((OAES_CTX **) &aes_ctx);
}
/* CryptoNight Step 5: Apply Keccak to the state again, and then
@@ -1339,10 +1451,6 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
memcpy(state.init, text, INIT_SIZE_BYTE);
hash_permutation(&state.hs);
extra_hashes[state.hs.b[0] & 3](&state, 200, hash);
-
-#ifdef FORCE_USE_HEAP
- aligned_free(local_hp_state);
-#endif
}
#else /* aarch64 && crypto */
diff --git a/src/crypto/tree-hash.c b/src/crypto/tree-hash.c
index 8f3ea3339..93a1bce4d 100644
--- a/src/crypto/tree-hash.c
+++ b/src/crypto/tree-hash.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2020, The Monero Project
+// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
diff --git a/src/crypto/wallet/CMakeLists.txt b/src/crypto/wallet/CMakeLists.txt
index 4ed986dce..ac1bdf7fd 100644
--- a/src/crypto/wallet/CMakeLists.txt
+++ b/src/crypto/wallet/CMakeLists.txt
@@ -1,4 +1,5 @@
-# Copyright (c) 2020, The Monero Project
+# Copyright (c) 2020-2022, The Monero Project
+
#
# All rights reserved.
#
diff --git a/src/crypto/wallet/crypto.h b/src/crypto/wallet/crypto.h
index a4c5d5a07..cee0ca18e 100644
--- a/src/crypto/wallet/crypto.h
+++ b/src/crypto/wallet/crypto.h
@@ -1,4 +1,5 @@
-// Copyright (c) 2020, The Monero Project
+// Copyright (c) 2020-2022, The Monero Project
+
//
// All rights reserved.
//
diff --git a/src/crypto/wallet/empty.h.in b/src/crypto/wallet/empty.h.in
index ac252e1bd..b884a57b5 100644
--- a/src/crypto/wallet/empty.h.in
+++ b/src/crypto/wallet/empty.h.in
@@ -1,4 +1,5 @@
-// Copyright (c) 2020, The Monero Project
+// Copyright (c) 2020-2022, The Monero Project
+
//
// All rights reserved.
//