diff --git a/CMakeLists.txt b/CMakeLists.txt
index a3f9840566..aefd9f46a3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -524,6 +524,7 @@ if(WIN32)
usp10
psapi
winhttp
+ bcrypt
)
endif()
diff --git a/README.md b/README.md
index 1482e60fb9..51333237ad 100644
--- a/README.md
+++ b/README.md
@@ -587,6 +587,9 @@ See `src/3rdparty/catch2/LICENSE.txt` for the complete license text.
The icu scriptrun implementation in `src/3rdparty/icu` is licensed under the Unicode license.
See `src/3rdparty/icu/LICENSE` for the complete license text.
+The monocypher implementation in `src/3rdparty/monocypher` is licensed under the 2-clause BSD and CC-0 license.
+See src/3rdparty/monocypher/LICENSE.md` for the complete license text.
+
## 4.0 Credits
See [CREDITS.md](./CREDITS.md)
diff --git a/src/3rdparty/CMakeLists.txt b/src/3rdparty/CMakeLists.txt
index 0ecb4593ca..021712883e 100644
--- a/src/3rdparty/CMakeLists.txt
+++ b/src/3rdparty/CMakeLists.txt
@@ -2,11 +2,11 @@ add_subdirectory(catch2)
add_subdirectory(fmt)
add_subdirectory(icu)
add_subdirectory(md5)
+add_subdirectory(monocypher)
add_subdirectory(squirrel)
add_subdirectory(nlohmann)
add_subdirectory(opengl)
add_subdirectory(cpp-btree)
-add_subdirectory(monocypher)
add_subdirectory(randombytes)
add_subdirectory(robin_hood)
diff --git a/src/3rdparty/monocypher/CHANGELOG.md b/src/3rdparty/monocypher/CHANGELOG.md
index 5f084bb48e..b109b2d5c1 100644
--- a/src/3rdparty/monocypher/CHANGELOG.md
+++ b/src/3rdparty/monocypher/CHANGELOG.md
@@ -1,3 +1,13 @@
+4.0.2
+-----
+2023/08/24
+
+- Fixed multiple-lanes Argon2.
+- Improved Poly1305 performance.
+- Improved Argon2 performance.
+- Makefiles no longer override standard environment variables.
+
+
4.0.1
-----
2023/03/06
diff --git a/src/3rdparty/monocypher/CMakeLists.txt b/src/3rdparty/monocypher/CMakeLists.txt
index 00d690839e..4b8a6b646a 100644
--- a/src/3rdparty/monocypher/CMakeLists.txt
+++ b/src/3rdparty/monocypher/CMakeLists.txt
@@ -1,4 +1,6 @@
add_files(
+ monocypher-ed25519.cpp
+ monocypher-ed25519.h
+ monocypher.cpp
monocypher.h
- monocypher.c
)
diff --git a/src/3rdparty/monocypher/README.md b/src/3rdparty/monocypher/README.md
index a88bf47c7e..59b43d9d83 100644
--- a/src/3rdparty/monocypher/README.md
+++ b/src/3rdparty/monocypher/README.md
@@ -5,7 +5,7 @@ Monocypher is an easy to use, easy to deploy, auditable crypto library
written in portable C. It approaches the size of [TweetNaCl][] and the
speed of [libsodium][].
-[Official site.](https://monocypher.org/)
+[Official site.](https://monocypher.org/)
[Official releases.](https://monocypher.org/download/)
[libsodium]: https://libsodium.org
diff --git a/src/3rdparty/monocypher/monocypher-ed25519.cpp b/src/3rdparty/monocypher/monocypher-ed25519.cpp
new file mode 100644
index 0000000000..4134463b6b
--- /dev/null
+++ b/src/3rdparty/monocypher/monocypher-ed25519.cpp
@@ -0,0 +1,500 @@
+// Monocypher version 4.0.2
+//
+// This file is dual-licensed. Choose whichever licence you want from
+// the two licences listed below.
+//
+// The first licence is a regular 2-clause BSD licence. The second licence
+// is the CC-0 from Creative Commons. It is intended to release Monocypher
+// to the public domain. The BSD licence serves as a fallback option.
+//
+// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
+//
+// ------------------------------------------------------------------------
+//
+// Copyright (c) 2017-2019, Loup Vaillant
+// 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.
+//
+// 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.
+//
+// ------------------------------------------------------------------------
+//
+// Written in 2017-2019 by Loup Vaillant
+//
+// To the extent possible under law, the author(s) have dedicated all copyright
+// and related neighboring rights to this software to the public domain
+// worldwide. This software is distributed without any warranty.
+//
+// You should have received a copy of the CC0 Public Domain Dedication along
+// with this software. If not, see
+//
+
+#include "monocypher-ed25519.h"
+
+#ifdef MONOCYPHER_CPP_NAMESPACE
+namespace MONOCYPHER_CPP_NAMESPACE {
+#endif
+
+/////////////////
+/// Utilities ///
+/////////////////
+#define FOR(i, min, max) for (size_t i = min; i < max; i++)
+#define COPY(dst, src, size) FOR(_i_, 0, size) (dst)[_i_] = (src)[_i_]
+#define ZERO(buf, size) FOR(_i_, 0, size) (buf)[_i_] = 0
+#define WIPE_CTX(ctx) crypto_wipe(ctx , sizeof(*(ctx)))
+#define WIPE_BUFFER(buffer) crypto_wipe(buffer, sizeof(buffer))
+#define MC_MIN(a, b) ((a) <= (b) ? (a) : (b))
+typedef uint8_t u8;
+typedef uint64_t u64;
+
+// Returns the smallest positive integer y such that
+// (x + y) % pow_2 == 0
+// Basically, it's how many bytes we need to add to "align" x.
+// Only works when pow_2 is a power of 2.
+// Note: we use ~x+1 instead of -x to avoid compiler warnings
+static size_t align(size_t x, size_t pow_2)
+{
+ return (~x + 1) & (pow_2 - 1);
+}
+
+static u64 load64_be(const u8 s[8])
+{
+ return((u64)s[0] << 56)
+ | ((u64)s[1] << 48)
+ | ((u64)s[2] << 40)
+ | ((u64)s[3] << 32)
+ | ((u64)s[4] << 24)
+ | ((u64)s[5] << 16)
+ | ((u64)s[6] << 8)
+ | (u64)s[7];
+}
+
+static void store64_be(u8 out[8], u64 in)
+{
+ out[0] = (in >> 56) & 0xff;
+ out[1] = (in >> 48) & 0xff;
+ out[2] = (in >> 40) & 0xff;
+ out[3] = (in >> 32) & 0xff;
+ out[4] = (in >> 24) & 0xff;
+ out[5] = (in >> 16) & 0xff;
+ out[6] = (in >> 8) & 0xff;
+ out[7] = in & 0xff;
+}
+
+static void load64_be_buf (u64 *dst, const u8 *src, size_t size) {
+ FOR(i, 0, size) { dst[i] = load64_be(src + i*8); }
+}
+
+///////////////
+/// SHA 512 ///
+///////////////
+static u64 rot(u64 x, int c ) { return (x >> c) | (x << (64 - c)); }
+static u64 ch (u64 x, u64 y, u64 z) { return (x & y) ^ (~x & z); }
+static u64 maj(u64 x, u64 y, u64 z) { return (x & y) ^ ( x & z) ^ (y & z); }
+static u64 big_sigma0(u64 x) { return rot(x, 28) ^ rot(x, 34) ^ rot(x, 39); }
+static u64 big_sigma1(u64 x) { return rot(x, 14) ^ rot(x, 18) ^ rot(x, 41); }
+static u64 lit_sigma0(u64 x) { return rot(x, 1) ^ rot(x, 8) ^ (x >> 7); }
+static u64 lit_sigma1(u64 x) { return rot(x, 19) ^ rot(x, 61) ^ (x >> 6); }
+
+static const u64 K[80] = {
+ 0x428a2f98d728ae22,0x7137449123ef65cd,0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc,
+ 0x3956c25bf348b538,0x59f111f1b605d019,0x923f82a4af194f9b,0xab1c5ed5da6d8118,
+ 0xd807aa98a3030242,0x12835b0145706fbe,0x243185be4ee4b28c,0x550c7dc3d5ffb4e2,
+ 0x72be5d74f27b896f,0x80deb1fe3b1696b1,0x9bdc06a725c71235,0xc19bf174cf692694,
+ 0xe49b69c19ef14ad2,0xefbe4786384f25e3,0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65,
+ 0x2de92c6f592b0275,0x4a7484aa6ea6e483,0x5cb0a9dcbd41fbd4,0x76f988da831153b5,
+ 0x983e5152ee66dfab,0xa831c66d2db43210,0xb00327c898fb213f,0xbf597fc7beef0ee4,
+ 0xc6e00bf33da88fc2,0xd5a79147930aa725,0x06ca6351e003826f,0x142929670a0e6e70,
+ 0x27b70a8546d22ffc,0x2e1b21385c26c926,0x4d2c6dfc5ac42aed,0x53380d139d95b3df,
+ 0x650a73548baf63de,0x766a0abb3c77b2a8,0x81c2c92e47edaee6,0x92722c851482353b,
+ 0xa2bfe8a14cf10364,0xa81a664bbc423001,0xc24b8b70d0f89791,0xc76c51a30654be30,
+ 0xd192e819d6ef5218,0xd69906245565a910,0xf40e35855771202a,0x106aa07032bbd1b8,
+ 0x19a4c116b8d2d0c8,0x1e376c085141ab53,0x2748774cdf8eeb99,0x34b0bcb5e19b48a8,
+ 0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb,0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3,
+ 0x748f82ee5defb2fc,0x78a5636f43172f60,0x84c87814a1f0ab72,0x8cc702081a6439ec,
+ 0x90befffa23631e28,0xa4506cebde82bde9,0xbef9a3f7b2c67915,0xc67178f2e372532b,
+ 0xca273eceea26619c,0xd186b8c721c0c207,0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178,
+ 0x06f067aa72176fba,0x0a637dc5a2c898a6,0x113f9804bef90dae,0x1b710b35131c471b,
+ 0x28db77f523047d84,0x32caab7b40c72493,0x3c9ebe0a15c9bebc,0x431d67c49c100d4c,
+ 0x4cc5d4becb3e42b6,0x597f299cfc657e2a,0x5fcb6fab3ad6faec,0x6c44198c4a475817
+};
+
+static void sha512_compress(crypto_sha512_ctx *ctx)
+{
+ u64 a = ctx->hash[0]; u64 b = ctx->hash[1];
+ u64 c = ctx->hash[2]; u64 d = ctx->hash[3];
+ u64 e = ctx->hash[4]; u64 f = ctx->hash[5];
+ u64 g = ctx->hash[6]; u64 h = ctx->hash[7];
+
+ FOR (j, 0, 16) {
+ u64 in = K[j] + ctx->input[j];
+ u64 t1 = big_sigma1(e) + ch (e, f, g) + h + in;
+ u64 t2 = big_sigma0(a) + maj(a, b, c);
+ h = g; g = f; f = e; e = d + t1;
+ d = c; c = b; b = a; a = t1 + t2;
+ }
+ size_t i16 = 0;
+ FOR(i, 1, 5) {
+ i16 += 16;
+ FOR (j, 0, 16) {
+ ctx->input[j] += lit_sigma1(ctx->input[(j- 2) & 15]);
+ ctx->input[j] += lit_sigma0(ctx->input[(j-15) & 15]);
+ ctx->input[j] += ctx->input[(j- 7) & 15];
+ u64 in = K[i16 + j] + ctx->input[j];
+ u64 t1 = big_sigma1(e) + ch (e, f, g) + h + in;
+ u64 t2 = big_sigma0(a) + maj(a, b, c);
+ h = g; g = f; f = e; e = d + t1;
+ d = c; c = b; b = a; a = t1 + t2;
+ }
+ }
+
+ ctx->hash[0] += a; ctx->hash[1] += b;
+ ctx->hash[2] += c; ctx->hash[3] += d;
+ ctx->hash[4] += e; ctx->hash[5] += f;
+ ctx->hash[6] += g; ctx->hash[7] += h;
+}
+
+// Write 1 input byte
+static void sha512_set_input(crypto_sha512_ctx *ctx, u8 input)
+{
+ size_t word = ctx->input_idx >> 3;
+ size_t byte = ctx->input_idx & 7;
+ ctx->input[word] |= (u64)input << (8 * (7 - byte));
+}
+
+// Increment a 128-bit "word".
+static void sha512_incr(u64 x[2], u64 y)
+{
+ x[1] += y;
+ if (x[1] < y) {
+ x[0]++;
+ }
+}
+
+void crypto_sha512_init(crypto_sha512_ctx *ctx)
+{
+ ctx->hash[0] = 0x6a09e667f3bcc908;
+ ctx->hash[1] = 0xbb67ae8584caa73b;
+ ctx->hash[2] = 0x3c6ef372fe94f82b;
+ ctx->hash[3] = 0xa54ff53a5f1d36f1;
+ ctx->hash[4] = 0x510e527fade682d1;
+ ctx->hash[5] = 0x9b05688c2b3e6c1f;
+ ctx->hash[6] = 0x1f83d9abfb41bd6b;
+ ctx->hash[7] = 0x5be0cd19137e2179;
+ ctx->input_size[0] = 0;
+ ctx->input_size[1] = 0;
+ ctx->input_idx = 0;
+ ZERO(ctx->input, 16);
+}
+
+void crypto_sha512_update(crypto_sha512_ctx *ctx,
+ const u8 *message, size_t message_size)
+{
+ // Avoid undefined NULL pointer increments with empty messages
+ if (message_size == 0) {
+ return;
+ }
+
+ // Align ourselves with word boundaries
+ if ((ctx->input_idx & 7) != 0) {
+ size_t nb_bytes = MC_MIN(align(ctx->input_idx, 8), message_size);
+ FOR (i, 0, nb_bytes) {
+ sha512_set_input(ctx, message[i]);
+ ctx->input_idx++;
+ }
+ message += nb_bytes;
+ message_size -= nb_bytes;
+ }
+
+ // Align ourselves with block boundaries
+ if ((ctx->input_idx & 127) != 0) {
+ size_t nb_words = MC_MIN(align(ctx->input_idx, 128), message_size) >> 3;
+ load64_be_buf(ctx->input + (ctx->input_idx >> 3), message, nb_words);
+ ctx->input_idx += nb_words << 3;
+ message += nb_words << 3;
+ message_size -= nb_words << 3;
+ }
+
+ // Compress block if needed
+ if (ctx->input_idx == 128) {
+ sha512_incr(ctx->input_size, 1024); // size is in bits
+ sha512_compress(ctx);
+ ctx->input_idx = 0;
+ ZERO(ctx->input, 16);
+ }
+
+ // Process the message block by block
+ FOR (i, 0, message_size >> 7) { // number of blocks
+ load64_be_buf(ctx->input, message, 16);
+ sha512_incr(ctx->input_size, 1024); // size is in bits
+ sha512_compress(ctx);
+ ctx->input_idx = 0;
+ ZERO(ctx->input, 16);
+ message += 128;
+ }
+ message_size &= 127;
+
+ if (message_size != 0) {
+ // Remaining words
+ size_t nb_words = message_size >> 3;
+ load64_be_buf(ctx->input, message, nb_words);
+ ctx->input_idx += nb_words << 3;
+ message += nb_words << 3;
+ message_size -= nb_words << 3;
+
+ // Remaining bytes
+ FOR (i, 0, message_size) {
+ sha512_set_input(ctx, message[i]);
+ ctx->input_idx++;
+ }
+ }
+}
+
+void crypto_sha512_final(crypto_sha512_ctx *ctx, u8 hash[64])
+{
+ // Add padding bit
+ if (ctx->input_idx == 0) {
+ ZERO(ctx->input, 16);
+ }
+ sha512_set_input(ctx, 128);
+
+ // Update size
+ sha512_incr(ctx->input_size, ctx->input_idx * 8);
+
+ // Compress penultimate block (if any)
+ if (ctx->input_idx > 111) {
+ sha512_compress(ctx);
+ ZERO(ctx->input, 14);
+ }
+ // Compress last block
+ ctx->input[14] = ctx->input_size[0];
+ ctx->input[15] = ctx->input_size[1];
+ sha512_compress(ctx);
+
+ // Copy hash to output (big endian)
+ FOR (i, 0, 8) {
+ store64_be(hash + i*8, ctx->hash[i]);
+ }
+
+ WIPE_CTX(ctx);
+}
+
+void crypto_sha512(u8 hash[64], const u8 *message, size_t message_size)
+{
+ crypto_sha512_ctx ctx;
+ crypto_sha512_init (&ctx);
+ crypto_sha512_update(&ctx, message, message_size);
+ crypto_sha512_final (&ctx, hash);
+}
+
+////////////////////
+/// HMAC SHA 512 ///
+////////////////////
+void crypto_sha512_hmac_init(crypto_sha512_hmac_ctx *ctx,
+ const u8 *key, size_t key_size)
+{
+ // hash key if it is too long
+ if (key_size > 128) {
+ crypto_sha512(ctx->key, key, key_size);
+ key = ctx->key;
+ key_size = 64;
+ }
+ // Compute inner key: padded key XOR 0x36
+ FOR (i, 0, key_size) { ctx->key[i] = key[i] ^ 0x36; }
+ FOR (i, key_size, 128) { ctx->key[i] = 0x36; }
+ // Start computing inner hash
+ crypto_sha512_init (&ctx->ctx);
+ crypto_sha512_update(&ctx->ctx, ctx->key, 128);
+}
+
+void crypto_sha512_hmac_update(crypto_sha512_hmac_ctx *ctx,
+ const u8 *message, size_t message_size)
+{
+ crypto_sha512_update(&ctx->ctx, message, message_size);
+}
+
+void crypto_sha512_hmac_final(crypto_sha512_hmac_ctx *ctx, u8 hmac[64])
+{
+ // Finish computing inner hash
+ crypto_sha512_final(&ctx->ctx, hmac);
+ // Compute outer key: padded key XOR 0x5c
+ FOR (i, 0, 128) {
+ ctx->key[i] ^= 0x36 ^ 0x5c;
+ }
+ // Compute outer hash
+ crypto_sha512_init (&ctx->ctx);
+ crypto_sha512_update(&ctx->ctx, ctx->key , 128);
+ crypto_sha512_update(&ctx->ctx, hmac, 64);
+ crypto_sha512_final (&ctx->ctx, hmac); // outer hash
+ WIPE_CTX(ctx);
+}
+
+void crypto_sha512_hmac(u8 hmac[64], const u8 *key, size_t key_size,
+ const u8 *message, size_t message_size)
+{
+ crypto_sha512_hmac_ctx ctx;
+ crypto_sha512_hmac_init (&ctx, key, key_size);
+ crypto_sha512_hmac_update(&ctx, message, message_size);
+ crypto_sha512_hmac_final (&ctx, hmac);
+}
+
+////////////////////
+/// HKDF SHA 512 ///
+////////////////////
+void crypto_sha512_hkdf_expand(u8 *okm, size_t okm_size,
+ const u8 *prk, size_t prk_size,
+ const u8 *info, size_t info_size)
+{
+ int not_first = 0;
+ u8 ctr = 1;
+ u8 blk[64];
+
+ while (okm_size > 0) {
+ size_t out_size = MC_MIN(okm_size, sizeof(blk));
+
+ crypto_sha512_hmac_ctx ctx;
+ crypto_sha512_hmac_init(&ctx, prk , prk_size);
+ if (not_first) {
+ // For some reason HKDF uses some kind of CBC mode.
+ // For some reason CTR mode alone wasn't enough.
+ // Like what, they didn't trust HMAC in 2010? Really??
+ crypto_sha512_hmac_update(&ctx, blk , sizeof(blk));
+ }
+ crypto_sha512_hmac_update(&ctx, info, info_size);
+ crypto_sha512_hmac_update(&ctx, &ctr, 1);
+ crypto_sha512_hmac_final(&ctx, blk);
+
+ COPY(okm, blk, out_size);
+
+ not_first = 1;
+ okm += out_size;
+ okm_size -= out_size;
+ ctr++;
+ }
+}
+
+void crypto_sha512_hkdf(u8 *okm , size_t okm_size,
+ const u8 *ikm , size_t ikm_size,
+ const u8 *salt, size_t salt_size,
+ const u8 *info, size_t info_size)
+{
+ // Extract
+ u8 prk[64];
+ crypto_sha512_hmac(prk, salt, salt_size, ikm, ikm_size);
+
+ // Expand
+ crypto_sha512_hkdf_expand(okm, okm_size, prk, sizeof(prk), info, info_size);
+}
+
+///////////////
+/// Ed25519 ///
+///////////////
+void crypto_ed25519_key_pair(u8 secret_key[64], u8 public_key[32], u8 seed[32])
+{
+ u8 a[64];
+ COPY(a, seed, 32); // a[ 0..31] = seed
+ crypto_wipe(seed, 32);
+ COPY(secret_key, a, 32); // secret key = seed
+ crypto_sha512(a, a, 32); // a[ 0..31] = scalar
+ crypto_eddsa_trim_scalar(a, a); // a[ 0..31] = trimmed scalar
+ crypto_eddsa_scalarbase(public_key, a); // public key = [trimmed scalar]B
+ COPY(secret_key + 32, public_key, 32); // secret key includes public half
+ WIPE_BUFFER(a);
+}
+
+static void hash_reduce(u8 h[32],
+ const u8 *a, size_t a_size,
+ const u8 *b, size_t b_size,
+ const u8 *c, size_t c_size,
+ const u8 *d, size_t d_size)
+{
+ u8 hash[64];
+ crypto_sha512_ctx ctx;
+ crypto_sha512_init (&ctx);
+ crypto_sha512_update(&ctx, a, a_size);
+ crypto_sha512_update(&ctx, b, b_size);
+ crypto_sha512_update(&ctx, c, c_size);
+ crypto_sha512_update(&ctx, d, d_size);
+ crypto_sha512_final (&ctx, hash);
+ crypto_eddsa_reduce(h, hash);
+}
+
+static void ed25519_dom_sign(u8 signature [64], const u8 secret_key[32],
+ const u8 *dom, size_t dom_size,
+ const u8 *message, size_t message_size)
+{
+ u8 a[64]; // secret scalar and prefix
+ u8 r[32]; // secret deterministic "random" nonce
+ u8 h[32]; // publically verifiable hash of the message (not wiped)
+ u8 R[32]; // first half of the signature (allows overlapping inputs)
+ const u8 *pk = secret_key + 32;
+
+ crypto_sha512(a, secret_key, 32);
+ crypto_eddsa_trim_scalar(a, a);
+ hash_reduce(r, dom, dom_size, a + 32, 32, message, message_size, 0, 0);
+ crypto_eddsa_scalarbase(R, r);
+ hash_reduce(h, dom, dom_size, R, 32, pk, 32, message, message_size);
+ COPY(signature, R, 32);
+ crypto_eddsa_mul_add(signature + 32, h, a, r);
+
+ WIPE_BUFFER(a);
+ WIPE_BUFFER(r);
+}
+
+void crypto_ed25519_sign(u8 signature [64], const u8 secret_key[64],
+ const u8 *message, size_t message_size)
+{
+ ed25519_dom_sign(signature, secret_key, 0, 0, message, message_size);
+}
+
+int crypto_ed25519_check(const u8 signature[64], const u8 public_key[32],
+ const u8 *msg, size_t msg_size)
+{
+ u8 h_ram[32];
+ hash_reduce(h_ram, signature, 32, public_key, 32, msg, msg_size, 0, 0);
+ return crypto_eddsa_check_equation(signature, public_key, h_ram);
+}
+
+static const u8 domain[34] = "SigEd25519 no Ed25519 collisions\1";
+
+void crypto_ed25519_ph_sign(uint8_t signature[64], const uint8_t secret_key[64],
+ const uint8_t message_hash[64])
+{
+ ed25519_dom_sign(signature, secret_key, domain, sizeof(domain),
+ message_hash, 64);
+}
+
+int crypto_ed25519_ph_check(const uint8_t sig[64], const uint8_t pk[32],
+ const uint8_t msg_hash[64])
+{
+ u8 h_ram[32];
+ hash_reduce(h_ram, domain, sizeof(domain), sig, 32, pk, 32, msg_hash, 64);
+ return crypto_eddsa_check_equation(sig, pk, h_ram);
+}
+
+
+#ifdef MONOCYPHER_CPP_NAMESPACE
+}
+#endif
diff --git a/src/3rdparty/monocypher/monocypher-ed25519.h b/src/3rdparty/monocypher/monocypher-ed25519.h
new file mode 100644
index 0000000000..1e6d705da7
--- /dev/null
+++ b/src/3rdparty/monocypher/monocypher-ed25519.h
@@ -0,0 +1,140 @@
+// Monocypher version 4.0.2
+//
+// This file is dual-licensed. Choose whichever licence you want from
+// the two licences listed below.
+//
+// The first licence is a regular 2-clause BSD licence. The second licence
+// is the CC-0 from Creative Commons. It is intended to release Monocypher
+// to the public domain. The BSD licence serves as a fallback option.
+//
+// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
+//
+// ------------------------------------------------------------------------
+//
+// Copyright (c) 2017-2019, Loup Vaillant
+// 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.
+//
+// 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.
+//
+// ------------------------------------------------------------------------
+//
+// Written in 2017-2019 by Loup Vaillant
+//
+// To the extent possible under law, the author(s) have dedicated all copyright
+// and related neighboring rights to this software to the public domain
+// worldwide. This software is distributed without any warranty.
+//
+// You should have received a copy of the CC0 Public Domain Dedication along
+// with this software. If not, see
+//
+
+#ifndef ED25519_H
+#define ED25519_H
+
+#include "monocypher.h"
+
+#ifdef MONOCYPHER_CPP_NAMESPACE
+namespace MONOCYPHER_CPP_NAMESPACE {
+#elif defined(__cplusplus)
+extern "C" {
+#endif
+
+////////////////////////
+/// Type definitions ///
+////////////////////////
+
+// Do not rely on the size or content on any of those types,
+// they may change without notice.
+typedef struct {
+ uint64_t hash[8];
+ uint64_t input[16];
+ uint64_t input_size[2];
+ size_t input_idx;
+} crypto_sha512_ctx;
+
+typedef struct {
+ uint8_t key[128];
+ crypto_sha512_ctx ctx;
+} crypto_sha512_hmac_ctx;
+
+
+// SHA 512
+// -------
+void crypto_sha512_init (crypto_sha512_ctx *ctx);
+void crypto_sha512_update(crypto_sha512_ctx *ctx,
+ const uint8_t *message, size_t message_size);
+void crypto_sha512_final (crypto_sha512_ctx *ctx, uint8_t hash[64]);
+void crypto_sha512(uint8_t hash[64],
+ const uint8_t *message, size_t message_size);
+
+// SHA 512 HMAC
+// ------------
+void crypto_sha512_hmac_init(crypto_sha512_hmac_ctx *ctx,
+ const uint8_t *key, size_t key_size);
+void crypto_sha512_hmac_update(crypto_sha512_hmac_ctx *ctx,
+ const uint8_t *message, size_t message_size);
+void crypto_sha512_hmac_final(crypto_sha512_hmac_ctx *ctx, uint8_t hmac[64]);
+void crypto_sha512_hmac(uint8_t hmac[64],
+ const uint8_t *key , size_t key_size,
+ const uint8_t *message, size_t message_size);
+
+// SHA 512 HKDF
+// ------------
+void crypto_sha512_hkdf_expand(uint8_t *okm, size_t okm_size,
+ const uint8_t *prk, size_t prk_size,
+ const uint8_t *info, size_t info_size);
+void crypto_sha512_hkdf(uint8_t *okm , size_t okm_size,
+ const uint8_t *ikm , size_t ikm_size,
+ const uint8_t *salt, size_t salt_size,
+ const uint8_t *info, size_t info_size);
+
+// Ed25519
+// -------
+// Signatures (EdDSA with curve25519 + SHA-512)
+// --------------------------------------------
+void crypto_ed25519_key_pair(uint8_t secret_key[64],
+ uint8_t public_key[32],
+ uint8_t seed[32]);
+void crypto_ed25519_sign(uint8_t signature [64],
+ const uint8_t secret_key[64],
+ const uint8_t *message, size_t message_size);
+int crypto_ed25519_check(const uint8_t signature [64],
+ const uint8_t public_key[32],
+ const uint8_t *message, size_t message_size);
+
+// Pre-hash variants
+void crypto_ed25519_ph_sign(uint8_t signature [64],
+ const uint8_t secret_key [64],
+ const uint8_t message_hash[64]);
+int crypto_ed25519_ph_check(const uint8_t signature [64],
+ const uint8_t public_key [32],
+ const uint8_t message_hash[64]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // ED25519_H
diff --git a/src/3rdparty/monocypher/monocypher.c b/src/3rdparty/monocypher/monocypher.cpp
similarity index 94%
rename from src/3rdparty/monocypher/monocypher.c
rename to src/3rdparty/monocypher/monocypher.cpp
index e056db0c5a..4a3be94f7d 100644
--- a/src/3rdparty/monocypher/monocypher.c
+++ b/src/3rdparty/monocypher/monocypher.cpp
@@ -1,4 +1,4 @@
-// Monocypher version 4.0.1
+// Monocypher version 4.0.2
//
// This file is dual-licensed. Choose whichever licence you want from
// the two licences listed below.
@@ -66,8 +66,8 @@ namespace MONOCYPHER_CPP_NAMESPACE {
#define ZERO(buf, size) FOR(_i_, 0, size) (buf)[_i_] = 0
#define WIPE_CTX(ctx) crypto_wipe(ctx , sizeof(*(ctx)))
#define WIPE_BUFFER(buffer) crypto_wipe(buffer, sizeof(buffer))
-#define MIN(a, b) ((a) <= (b) ? (a) : (b))
-#define MAX(a, b) ((a) >= (b) ? (a) : (b))
+#define MC_MIN(a, b) ((a) <= (b) ? (a) : (b))
+#define MC_MAX(a, b) ((a) >= (b) ? (a) : (b))
typedef int8_t i8;
typedef uint8_t u8;
@@ -81,10 +81,10 @@ static const u8 zero[128] = {0};
// returns the smallest positive integer y such that
// (x + y) % pow_2 == 0
-// Basically, it's how many bytes we need to add to "align" x.
+// Basically, y is the "gap" missing to align x.
// Only works when pow_2 is a power of 2.
// Note: we use ~x+1 instead of -x to avoid compiler warnings
-static size_t align(size_t x, size_t pow_2)
+static size_t gap(size_t x, size_t pow_2)
{
return (~x + 1) & (pow_2 - 1);
}
@@ -307,74 +307,60 @@ u64 crypto_chacha20_x(u8 *cipher_text, const u8 *plain_text,
// end <= 1
// Postcondition:
// ctx->h <= 4_ffffffff_ffffffff_ffffffff_ffffffff
-static void poly_block(crypto_poly1305_ctx *ctx, const u8 in[16], unsigned end)
+static void poly_blocks(crypto_poly1305_ctx *ctx, const u8 *in,
+ size_t nb_blocks, unsigned end)
{
- u32 s[4];
- load32_le_buf(s, in, 4);
-
- //- PROOF Poly1305
- //-
- //- # Inputs & preconditions
- //- ctx->h[0] = u32()
- //- ctx->h[1] = u32()
- //- ctx->h[2] = u32()
- //- ctx->h[3] = u32()
- //- ctx->h[4] = u32(limit = 4)
- //-
- //- ctx->r[0] = u32(limit = 0x0fffffff)
- //- ctx->r[1] = u32(limit = 0x0ffffffc)
- //- ctx->r[2] = u32(limit = 0x0ffffffc)
- //- ctx->r[3] = u32(limit = 0x0ffffffc)
- //-
- //- s[0] = u32()
- //- s[1] = u32()
- //- s[2] = u32()
- //- s[3] = u32()
- //-
- //- end = unsigned(limit = 1)
-
- // s = h + c, without carry propagation
- const u64 s0 = ctx->h[0] + (u64)s[0]; // s0 <= 1_fffffffe
- const u64 s1 = ctx->h[1] + (u64)s[1]; // s1 <= 1_fffffffe
- const u64 s2 = ctx->h[2] + (u64)s[2]; // s2 <= 1_fffffffe
- const u64 s3 = ctx->h[3] + (u64)s[3]; // s3 <= 1_fffffffe
- const u32 s4 = ctx->h[4] + end; // s4 <= 5
-
// Local all the things!
- const u32 r0 = ctx->r[0]; // r0 <= 0fffffff
- const u32 r1 = ctx->r[1]; // r1 <= 0ffffffc
- const u32 r2 = ctx->r[2]; // r2 <= 0ffffffc
- const u32 r3 = ctx->r[3]; // r3 <= 0ffffffc
- const u32 rr0 = (r0 >> 2) * 5; // rr0 <= 13fffffb // lose 2 bits...
- const u32 rr1 = (r1 >> 2) + r1; // rr1 <= 13fffffb // rr1 == (r1 >> 2) * 5
- const u32 rr2 = (r2 >> 2) + r2; // rr2 <= 13fffffb // rr1 == (r2 >> 2) * 5
- const u32 rr3 = (r3 >> 2) + r3; // rr3 <= 13fffffb // rr1 == (r3 >> 2) * 5
+ const u32 r0 = ctx->r[0];
+ const u32 r1 = ctx->r[1];
+ const u32 r2 = ctx->r[2];
+ const u32 r3 = ctx->r[3];
+ const u32 rr0 = (r0 >> 2) * 5; // lose 2 bits...
+ const u32 rr1 = (r1 >> 2) + r1; // rr1 == (r1 >> 2) * 5
+ const u32 rr2 = (r2 >> 2) + r2; // rr1 == (r2 >> 2) * 5
+ const u32 rr3 = (r3 >> 2) + r3; // rr1 == (r3 >> 2) * 5
+ const u32 rr4 = r0 & 3; // ...recover 2 bits
+ u32 h0 = ctx->h[0];
+ u32 h1 = ctx->h[1];
+ u32 h2 = ctx->h[2];
+ u32 h3 = ctx->h[3];
+ u32 h4 = ctx->h[4];
- // (h + c) * r, without carry propagation
- const u64 x0 = s0*r0+ s1*rr3+ s2*rr2+ s3*rr1+ s4*rr0; // <= 97ffffe007fffff8
- const u64 x1 = s0*r1+ s1*r0 + s2*rr3+ s3*rr2+ s4*rr1; // <= 8fffffe20ffffff6
- const u64 x2 = s0*r2+ s1*r1 + s2*r0 + s3*rr3+ s4*rr2; // <= 87ffffe417fffff4
- const u64 x3 = s0*r3+ s1*r2 + s2*r1 + s3*r0 + s4*rr3; // <= 7fffffe61ffffff2
- const u32 x4 = s4 * (r0 & 3); // ...recover 2 bits // <= f
+ FOR (i, 0, nb_blocks) {
+ // h + c, without carry propagation
+ const u64 s0 = (u64)h0 + load32_le(in); in += 4;
+ const u64 s1 = (u64)h1 + load32_le(in); in += 4;
+ const u64 s2 = (u64)h2 + load32_le(in); in += 4;
+ const u64 s3 = (u64)h3 + load32_le(in); in += 4;
+ const u32 s4 = h4 + end;
- // partial reduction modulo 2^130 - 5
- const u32 u5 = x4 + (x3 >> 32); // u5 <= 7ffffff5
- const u64 u0 = (u5 >> 2) * 5 + (x0 & 0xffffffff);
- const u64 u1 = (u0 >> 32) + (x1 & 0xffffffff) + (x0 >> 32);
- const u64 u2 = (u1 >> 32) + (x2 & 0xffffffff) + (x1 >> 32);
- const u64 u3 = (u2 >> 32) + (x3 & 0xffffffff) + (x2 >> 32);
- const u64 u4 = (u3 >> 32) + (u5 & 3);
+ // (h + c) * r, without carry propagation
+ const u64 x0 = s0*r0+ s1*rr3+ s2*rr2+ s3*rr1+ s4*rr0;
+ const u64 x1 = s0*r1+ s1*r0 + s2*rr3+ s3*rr2+ s4*rr1;
+ const u64 x2 = s0*r2+ s1*r1 + s2*r0 + s3*rr3+ s4*rr2;
+ const u64 x3 = s0*r3+ s1*r2 + s2*r1 + s3*r0 + s4*rr3;
+ const u32 x4 = s4*rr4;
- // Update the hash
- ctx->h[0] = u0 & 0xffffffff; // u0 <= 1_9ffffff0
- ctx->h[1] = u1 & 0xffffffff; // u1 <= 1_97ffffe0
- ctx->h[2] = u2 & 0xffffffff; // u2 <= 1_8fffffe2
- ctx->h[3] = u3 & 0xffffffff; // u3 <= 1_87ffffe4
- ctx->h[4] = u4 & 0xffffffff; // u4 <= 4
+ // partial reduction modulo 2^130 - 5
+ const u32 u5 = x4 + (x3 >> 32); // u5 <= 7ffffff5
+ const u64 u0 = (u5 >> 2) * 5 + (x0 & 0xffffffff);
+ const u64 u1 = (u0 >> 32) + (x1 & 0xffffffff) + (x0 >> 32);
+ const u64 u2 = (u1 >> 32) + (x2 & 0xffffffff) + (x1 >> 32);
+ const u64 u3 = (u2 >> 32) + (x3 & 0xffffffff) + (x2 >> 32);
+ const u32 u4 = (u3 >> 32) + (u5 & 3); // u4 <= 4
- //- # postconditions
- //- ASSERT(ctx->h[4].limit() <= 4)
- //- CQFD Poly1305
+ // Update the hash
+ h0 = u0 & 0xffffffff;
+ h1 = u1 & 0xffffffff;
+ h2 = u2 & 0xffffffff;
+ h3 = u3 & 0xffffffff;
+ h4 = u4;
+ }
+ ctx->h[0] = h0;
+ ctx->h[1] = h1;
+ ctx->h[2] = h2;
+ ctx->h[3] = h3;
+ ctx->h[4] = h4;
}
void crypto_poly1305_init(crypto_poly1305_ctx *ctx, const u8 key[32])
@@ -391,8 +377,13 @@ void crypto_poly1305_init(crypto_poly1305_ctx *ctx, const u8 key[32])
void crypto_poly1305_update(crypto_poly1305_ctx *ctx,
const u8 *message, size_t message_size)
{
+ // Avoid undefined NULL pointer increments with empty messages
+ if (message_size == 0) {
+ return;
+ }
+
// Align ourselves with block boundaries
- size_t aligned = MIN(align(ctx->c_idx, 16), message_size);
+ size_t aligned = MC_MIN(gap(ctx->c_idx, 16), message_size);
FOR (i, 0, aligned) {
ctx->c[ctx->c_idx] = *message;
ctx->c_idx++;
@@ -402,16 +393,14 @@ void crypto_poly1305_update(crypto_poly1305_ctx *ctx,
// If block is complete, process it
if (ctx->c_idx == 16) {
- poly_block(ctx, ctx->c, 1);
+ poly_blocks(ctx, ctx->c, 1, 1);
ctx->c_idx = 0;
}
// Process the message block by block
size_t nb_blocks = message_size >> 4;
- FOR (i, 0, nb_blocks) {
- poly_block(ctx, message, 1);
- message += 16;
- }
+ poly_blocks(ctx, message, nb_blocks, 1);
+ message += nb_blocks << 4;
message_size &= 15;
// remaining bytes (we never complete a block here)
@@ -429,7 +418,7 @@ void crypto_poly1305_final(crypto_poly1305_ctx *ctx, u8 mac[16])
if (ctx->c_idx != 0) {
ZERO(ctx->c + ctx->c_idx, 16 - ctx->c_idx);
ctx->c[ctx->c_idx] = 1;
- poly_block(ctx, ctx->c, 0);
+ poly_blocks(ctx, ctx->c, 1, 0);
}
// check if we should subtract 2^130-5 by performing the
@@ -576,7 +565,7 @@ void crypto_blake2b_update(crypto_blake2b_ctx *ctx,
// Align with word boundaries
if ((ctx->input_idx & 7) != 0) {
- size_t nb_bytes = MIN(align(ctx->input_idx, 8), message_size);
+ size_t nb_bytes = MC_MIN(gap(ctx->input_idx, 8), message_size);
size_t word = ctx->input_idx >> 3;
size_t byte = ctx->input_idx & 7;
FOR (i, 0, nb_bytes) {
@@ -589,7 +578,7 @@ void crypto_blake2b_update(crypto_blake2b_ctx *ctx,
// Align with block boundaries (faster than byte by byte)
if ((ctx->input_idx & 127) != 0) {
- size_t nb_words = MIN(align(ctx->input_idx, 128), message_size) >> 3;
+ size_t nb_words = MC_MIN(gap(ctx->input_idx, 128), message_size) >> 3;
load64_le_buf(ctx->input + (ctx->input_idx >> 3), message, nb_words);
ctx->input_idx += nb_words << 3;
message += nb_words << 3;
@@ -637,7 +626,7 @@ void crypto_blake2b_update(crypto_blake2b_ctx *ctx,
void crypto_blake2b_final(crypto_blake2b_ctx *ctx, u8 *hash)
{
blake2b_compress(ctx, 1); // compress the last block
- size_t hash_size = MIN(ctx->hash_size, 64);
+ size_t hash_size = MC_MIN(ctx->hash_size, 64);
size_t nb_words = hash_size >> 3;
store64_le_buf(hash, ctx->hash, nb_words);
FOR (i, nb_words << 3, hash_size) {
@@ -698,7 +687,7 @@ static void extended_hash(u8 *digest, u32 digest_size,
const u8 *input , u32 input_size)
{
crypto_blake2b_ctx ctx;
- crypto_blake2b_init (&ctx, MIN(digest_size, 64));
+ crypto_blake2b_init (&ctx, MC_MIN(digest_size, 64));
blake_update_32 (&ctx, digest_size);
crypto_blake2b_update(&ctx, input, input_size);
crypto_blake2b_final (&ctx, digest);
@@ -721,12 +710,12 @@ static void extended_hash(u8 *digest, u32 digest_size,
}
}
-#define LSB(x) ((x) & 0xffffffff)
+#define LSB(x) ((u64)(u32)x)
#define G(a, b, c, d) \
- a += b + 2 * LSB(a) * LSB(b); d ^= a; d = rotr64(d, 32); \
- c += d + 2 * LSB(c) * LSB(d); b ^= c; b = rotr64(b, 24); \
- a += b + 2 * LSB(a) * LSB(b); d ^= a; d = rotr64(d, 16); \
- c += d + 2 * LSB(c) * LSB(d); b ^= c; b = rotr64(b, 63)
+ a += b + ((LSB(a) * LSB(b)) << 1); d ^= a; d = rotr64(d, 32); \
+ c += d + ((LSB(c) * LSB(d)) << 1); b ^= c; b = rotr64(b, 24); \
+ a += b + ((LSB(a) * LSB(b)) << 1); d ^= a; d = rotr64(d, 16); \
+ c += d + ((LSB(c) * LSB(d)) << 1); b ^= c; b = rotr64(b, 63)
#define ROUND(v0, v1, v2, v3, v4, v5, v6, v7, \
v8, v9, v10, v11, v12, v13, v14, v15) \
G(v0, v4, v8, v12); G(v1, v5, v9, v13); \
@@ -874,16 +863,22 @@ void crypto_argon2(u8 *hash, u32 hash_size, void *work_area,
u32 next_slice = ((slice + 1) % 4) * segment_size;
u32 window_start = pass == 0 ? 0 : next_slice;
u32 nb_segments = pass == 0 ? slice : 3;
- u32 window_size = nb_segments * segment_size + block - 1;
+ u64 lane =
+ pass == 0 && slice == 0
+ ? segment
+ : (index_seed >> 32) % config.nb_lanes;
+ u32 window_size =
+ nb_segments * segment_size +
+ (lane == segment ? block-1 :
+ block == 0 ? (u32)-1 : 0);
// Find reference block
u64 j1 = index_seed & 0xffffffff; // block selector
- u64 j2 = index_seed >> 32; // lane selector
u64 x = (j1 * j1) >> 32;
u64 y = (window_size * x) >> 32;
u64 z = (window_size - 1) - y;
u64 ref = (window_start + z) % lane_size;
- u32 index = (j2%config.nb_lanes)*lane_size + (u32)ref;
+ u32 index = lane * lane_size + (u32)ref;
blk *reference = blocks + index;
// Shuffle the previous & reference block
@@ -1244,25 +1239,25 @@ static void fe_mul(fe h, const fe f, const fe g)
// |G1|, |G3|, |G5|, |G7|, |G9| < 2^30
i64 t0 = f0*(i64)g0 + F1*(i64)G9 + f2*(i64)G8 + F3*(i64)G7 + f4*(i64)G6
- + F5*(i64)G5 + f6*(i64)G4 + F7*(i64)G3 + f8*(i64)G2 + F9*(i64)G1;
+ + F5*(i64)G5 + f6*(i64)G4 + F7*(i64)G3 + f8*(i64)G2 + F9*(i64)G1;
i64 t1 = f0*(i64)g1 + f1*(i64)g0 + f2*(i64)G9 + f3*(i64)G8 + f4*(i64)G7
- + f5*(i64)G6 + f6*(i64)G5 + f7*(i64)G4 + f8*(i64)G3 + f9*(i64)G2;
+ + f5*(i64)G6 + f6*(i64)G5 + f7*(i64)G4 + f8*(i64)G3 + f9*(i64)G2;
i64 t2 = f0*(i64)g2 + F1*(i64)g1 + f2*(i64)g0 + F3*(i64)G9 + f4*(i64)G8
- + F5*(i64)G7 + f6*(i64)G6 + F7*(i64)G5 + f8*(i64)G4 + F9*(i64)G3;
+ + F5*(i64)G7 + f6*(i64)G6 + F7*(i64)G5 + f8*(i64)G4 + F9*(i64)G3;
i64 t3 = f0*(i64)g3 + f1*(i64)g2 + f2*(i64)g1 + f3*(i64)g0 + f4*(i64)G9
- + f5*(i64)G8 + f6*(i64)G7 + f7*(i64)G6 + f8*(i64)G5 + f9*(i64)G4;
+ + f5*(i64)G8 + f6*(i64)G7 + f7*(i64)G6 + f8*(i64)G5 + f9*(i64)G4;
i64 t4 = f0*(i64)g4 + F1*(i64)g3 + f2*(i64)g2 + F3*(i64)g1 + f4*(i64)g0
- + F5*(i64)G9 + f6*(i64)G8 + F7*(i64)G7 + f8*(i64)G6 + F9*(i64)G5;
+ + F5*(i64)G9 + f6*(i64)G8 + F7*(i64)G7 + f8*(i64)G6 + F9*(i64)G5;
i64 t5 = f0*(i64)g5 + f1*(i64)g4 + f2*(i64)g3 + f3*(i64)g2 + f4*(i64)g1
- + f5*(i64)g0 + f6*(i64)G9 + f7*(i64)G8 + f8*(i64)G7 + f9*(i64)G6;
+ + f5*(i64)g0 + f6*(i64)G9 + f7*(i64)G8 + f8*(i64)G7 + f9*(i64)G6;
i64 t6 = f0*(i64)g6 + F1*(i64)g5 + f2*(i64)g4 + F3*(i64)g3 + f4*(i64)g2
- + F5*(i64)g1 + f6*(i64)g0 + F7*(i64)G9 + f8*(i64)G8 + F9*(i64)G7;
+ + F5*(i64)g1 + f6*(i64)g0 + F7*(i64)G9 + f8*(i64)G8 + F9*(i64)G7;
i64 t7 = f0*(i64)g7 + f1*(i64)g6 + f2*(i64)g5 + f3*(i64)g4 + f4*(i64)g3
- + f5*(i64)g2 + f6*(i64)g1 + f7*(i64)g0 + f8*(i64)G9 + f9*(i64)G8;
+ + f5*(i64)g2 + f6*(i64)g1 + f7*(i64)g0 + f8*(i64)G9 + f9*(i64)G8;
i64 t8 = f0*(i64)g8 + F1*(i64)g7 + f2*(i64)g6 + F3*(i64)g5 + f4*(i64)g4
- + F5*(i64)g3 + f6*(i64)g2 + F7*(i64)g1 + f8*(i64)g0 + F9*(i64)G9;
+ + F5*(i64)g3 + f6*(i64)g2 + F7*(i64)g1 + f8*(i64)g0 + F9*(i64)G9;
i64 t9 = f0*(i64)g9 + f1*(i64)g8 + f2*(i64)g7 + f3*(i64)g6 + f4*(i64)g5
- + f5*(i64)g4 + f6*(i64)g3 + f7*(i64)g2 + f8*(i64)g1 + f9*(i64)g0;
+ + f5*(i64)g4 + f6*(i64)g3 + f7*(i64)g2 + f8*(i64)g1 + f9*(i64)g0;
// t0 < 0.67 * 2^61
// t1 < 0.41 * 2^61
// t2 < 0.52 * 2^61
@@ -1296,25 +1291,25 @@ static void fe_sq(fe h, const fe f)
// |f5_38|, |f6_19|, |f7_38|, |f8_19|, |f9_38| < 2^31
i64 t0 = f0 *(i64)f0 + f1_2*(i64)f9_38 + f2_2*(i64)f8_19
- + f3_2*(i64)f7_38 + f4_2*(i64)f6_19 + f5 *(i64)f5_38;
+ + f3_2*(i64)f7_38 + f4_2*(i64)f6_19 + f5 *(i64)f5_38;
i64 t1 = f0_2*(i64)f1 + f2 *(i64)f9_38 + f3_2*(i64)f8_19
- + f4 *(i64)f7_38 + f5_2*(i64)f6_19;
+ + f4 *(i64)f7_38 + f5_2*(i64)f6_19;
i64 t2 = f0_2*(i64)f2 + f1_2*(i64)f1 + f3_2*(i64)f9_38
- + f4_2*(i64)f8_19 + f5_2*(i64)f7_38 + f6 *(i64)f6_19;
+ + f4_2*(i64)f8_19 + f5_2*(i64)f7_38 + f6 *(i64)f6_19;
i64 t3 = f0_2*(i64)f3 + f1_2*(i64)f2 + f4 *(i64)f9_38
- + f5_2*(i64)f8_19 + f6 *(i64)f7_38;
+ + f5_2*(i64)f8_19 + f6 *(i64)f7_38;
i64 t4 = f0_2*(i64)f4 + f1_2*(i64)f3_2 + f2 *(i64)f2
- + f5_2*(i64)f9_38 + f6_2*(i64)f8_19 + f7 *(i64)f7_38;
+ + f5_2*(i64)f9_38 + f6_2*(i64)f8_19 + f7 *(i64)f7_38;
i64 t5 = f0_2*(i64)f5 + f1_2*(i64)f4 + f2_2*(i64)f3
- + f6 *(i64)f9_38 + f7_2*(i64)f8_19;
+ + f6 *(i64)f9_38 + f7_2*(i64)f8_19;
i64 t6 = f0_2*(i64)f6 + f1_2*(i64)f5_2 + f2_2*(i64)f4
- + f3_2*(i64)f3 + f7_2*(i64)f9_38 + f8 *(i64)f8_19;
+ + f3_2*(i64)f3 + f7_2*(i64)f9_38 + f8 *(i64)f8_19;
i64 t7 = f0_2*(i64)f7 + f1_2*(i64)f6 + f2_2*(i64)f5
- + f3_2*(i64)f4 + f8 *(i64)f9_38;
+ + f3_2*(i64)f4 + f8 *(i64)f9_38;
i64 t8 = f0_2*(i64)f8 + f1_2*(i64)f7_2 + f2_2*(i64)f6
- + f3_2*(i64)f5_2 + f4 *(i64)f4 + f9 *(i64)f9_38;
+ + f3_2*(i64)f5_2 + f4 *(i64)f4 + f9 *(i64)f9_38;
i64 t9 = f0_2*(i64)f9 + f1_2*(i64)f8 + f2_2*(i64)f7
- + f3_2*(i64)f6 + f4 *(i64)f5_2;
+ + f3_2*(i64)f6 + f4 *(i64)f5_2;
// t0 < 0.67 * 2^61
// t1 < 0.41 * 2^61
// t2 < 0.52 * 2^61
@@ -1417,17 +1412,17 @@ static int invsqrt(fe isr, const fe x)
// Can be achieved with a simple double & add ladder,
// but it would be slower.
fe_sq(t0, x);
- fe_sq(t1,t0); fe_sq(t1, t1); fe_mul(t1, x, t1);
+ fe_sq(t1,t0); fe_sq(t1, t1); fe_mul(t1, x, t1);
fe_mul(t0, t0, t1);
- fe_sq(t0, t0); fe_mul(t0, t1, t0);
- fe_sq(t1, t0); FOR (i, 1, 5) fe_sq(t1, t1); fe_mul(t0, t1, t0);
- fe_sq(t1, t0); FOR (i, 1, 10) fe_sq(t1, t1); fe_mul(t1, t1, t0);
- fe_sq(t2, t1); FOR (i, 1, 20) fe_sq(t2, t2); fe_mul(t1, t2, t1);
- fe_sq(t1, t1); FOR (i, 1, 10) fe_sq(t1, t1); fe_mul(t0, t1, t0);
- fe_sq(t1, t0); FOR (i, 1, 50) fe_sq(t1, t1); fe_mul(t1, t1, t0);
- fe_sq(t2, t1); FOR (i, 1, 100) fe_sq(t2, t2); fe_mul(t1, t2, t1);
- fe_sq(t1, t1); FOR (i, 1, 50) fe_sq(t1, t1); fe_mul(t0, t1, t0);
- fe_sq(t0, t0); FOR (i, 1, 2) fe_sq(t0, t0); fe_mul(t0, t0, x);
+ fe_sq(t0, t0); fe_mul(t0, t1, t0);
+ fe_sq(t1, t0); FOR (i, 1, 5) { fe_sq(t1, t1); } fe_mul(t0, t1, t0);
+ fe_sq(t1, t0); FOR (i, 1, 10) { fe_sq(t1, t1); } fe_mul(t1, t1, t0);
+ fe_sq(t2, t1); FOR (i, 1, 20) { fe_sq(t2, t2); } fe_mul(t1, t2, t1);
+ fe_sq(t1, t1); FOR (i, 1, 10) { fe_sq(t1, t1); } fe_mul(t0, t1, t0);
+ fe_sq(t1, t0); FOR (i, 1, 50) { fe_sq(t1, t1); } fe_mul(t1, t1, t0);
+ fe_sq(t2, t1); FOR (i, 1, 100) { fe_sq(t2, t2); } fe_mul(t1, t2, t1);
+ fe_sq(t1, t1); FOR (i, 1, 50) { fe_sq(t1, t1); } fe_mul(t0, t1, t0);
+ fe_sq(t0, t0); FOR (i, 1, 2) { fe_sq(t0, t0); } fe_mul(t0, t0, x);
// quartic = x^((p-1)/4)
i32 *quartic = t1;
@@ -1947,7 +1942,7 @@ static int slide_step(slide_ctx *ctx, int width, int i, const u8 scalar[32])
ctx->next_check--;
} else {
// compute digit of next window
- int w = MIN(width, i + 1);
+ int w = MC_MIN(width, i + 1);
int v = -(scalar_bit(scalar, i) << (w-1));
FOR_T (int, j, 0, w-1) {
v += scalar_bit(scalar, i-(w-1)+j) << j;
@@ -2006,7 +2001,7 @@ int crypto_eddsa_check_equation(const u8 signature[64], const u8 public_key[32],
// Merged double and add ladder, fused with sliding
slide_ctx h_slide; slide_init(&h_slide, h);
slide_ctx s_slide; slide_init(&s_slide, s);
- int i = MAX(h_slide.next_check, s_slide.next_check);
+ int i = MC_MAX(h_slide.next_check, s_slide.next_check);
ge *sum = &minus_A; // reuse minus_A for the sum
ge_zero(sum);
while (i >= 0) {
@@ -2870,9 +2865,9 @@ static void lock_auth(u8 mac[16], const u8 auth_key[32],
crypto_poly1305_ctx poly_ctx; // auto wiped...
crypto_poly1305_init (&poly_ctx, auth_key);
crypto_poly1305_update(&poly_ctx, ad , ad_size);
- crypto_poly1305_update(&poly_ctx, zero , align(ad_size, 16));
+ crypto_poly1305_update(&poly_ctx, zero , gap(ad_size, 16));
crypto_poly1305_update(&poly_ctx, cipher_text, text_size);
- crypto_poly1305_update(&poly_ctx, zero , align(text_size, 16));
+ crypto_poly1305_update(&poly_ctx, zero , gap(text_size, 16));
crypto_poly1305_update(&poly_ctx, sizes , 16);
crypto_poly1305_final (&poly_ctx, mac); // ...here
}
diff --git a/src/3rdparty/monocypher/monocypher.h b/src/3rdparty/monocypher/monocypher.h
index 8f466e318f..765a07ff3f 100644
--- a/src/3rdparty/monocypher/monocypher.h
+++ b/src/3rdparty/monocypher/monocypher.h
@@ -1,4 +1,4 @@
-// Monocypher version 4.0.1
+// Monocypher version 4.0.2
//
// This file is dual-licensed. Choose whichever licence you want from
// the two licences listed below.
diff --git a/src/core/random_func.cpp b/src/core/random_func.cpp
index e26713890d..4f898333bd 100644
--- a/src/core/random_func.cpp
+++ b/src/core/random_func.cpp
@@ -10,6 +10,8 @@
#include "../stdafx.h"
#include "random_func.hpp"
#include "bitmath_func.hpp"
+#include "../debug.h"
+#include
#include
#ifdef RANDOM_DEBUG
@@ -21,6 +23,17 @@
#include "../date_func.h"
#endif /* RANDOM_DEBUG */
+#if defined(_WIN32)
+# include
+# include
+#elif defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__)
+// No includes required.
+#elif defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 25)))
+# include
+#elif defined(__EMSCRIPTEN__)
+# include
+#endif
+
#include "../safeguards.h"
Randomizer _random, _interactive_random;
@@ -84,3 +97,53 @@ uint32_t DoRandomRange(uint32_t limit, int line, const char *file)
return ((uint64_t)DoRandom(line, file) * (uint64_t)limit) >> 32;
}
#endif /* RANDOM_DEBUG */
+
+/**
+ * Fill the given buffer with random bytes.
+ *
+ * This function will attempt to use a cryptographically-strong random
+ * generator, but will fall back to a weaker random generator if none is
+ * available.
+ *
+ * In the end, the buffer will always be filled with some form of random
+ * bytes when this function returns.
+ *
+ * @param buf The buffer to fill with random bytes.
+ */
+void RandomBytesWithFallback(std::span buf)
+{
+#if defined(_WIN32)
+ auto res = BCryptGenRandom(nullptr, static_cast(buf.data()), static_cast(buf.size()), BCRYPT_USE_SYSTEM_PREFERRED_RNG);
+ if (res >= 0) return;
+#elif defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__)
+ arc4random_buf(buf.data(), buf.size());
+ return;
+#elif defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 25)))
+ auto res = getrandom(buf.data(), buf.size(), 0);
+ if (res > 0 && static_cast(res) == buf.size()) return;
+#elif defined(__EMSCRIPTEN__)
+ auto res = EM_ASM_INT({
+ var buf = $0;
+ var bytes = $1;
+
+ var crypto = window.crypto;
+ if (crypto === undefined || crypto.getRandomValues === undefined) {
+ return -1;
+ }
+
+ crypto.getRandomValues(Module.HEAPU8.subarray(buf, buf + bytes));
+ return 1;
+ }, buf.data(), buf.size());
+ if (res > 0) return;
+#else
+# warning "No cryptographically-strong random generator available; using a fallback instead"
+#endif
+
+ static std::atomic warned_once = false;
+ bool have_warned = warned_once.exchange(true);
+ DEBUG(misc, have_warned ? 1 : 0, "Cryptographically-strong random generator unavailable; using fallback");
+
+ for (uint i = 0; i < buf.size(); i++) {
+ buf[i] = static_cast(InteractiveRandom());
+ }
+}
diff --git a/src/core/random_func.hpp b/src/core/random_func.hpp
index 03c01913d0..5e8c1d939e 100644
--- a/src/core/random_func.hpp
+++ b/src/core/random_func.hpp
@@ -177,4 +177,6 @@ inline bool Chance16R(const uint a, const uint b, uint32_t &r)
}
#endif /* RANDOM_DEBUG */
+void RandomBytesWithFallback(std::span buf);
+
#endif /* RANDOM_FUNC_HPP */
diff --git a/src/misc.cpp b/src/misc.cpp
index f73dc92c95..ca38c6f10c 100644
--- a/src/misc.cpp
+++ b/src/misc.cpp
@@ -42,6 +42,7 @@
#include "event_logs.h"
#include "string_func.h"
#include "plans_func.h"
+#include "core/format.hpp"
#include "3rdparty/monocypher/monocypher.h"
#include "safeguards.h"
@@ -75,23 +76,27 @@ void InitializeOldNames();
/**
* Generate a unique ID.
+ *
+ * It isn't as much of an unique ID but more a hashed digest of a random
+ * string and a time. It is very likely to be unique, but it does not follow
+ * any UUID standard.
*/
std::string GenerateUid(std::string_view subject)
{
- extern void NetworkRandomBytesWithFallback(void *buf, size_t n);
+ std::array random_bytes;
+ RandomBytesWithFallback(random_bytes);
- uint8_t random_bytes[32];
- NetworkRandomBytesWithFallback(random_bytes, lengthof(random_bytes));
-
- uint8_t digest[16];
+ auto current_time = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count();
+ std::string coding_string = fmt::format("{}{}", current_time, subject);
+ std::array digest;
crypto_blake2b_ctx ctx;
- crypto_blake2b_init (&ctx, lengthof(digest));
- crypto_blake2b_update(&ctx, random_bytes, lengthof(random_bytes));
- crypto_blake2b_update(&ctx, (const byte *)subject.data(), subject.size());
- crypto_blake2b_final (&ctx, digest);
+ crypto_blake2b_init(&ctx, digest.size());
+ crypto_blake2b_update(&ctx, random_bytes.data(), random_bytes.size());
+ crypto_blake2b_update(&ctx, reinterpret_cast(coding_string.data()), coding_string.size());
+ crypto_blake2b_final(&ctx, digest.data());
- return FormatArrayAsHex({digest, lengthof(digest)});
+ return FormatArrayAsHex(digest);
}
/**