dilithium

This commit is contained in:
Denis Angell
2025-05-27 22:56:10 +02:00
parent a5ea86fdfc
commit ef800d7038
18 changed files with 24587 additions and 22 deletions

View File

@@ -153,6 +153,7 @@ target_link_libraries (xrpl_core
Ripple::syslibs
secp256k1::secp256k1
ed25519::ed25519
NIH::dilithium2_ref
date::date
Ripple::opts)
#[=================================[

View File

@@ -0,0 +1,84 @@
include(FetchContent)
ExternalProject_Add(
dilithium_src
PREFIX ${nih_cache_path}
GIT_REPOSITORY https://github.com/pq-crystals/dilithium.git
GIT_TAG v3.1
CMAKE_ARGS
-DDILITHIUM_MODE=2
-DDILITHIUM_RANDOMIZED_SIGNING=ON
-DDILITHIUM_USE_AES=ON
LOG_BUILD ON
LOG_CONFIGURE ON
COMMAND
pwd
BUILD_COMMAND
${CMAKE_COMMAND}
--build .
--config $<CONFIG>
$<$<VERSION_GREATER_EQUAL:${CMAKE_VERSION},3.12>:--parallel ${ep_procs}>
INSTALL_COMMAND ""
BUILD_BYPRODUCTS
<BINARY_DIR>/ref/libdilithium2_ref.a
<BINARY_DIR>/ref/libdilithium2aes_ref.a
<BINARY_DIR>/ref/libfips202_ref.a
)
ExternalProject_Get_Property(dilithium_src BINARY_DIR)
ExternalProject_Get_Property(dilithium_src SOURCE_DIR)
set(dilithium_src_SOURCE_DIR "${SOURCE_DIR}")
set(dilithium_src_BINARY_DIR "${BINARY_DIR}")
# Check if the api.h file exists
include_directories("${dilithium_src_SOURCE_DIR}/ref")
# Create imported targets for each static library
add_library(dilithium::dilithium2_ref STATIC IMPORTED GLOBAL)
set_target_properties(dilithium::dilithium2_ref PROPERTIES
IMPORTED_LOCATION "${dilithium_src_BINARY_DIR}/ref/libdilithium2_ref.a"
INTERFACE_INCLUDE_DIRECTORIES "${dilithium_src_SOURCE_DIR}/ref/"
)
add_library(dilithium::dilithium2aes_ref STATIC IMPORTED GLOBAL)
set_target_properties(dilithium::dilithium2aes_ref PROPERTIES
IMPORTED_LOCATION "${dilithium_src_BINARY_DIR}/ref/libdilithium2aes_ref.a"
INTERFACE_INCLUDE_DIRECTORIES "${dilithium_src_SOURCE_DIR}/ref/"
)
add_library(dilithium::libfips202_ref STATIC IMPORTED GLOBAL)
set_target_properties(dilithium::libfips202_ref PROPERTIES
IMPORTED_LOCATION "${dilithium_src_BINARY_DIR}/ref/libfips202_ref.a"
INTERFACE_INCLUDE_DIRECTORIES "${dilithium_src_SOURCE_DIR}/ref/"
)
add_dependencies(dilithium::dilithium2_ref dilithium_src)
add_dependencies(dilithium::dilithium2aes_ref dilithium_src)
add_dependencies(dilithium::libfips202_ref dilithium_src)
# Add a custom command to generate randombytes.c
add_custom_command(
OUTPUT "${dilithium_src_BINARY_DIR}/ref/randombytes.c"
COMMAND ${CMAKE_COMMAND} -E copy "${dilithium_src_SOURCE_DIR}/ref/randombytes.c" "${dilithium_src_BINARY_DIR}/ref/randombytes.c"
DEPENDS dilithium_src
)
# Add the randombytes_ref library
add_library(randombytes_ref STATIC "${dilithium_src_BINARY_DIR}/ref/randombytes.c")
# Include the Dilithium ref directory for headers
target_include_directories(randombytes_ref PUBLIC "${dilithium_src_SOURCE_DIR}/ref")
# Ensure that randombytes_ref depends on the Dilithium source so it's built after
add_dependencies(randombytes_ref dilithium_src)
# Create an interface library that links to both
target_link_libraries(ripple_libs INTERFACE
randombytes_ref
dilithium::dilithium2_ref
dilithium::dilithium2aes_ref
dilithium::libfips202_ref
)
# Link the Dilithium library to your target
add_library(NIH::dilithium2_ref ALIAS dilithium::dilithium2_ref)

View File

@@ -81,6 +81,7 @@ endif ()
include(RippledCompiler)
include(RippledInterface)
include(deps/dilithium)
###
if (NOT USE_CONAN)
add_subdirectory(src/secp256k1)

View File

@@ -587,6 +587,23 @@ SetAccount::doApply()
}
}
//
// QuantumSignature
//
if (ctx_.view().rules().enabled(featureQuantumSigning))
{
if (uSetFlag == asfForceQuantum)
{
JLOG(j_.trace()) << "Set lsfForceQuantum.";
uFlagsOut |= lsfForceQuantum;
}
else if (uClearFlag == asfForceQuantum)
{
JLOG(j_.trace()) << "Clear lsfForceQuantum.";
uFlagsOut &= ~lsfForceQuantum;
}
}
if (uFlagsIn != uFlagsOut)
sle->setFieldU32(sfFlags, uFlagsOut);

View File

@@ -40,6 +40,13 @@
#include <ripple/protocol/UintTypes.h>
#include <limits>
#include <set>
extern "C" {
#include "api.h"
}
#ifndef DILITHIUM_PK_SIZE
#define DILITHIUM_PK_SIZE pqcrystals_dilithium2_PUBLICKEYBYTES
#endif
namespace ripple {
@@ -857,13 +864,18 @@ Transactor::checkSingleSign(PreclaimContext const& ctx)
}
// Look up the account.
auto const idSigner = calcAccountID(PublicKey(makeSlice(pkSigner)));
PublicKey pubKey = PublicKey(makeSlice(pkSigner));
auto const idSigner = calcAccountID(pubKey);
auto const idAccount = ctx.tx.getAccountID(sfAccount);
auto const sleAccount = ctx.view.read(keylet::account(idAccount));
if (!sleAccount)
return terNO_ACCOUNT;
if (ctx.view.rules().enabled(featureQuantumSigning) &&
sleAccount->isFlag(lsfForceQuantum) && pubKey.size() != DILITHIUM_PK_SIZE)
return telBAD_PUBLIC_KEY;
bool const isMasterDisabled = sleAccount->isFlag(lsfDisableMaster);
if (ctx.view.rules().enabled(fixMasterKeyAsRegularKey))

