Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quantum Resistant Signatures [DO NOT MERGE] #405

Open
wants to merge 11 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Builds/CMake/RippledCore.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ target_link_libraries (xrpl_core
Ripple::syslibs
NIH::secp256k1
NIH::ed25519-donna
NIH::dilithium2_ref
date::date
Ripple::opts)
#[=================================[
Expand Down
84 changes: 84 additions & 0 deletions Builds/CMake/deps/dilithium.cmake
Original file line number Diff line number Diff line change
@@ -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)
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ include(deps/gRPC)
include(deps/cassandra)
include(deps/Postgres)
include(deps/WasmEdge)
include(deps/dilithium)

###

Expand Down
17 changes: 17 additions & 0 deletions src/ripple/app/tx/impl/SetAccount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
14 changes: 13 additions & 1 deletion src/ripple/app/tx/impl/Transactor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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))
Expand Down
3 changes: 2 additions & 1 deletion src/ripple/protocol/Feature.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 = 75;
static constexpr std::size_t numFeatures = 76;

/** Amendments that this server supports and the default voting behavior.
Whether they are enabled depends on the Rules defined in the validated
Expand Down Expand Up @@ -363,6 +363,7 @@ extern uint256 const fixPageCap;
extern uint256 const fix240911;
extern uint256 const fixFloatDivide;
extern uint256 const fixReduceImport;
extern uint256 const featureQuantumSigning;

} // namespace ripple

Expand Down
7 changes: 7 additions & 0 deletions src/ripple/protocol/KeyType.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace ripple {
enum class KeyType {
secp256k1 = 0,
ed25519 = 1,
dilithium = 2,
};

inline std::optional<KeyType>
Expand All @@ -39,6 +40,9 @@ keyTypeFromString(std::string const& s)
if (s == "ed25519")
return KeyType::ed25519;

if (s == "dilithium")
return KeyType::dilithium;

return {};
}

Expand All @@ -50,6 +54,9 @@ to_string(KeyType type)

if (type == KeyType::ed25519)
return "ed25519";

if (type == KeyType::dilithium)
return "dilithium";

return "INVALID";
}
Expand Down
1 change: 1 addition & 0 deletions src/ripple/protocol/LedgerFormats.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
7 changes: 5 additions & 2 deletions src/ripple/protocol/PublicKey.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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*;
Expand Down
14 changes: 10 additions & 4 deletions src/ripple/protocol/SecretKey.h
Original file line number Diff line number Diff line change
Expand Up @@ -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*;
Expand All @@ -49,6 +50,7 @@ class SecretKey
~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*
Expand All @@ -60,7 +62,7 @@ class SecretKey
std::size_t
size() const
{
return sizeof(buf_);
return size_;
}

/** Convert the secret key to a hexadecimal string.
Expand All @@ -86,13 +88,13 @@ class SecretKey
const_iterator
end() const noexcept
{
return buf_ + sizeof(buf_);
return buf_ + size_;
}

const_iterator
cend() const noexcept
{
return buf_ + sizeof(buf_);
return buf_ + size_;
}
};

Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions src/ripple/protocol/TxFlags.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ enum AccountFlags : uint32_t {
asfDisallowIncomingPayChan = 14,
asfDisallowIncomingTrustline = 15,
asfDisallowIncomingRemit = 16,
asfForceQuantum = 17,
};

// OfferCreate flags:
Expand Down
1 change: 1 addition & 0 deletions src/ripple/protocol/impl/Feature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ REGISTER_FIX (fixPageCap, Supported::yes, VoteBehavior::De
REGISTER_FIX (fix240911, Supported::yes, VoteBehavior::DefaultYes);
REGISTER_FIX (fixFloatDivide, Supported::yes, VoteBehavior::DefaultYes);
REGISTER_FIX (fixReduceImport, 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.
Expand Down
21 changes: 21 additions & 0 deletions src/ripple/protocol/impl/PublicKey.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@
#include <boost/multiprecision/cpp_int.hpp>
#include <ed25519-donna/ed25519.h>

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&
Expand Down Expand Up @@ -212,6 +224,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;
Expand Down Expand Up @@ -294,6 +310,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;
}
Expand Down
Loading
Loading