aboutsummaryrefslogtreecommitdiff
path: root/src/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto')
-rw-r--r--src/crypto/CMakeLists.txt2
-rw-r--r--src/crypto/chacha.h4
-rw-r--r--src/crypto/crypto.cpp4
-rw-r--r--src/crypto/crypto.h21
-rw-r--r--src/crypto/crypto_device.cpp79
-rw-r--r--src/crypto/hash-ops.h3
-rw-r--r--src/crypto/hash.h4
-rw-r--r--src/crypto/slow-hash.c95
8 files changed, 199 insertions, 13 deletions
diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt
index 71dcedcab..35c099697 100644
--- a/src/crypto/CMakeLists.txt
+++ b/src/crypto/CMakeLists.txt
@@ -33,6 +33,7 @@ set(crypto_sources
crypto-ops-data.c
crypto-ops.c
crypto.cpp
+ crypto_device.cpp
groestl.c
hash-extra-blake.c
hash-extra-groestl.c
@@ -77,6 +78,7 @@ monero_add_library(cncrypto
target_link_libraries(cncrypto
PUBLIC
epee
+ device
${Boost_SYSTEM_LIBRARY}
PRIVATE
${EXTRA_LIBRARIES})
diff --git a/src/crypto/chacha.h b/src/crypto/chacha.h
index f74d0c352..22da53bd0 100644
--- a/src/crypto/chacha.h
+++ b/src/crypto/chacha.h
@@ -69,10 +69,10 @@ namespace crypto {
chacha20(data, length, key.data(), reinterpret_cast<const uint8_t*>(&iv), cipher);
}
- inline void generate_chacha_key(const void *data, size_t size, chacha_key& key) {
+ inline void generate_chacha_key(const void *data, size_t size, chacha_key& key, int cn_variant = 0, bool prehashed=false) {
static_assert(sizeof(chacha_key) <= sizeof(hash), "Size of hash must be at least that of chacha_key");
tools::scrubbed_arr<char, HASH_SIZE> pwd_hash;
- crypto::cn_slow_hash(data, size, pwd_hash.data());
+ crypto::cn_slow_hash_pre(data, size, pwd_hash.data(), cn_variant, prehashed);
memcpy(&key, pwd_hash.data(), sizeof(key));
}
diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp
index d9b8b6787..0c70b9eeb 100644
--- a/src/crypto/crypto.cpp
+++ b/src/crypto/crypto.cpp
@@ -107,7 +107,7 @@ namespace crypto {
/*
* generate public and secret keys from a random 256-bit integer
- * TODO: allow specifiying random value (for wallet recovery)
+ * TODO: allow specifying random value (for wallet recovery)
*
*/
secret_key crypto_ops::generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover) {
@@ -436,7 +436,7 @@ namespace crypto {
return sc_isnonzero(&c2) == 0;
}
- static void hash_to_ec(const public_key &key, ge_p3 &res) {
+ void crypto_ops::hash_to_ec(const public_key &key, ge_p3 &res) {
hash h;
ge_p2 point;
ge_p1p1 point2;
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 81ebfb9e2..75b333473 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -46,6 +46,10 @@
#include "hex.h"
#include "span.h"
#include "hash.h"
+#include "device/device_declare.hpp"
+extern "C" {
+ #include "crypto-ops.h"
+}
namespace crypto {
@@ -113,6 +117,9 @@ namespace crypto {
void operator=(const crypto_ops &);
~crypto_ops();
+ static void hash_to_ec(const public_key &key, ge_p3 &res) ;
+ friend void hash_to_ec(const public_key &key, ge_p3 &res) ;
+
static secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key = secret_key(), bool recover = false);
friend secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover);
static bool check_key(const public_key &);
@@ -149,6 +156,17 @@ namespace crypto {
const public_key *const *, std::size_t, const signature *);
};
+ secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover, hw::device &hwdev);
+ secret_key generate_keys(public_key &pub, secret_key &sec, hw::device &hwdev);
+ bool secret_key_to_public_key(const secret_key &sec, public_key &pub, hw::device &hwdev);
+ bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation, hw::device &hwdev);
+ void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res, hw::device &hwdev) ;
+ bool derive_public_key(const key_derivation &derivation, size_t output_index, const public_key &base, public_key &derived_key, hw::device &hwdev);
+ void derive_secret_key(const key_derivation &derivation, size_t output_index, const secret_key &base, secret_key &derived_key, hw::device &hwdev);
+ bool derive_subaddress_public_key(const public_key &out_key, const key_derivation &derivation, std::size_t output_index, public_key &derived_key, hw::device &hwdev);
+ void generate_key_image(const public_key &pub, const secret_key &sec, key_image &image, hw::device &hwdev);
+
+
/* Generate N random bytes
*/
inline void rand(size_t N, uint8_t *bytes) {
@@ -166,6 +184,9 @@ namespace crypto {
return res;
}
+ inline void hash_to_ec(const public_key &key, ge_p3 &res) {
+ crypto_ops::hash_to_ec(key,res);
+ }
/* Generate a new key pair
*/
inline secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key = secret_key(), bool recover = false) {
diff --git a/src/crypto/crypto_device.cpp b/src/crypto/crypto_device.cpp
new file mode 100644
index 000000000..5536857c8
--- /dev/null
+++ b/src/crypto/crypto_device.cpp
@@ -0,0 +1,79 @@
+// Copyright (c) 2014-2018, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+
+#include "crypto.h"
+#include "device/device.hpp"
+#include "device/log.hpp"
+
+namespace crypto {
+
+ secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover, hw::device &hwdev) {
+ secret_key rng;
+ hwdev.generate_keys(pub, sec, recovery_key, recover, rng);
+ return rng;
+ }
+
+ secret_key generate_keys(public_key &pub, secret_key &sec, hw::device &hwdev) {
+ secret_key rng;
+ hwdev.generate_keys(pub, sec, secret_key(), false, rng);
+ return rng;
+ }
+
+
+ bool secret_key_to_public_key(const secret_key &sec, public_key &pub, hw::device &hwdev) {
+ return hwdev.secret_key_to_public_key(sec, pub);
+ }
+
+ bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation, hw::device &hwdev) {
+ return hwdev.generate_key_derivation(key1, key2, derivation);
+ }
+
+ void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res, hw::device &hwdev) {
+ hwdev.derivation_to_scalar(derivation, output_index, res);
+ }
+
+ bool derive_public_key(const key_derivation &derivation, size_t output_index,
+ const public_key &base, public_key &derived_key, hw::device &hwdev) {
+ return hwdev.derive_public_key(derivation, output_index, base, derived_key);
+ }
+
+ void derive_secret_key(const key_derivation &derivation, size_t output_index,
+ const secret_key &base, secret_key &derived_key, hw::device &hwdev) {
+ hwdev.derive_secret_key(derivation, output_index, base, derived_key);
+ }
+
+ bool derive_subaddress_public_key(const public_key &out_key, const key_derivation &derivation, std::size_t output_index, public_key &derived_key, hw::device &hwdev) {
+ return hwdev.derive_subaddress_public_key(out_key, derivation, output_index, derived_key);
+ }
+
+ void generate_key_image(const public_key &pub, const secret_key &sec, key_image &image, hw::device &hwdev) {
+ hwdev.generate_key_image(pub,sec,image);
+ }
+} \ No newline at end of file
diff --git a/src/crypto/hash-ops.h b/src/crypto/hash-ops.h
index 47c6f6425..934d464de 100644
--- a/src/crypto/hash-ops.h
+++ b/src/crypto/hash-ops.h
@@ -79,7 +79,8 @@ enum {
};
void cn_fast_hash(const void *data, size_t length, char *hash);
-void cn_slow_hash(const void *data, size_t length, char *hash);
+void cn_slow_hash(const void *data, size_t length, char *hash, int variant);
+void cn_slow_hash_pre(const void *data, size_t length, char *hash, int variant, bool pre);
void hash_extra_blake(const void *data, size_t length, char *hash);
void hash_extra_groestl(const void *data, size_t length, char *hash);
diff --git a/src/crypto/hash.h b/src/crypto/hash.h
index 14104699b..bf4f4c096 100644
--- a/src/crypto/hash.h
+++ b/src/crypto/hash.h
@@ -71,8 +71,8 @@ namespace crypto {
return h;
}
- inline void cn_slow_hash(const void *data, std::size_t length, hash &hash) {
- cn_slow_hash(data, length, reinterpret_cast<char *>(&hash));
+ inline void cn_slow_hash(const void *data, std::size_t length, hash &hash, int variant = 0) {
+ cn_slow_hash(data, length, reinterpret_cast<char *>(&hash), variant);
}
inline void tree_hash(const hash *hashes, std::size_t count, hash &root_hash) {
diff --git a/src/crypto/slow-hash.c b/src/crypto/slow-hash.c
index f921b2455..8c7dad8e0 100644
--- a/src/crypto/slow-hash.c
+++ b/src/crypto/slow-hash.c
@@ -32,6 +32,8 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
#include "common/int-util.h"
#include "hash-ops.h"
@@ -47,6 +49,46 @@
extern int aesb_single_round(const uint8_t *in, uint8_t*out, const uint8_t *expandedKey);
extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *expandedKey);
+#define VARIANT1_1(p) \
+ do if (variant > 0) \
+ { \
+ const uint8_t tmp = ((const uint8_t*)(p))[11]; \
+ static const uint32_t table = 0x75310; \
+ const uint8_t index = (((tmp >> 3) & 6) | (tmp & 1)) << 1; \
+ ((uint8_t*)(p))[11] = tmp ^ ((table >> index) & 0x30); \
+ } while(0)
+
+#define VARIANT1_2(p) \
+ do if (variant > 0) \
+ { \
+ xor64(p, tweak1_2); \
+ } while(0)
+
+#define VARIANT1_CHECK() \
+ do if (length < 43) \
+ { \
+ fprintf(stderr, "Cryptonight variants need at least 43 bytes of data"); \
+ _exit(1); \
+ } while(0)
+
+#define NONCE_POINTER (((const uint8_t*)data)+35)
+
+#define VARIANT1_PORTABLE_INIT() \
+ uint8_t tweak1_2[8]; \
+ do if (variant > 0) \
+ { \
+ VARIANT1_CHECK(); \
+ memcpy(&tweak1_2, &state.hs.b[192], sizeof(tweak1_2)); \
+ xor64(tweak1_2, NONCE_POINTER); \
+ } while(0)
+
+#define VARIANT1_INIT64() \
+ if (variant > 0) \
+ { \
+ VARIANT1_CHECK(); \
+ } \
+ const uint64_t tweak1_2 = variant > 0 ? (state.hs.w[24] ^ (*((const uint64_t*)NONCE_POINTER))) : 0
+
#if !defined NO_AES && (defined(__x86_64__) || (defined(_MSC_VER) && defined(_WIN64)))
// Optimised code below, uses x86-specific intrinsics, SSE2, AES-NI
// Fall back to more portable code is down at the bottom
@@ -125,6 +167,7 @@ extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *exp
_mm_store_si128(R128(c), _c); \
_b = _mm_xor_si128(_b, _c); \
_mm_store_si128(R128(&hp_state[j]), _b); \
+ VARIANT1_1(&hp_state[j]); \
j = state_index(c); \
p = U64(&hp_state[j]); \
b[0] = p[0]; b[1] = p[1]; \
@@ -133,6 +176,7 @@ extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *exp
p = U64(&hp_state[j]); \
p[0] = a[0]; p[1] = a[1]; \
a[0] ^= b[0]; a[1] ^= b[1]; \
+ VARIANT1_2(p + 1); \
_b = _c; \
#if defined(_MSC_VER)
@@ -183,6 +227,11 @@ STATIC INLINE void xor_blocks(uint8_t *a, const uint8_t *b)
U64(a)[1] ^= U64(b)[1];
}
+STATIC INLINE void xor64(uint64_t *a, const uint64_t b)
+{
+ *a ^= b;
+}
+
/**
* @brief uses cpuid to determine if the CPU supports the AES instructions
* @return true if the CPU supports AES, false otherwise
@@ -515,8 +564,11 @@ void slow_hash_free_state(void)
* @param length the length in bytes of the data
* @param hash a pointer to a buffer in which the final 256 bit hash will be stored
*/
+void cn_slow_hash(const void *data, size_t length, char *hash, int variant) {
+ cn_slow_hash_pre(data,length,hash,variant,false);
+}
-void cn_slow_hash(const void *data, size_t length, char *hash)
+void cn_slow_hash_pre(const void *data, size_t length, char *hash, int variant, bool prehashed)
{
RDATA_ALIGN16 uint8_t expandedKey[240]; /* These buffers are aligned to use later with SSE functions */
@@ -543,10 +595,15 @@ void cn_slow_hash(const void *data, size_t length, char *hash)
slow_hash_allocate_state();
/* CryptoNight Step 1: Use Keccak1600 to initialize the 'state' (and 'text') buffers from the data. */
-
- hash_process(&state.hs, data, length);
+ if (prehashed) {
+ memcpy(&state.hs, data, length);
+ } else {
+ hash_process(&state.hs, data, length);
+ }
memcpy(text, state.init, INIT_SIZE_BYTE);
+ VARIANT1_INIT64();
+
/* CryptoNight Step 2: Iteratively encrypt the results from Keccak to fill
* the 2MB large random access buffer.
*/
@@ -670,6 +727,11 @@ void slow_hash_free_state(void)
#define U64(x) ((uint64_t *) (x))
+STATIC INLINE void xor64(uint64_t *a, const uint64_t b)
+{
+ *a ^= b;
+}
+
#pragma pack(push, 1)
union cn_slow_hash_state
{
@@ -706,6 +768,7 @@ union cn_slow_hash_state
vst1q_u8((uint8_t *)c, _c); \
_b = veorq_u8(_b, _c); \
vst1q_u8(&hp_state[j], _b); \
+ VARIANT1_1(&hp_state[j]); \
j = state_index(c); \
p = U64(&hp_state[j]); \
b[0] = p[0]; b[1] = p[1]; \
@@ -714,6 +777,7 @@ union cn_slow_hash_state
p = U64(&hp_state[j]); \
p[0] = a[0]; p[1] = a[1]; \
a[0] ^= b[0]; a[1] ^= b[1]; \
+ VARIANT1_2(p + 1); \
_b = _c; \
@@ -845,7 +909,7 @@ STATIC INLINE void aes_pseudo_round_xor(const uint8_t *in, uint8_t *out, const u
}
}
-void cn_slow_hash(const void *data, size_t length, char *hash)
+void cn_slow_hash(const void *data, size_t length, char *hash, int variant)
{
RDATA_ALIGN16 uint8_t expandedKey[240];
RDATA_ALIGN16 uint8_t hp_state[MEMORY];
@@ -871,6 +935,8 @@ void cn_slow_hash(const void *data, size_t length, char *hash)
hash_process(&state.hs, data, length);
memcpy(text, state.init, INIT_SIZE_BYTE);
+ VARIANT1_INIT64();
+
/* CryptoNight Step 2: Iteratively encrypt the results from Keccak to fill
* the 2MB large random access buffer.
*/
@@ -1039,7 +1105,7 @@ STATIC INLINE void xor_blocks(uint8_t* a, const uint8_t* b)
U64(a)[1] ^= U64(b)[1];
}
-void cn_slow_hash(const void *data, size_t length, char *hash)
+void cn_slow_hash(const void *data, size_t length, char *hash, int variant)
{
uint8_t text[INIT_SIZE_BYTE];
uint8_t a[AES_BLOCK_SIZE];
@@ -1068,6 +1134,8 @@ void cn_slow_hash(const void *data, size_t length, char *hash)
hash_process(&state.hs, data, length);
memcpy(text, state.init, INIT_SIZE_BYTE);
+ VARIANT1_INIT64();
+
aes_ctx = (oaes_ctx *) oaes_alloc();
oaes_key_import_data(aes_ctx, state.hs.b, AES_KEY_SIZE);
@@ -1097,6 +1165,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash)
xor_blocks(b, p);
swap_blocks(b, p);
swap_blocks(a, b);
+ VARIANT1_1(p);
// Iteration 2
p = &long_state[state_index(a)];
@@ -1106,6 +1175,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash)
swap_blocks(b, p);
xor_blocks(b, p);
swap_blocks(a, b);
+ VARIANT1_2(U64(p) + 1);
}
memcpy(text, state.init, INIT_SIZE_BYTE);
@@ -1200,6 +1270,15 @@ static void xor_blocks(uint8_t* a, const uint8_t* b) {
}
}
+static void xor64(uint8_t* left, const uint8_t* right)
+{
+ size_t i;
+ for (i = 0; i < 8; ++i)
+ {
+ left[i] ^= right[i];
+ }
+}
+
#pragma pack(push, 1)
union cn_slow_hash_state {
union hash_state hs;
@@ -1210,7 +1289,7 @@ union cn_slow_hash_state {
};
#pragma pack(pop)
-void cn_slow_hash(const void *data, size_t length, char *hash) {
+void cn_slow_hash(const void *data, size_t length, char *hash, int variant) {
uint8_t long_state[MEMORY];
union cn_slow_hash_state state;
uint8_t text[INIT_SIZE_BYTE];
@@ -1227,6 +1306,8 @@ void cn_slow_hash(const void *data, size_t length, char *hash) {
memcpy(aes_key, state.hs.b, AES_KEY_SIZE);
aes_ctx = (oaes_ctx *) oaes_alloc();
+ VARIANT1_PORTABLE_INIT();
+
oaes_key_import_data(aes_ctx, aes_key, AES_KEY_SIZE);
for (i = 0; i < MEMORY / INIT_SIZE_BYTE; i++) {
for (j = 0; j < INIT_SIZE_BLK; j++) {
@@ -1254,6 +1335,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash) {
copy_block(&long_state[j * AES_BLOCK_SIZE], c);
assert(j == e2i(a, MEMORY / AES_BLOCK_SIZE));
swap_blocks(a, b);
+ VARIANT1_1(&long_state[j * AES_BLOCK_SIZE]);
/* Iteration 2 */
j = e2i(a, MEMORY / AES_BLOCK_SIZE);
copy_block(c, &long_state[j * AES_BLOCK_SIZE]);
@@ -1261,6 +1343,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash) {
sum_half_blocks(b, d);
swap_blocks(b, c);
xor_blocks(b, c);
+ VARIANT1_2(c + 8);
copy_block(&long_state[j * AES_BLOCK_SIZE], c);
assert(j == e2i(a, MEMORY / AES_BLOCK_SIZE));
swap_blocks(a, b);