View File

@@ -74,7 +74,7 @@ namespace detail {
// Feature.cpp. Because it's only used to reserve storage, and determine how
// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
// the actual number of amendments. A LogicError on startup will verify this.
static constexpr std::size_t numFeatures = 81;
static constexpr std::size_t numFeatures = 82;
/** Amendments that this server supports and the default voting behavior.
Whether they are enabled depends on the Rules defined in the validated
@@ -369,6 +369,7 @@ extern uint256 const fixXahauV3;
extern uint256 const fix20250131;
extern uint256 const featureHookCanEmit;
extern uint256 const fixRewardClaimFlags;
extern uint256 const featureQuantumSigning;
} // namespace ripple

View File

@@ -28,6 +28,7 @@ namespace ripple {
enum class KeyType {
secp256k1 = 0,
ed25519 = 1,
dilithium = 2,
};
inline std::optional<KeyType>
@@ -39,6 +40,9 @@ keyTypeFromString(std::string const& s)
if (s == "ed25519")
return KeyType::ed25519;
if (s == "dilithium")
return KeyType::dilithium;
return {};
}
@@ -50,6 +54,9 @@ to_string(KeyType type)
if (type == KeyType::ed25519)
return "ed25519";
if (type == KeyType::dilithium)
return "dilithium";
return "INVALID";
}

View File

@@ -275,6 +275,7 @@ enum LedgerSpecificFlags {
0x00800000, // True, trust lines allow rippling by default
lsfDepositAuth = 0x01000000, // True, all deposits require authorization
lsfTshCollect = 0x02000000, // True, allow TSH collect-calls to acc hooks
lsfForceQuantum = 0x04000000, // True, force quantum-resistant signature
lsfDisallowIncomingNFTokenOffer =
0x04000000, // True, reject new incoming NFT offers
lsfDisallowIncomingCheck =

View File

@@ -43,10 +43,11 @@ namespace ripple {
information needed to determine the cryptosystem
parameters used is stored inside the key.
As of this writing two systems are supported:
As of this writing three systems are supported:
secp256k1
ed25519
dilithium
secp256k1 public keys consist of a 33 byte
compressed public key, with the lead byte equal
@@ -55,12 +56,14 @@ namespace ripple {
The ed25519 public keys consist of a 1 byte
prefix constant 0xED, followed by 32 bytes of
public key data.
The dilithium public keys will have their own specific format.
*/
class PublicKey
{
protected:
std::uint8_t buf_[1312];
std::size_t size_ = 0;
std::uint8_t buf_[33]; // should be large enough
public:
using const_iterator = std::uint8_t const*;

View File

@@ -36,7 +36,8 @@ namespace ripple {
class SecretKey
{
private:
std::uint8_t buf_[32];
std::uint8_t buf_[2528];
std::size_t size_ = 0;
public:
using const_iterator = std::uint8_t const*;
@@ -49,6 +50,7 @@ public:
~SecretKey();
SecretKey(std::array<std::uint8_t, 32> const& data);
SecretKey(std::array<std::uint8_t, 2528> const& data);
SecretKey(Slice const& slice);
std::uint8_t const*
@@ -60,7 +62,7 @@ public:
std::size_t
size() const
{
return sizeof(buf_);
return size_;
}
/** Convert the secret key to a hexadecimal string.
@@ -86,13 +88,13 @@ public:
const_iterator
end() const noexcept
{
return buf_ + sizeof(buf_);
return buf_ + size_;
}
const_iterator
cend() const noexcept
{
return buf_ + sizeof(buf_);
return buf_ + size_;
}
};
@@ -126,6 +128,10 @@ toBase58(TokenType type, SecretKey const& sk)
SecretKey
randomSecretKey();
/** Create a secret key using secure random numbers. */
SecretKey
randomSecretKey(KeyType type);
/** Generate a new secret key deterministically. */
SecretKey
generateSecretKey(KeyType type, Seed const& seed);

View File

@@ -92,6 +92,7 @@ enum AccountFlags : uint32_t {
asfDisallowIncomingPayChan = 14,
asfDisallowIncomingTrustline = 15,
asfDisallowIncomingRemit = 16,
asfForceQuantum = 17,
};
// OfferCreate flags:

View File

@@ -475,6 +475,7 @@ REGISTER_FIX (fixXahauV3, Supported::yes, VoteBehavior::De
REGISTER_FIX (fix20250131, Supported::yes, VoteBehavior::DefaultYes);
REGISTER_FEATURE(HookCanEmit, Supported::yes, VoteBehavior::DefaultNo);
REGISTER_FIX (fixRewardClaimFlags, Supported::yes, VoteBehavior::DefaultYes);
REGISTER_FEATURE(QuantumSigning, Supported::yes, VoteBehavior::DefaultYes);
// The following amendments are obsolete, but must remain supported
// because they could potentially get enabled.

View File

@@ -26,6 +26,18 @@
#include <ed25519.h>
#include <type_traits>
extern "C" {
#include "api.h"
}
#ifndef CRYPTO_PUBLICKEYBYTES
#define CRYPTO_PUBLICKEYBYTES pqcrystals_dilithium2_PUBLICKEYBYTES
#endif
#ifndef crypto_sign_verify
#define crypto_sign_verify pqcrystals_dilithium2_ref_verify
#endif
namespace ripple {
std::ostream&
@@ -213,6 +225,10 @@ publicKeyType(Slice const& slice)
if (slice[0] == 0x02 || slice[0] == 0x03)
return KeyType::secp256k1;
}
else if (slice.size() == CRYPTO_PUBLICKEYBYTES)
{
return KeyType::dilithium;
}
return std::nullopt;
@@ -295,6 +311,11 @@ verify(
m.data(), m.size(), publicKey.data() + 1, sig.data()) ==
0;
}
else if (*type == KeyType::dilithium)
{
return crypto_sign_verify(
sig.data(), sig.size(), m.data(), m.size(), publicKey.data()) == 0;
}
}
return false;
}

View File

@@ -25,26 +25,89 @@
#include <ripple/protocol/SecretKey.h>
#include <ripple/protocol/digest.h>
#include <ripple/protocol/impl/secp256k1.h>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <ed25519.h>
#pragma push_macro("L")
#pragma push_macro("K")
#pragma push_macro("N")
#pragma push_macro("S")
#pragma push_macro("U")
#pragma push_macro("D")
#undef L
#undef K
#undef N
#undef S
#undef U
#undef D
extern "C" {
#include "api.h"
#include "fips202.h"
#include "packing.h"
#include "params.h"
#include "poly.h"
#include "polyvec.h"
#include "sign.h"
}
#include <iomanip>
#include <iostream>
#include <iterator>
#include <ostream>
#include <sstream>
#include <stdexcept>
// Define the dilithium functions and sizes with respect to functions named here
#ifndef CRYPTO_PUBLICKEYBYTES
#define CRYPTO_PUBLICKEYBYTES pqcrystals_dilithium2_PUBLICKEYBYTES
#endif
#ifndef CRYPTO_SECRETKEYBYTES
#define CRYPTO_SECRETKEYBYTES pqcrystals_dilithium2_SECRETKEYBYTES
#endif
#ifndef CRYPTO_BYTES
#define CRYPTO_BYTES pqcrystals_dilithium2_BYTES
#endif
#ifndef crypto_sign_keypair
#define crypto_sign_keypair pqcrystals_dilithium2_ref_keypair
#endif
#ifndef crypto_sign_signature
#define crypto_sign_signature pqcrystals_dilithium2_ref_signature
#endif
namespace ripple {
SecretKey::~SecretKey()
{
secure_erase(buf_, sizeof(buf_));
secure_erase(buf_, size_);
}
SecretKey::SecretKey(std::array<std::uint8_t, 32> const& key)
{
size_ = 32;
std::memcpy(buf_, key.data(), key.size());
}
SecretKey::SecretKey(std::array<std::uint8_t, 2528> const& key)
{
size_ = 2528;
std::memcpy(buf_, key.data(), key.size());
}
SecretKey::SecretKey(Slice const& slice)
{
if (slice.size() != sizeof(buf_))
if (slice.size() != 32 && slice.size() != 2528)
{
LogicError("SecretKey::SecretKey: invalid size");
std::memcpy(buf_, slice.data(), sizeof(buf_));
}
size_ = slice.size();
std::memcpy(buf_, slice.data(), size_);
}
std::string
@@ -234,6 +297,18 @@ signDigest(PublicKey const& pk, SecretKey const& sk, uint256 const& digest)
return Buffer{sig, len};
}
std::string
toHexString(const uint8_t* data, size_t length)
{
std::ostringstream oss;
for (size_t i = 0; i < length; ++i)
{
oss << std::uppercase << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<int>(data[i]);
}
return oss.str();
}
Buffer
sign(PublicKey const& pk, SecretKey const& sk, Slice const& m)
{
@@ -269,7 +344,13 @@ sign(PublicKey const& pk, SecretKey const& sk, Slice const& m)
secp256k1Context(), sig, &len, &sig_imp) != 1)
LogicError(
"sign: secp256k1_ecdsa_signature_serialize_der failed");
return Buffer{sig, len};
}
case KeyType::dilithium: {
uint8_t sig[CRYPTO_BYTES];
size_t len;
crypto_sign_signature(sig, &len, m.data(), m.size(), sk.data());
return Buffer{sig, len};
}
default:
@@ -280,11 +361,143 @@ sign(PublicKey const& pk, SecretKey const& sk, Slice const& m)
SecretKey
randomSecretKey()
{
std::uint8_t buf[32];
beast::rngfill(buf, sizeof(buf), crypto_prng());
SecretKey sk(Slice{buf, sizeof(buf)});
secure_erase(buf, sizeof(buf));
return sk;
return randomSecretKey(KeyType::secp256k1);
}
SecretKey
randomSecretKey(KeyType type)
{
switch (type)
{
case KeyType::ed25519:
case KeyType::secp256k1: {
std::uint8_t buf[32];
beast::rngfill(buf, sizeof(buf), crypto_prng());
SecretKey sk(Slice{buf, sizeof(buf)});
secure_erase(buf, sizeof(buf));
return sk;
}
case KeyType::dilithium: {
uint8_t pk[CRYPTO_PUBLICKEYBYTES];
uint8_t buf[CRYPTO_SECRETKEYBYTES];
crypto_sign_keypair(pk, buf);
SecretKey sk(Slice{buf, CRYPTO_SECRETKEYBYTES});
secure_erase(buf, sizeof(buf));
return sk;
}
}
}
void
expand_mat(polyvecl mat[K], const uint8_t rho[SEEDBYTES])
{
unsigned int i, j;
uint16_t nonce;
for (i = 0; i < K; ++i)
{
for (j = 0; j < L; ++j)
{
nonce = (i << 8) + j; // Combine indices i and j into a nonce
poly_uniform(&mat[i].vec[j], rho, nonce);
}
}
}
int
pqcrystals_dilithium2_ref_keypair_seed(
uint8_t* pk,
uint8_t* sk,
const uint8_t* seed)
{
uint8_t seedbuf[3 * SEEDBYTES];
uint8_t tr[CRHBYTES];
const uint8_t* rho;
const uint8_t* rhoprime;
const uint8_t* key;
polyvecl mat[K], s1, s1hat;
polyveck t1, t0, s2;
unsigned int i;
/* Use the provided seed to generate rho, rhoprime, and key */
shake256(seedbuf, 3 * SEEDBYTES, seed, SEEDBYTES);
rho = seedbuf;
rhoprime = rho + SEEDBYTES;
key = rhoprime + SEEDBYTES;
/* Expand matrix */
expand_mat(mat, rho);
/* Sample short vectors s1 and s2 using rhoprime */
polyvecl_uniform_eta(&s1, rhoprime, 0);
polyveck_uniform_eta(&s2, rhoprime, L);
/* Compute t = As1 + s2 */
s1hat = s1;
polyvecl_ntt(&s1hat);
for (i = 0; i < K; ++i)
{
polyvecl_pointwise_acc_montgomery(&t1.vec[i], &mat[i], &s1hat);
poly_invntt_tomont(&t1.vec[i]);
}
polyveck_add(&t1, &t1, &s2);
/* Extract t1 and write public key */
polyveck_caddq(&t1);
polyveck_power2round(&t1, &t0, &t1);
pack_pk(pk, rho, &t1);
/* Hash rho and t1 to obtain tr */
uint8_t buf[CRYPTO_PUBLICKEYBYTES];
memcpy(buf, pk, CRYPTO_PUBLICKEYBYTES);
shake256(tr, CRHBYTES, buf, CRYPTO_PUBLICKEYBYTES);
/* Pack secret key */
pack_sk(sk, rho, tr, key, &t0, &s1, &s2);
/* Clean sensitive data */
secure_erase(seedbuf, sizeof(seedbuf));
secure_erase((void*)&s1, sizeof(s1));
secure_erase((void*)&s1hat, sizeof(s1hat));
secure_erase((void*)&s2, sizeof(s2));
secure_erase((void*)&t0, sizeof(t0));
secure_erase((void*)&t1, sizeof(t1));
return 0;
}
int
pqcrystals_dilithium2_ref_publickey(uint8_t* pk, const uint8_t* sk)
{
uint8_t seedbuf[3 * SEEDBYTES + 2 * CRHBYTES];
uint8_t *rho, *tr, *key;
polyvecl mat[K], s1, s1hat;
polyveck t0, t1, s2;
rho = seedbuf;
tr = rho + SEEDBYTES;
key = tr + SEEDBYTES;
unpack_sk(rho, tr, key, &t0, &s1, &s2, sk);
/* Expand matrix */
polyvec_matrix_expand(mat, rho);
/* Matrix-vector multiplication */
s1hat = s1;
polyvecl_ntt(&s1hat);
polyvec_matrix_pointwise_montgomery(&t1, mat, &s1hat);
polyveck_reduce(&t1);
polyveck_invntt_tomont(&t1);
/* Add error vector s2 */
polyveck_add(&t1, &t1, &s2);
/* Extract t1 and write public key */
polyveck_caddq(&t1);
polyveck_power2round(&t1, &t0, &t1);
pack_pk(pk, rho, &t1);
return 1;
}
SecretKey
@@ -306,6 +519,17 @@ generateSecretKey(KeyType type, Seed const& seed)
return sk;
}
if (type == KeyType::dilithium)
{
uint8_t pk[CRYPTO_PUBLICKEYBYTES];
uint8_t buf[CRYPTO_SECRETKEYBYTES];
auto key = sha512Half_s(Slice(seed.data(), seed.size()));
pqcrystals_dilithium2_ref_keypair_seed(pk, buf, key.data());
SecretKey sk{Slice{buf, CRYPTO_SECRETKEYBYTES}};
secure_erase(buf, CRYPTO_SECRETKEYBYTES);
return sk;
}
LogicError("generateSecretKey: unknown key type");
}
@@ -342,6 +566,14 @@ derivePublicKey(KeyType type, SecretKey const& sk)
ed25519_publickey(sk.data(), &buf[1]);
return PublicKey(Slice{buf, sizeof(buf)});
}
case KeyType::dilithium: {
uint8_t pk_data[CRYPTO_PUBLICKEYBYTES];
if (pqcrystals_dilithium2_ref_publickey(pk_data, sk.data()) != 1)
LogicError(
"derivePublicKey: secp256k1_ec_pubkey_serialize failed");
return PublicKey{Slice{pk_data, CRYPTO_PUBLICKEYBYTES}};
}
default:
LogicError("derivePublicKey: bad key type");
};
@@ -356,18 +588,23 @@ generateKeyPair(KeyType type, Seed const& seed)
detail::Generator g(seed);
return g(0);
}
default:
case KeyType::ed25519: {
auto const sk = generateSecretKey(type, seed);
return {derivePublicKey(type, sk), sk};
}
case KeyType::dilithium: {
auto const sk = generateSecretKey(type, seed);
return {derivePublicKey(type, sk), sk};
}
default:
throw std::invalid_argument("Unsupported key type");
}
}
std::pair<PublicKey, SecretKey>
randomKeyPair(KeyType type)
{
auto const sk = randomSecretKey();
auto const sk = randomSecretKey(type);
return {derivePublicKey(type, sk), sk};
}
@@ -378,9 +615,16 @@ parseBase58(TokenType type, std::string const& s)
auto const result = decodeBase58Token(s, type);
if (result.empty())
return std::nullopt;
if (result.size() != 32)
if (result.size() != 32 && result.size() != 2528)
return std::nullopt;
return SecretKey(makeSlice(result));
}
} // namespace ripple
#pragma pop_macro("K")
#pragma pop_macro("L")
#pragma pop_macro("N")
#pragma pop_macro("S")
#pragma pop_macro("U")
#pragma pop_macro("D")

