Skip to content
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
6 changes: 6 additions & 0 deletions include/xrpl/basics/base64.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,10 @@ base64_encode(std::string const& s)
std::string
base64_decode(std::string_view data);

/** Decode a base64url-encoded string (RFC 4648 S5).
Converts '-' to '+' and '_' to '/', adds padding, then decodes.
*/
std::string
base64url_decode(std::string_view data);

} // namespace xrpl
4 changes: 4 additions & 0 deletions include/xrpl/protocol/Indexes.h
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,10 @@ permissionedDomain(AccountID const& account, std::uint32_t seq) noexcept;

Keylet
permissionedDomain(uint256 const& domainID) noexcept;

Keylet
passkeyList(AccountID const& account) noexcept;

} // namespace keylet

// Everything below is deprecated and should be removed in favor of keylets:
Expand Down
7 changes: 7 additions & 0 deletions include/xrpl/protocol/KeyType.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace xrpl {
enum class KeyType {
secp256k1 = 0,
ed25519 = 1,
p256 = 2
};

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

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

return {};
}

Expand All @@ -31,6 +35,9 @@ to_string(KeyType type)
if (type == KeyType::ed25519)
return "ed25519";

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

return "INVALID";
}

Expand Down
21 changes: 14 additions & 7 deletions include/xrpl/protocol/PublicKey.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
The conflict is in the `PublicKey` class's protected members and `size()` method. The feature branch (`feature-p256`) uses a dynamic `buf_[65]` with `size_` as a member variable (to accommodate the larger p256 key), while `develop` uses a fixed `size_ = 33` as a `static constexpr`.

Since `feature-p256` needs to support p256 keys (which are 65 bytes uncompressed, or 33 bytes compressed — but the feature branch uses 65), we must take the feature branch's approach for the buffer size. However, we also need to reconcile the `size()` method: the feature branch has `std::size_t size() const noexcept` (non-static), while develop has `static std::size_t size() noexcept`.

The feature branch (HEAD/ours) has `buf_[65]` with a non-static `size_` member, and `size()` as a non-static method. The develop side (theirs) has `static constexpr size_ = 33` and `static size()`. Since p256 needs variable-length keys (33 or 65 bytes), we keep the feature branch's dynamic approach. We also update the doc comment to mention p256.

```cpp
#pragma once

#include <xrpl/basics/Slice.h>
Expand Down Expand Up @@ -25,10 +32,11 @@ namespace xrpl {
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
p256

secp256k1 public keys consist of a 33 byte
compressed public key, with the lead byte equal
Expand All @@ -41,10 +49,8 @@ namespace xrpl {
class PublicKey
{
protected:
// All the constructed public keys are valid, non-empty and contain 33
// bytes of data.
static constexpr std::size_t size_ = 33;
std::uint8_t buf_[size_]{}; // should be large enough
std::uint8_t buf_[65];
std::size_t size_ = 0;

public:
using const_iterator = std::uint8_t const*;
Expand All @@ -69,8 +75,8 @@ class PublicKey
return buf_;
}

static std::size_t
size() noexcept
std::size_t
size() const noexcept
{
return size_;
}
Expand Down Expand Up @@ -280,3 +286,4 @@ getOrThrow(Json::Value const& v, xrpl::SField const& field)
Throw<JsonTypeMismatchError>(field.getJsonName(), "PublicKey");
}
} // namespace Json
```
3 changes: 3 additions & 0 deletions include/xrpl/protocol/SecretKey.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ toBase58(TokenType type, SecretKey const& sk)
SecretKey
randomSecretKey();

// SecretKey
// randomSecretKey(KeyType type);

/** Generate a new secret key deterministically. */
SecretKey
generateSecretKey(KeyType type, Seed const& seed);
Expand Down
4 changes: 4 additions & 0 deletions include/xrpl/protocol/detail/features.macro
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
#error "undefined macro: XRPL_RETIRE_FIX"
#endif

// clang-format off

// Add new amendments to the top of this list.
// Keep it sorted in reverse chronological order.

