aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkoe <ukoe@protonmail.com>2022-12-01 17:32:40 -0600
committerkoe <ukoe@protonmail.com>2023-06-28 09:52:27 -0500
commit16d17f67072aee08ea787b0877db67a89d6db811 (patch)
tree5e2c76da1750e10dff37e6b22d985024195ff0cc
parentMerge pull request #8884 (diff)
downloadmonero-16d17f67072aee08ea787b0877db67a89d6db811.tar.xz
add crypto/generators for direct access to canonical fixed generators
-rw-r--r--src/crypto/CMakeLists.txt1
-rw-r--r--src/crypto/generators.cpp186
-rw-r--r--src/crypto/generators.h47
-rw-r--r--tests/unit_tests/crypto.cpp24
4 files changed, 258 insertions, 0 deletions
diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt
index e17584c90..5dfc121ce 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
+ generators.cpp
groestl.c
hash-extra-blake.c
hash-extra-groestl.c
diff --git a/src/crypto/generators.cpp b/src/crypto/generators.cpp
new file mode 100644
index 000000000..a4539f473
--- /dev/null
+++ b/src/crypto/generators.cpp
@@ -0,0 +1,186 @@
+// Copyright (c) 2022, 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 "generators.h"
+
+#include "crypto.h"
+extern "C"
+{
+#include "crypto-ops.h"
+}
+#include "hash.h"
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <mutex>
+
+namespace crypto
+{
+
+/// constexpr assert for old gcc bug: https://stackoverflow.com/questions/34280729/throw-in-constexpr-function
+/// - this function won't compile in a constexpr context if b == false
+constexpr void constexpr_assert(const bool b) { b ? 0 : throw std::runtime_error("constexpr assert failed"); };
+
+/// constexpr paste bytes into an array-of-bytes type
+template<typename T>
+constexpr T bytes_to(const std::initializer_list<unsigned char> bytes)
+{
+ T out{}; // zero-initialize trailing bytes
+
+ auto current = std::begin(out.data);
+ constexpr_assert(static_cast<long>(bytes.size()) <= std::end(out.data) - current);
+
+ for (const unsigned char byte : bytes)
+ *current++ = byte;
+ return out;
+}
+
+// generators
+//standard ed25519 generator G: {x, 4/5} (positive x when decompressing y = 4/5)
+constexpr public_key G = bytes_to<public_key>({ 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 });
+//pedersen commitment generator H: toPoint(cn_fast_hash(G))
+constexpr public_key H = bytes_to<public_key>({ 0x8b, 0x65, 0x59, 0x70, 0x15, 0x37, 0x99, 0xaf, 0x2a, 0xea, 0xdc, 0x9f, 0xf1,
+ 0xad, 0xd0, 0xea, 0x6c, 0x72, 0x51, 0xd5, 0x41, 0x54, 0xcf, 0xa9, 0x2c, 0x17, 0x3a, 0x0d, 0xd3, 0x9c, 0x1f, 0x94 });
+static ge_p3 G_p3;
+static ge_p3 H_p3;
+static ge_cached G_cached;
+static ge_cached H_cached;
+
+// misc
+static std::once_flag init_gens_once_flag;
+
+//-------------------------------------------------------------------------------------------------------------------
+//-------------------------------------------------------------------------------------------------------------------
+static public_key reproduce_generator_G()
+{
+ // G = {x, 4/5 mod q}
+ fe four, five, inv_five, y;
+ fe_0(four);
+ fe_0(five);
+ four[0] = 4;
+ five[0] = 5;
+ fe_invert(inv_five, five);
+ fe_mul(y, four, inv_five);
+
+ public_key reproduced_G;
+ fe_tobytes(to_bytes(reproduced_G), y);
+
+ return reproduced_G;
+}
+//-------------------------------------------------------------------------------------------------------------------
+//-------------------------------------------------------------------------------------------------------------------
+static public_key reproduce_generator_H()
+{
+ // H = 8*to_point(keccak(G))
+ // note: this does not use the point_from_bytes() function found in H_p(), instead directly interpreting the
+ // input bytes as a compressed point (this can fail, so should not be used generically)
+ // note2: to_point(keccak(G)) is known to succeed for the canonical value of G (it will fail 7/8ths of the time
+ // normally)
+ ge_p3 temp_p3;
+ ge_p2 temp_p2;
+ ge_p1p1 temp_p1p1;
+
+ hash H_temp_hash{cn_fast_hash(to_bytes(G), sizeof(ec_point))};
+ (void)H_temp_hash; //suppress unused warning
+ assert(ge_frombytes_vartime(&temp_p3, reinterpret_cast<const unsigned char*>(&H_temp_hash)) == 0);
+ ge_p3_to_p2(&temp_p2, &temp_p3);
+ ge_mul8(&temp_p1p1, &temp_p2);
+ ge_p1p1_to_p3(&temp_p3, &temp_p1p1);
+
+ public_key reproduced_H;
+ ge_p3_tobytes(to_bytes(reproduced_H), &temp_p3);
+
+ return reproduced_H;
+}
+//-------------------------------------------------------------------------------------------------------------------
+// Make generators, but only once
+//-------------------------------------------------------------------------------------------------------------------
+static void init_gens()
+{
+ std::call_once(init_gens_once_flag,
+ [&](){
+
+ // sanity check the generators
+ static_assert(static_cast<unsigned char>(G.data[0]) == 0x58, "compile-time constant sanity check");
+ static_assert(static_cast<unsigned char>(H.data[0]) == 0x8b, "compile-time constant sanity check");
+
+ // build ge_p3 representations of generators
+ const int G_deserialize = ge_frombytes_vartime(&G_p3, to_bytes(G));
+ const int H_deserialize = ge_frombytes_vartime(&H_p3, to_bytes(H));
+
+ (void)G_deserialize; assert(G_deserialize == 0);
+ (void)H_deserialize; assert(H_deserialize == 0);
+
+ // get cached versions
+ ge_p3_to_cached(&G_cached, &G_p3);
+ ge_p3_to_cached(&H_cached, &H_p3);
+
+ // in debug mode, check that generators are reproducible
+ (void)reproduce_generator_G; assert(reproduce_generator_G() == G);
+ (void)reproduce_generator_H; assert(reproduce_generator_H() == H);
+
+ });
+}
+//-------------------------------------------------------------------------------------------------------------------
+public_key get_G()
+{
+ return G;
+}
+//-------------------------------------------------------------------------------------------------------------------
+public_key get_H()
+{
+ return H;
+}
+//-------------------------------------------------------------------------------------------------------------------
+ge_p3 get_G_p3()
+{
+ init_gens();
+ return G_p3;
+}
+//-------------------------------------------------------------------------------------------------------------------
+ge_p3 get_H_p3()
+{
+ init_gens();
+ return H_p3;
+}
+//-------------------------------------------------------------------------------------------------------------------
+ge_cached get_G_cached()
+{
+ init_gens();
+ return G_cached;
+}
+//-------------------------------------------------------------------------------------------------------------------
+ge_cached get_H_cached()
+{
+ init_gens();
+ return H_cached;
+}
+//-------------------------------------------------------------------------------------------------------------------
+} //namespace crypto
diff --git a/src/crypto/generators.h b/src/crypto/generators.h
new file mode 100644
index 000000000..797336203
--- /dev/null
+++ b/src/crypto/generators.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2022, 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.
+
+#pragma once
+
+extern "C"
+{
+#include "crypto-ops.h"
+}
+#include "crypto.h"
+
+namespace crypto
+{
+
+public_key get_G();
+public_key get_H();
+ge_p3 get_G_p3();
+ge_p3 get_H_p3();
+ge_cached get_G_cached();
+ge_cached get_H_cached();
+
+} //namespace crypto
diff --git a/tests/unit_tests/crypto.cpp b/tests/unit_tests/crypto.cpp
index 4cac0b89f..e41f3955f 100644
--- a/tests/unit_tests/crypto.cpp
+++ b/tests/unit_tests/crypto.cpp
@@ -32,8 +32,15 @@
#include <sstream>
#include <string>
+extern "C"
+{
+#include "crypto/crypto-ops.h"
+}
+#include "crypto/generators.h"
#include "cryptonote_basic/cryptonote_basic_impl.h"
#include "cryptonote_basic/merge_mining.h"
+#include "ringct/rctOps.h"
+#include "ringct/rctTypes.h"
namespace
{
@@ -312,3 +319,20 @@ TEST(Crypto, tree_branch)
}
}
}
+
+TEST(Crypto, generator_consistency)
+{
+ // crypto/generators.h
+ const crypto::public_key G{crypto::get_G()};
+ const crypto::public_key H{crypto::get_H()};
+ const ge_p3 H_p3 = crypto::get_H_p3();
+
+ // crypto/crypto-ops.h
+ ASSERT_TRUE(memcmp(&H_p3, &ge_p3_H, sizeof(ge_p3)) == 0);
+
+ // ringct/rctOps.h
+ ASSERT_TRUE(memcmp(G.data, rct::G.bytes, 32) == 0);
+
+ // ringct/rctTypes.h
+ ASSERT_TRUE(memcmp(H.data, rct::H.bytes, 32) == 0);
+}