View File

@@ -100,10 +100,38 @@ class Wildcard_test : public beast::unit_test::suite
}
}
void
testSimplePayment(FeatureBitset features)
{
using namespace test::jtx;
testcase("simple payment");
Env env{*this, envconfig(), features};
Account const alice{"alice"};
Account const bob{"bob"};
Account const carol{"carol"};
Account const dave{"dave", KeyType::dilithium};
env.fund(XRP(1000), alice, bob, carol, dave);
env.close();
env(fset(dave, asfForceQuantum));
env(pay(dave, bob, XRP(100)));
env.close();
Json::Value params;
params[jss::ledger_index] = env.current()->seq() - 1;
params[jss::transactions] = true;
params[jss::expand] = true;
auto const jrr = env.rpc("json", "ledger", to_string(params));
std::cout << jrr << std::endl;
}
void
testWithFeats(FeatureBitset features)
{
testWildcardSign(features);
// testWildcardSign(features);
testSimplePayment(features);
}
public:

View File

@@ -366,7 +366,7 @@ public:
std::array<PublicKey, 32> keys;
for (std::size_t i = 0; i != keys.size(); ++i)
keys[i] = derivePublicKey(keyType, randomSecretKey());
keys[i] = derivePublicKey(keyType, randomSecretKey(keyType));
for (std::size_t i = 0; i != keys.size(); ++i)
{
@@ -431,6 +431,54 @@ public:
}
testBase58(KeyType::ed25519);
// testcase("Base58: dilithium");
// {
// auto const pk1 = derivePublicKey(
// KeyType::dilithium,
// generateSecretKey(
// KeyType::dilithium, generateSeed("masterpassphrase")));
// auto const pk2 = parseBase58<PublicKey>(
// TokenType::NodePublic,
// "p9pow2SA5t1GpXJCZiWeWiKjZ4xav57jYgDzAhesVequQtwp2UMQ1ezUUE81t7"
// "QY7zyvWqsRCTuxDAyZikit8Qwrr3Gcq5nNdW9DzbqjiY18Ze5ZZCdpNmkcsye6"
// "MajNjTrjbr7VzcH2HksZnRB6gTiy8Ktm3s6jwU9wiDHo3kbZdY1UbV9MZXSweg"
// "abP9s1oFRMSCZ3UQJAPHBVeCyd9LCp4oV3kj3TVSo7VF8D5xzgwFvtiwXxcAae"
// "sKnG5u1NgyYPFNqXFZA48ezBjmsYTt5ZKcKcCShkKa5tN4dME4NCagDa9G8U24"
// "8HShgFkVHCwjpRcyAEPehN9TUowySQZZFNQu8887sQ1M22BJ6rmSkfLAbV6jpm"
// "HinSjURu67SZ1vvNm5rmEEcLvpMwHibwJQkurVD7LYXUJrL2uXUf5AiuZycJEi"
// "1XZcd6sQaNAp64FPecRzWMnLM9eqg2nJQGt9YP7Gv6S2JV5m3AULsebDDZ1hYR"
// "7CUNfAeo3Dj6SoatPJaqED5GfQK2Z451QHQr9FQXsLMJ9bfXhQDJJYTa3kKyo9"
// "1wtaZataHyhDaGpJ3WwuDV1adkfgcrMLbK52mi6Qqznm22WQRxVtp2heuEees9"
// "zGgSnfWhFSQ7QNaQStQ9jdPErqQFmscN6Evq1b283ABuJk22EKMPz1JWJmPXvy"
// "rUKFwqf5u5AXkZVZZ8zEPmoLzsNoFVBDneAt2FbAh5n45rfUQs1BFeFEn6wcfY"
// "mh61t4xdzcSZpcJHHZWqRXBaPFWbgHKqWmxnnwdMZik565WuPmQhD7BpcmbMsx"
// "ffS8QEqPgwKAHNSnrGw7ZZf2nsb6C37ydmVecswmjRVosCTsBniBxLvDzzcGpa"
// "oyyG7RD6X8bAKmSyD9VJFtwqXWj8hi9d6P729cwuthmzUhmTsYYiSCy4aoPM8o"
// "U3pHheiydExXeifbXubwvS3LKAk48dyVCN1LhcwELn8hzUqnZ79whzFR72CPhv"
// "DQgZU9NmG7SBZteV3P5oTEdWeqFwGf9umZQbMAGoaCfjE27zgjzd6GfFsZ6AUn"
// "2xCrEfwoEg4uhB9PC9QsturSWWV88S1YTtR7pbEbGtEVBgTkcNMSk2XijUJBGC"
// "r83964fMtsbuj9DyqJgQSg1za6cHfgJt9pzmVoCNBRoBLGcsWn8CZAcxUGZkhm"
// "k2nwERPsCci56kV2UEfTKpq4PqUYWmxi2fvbvamqCWv6kQgBA3FLWXu8rXtsa9"
// "vUx2fV1jiVogFRewsxZ3YCdmAVNmt89jb2ECQX4rdEqDXwfWJPxRUY2JD3JSZi"
// "jWpHVqMJiHGu6KgeGvCcGmiqBvYom3D9ACQxA9QGTCdQh4AYYYjSwDabA7nB4A"
// "EVw2v5L7Z2uz76BHXMcWCHu1B3q57kVihrNfKYGDLcscw9TebPKTimZEqV2PB3"
// "h5YA9P9VKgnRKmkFr8qMQRrVR2ekGafMB2PVRmrMLkZkYNx9exE1mvkN7VoD4t"
// "QyRzQNsSh3xJq6PdBYX5KTm5ouw7DVxev4PQUNiHtZVExZGfjykgzoRojvD7s7"
// "64BpWNyyRAU4zyMT5UU1BdtBQQzdMxxZWMsH6LHkX7dahTPkGAEtQn1gPrJdLP"
// "uPtryue9ps2wNpVWT8T1Riw5fXgZ4NHfJb5hRwX95vg1WKXYMttHMBL6Zi7QEf"
// "9VSdrt2qTw3MTG3F4A3uxJhyapzv1XBfxdKUTRbEh3h59CTmxLZauPBKE2QW5a"
// "jDUwoZKv9cV6isLfNe49XYSWa4ger9X3Gfga8xxPrmaxnWeST2qjfUkhuqi44F"
// "v");
// BEAST_EXPECT(pk2);
// BEAST_EXPECT(pk1 == *pk2);
// }
// testBase58(KeyType::dilithium);
}
void