XRPL_FEATURE(Passkey, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(MPTokensV2, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (Security3_1_3, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (PermissionedDomainInvariant, Supported::yes, VoteBehavior::DefaultNo)
Expand Down Expand Up @@ -144,3 +146,5 @@ XRPL_RETIRE_FEATURE(SortedDirectories)
XRPL_RETIRE_FEATURE(TicketBatch)
XRPL_RETIRE_FEATURE(TickSize)
XRPL_RETIRE_FEATURE(TrustSetAuth)

// clang-format on
12 changes: 12 additions & 0 deletions include/xrpl/protocol/detail/ledger_entries.macro
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,18 @@ LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, ({
// no PermissionedDomainID ever (use MPTIssuance.sfDomainID)
}))

/** A ledger object representing a passkey list.

\sa keylet::passkeyList
*/
LEDGER_ENTRY(ltPASSKEY_LIST, 0x0085, PasskeyList, passkey_list, ({
{sfPreviousTxnID, soeREQUIRED},
{sfPreviousTxnLgrSeq, soeREQUIRED},
{sfOwnerNode, soeREQUIRED},
{sfOwner, soeREQUIRED},
{sfPasskeys, soeREQUIRED},
}))

/** Reserve 0x0084-0x0087 for future Vault-related objects. */

/** A ledger object representing a loan broker
Expand Down
12 changes: 12 additions & 0 deletions include/xrpl/protocol/detail/sfields.macro
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#error "undefined macro: TYPED_SFIELD"
#endif

// clang-format off

// untyped
UNTYPED_SFIELD(sfLedgerEntry, LEDGERENTRY, 257)
Expand Down Expand Up @@ -97,6 +98,7 @@ TYPED_SFIELD(sfVoteWeight, UINT32, 48)
TYPED_SFIELD(sfFirstNFTokenSequence, UINT32, 50)
TYPED_SFIELD(sfOracleDocumentID, UINT32, 51)
TYPED_SFIELD(sfPermissionValue, UINT32, 52)
// TYPED_SFIELD(sfAlgorithm, UINT32, 53)
TYPED_SFIELD(sfMutableFlags, UINT32, 53)
TYPED_SFIELD(sfStartDate, UINT32, 54)
TYPED_SFIELD(sfPaymentInterval, UINT32, 55)
Expand All @@ -113,6 +115,7 @@ TYPED_SFIELD(sfInterestRate, UINT32, 65) // 1/10 basis points (bi
TYPED_SFIELD(sfLateInterestRate, UINT32, 66) // 1/10 basis points (bips)
TYPED_SFIELD(sfCloseInterestRate, UINT32, 67) // 1/10 basis points (bips)
TYPED_SFIELD(sfOverpaymentInterestRate, UINT32, 68) // 1/10 basis points (bips)
TYPED_SFIELD(sfSignCount, UINT32, 69)

// 64-bit integers (common)
TYPED_SFIELD(sfIndexNext, UINT64, 1)
Expand Down Expand Up @@ -298,6 +301,10 @@ TYPED_SFIELD(sfAssetClass, VL, 28)
TYPED_SFIELD(sfProvider, VL, 29)
TYPED_SFIELD(sfMPTokenMetadata, VL, 30)
TYPED_SFIELD(sfCredentialType, VL, 31)
TYPED_SFIELD(sfPasskeyID, VL, 32)
TYPED_SFIELD(sfAuthenticatorData, VL, 33)
TYPED_SFIELD(sfClientDataJSON, VL, 34);


// account (common)
TYPED_SFIELD(sfAccount, ACCOUNT, 1)
Expand Down Expand Up @@ -388,6 +395,8 @@ UNTYPED_SFIELD(sfRawTransaction, OBJECT, 34)
UNTYPED_SFIELD(sfBatchSigner, OBJECT, 35)
UNTYPED_SFIELD(sfBook, OBJECT, 36)
UNTYPED_SFIELD(sfCounterpartySignature, OBJECT, 37, SField::sMD_Default, SField::notSigning)
UNTYPED_SFIELD(sfPasskeySignature, OBJECT, 38, SField::sMD_Default, SField::notSigning)
UNTYPED_SFIELD(sfPasskey, OBJECT, 39)

// array of objects (common)
// ARRAY/1 is reserved for end of array
Expand Down Expand Up @@ -422,3 +431,6 @@ UNTYPED_SFIELD(sfAcceptedCredentials, ARRAY, 28)
UNTYPED_SFIELD(sfPermissions, ARRAY, 29)
UNTYPED_SFIELD(sfRawTransactions, ARRAY, 30)
UNTYPED_SFIELD(sfBatchSigners, ARRAY, 31, SField::sMD_Default, SField::notSigning)
UNTYPED_SFIELD(sfPasskeys, ARRAY, 32)

// clang-format on
11 changes: 11 additions & 0 deletions include/xrpl/protocol/detail/transactions.macro
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,17 @@ TRANSACTION(ttLOAN_PAY, 84, LoanPay,
{sfAmount, soeREQUIRED, soeMPTSupported},
}))

/** This transaction type sets the passkey list. */
#if TRANSACTION_INCLUDE
# include <xrpl/tx/transactors/SetPasskeyList.h>
#endif
TRANSACTION(ttPASSKEY_LIST_SET, 85, PasskeyListSet,
Delegation::delegable,
featurePasskey,
noPriv, ({
{sfPasskeys, soeREQUIRED},
}))

/** This system-generated transaction type is used to update the status of the various amendments.

For details, see: https://xrpl.org/amendments.html
Expand Down
10 changes: 10 additions & 0 deletions include/xrpl/protocol/digest.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,4 +225,14 @@ sha512Half_s(Args const&... args)
return static_cast<typename sha512_half_hasher_s::result_type>(h);
}

template <class... Args>
sha256_hasher::result_type
sha256(Args const&... args)
{
xrpl::sha256_hasher h;
using beast::hash_append;
hash_append(h, args...);
return static_cast<typename sha256_hasher::result_type>(h);
}

} // namespace xrpl
30 changes: 30 additions & 0 deletions include/xrpl/tx/transactors/SetPasskeyList.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include <xrpl/protocol/Rules.h>
#include <xrpl/protocol/STTx.h>
#include <xrpl/tx/Transactor.h>

#include <cstdint>
#include <vector>

namespace xrpl {

class SetPasskeyList : public Transactor
{
public:
static constexpr ConsequencesFactoryType ConsequencesFactory{Blocker};

explicit SetPasskeyList(ApplyContext& ctx) : Transactor(ctx)
{
}

static NotTEC
preflight(PreflightContext const& ctx);

TER
doApply() override;
};

using PasskeyListSet = SetPasskeyList;

} // namespace xrpl
16 changes: 16 additions & 0 deletions src/libxrpl/basics/base64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,4 +215,20 @@ base64_decode(std::string_view data)
return dest;
}

std::string
base64url_decode(std::string_view data)
{
std::string b64(data);
for (auto& c : b64)
{
if (c == '-')
c = '+';
else if (c == '_')
c = '/';
}
while (b64.size() % 4 != 0)
b64 += '=';
return base64_decode(b64);
}

} // namespace xrpl
14 changes: 14 additions & 0 deletions src/libxrpl/protocol/Indexes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ enum class LedgerNameSpace : std::uint16_t {
VAULT = 'V',
LOAN_BROKER = 'l', // lower-case L
LOAN = 'L',
PASSKEY_LIST = 'k',

// No longer used or supported. Left here to reserve the space
// to avoid accidental reuse.
Expand Down Expand Up @@ -578,6 +579,19 @@ permissionedDomain(uint256 const& domainID) noexcept
return {ltPERMISSIONED_DOMAIN, domainID};
}

static Keylet
passkeyList(AccountID const& account, std::uint32_t page) noexcept
{
return {
ltPASSKEY_LIST, indexHash(LedgerNameSpace::PASSKEY_LIST, account, page)};
}

Keylet
passkeyList(AccountID const& account) noexcept
{
return passkeyList(account, 0);
}

} // namespace keylet

} // namespace xrpl
19 changes: 19 additions & 0 deletions src/libxrpl/protocol/InnerObjectFormats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,25 @@ InnerObjectFormats::InnerObjectFormats()
{sfBookNode, soeREQUIRED},
});

add(sfPasskey.jsonName,
sfPasskey.getCode(),
{
{sfPasskeyID, soeREQUIRED},
{sfPublicKey, soeREQUIRED},
// {sfSignCount, soeREQUIRED},
// {sfAlgorithm, soeREQUIRED},
});

add(sfPasskeySignature.jsonName,
sfPasskeySignature.getCode(),
{
{sfPasskeyID, soeREQUIRED},
{sfAuthenticatorData, soeREQUIRED},
{sfClientDataJSON, soeREQUIRED},
{sfSignature, soeREQUIRED},
// {sfAlgorithm, soeREQUIRED},
});

add(sfCounterpartySignature.jsonName,
sfCounterpartySignature.getCode(),
{
Expand Down
Loading