Compare commits

...

1 Commits

Author SHA1 Message Date
Denis Angell
ef800d7038 dilithium 2025-05-27 22:56:10 +02:00
18 changed files with 24587 additions and 22 deletions

View File

@@ -153,6 +153,7 @@ target_link_libraries (xrpl_core
Ripple::syslibs Ripple::syslibs
secp256k1::secp256k1 secp256k1::secp256k1
ed25519::ed25519 ed25519::ed25519
NIH::dilithium2_ref
date::date date::date
Ripple::opts) 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(RippledCompiler)
include(RippledInterface) include(RippledInterface)
include(deps/dilithium)
### ###
if (NOT USE_CONAN) if (NOT USE_CONAN)
add_subdirectory(src/secp256k1) 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) if (uFlagsIn != uFlagsOut)
sle->setFieldU32(sfFlags, uFlagsOut); sle->setFieldU32(sfFlags, uFlagsOut);

View File

@@ -40,6 +40,13 @@
#include <ripple/protocol/UintTypes.h> #include <ripple/protocol/UintTypes.h>
#include <limits> #include <limits>
#include <set> #include <set>
extern "C" {
#include "api.h"
}
#ifndef DILITHIUM_PK_SIZE
#define DILITHIUM_PK_SIZE pqcrystals_dilithium2_PUBLICKEYBYTES
#endif
namespace ripple { namespace ripple {
@@ -857,13 +864,18 @@ Transactor::checkSingleSign(PreclaimContext const& ctx)
} }
// Look up the account. // 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 idAccount = ctx.tx.getAccountID(sfAccount);
auto const sleAccount = ctx.view.read(keylet::account(idAccount)); auto const sleAccount = ctx.view.read(keylet::account(idAccount));
if (!sleAccount) if (!sleAccount)
return terNO_ACCOUNT; 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); bool const isMasterDisabled = sleAccount->isFlag(lsfDisableMaster);
if (ctx.view.rules().enabled(fixMasterKeyAsRegularKey)) 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 // 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 // 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. // 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. /** Amendments that this server supports and the default voting behavior.
Whether they are enabled depends on the Rules defined in the validated 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 fix20250131;
extern uint256 const featureHookCanEmit; extern uint256 const featureHookCanEmit;
extern uint256 const fixRewardClaimFlags; extern uint256 const fixRewardClaimFlags;
extern uint256 const featureQuantumSigning;
} // namespace ripple } // namespace ripple

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -26,6 +26,18 @@
#include <ed25519.h> #include <ed25519.h>
#include <type_traits> #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 { namespace ripple {
std::ostream& std::ostream&
@@ -214,6 +226,10 @@ publicKeyType(Slice const& slice)
if (slice[0] == 0x02 || slice[0] == 0x03) if (slice[0] == 0x02 || slice[0] == 0x03)
return KeyType::secp256k1; return KeyType::secp256k1;
} }
else if (slice.size() == CRYPTO_PUBLICKEYBYTES)
{
return KeyType::dilithium;
}
return std::nullopt; return std::nullopt;
} }
@@ -295,6 +311,11 @@ verify(
m.data(), m.size(), publicKey.data() + 1, sig.data()) == m.data(), m.size(), publicKey.data() + 1, sig.data()) ==
0; 0;
} }
else if (*type == KeyType::dilithium)
{
return crypto_sign_verify(
sig.data(), sig.size(), m.data(), m.size(), publicKey.data()) == 0;
}
} }
return false; return false;
} }

View File