File diff suppressed because it is too large Load Diff

View File

@@ -220,6 +220,135 @@ public:
}
}
{
testcase("Node keypair generation & signing (dilithium)");
auto const secretKey = generateSecretKey(
KeyType::dilithium, generateSeed("masterpassphrase"));
auto const publicKey =
derivePublicKey(KeyType::dilithium, secretKey);
BEAST_EXPECT(
toBase58(TokenType::NodePublic, publicKey) ==
"p9pow2SA5t1GpXJCZiWeWiKjZ4xav57jYgDzAhesVequQtwp2UMQ1ezUUE81t7"
"QY7zyvWqsRCTuxDAyZikit8Qwrr3Gcq5nNdW9DzbqjiY18Ze5ZZCdpNmkcsye6"
"MajNjTrjbr7VzcH2HksZnRB6gTiy8Ktm3s6jwU9wiDHo3kbZdY1UbV9MZXSweg"
"abP9s1oFRMSCZ3UQJAPHBVeCyd9LCp4oV3kj3TVSo7VF8D5xzgwFvtiwXxcAae"
"sKnG5u1NgyYPFNqXFZA48ezBjmsYTt5ZKcKcCShkKa5tN4dME4NCagDa9G8U24"
"8HShgFkVHCwjpRcyAEPehN9TUowySQZZFNQu8887sQ1M22BJ6rmSkfLAbV6jpm"
"HinSjURu67SZ1vvNm5rmEEcLvpMwHibwJQkurVD7LYXUJrL2uXUf5AiuZycJEi"
"1XZcd6sQaNAp64FPecRzWMnLM9eqg2nJQGt9YP7Gv6S2JV5m3AULsebDDZ1hYR"
"7CUNfAeo3Dj6SoatPJaqED5GfQK2Z451QHQr9FQXsLMJ9bfXhQDJJYTa3kKyo9"
"1wtaZataHyhDaGpJ3WwuDV1adkfgcrMLbK52mi6Qqznm22WQRxVtp2heuEees9"
"zGgSnfWhFSQ7QNaQStQ9jdPErqQFmscN6Evq1b283ABuJk22EKMPz1JWJmPXvy"
"rUKFwqf5u5AXkZVZZ8zEPmoLzsNoFVBDneAt2FbAh5n45rfUQs1BFeFEn6wcfY"
"mh61t4xdzcSZpcJHHZWqRXBaPFWbgHKqWmxnnwdMZik565WuPmQhD7BpcmbMsx"
"ffS8QEqPgwKAHNSnrGw7ZZf2nsb6C37ydmVecswmjRVosCTsBniBxLvDzzcGpa"
"oyyG7RD6X8bAKmSyD9VJFtwqXWj8hi9d6P729cwuthmzUhmTsYYiSCy4aoPM8o"
"U3pHheiydExXeifbXubwvS3LKAk48dyVCN1LhcwELn8hzUqnZ79whzFR72CPhv"
"DQgZU9NmG7SBZteV3P5oTEdWeqFwGf9umZQbMAGoaCfjE27zgjzd6GfFsZ6AUn"
"2xCrEfwoEg4uhB9PC9QsturSWWV88S1YTtR7pbEbGtEVBgTkcNMSk2XijUJBGC"
"r83964fMtsbuj9DyqJgQSg1za6cHfgJt9pzmVoCNBRoBLGcsWn8CZAcxUGZkhm"
"k2nwERPsCci56kV2UEfTKpq4PqUYWmxi2fvbvamqCWv6kQgBA3FLWXu8rXtsa9"
"vUx2fV1jiVogFRewsxZ3YCdmAVNmt89jb2ECQX4rdEqDXwfWJPxRUY2JD3JSZi"
"jWpHVqMJiHGu6KgeGvCcGmiqBvYom3D9ACQxA9QGTCdQh4AYYYjSwDabA7nB4A"
"EVw2v5L7Z2uz76BHXMcWCHu1B3q57kVihrNfKYGDLcscw9TebPKTimZEqV2PB3"
"h5YA9P9VKgnRKmkFr8qMQRrVR2ekGafMB2PVRmrMLkZkYNx9exE1mvkN7VoD4t"
"QyRzQNsSh3xJq6PdBYX5KTm5ouw7DVxev4PQUNiHtZVExZGfjykgzoRojvD7s7"
"64BpWNyyRAU4zyMT5UU1BdtBQQzdMxxZWMsH6LHkX7dahTPkGAEtQn1gPrJdLP"
"uPtryue9ps2wNpVWT8T1Riw5fXgZ4NHfJb5hRwX95vg1WKXYMttHMBL6Zi7QEf"
"9VSdrt2qTw3MTG3F4A3uxJhyapzv1XBfxdKUTRbEh3h59CTmxLZauPBKE2QW5a"
"jDUwoZKv9cV6isLfNe49XYSWa4ger9X3Gfga8xxPrmaxnWeST2qjfUkhuqi44F"
"v");
BEAST_EXPECT(
toBase58(TokenType::NodePrivate, secretKey) ==
"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");
BEAST_EXPECT(
to_string(calcNodeID(publicKey)) ==
"8A94F2BC52E94646EC83CD988657FE37A9D5CDB5");
auto sig = sign(publicKey, secretKey, makeSlice(message1));
BEAST_EXPECT(sig.size() != 0);
BEAST_EXPECT(verify(publicKey, makeSlice(message1), sig));
// Correct public key but wrong message
BEAST_EXPECT(!verify(publicKey, makeSlice(message2), sig));
// Verify with incorrect public key
{
auto const otherPublicKey = derivePublicKey(
KeyType::ed25519,
generateSecretKey(
KeyType::ed25519, generateSeed("otherpassphrase")));
BEAST_EXPECT(!verify(otherPublicKey, makeSlice(message1), sig));
}
// Correct public key but wrong signature
{
// Slightly change the signature:
if (auto ptr = sig.data())
ptr[sig.size() / 2]++;
BEAST_EXPECT(!verify(publicKey, makeSlice(message1), sig));
}
}
{
testcase("Account keypair generation & signing (secp256k1)");
@@ -303,6 +432,132 @@ public:
BEAST_EXPECT(!verify(pk, makeSlice(message1), sig));
}
}
{
testcase("Account keypair generation & signing (dilithium)");
auto const [pk, sk] = generateKeyPair(
KeyType::dilithium, generateSeed("masterpassphrase"));
BEAST_EXPECT(
to_string(calcAccountID(pk)) ==
"rDdkg2HADzqCh6s6CyZ53ExSQ3fRMEycuV");
BEAST_EXPECT(
toBase58(TokenType::AccountPublic, pk) ==
"pRUFoiSyVkDrDDrZekFKmqdYfDznimyyHb6XzWVPRqgpniKgQeNKenTpvr3Y4V"
"Sbdx2rSdUzi52f4wnQ9UqctLsuP7VzpmLcj5gSnzZC4rSu4QNmEDtYxUswp3d9"
"7UiDdbUjWikPHrWmuyi8n1VpmbwHKWmXppKuxNLDLX73cP8MBGTmP5JdcrFrtm"
"kNMxp9Q81GbyvseaVHPYexjzpHwt6zm2og4hCNegehnBNqcDJcyRyh39cCkKao"
"Y1MK5iAhEXpXAwc8Wf9bVTouA15pbCmz7GL8SXFNmHD7xJRxbTmSpMAZSuhE6Y"
"e9dZAeAeJNpcjsmFWUuz8yhuH5s9PE9idKERYrLExV1FXTDhDA6F2ZR5duff2Z"
"aveYacowDHtQya3gErmq5ccJqZVFu2qWM5gwUrJ1BLD85jWeL25aMW1U6YDvJz"
"V4cvzo2oHdnS6wQMwN3vH56QEKta19BoGkntYhyUZipx7e1Nhp5NNccSCqR4uB"
"LB2dAgteUcCvwvkXFwy91xhGa7WqDRBzCVnEDVzaEZY1P4MjN1iguvtPhUXY8R"
"7drgMYzPUZr5yik6DKRnNS1Ub9aaxfvj8NCQWcUXbSQsFkN5AJYbrkLW7kAjVm"
"J1xuY9E2L8vFKfywJ4Dy6dkZ7raetT1BEQWKtCa2pP8Hq3nCjJdpjS9VM3CtgN"
"doxEg1tnd5G3qk658UGPb3hLkushX4q5nNuB9oXtfey3fPNguYSKqcusQqSw6y"
"2DqN91Bu6Q15PCgaCjrCBjRFCqVxsiybj6SVNDCcUEVD9JXVKCCA3ZijKdvEmJ"
"ESwLJe7qd7hmKuiMWy3yUqt9LrtJE5fb6tqzr6qC2n8YRenbgBEGVr1jt7CCad"
"2qwLQKg8BuuvSTRyHCKuvWDQ15YB5aKQdLrQWhEE8uDWP4jPTjovAZBsVunzBC"
"UTEnNfMyfgBGCK5fqa1i2tYqMMKJgkHVg2uPPCet3Xi37AVJMDnMsd8LQhH2X7"
"r52FCUFGinGyN7yNNMFGSQ4XVxY2V8611fRfg8M9MgVjXxvdVPwBZXGiWAr927"
"Gy2GfwG6TPeZprMmRNaZA22LzPbg7iQoHYs2JSGpWzMtDAsUZjt7QPUE5hiKpU"
"p7YHW5MSgGv3m49FL3s3fCBjQFCwR6oKErtMjNvRRMRzdSxJA3J1FbYvejbEXP"
"uJMeBN6mUabqFqjfyfZBCR424J4maY8zz4rHsj96Hp4Ya7y5fcx8uMuw3SiMoB"
"MYRVY3kQqvvEnGtfonjxwNLtnsnJs2t1JS7t9asUnQQr9U3zdACGnkMAYfdKGh"
"uY3UufNrnKHwtj524Vmr3Yi7W9YUcpKw8PSySty1GDn8Q25dS3Ja2hQuxj8WVp"
"8RTa9U9LcgpkF51u1Ao8XufqSN5dwmEaY3bocGW46sARCWEUeqYLhEKeQotSEQ"
"L6JJCxsrL8zYGC3hgNsT5gHMmu6SWjQEPe7ep6CrHiMDJ2QEZkucRh6mUigKf2"
"wb5pJ1c3mR84CcXkHCwWRHi5vVk8aER3bUr1MpioJriDbpU8MSGA5LfpfyqeQa"
"8QrKnprCzsXEGmKvjF7ciUpw98h9rZj3gAAVGJth7Zsqtwt4CpFbqxbLw6566z"
"jvwaJtcrQ9y4jHkfxqRDP8Ezcr3We7k3s8EhxPnB2MZiu7rKJJbXRJgRSpSnmA"
"gWvVn11DazifjgkSUcGtybuNaAr7t9Eno3ATzyQMQuAUWySX8YTF2bYwjSLEaX"
"Jf9ynQnBqbQu7f1BJCkKX88fv8ad8yCVJTcVtCvg6PpQsUzHVKxysptENQSTFq"
"C");
BEAST_EXPECT(
toBase58(TokenType::AccountSecret, sk) ==
"KZhAYmWBS8ZU3yfdrr6j1QGw988Dao5RNGxmSBUZAM9ttzDEuXEXP7tVqZ6JzN"
"cEpm8kgAADqhxhC6Ai27mX3m3PFZWQ9Y1oA8rZfBzKrr1rB6EJEb2Z7z3J214B"
"m5ZEC7ePiHrgdVuk2VHmKNzkvfu8EDW3Qk6T4M894v5xFsrpshLVmxhpcCwMR6"
"YyfRNiyKmxFfN6PnHuxUuibqV7ue1gytMspTmjUhupH3LuvqTFKrjWfvdgE4CX"
"dnCtSvnWChYyLLJftCkHHXMEA1PffhP9r1gaiGebvTinmcEbAHewJGyMgazQZB"
"4aJzTcnXQKKwgHHzVJ6uX8ifPQZx4e6C2NqSbgmwwpgEMYwcAcNiz3PWqukYqU"
"Qc85c4eYbcs8tZMf2gxFpYnJ2dFF7vLvM74jVEaZYs8V68gdx6H8gDHfX8VUFT"
"CSRiBda6serdsod6ZsoENYmLw7FpHvHUreVxnu1XFYZzmzXV3mgCpfpcXtiAKP"
"ub8BLTxz4ZYR6DXd3orGStMZCVQ1dWHpvHhHXxc9XgKVT4VEt6HAnnYhvbMTXs"
"mmxgk6nJ1E2QBotymEZhsSrKxwrSZFUskDaMkdabi8ifEhk3FwH8w1NG8EQ17o"
"UTjwio14V4SHvUsWFapkMUhSxXGFNdvMchWYnP9mAKqkgKm9mSBhZJaHZA1PT5"
"okHxPNbVNNZQQvtM55Zr5Fyj7V29aGf7D3XJcVD1KzGQDuuzhzQQbxKptQjbGY"
"Fe9e81diGpnad2qiuevYwyK1YmMxmcos57jGWwL9mpKFBS9nS1TEmuJwHoegPt"
"QWQfctVGYyJYCKxDDp6vkpAf7EFSjTdqwXSxRAi9iGw35GDg7xkd3Hcs5iJims"
"AFNBuHdSFPNB78c6NzhTShWQ4ztUAYMkfZmsvoHPw2dRmUznUBTwKSzUAa4bvu"
"Ew5W2LsaGY5yCaFLfVfPp7JEMZDbt5JDwuCYTkWeGiZaKm5UuFaQzBSmDv9XC5"
"xMgpfdcm4HDe8PbowmM4x4wLKLPDqVUcQBMTdk7HquTwCCGRKkApPBDHccuDM5"
"nuPwTJwxSwXuJRRa8MxSSNBSwR7KzQheWjLH1iUbv6fNxJUuFModknUairfmsk"
"hrbGuLx3rC61jbt7jTW3NkAY3YDsaTzLxiB8URmnDBhCHPYLKmGPKH2gvvXn9C"
"AusXDW9vpnrvXHpuUvLhZSPX4JrHbFfUmhiVjkN4mDycn3KaGbZK9ncZx6vJC6"
"9otwdCzefJtWQq7axjnJyzPi7Y2ZimLyjPSociKjb9F19e8gApHtkDvHpmZgcY"
"Ao2z9SLcyfMsbjXNRStn4iHxN2y3v9YQ6uDucEhJ9yoLEgEWsMLmEgvfBMFy93"
"xnGeVEyuTgUMPupGZQNEzwS1EesPGx5t6gPSQmsaEcHnGFdjbDfpTK5CZxFHrh"
"rKk3trav8H9MP24cxzQ1MpNpNfjUQbyV6R3wNZrmzRpGWNXhYNuzbWpochuMf2"
"CYk8BTKujHw989ULnqsJDzW2mKe7nAaX7Mk1eoByiDcXWUU5Qu61knzuKefyDU"
"9CQoVzukTAG1VTUugZQYrVXBPa26Z1AcQAbn9viAWpZucyEsaQaeT6to7PpFcg"
"d2mNUEqcSQnALSzFZKbiKRzZngsAn54Htbfs5MBydatX7CEhUYQuiMfA4n3JCF"
"7TfH7FeFZLGkTZ6E8giqCRbgPh3DEkygfkcBKrczAy1rv3zD6GPMaZpLG8FE1v"
"xbdNdgbaimLneEctwuH8x7Vds95xcPoYptbu2PytxLKtAc7Kc23iYiwitPLXL5"
"EmWoG71quUnJiLdwkXN3sn4eMs5Tp5URGdDgXmFw47XNhwD59Y8Dv6H7QFxdSw"
"gmewkFWBFgjV8AHg9brWG6HPdV5AZB4krZiXSCXMjvvUAj36ojJMiU2sgYaiUA"
"HKcoNQzkfr3JpuNfLVJHtAGxBg2nybU9Sb1TptBHvC1NHkqzUQFRXz1D1MeaqV"
"ooF5qn8VZyPugjCd84AZHKbipacR7VnwHYbFi9uvisraw8CEki8z3sPRUTSyeR"
"qxQfYZvpKqHwygERm3y7CqQCwFeVvsK9i1aNU5AAUDera91iVDRGYo8gZT9Snb"
"5FvG3RAVNyETfynxMEQx34w4Dxcs46QZXuyyFedjiJBjXC21d3DjHixos9mv8J"
"xA1wnBTanDJJc6Hfc1Cu4VCTBK21JXkRhuGeC47XWAWhFvuNcL8tf6HyA2zNVJ"
"hCyk4yFSYEBy2BPXP7QdFiARJM2bRSmmXWMAbUm685pJZar3fiwxpJuMS394os"
"J8ouafHw56xBySghcSU5tgvPbeixeWHxh6w1JsLwMWiH1z4ZDWSk62SRVk2Bg8"
"xQzGd6izQWM3Qy99FqauZqCfNDRtmcHQhJrZmeTWJYNxJ2Swy6bAyZrjKGe379"
"4UiQ59cskVfbZxsiJhh7D4TVX7PRC6GsxzioZL2p4eutnSz49WxKL92554f7Hf"
"PWBN3ENoRfF8MvWQUJ4VvrTAHE4GjLo3tdkw4NAFzR2ZPpP7nCP4sHxyKSSAWC"
"Myk4mwKp4g1mEBBgTnEJaD3ppfft8B62SCdvjwCzvoh1pq3ZrPA578FuBJRcoP"
"ML3bWddKb2G8p5BGASKMeETE2VmzznM9wDfW4Xq3Aa5VpApDy3BH2MqM3yGEEM"
"PbAeeL3L4pjSQ8Z8oKq244spHANjuVwi28fbSQTPn1Wq1uuqhvnqiurdqTYDB5"
"XJ6agh6stcLP6v4sDizLJaENpBQiQ7qjawUzzNwMiJMSq6b1N4DiLcJNwRBjNm"
"jQPHBexAwkLrxC3nUNUyDtny58Msvknua9wcCRRTCMEg9xUmD6sB9kpdHDUXsg"
"oUQvMoRhPakzyyNJfUB28YUJ7KDupy9VHdAuTtzGiUNkNXKckACsGZ6nS2iRJh"
"ooZH5dzEiu99tSBFPUVBQT15Ughrdn1v5n8SwwKAXe3qNRy9WF9HLd8vDsFKyV"
"tPQJKSYkP76SdyPZxDT1PKVCx7EBm7B5o2S459tyYBX4T7Z9JdtWzsD49nGxNy"
"SrBwCBLfcvR6aK8EcA9G2ewaqKjAzVFRVw1oDEKnj6DKHtf3n4vNqxx6oPn5G7"
"riMYCohgBWVXHcv9qWDaUQAhaJjK8ES7nTuAdo7cQ7XY78KWDc1WgiHojAxC8a"
"tVVspKHFY98HM7rvmzsydMRhFPYaFBhVctLzvg6ok6enMyU9TyjVfEbWRXV3J5"
"JMGqkABYnx6nriz9YFRDuQh6fwof4KUyjpUXk5eGPxtGAYSAqbNNFpDAmf6n8h"
"ybHqHGYV1rGeC9dVdGwgzHNjbgrUkDSx6vTHCWP8kvfMMtHtmGxuRCcPCz88yU"
"LNYo6YSHBp1LKfFBcZiCA45DLac4L69SHeueLdJKZrCHBAwg3Df6J7dDhbzCHK"
"SUqMDaZzaNTynHcLK79Jya86dLuzKh5Mk2qEoFysGRSr2MhsP");
auto sig = sign(pk, sk, makeSlice(message1));
BEAST_EXPECT(sig.size() != 0);
BEAST_EXPECT(verify(pk, makeSlice(message1), sig));
// Correct public key but wrong message
BEAST_EXPECT(!verify(pk, makeSlice(message2), sig));
// Verify with incorrect public key
{
auto const otherKeyPair = generateKeyPair(
KeyType::ed25519, generateSeed("otherpassphrase"));
BEAST_EXPECT(
!verify(otherKeyPair.first, makeSlice(message1), sig));
}
// Correct public key but wrong signature
{
// Slightly change the signature:
if (auto ptr = sig.data())
ptr[sig.size() / 2]++;
BEAST_EXPECT(!verify(pk, makeSlice(message1), sig));
}
}
}
void