@@ -25,26 +25,89 @@
#include <ripple/protocol/SecretKey.h> #include <ripple/protocol/SecretKey.h>
#include <ripple/protocol/digest.h> #include <ripple/protocol/digest.h>
#include <ripple/protocol/impl/secp256k1.h> #include <ripple/protocol/impl/secp256k1.h>
#include <cstddef>
#include <cstdint>
#include <cstring> #include <cstring>
#include <ed25519.h> #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 { namespace ripple {
SecretKey::~SecretKey() SecretKey::~SecretKey()
{ {
secure_erase(buf_, sizeof(buf_)); secure_erase(buf_, size_);
} }
SecretKey::SecretKey(std::array<std::uint8_t, 32> const& key) 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()); std::memcpy(buf_, key.data(), key.size());
} }
SecretKey::SecretKey(Slice const& slice) SecretKey::SecretKey(Slice const& slice)
{ {
if (slice.size() != sizeof(buf_)) if (slice.size() != 32 && slice.size() != 2528)
{
LogicError("SecretKey::SecretKey: invalid size"); LogicError("SecretKey::SecretKey: invalid size");
std::memcpy(buf_, slice.data(), sizeof(buf_)); }
size_ = slice.size();
std::memcpy(buf_, slice.data(), size_);
} }
std::string std::string
@@ -234,6 +297,18 @@ signDigest(PublicKey const& pk, SecretKey const& sk, uint256 const& digest)
return Buffer{sig, len}; 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 Buffer
sign(PublicKey const& pk, SecretKey const& sk, Slice const& m) sign(PublicKey const& pk, SecretKey const& sk, Slice const& m)
{ {
@@ -272,6 +347,12 @@ sign(PublicKey const& pk, SecretKey const& sk, Slice const& m)
return Buffer{sig, len}; 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: default:
LogicError("sign: invalid type"); LogicError("sign: invalid type");
} }
@@ -280,11 +361,143 @@ sign(PublicKey const& pk, SecretKey const& sk, Slice const& m)
SecretKey SecretKey
randomSecretKey() randomSecretKey()
{ {
return randomSecretKey(KeyType::secp256k1);
}
SecretKey
randomSecretKey(KeyType type)
{
switch (type)
{
case KeyType::ed25519:
case KeyType::secp256k1: {
std::uint8_t buf[32]; std::uint8_t buf[32];
beast::rngfill(buf, sizeof(buf), crypto_prng()); beast::rngfill(buf, sizeof(buf), crypto_prng());
SecretKey sk(Slice{buf, sizeof(buf)}); SecretKey sk(Slice{buf, sizeof(buf)});
secure_erase(buf, sizeof(buf)); secure_erase(buf, sizeof(buf));
return sk; 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 SecretKey
@@ -306,6 +519,17 @@ generateSecretKey(KeyType type, Seed const& seed)
return sk; 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"); LogicError("generateSecretKey: unknown key type");
} }
@@ -342,6 +566,14 @@ derivePublicKey(KeyType type, SecretKey const& sk)
ed25519_publickey(sk.data(), &buf[1]); ed25519_publickey(sk.data(), &buf[1]);
return PublicKey(Slice{buf, sizeof(buf)}); 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: default:
LogicError("derivePublicKey: bad key type"); LogicError("derivePublicKey: bad key type");
}; };
@@ -356,18 +588,23 @@ generateKeyPair(KeyType type, Seed const& seed)
detail::Generator g(seed); detail::Generator g(seed);
return g(0); return g(0);
} }
default:
case KeyType::ed25519: { case KeyType::ed25519: {
auto const sk = generateSecretKey(type, seed); auto const sk = generateSecretKey(type, seed);
return {derivePublicKey(type, sk), sk}; 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> std::pair<PublicKey, SecretKey>
randomKeyPair(KeyType type) randomKeyPair(KeyType type)
{ {
auto const sk = randomSecretKey(); auto const sk = randomSecretKey(type);
return {derivePublicKey(type, sk), sk}; return {derivePublicKey(type, sk), sk};
} }
@@ -378,9 +615,16 @@ parseBase58(TokenType type, std::string const& s)
auto const result = decodeBase58Token(s, type); auto const result = decodeBase58Token(s, type);
if (result.empty()) if (result.empty())
return std::nullopt; return std::nullopt;
if (result.size() != 32) if (result.size() != 32 && result.size() != 2528)
return std::nullopt; return std::nullopt;
return SecretKey(makeSlice(result)); return SecretKey(makeSlice(result));
} }
} // namespace ripple } // 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 void
testWithFeats(FeatureBitset features) testWithFeats(FeatureBitset features)
{ {
testWildcardSign(features); // testWildcardSign(features);
testSimplePayment(features);
} }
public: public:

View File

@@ -366,7 +366,7 @@ public:
std::array<PublicKey, 32> keys; std::array<PublicKey, 32> keys;
for (std::size_t i = 0; i != keys.size(); ++i) 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) for (std::size_t i = 0; i != keys.size(); ++i)
{ {
@@ -431,6 +431,54 @@ public:
} }
testBase58(KeyType::ed25519); 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 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)"); testcase("Account keypair generation & signing (secp256k1)");
@@ -303,6 +432,132 @@ public:
BEAST_EXPECT(!verify(pk, makeSlice(message1), sig)); 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) ==
"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");
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 void