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
2 changes: 2 additions & 0 deletions API-CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ This section contains changes targeting a future version.

### Additions

- `ledger_entry`, `account_objects`: Added the `Ballot` and `BallotVote` ledger entry types introduced by the `ConfidentialVoting` amendment. `ledger_entry` accepts a `ballot` request object (`owner` + `seq`) and a `ballot_vote` request object (`ballot_id` + `account`), or a hex object ID for either. `account_objects` returns these entries and accepts them as `type` filters.

- `account_tx`: Added an optional `delegate` request object to filter delegated transactions. The object requires `delegate_filter`, which must be either `actor` for transactions owned by the requested account but signed by another account, or `authorizer` for transactions signed by the requested account on behalf of another account. The optional `counter_party` account narrows the results to a specific signer/delegate for `actor` or a specific owner/delegator for `authorizer`. Malformed `delegate`, `delegate_filter`, and `counter_party` values return standard invalid field errors, and invalid account IDs return `actMalformed`.
When paginating delegate-filtered queries, a marker from a delegate-filtered query includes a `delegate` flag and is only valid for follow-up requests that also supply `delegate` (mixing marker conventions returns `invalidParams`). Because filtering is applied after the ledger scan, a page may contain fewer results than `limit` (possibly zero) while still returning a marker, so callers must continue until no marker is present.

Expand Down
85 changes: 85 additions & 0 deletions include/xrpl/protocol/ConfidentialTransfer.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <cstdint>
#include <limits>
#include <optional>
#include <vector>

namespace xrpl {

Expand Down Expand Up @@ -433,4 +434,88 @@ verifyConvertBackProof(
uint64_t amount,
uint256 const& contextHash);

/**
* @brief Generates the context hash for a BallotCastVote transaction.
*
* Binds the cast's range proof to this specific transaction, preventing
* proof reuse across ballots or accounts.
*
* @param account The voter's account ID.
* @param ballotID The target ballot's ledger index.
* @param sequence The transaction sequence number or ticket number.
* @return A 256-bit context hash unique to this cast.
*/
uint256
getBallotCastContextHash(AccountID const& account, uint256 const& ballotID, std::uint32_t sequence);

/**
* @brief Generates the context hash for a BallotFinalize transaction.
*
* Binds each per-option decryption-correctness proof to this specific
* finalize transaction.
*
* @param account The tally authority's account ID.
* @param ballotID The target ballot's ledger index.
* @param sequence The transaction sequence number or ticket number.
* @return A 256-bit context hash unique to this finalize.
*/
uint256
getBallotFinalizeContextHash(
AccountID const& account,
uint256 const& ballotID,
std::uint32_t sequence);

/**
* @brief Verifies an aggregated Bulletproof range proof over ballot option
* commitments.
*
* Proves that every one of the N per-option values committed in
* @p commitments lies in the non-negative range, so a vote cannot subtract
* weight from a disliked option. Thin wrapper over
* mpt_verify_aggregated_bulletproof.
*
* @param proof The serialized aggregated Bulletproof.
* @param commitments One 33-byte Pedersen commitment per option.
* @param contextHash The 256-bit context hash binding the proof.
* @return tesSUCCESS if the proof is valid, or an error code otherwise.
*/
TER
verifyBallotRangeProof(
Slice const& proof,
std::vector<Slice> const& commitments,
uint256 const& contextHash);

/**
* @brief Verifies the ciphertext-commitment linkage for one ballot option.
*
* Proves that the option's ElGamal ciphertext(s) encrypt the same value that
* its Pedersen commitment commits to, and that every mirror ciphertext (tally,
* optional auditor, optional voter) encrypts that same value under shared
* randomness. Combined with the aggregated range proof over the commitment,
* this pins the tally update to a non-negative value the voter cannot forge —
* the verifiable-encryption guarantee a vote needs because it encrypts under
* the tally key, which the voter does not own.
*
* Wraps secp256k1_compact_standard_verify. The balance-linkage terms of that
* relation are neutralized with a canonical witness (sk_A = 1, rho_b = 1), so
* pk_A = G, PC_b = H and B1 = B2 = G are reconstructed identically here and by
* the prover, and only the 192-byte proof is carried on the wire.
*
* @param pubKeys The n mirror public keys, tally key first (33 bytes each).
* @param c1 The shared ElGamal C1 component (33 bytes).
* @param c2PerKey The n ElGamal C2 components, one per mirror key (33 bytes).
* @param commitment The option's Pedersen commitment PC_m (33 bytes).
* @param proof The 192-byte compact sigma linkage proof.
* @param contextHash The 256-bit context hash binding the proof.
* @return tesSUCCESS if the linkage holds, or an error code otherwise.
*/
TER
verifyBallotVoteLinkage(
std::vector<Slice> const& pubKeys,
Slice const& c1,
std::vector<Slice> const& c2PerKey,
Slice const& commitment,
Slice const& proof,
uint256 const& contextHash);

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

Keylet
permissionedDomain(uint256 const& domainID) noexcept;

/**
* A ballot owned by `owner`, keyed by the creating transaction sequence.
*/
Keylet
ballot(AccountID const& owner, std::uint32_t seq) noexcept;

inline Keylet
ballot(uint256 const& ballotID)
{
return {ltBALLOT, ballotID};
}

/**
* A voter's cast on the ballot identified by `ballotID`.
*/
Keylet
ballotVote(uint256 const& ballotID, AccountID const& voter) noexcept;

inline Keylet
ballotVote(uint256 const& key)
{
return {ltBALLOT_VOTE, key};
}
} // namespace keylet

// Everything below is deprecated and should be removed in favor of keylets:
Expand Down
6 changes: 5 additions & 1 deletion include/xrpl/protocol/LedgerFormats.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,11 @@ enum LedgerEntryType : std::uint16_t {
\
LEDGER_OBJECT(Sponsorship, \
LSF_FLAG(lsfSponsorshipRequireSignForFee, 0x00010000) \
LSF_FLAG(lsfSponsorshipRequireSignForReserve, 0x00020000))
LSF_FLAG(lsfSponsorshipRequireSignForReserve, 0x00020000)) \
\
LEDGER_OBJECT(Ballot, \
LSF_FLAG(lsfBallotFinalized, 0x00000001) /* True, results have been published */ \
LSF_FLAG(lsfVoterRecoverable, 0x00000002)) /* True, casts carry a voter self-recovery vector */

// clang-format on

Expand Down
4 changes: 4 additions & 0 deletions include/xrpl/protocol/TER.h
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,10 @@ enum TECcodes : TERUnderlyingType {
tecNO_DELEGATE_PERMISSION = 198,
tecBAD_PROOF = 199,
tecNO_SPONSOR_PERMISSION = 200,
tecBALLOT_CLOSED = 201,
tecBALLOT_VOTED = 202,
tecBALLOT_NOT_OPEN = 203,
tecBALLOT_EXISTS = 204,
};

//------------------------------------------------------------------------------
Expand Down
4 changes: 4 additions & 0 deletions include/xrpl/protocol/TxFlags.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ inline constexpr FlagValue tfUniversalMask = ~tfUniversal;
TF_FLAG(tfSponsorshipEnd, 0x00010000) \
TF_FLAG(tfSponsorshipCreate, 0x00020000) \
TF_FLAG(tfSponsorshipReassign, 0x00040000), \
MASK_ADJ(0)) \
\
TRANSACTION(BallotCreate, \
TF_FLAG(tfVoterRecoverable, lsfVoterRecoverable), /* casts must carry a voter self-recovery vector */ \
MASK_ADJ(0))

// clang-format on
Expand Down
1 change: 1 addition & 0 deletions include/xrpl/protocol/detail/features.macro
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
// Add new amendments to the top of this list.
// Keep it sorted in reverse chronological order.

XRPL_FEATURE(ConfidentialVoting, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(Sponsor, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(BatchV1_1, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(LendingProtocolV1_1, Supported::No, VoteBehavior::DefaultNo)
Expand Down
45 changes: 45 additions & 0 deletions include/xrpl/protocol/detail/ledger_entries.macro
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ LEDGER_ENTRY(ltMPTOKEN_ISSUANCE, 0x007e, MPTokenIssuance, mpt_issuance, ({
{sfIssuerEncryptionKey, SoeOptional},
{sfAuditorEncryptionKey, SoeOptional},
{sfConfidentialOutstandingAmount, SoeDefault},
{sfBallotID, SoeOptional}, // ConfidentialVoting: the issuance's open ballot, if any
}))

/** A ledger object which tracks MPToken
Expand All @@ -428,6 +429,8 @@ LEDGER_ENTRY(ltMPTOKEN, 0x007f, MPToken, mptoken, ({
{sfIssuerEncryptedBalance, SoeOptional},
{sfAuditorEncryptedBalance, SoeOptional},
{sfHolderEncryptionKey, SoeOptional},
{sfVoteLockedAmount, SoeOptional}, // ConfidentialVoting: locked while a ballot is open
{sfBallotID, SoeOptional}, // ConfidentialVoting: the ballot holding the lock
}))

/** A ledger object which tracks Oracle
Expand Down Expand Up @@ -636,5 +639,47 @@ LEDGER_ENTRY(ltSPONSORSHIP, 0x0090, Sponsorship, sponsorship, ({
{sfSponseeNode, SoeRequired},
}))

/** A ledger object representing a confidential ballot with a homomorphically
encrypted tally.

\sa keylet::ballot
*/
LEDGER_ENTRY(ltBALLOT, 0x0091, Ballot, ballot, ({
{sfOwner, SoeRequired},
{sfSequence, SoeRequired},
{sfMPTokenIssuanceID, SoeOptional}, // token mode (one-of with sfDomainID)
{sfDomainID, SoeOptional}, // credential mode (one-of)
{sfDigest, SoeRequired}, // hash of the off-ledger ballot document
{sfURI, SoeOptional},
{sfOptionCount, SoeRequired},
{sfTallyPublicKey, SoeRequired},
{sfAuditorEncryptionKey, SoeOptional}, // optional auditor ElGamal key
{sfEncryptedTally, SoeRequired}, // one ElGamal ciphertext per option
{sfOpenTime, SoeRequired},
{sfCloseTime, SoeRequired},
{sfVoteCount, SoeDefault},
{sfResults, SoeOptional}, // plaintext counts, present after finalize
{sfOwnerNode, SoeRequired},
{sfPreviousTxnID, SoeRequired},
{sfPreviousTxnLgrSeq, SoeRequired},
}))

/** A ledger object recording a single voter's cast on a Ballot.

\sa keylet::ballotVote
*/
LEDGER_ENTRY(ltBALLOT_VOTE, 0x0092, BallotVote, ballot_vote, ({
{sfAccount, SoeRequired}, // voter
{sfBallotID, SoeRequired},
{sfBallotWeight, SoeRequired},
{sfEncryptedVotes, SoeRequired}, // vote vector under the tally key
{sfAuditorEncryptedVotes, SoeOptional}, // present iff the ballot has an auditor key
{sfVoterPublicKey, SoeOptional}, // present iff lsfVoterRecoverable
{sfVoterEncryptedVotes, SoeOptional}, // present iff lsfVoterRecoverable
{sfOwnerNode, SoeRequired},
{sfPreviousTxnID, SoeRequired},
{sfPreviousTxnLgrSeq, SoeRequired},
}))

#undef EXPAND
#undef LEDGER_ENTRY_DUPLICATE
16 changes: 16 additions & 0 deletions include/xrpl/protocol/detail/sfields.macro
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ TYPED_SFIELD(sfUNLModifyDisabling, UINT8, 17)
TYPED_SFIELD(sfHookResult, UINT8, 18)
TYPED_SFIELD(sfWasLockingChainSend, UINT8, 19)
TYPED_SFIELD(sfWithdrawalPolicy, UINT8, 20)
TYPED_SFIELD(sfOptionCount, UINT8, 21)

// 16-bit integers (common)
TYPED_SFIELD(sfLedgerEntryType, UINT16, 1, SField::kSmdNever)
Expand Down Expand Up @@ -119,6 +120,8 @@ TYPED_SFIELD(sfSponsoringOwnerCount, UINT32, 71)
TYPED_SFIELD(sfSponsoringAccountCount, UINT32, 72)
TYPED_SFIELD(sfRemainingOwnerCount, UINT32, 73)
TYPED_SFIELD(sfSponsorFlags, UINT32, 74)
TYPED_SFIELD(sfOpenTime, UINT32, 75)
TYPED_SFIELD(sfVoteCount, UINT32, 76)

// 64-bit integers (common)
TYPED_SFIELD(sfIndexNext, UINT64, 1)
Expand Down Expand Up @@ -154,6 +157,8 @@ TYPED_SFIELD(sfVaultNode, UINT64, 30)
TYPED_SFIELD(sfLoanBrokerNode, UINT64, 31)
TYPED_SFIELD(sfConfidentialOutstandingAmount, UINT64, 32, SField::kSmdBaseTen|SField::kSmdDefault)
TYPED_SFIELD(sfSponseeNode, UINT64, 33)
TYPED_SFIELD(sfBallotWeight, UINT64, 34)
TYPED_SFIELD(sfVoteLockedAmount, UINT64, 35, SField::kSmdBaseTen|SField::kSmdDefault)

// 128-bit
TYPED_SFIELD(sfEmailHash, UINT128, 1)
Expand Down Expand Up @@ -216,6 +221,7 @@ TYPED_SFIELD(sfLoanID, UINT256, 38)
TYPED_SFIELD(sfReferenceHolding, UINT256, 39)
TYPED_SFIELD(sfBlindingFactor, UINT256, 40)
TYPED_SFIELD(sfObjectID, UINT256, 41)
TYPED_SFIELD(sfBallotID, UINT256, 42)

// number (common)
TYPED_SFIELD(sfNumber, NUMBER, 1)
Expand Down Expand Up @@ -326,6 +332,9 @@ TYPED_SFIELD(sfAuditorEncryptedAmount, VL, 43)
TYPED_SFIELD(sfAuditorEncryptionKey, VL, 44)
TYPED_SFIELD(sfAmountCommitment, VL, 45)
TYPED_SFIELD(sfBalanceCommitment, VL, 46)
TYPED_SFIELD(sfEncryptedVote, VL, 47)
TYPED_SFIELD(sfTallyPublicKey, VL, 48)
TYPED_SFIELD(sfVoterPublicKey, VL, 49)

// account (common)
TYPED_SFIELD(sfAccount, ACCOUNT, 1)
Expand Down Expand Up @@ -422,6 +431,8 @@ UNTYPED_SFIELD(sfBatchSigner, OBJECT, 35)
UNTYPED_SFIELD(sfBook, OBJECT, 36)
UNTYPED_SFIELD(sfCounterpartySignature, OBJECT, 37, SField::kSmdDefault, SField::kNotSigning)
UNTYPED_SFIELD(sfSponsorSignature, OBJECT, 38, SField::kSmdDefault, SField::kNotSigning)
UNTYPED_SFIELD(sfBallotOption, OBJECT, 39)
UNTYPED_SFIELD(sfBallotResult, OBJECT, 40)

// array of objects (common)
// ARRAY/1 is reserved for end of array
Expand Down Expand Up @@ -456,3 +467,8 @@ UNTYPED_SFIELD(sfAcceptedCredentials, ARRAY, 28)
UNTYPED_SFIELD(sfPermissions, ARRAY, 29)
UNTYPED_SFIELD(sfRawTransactions, ARRAY, 30)
UNTYPED_SFIELD(sfBatchSigners, ARRAY, 31, SField::kSmdDefault, SField::kNotSigning)
UNTYPED_SFIELD(sfEncryptedTally, ARRAY, 32)
UNTYPED_SFIELD(sfEncryptedVotes, ARRAY, 33)
UNTYPED_SFIELD(sfAuditorEncryptedVotes, ARRAY, 34)
UNTYPED_SFIELD(sfVoterEncryptedVotes, ARRAY, 35)
UNTYPED_SFIELD(sfResults, ARRAY, 36)
66 changes: 66 additions & 0 deletions include/xrpl/protocol/detail/transactions.macro
Original file line number Diff line number Diff line change
Expand Up @@ -1194,6 +1194,72 @@ TRANSACTION(ttSPONSORSHIP_SET, 91, SponsorshipSet,
{sfRemainingOwnerCount, SoeOptional},
}))

/** This transaction type creates a confidential Ballot. */
#if TRANSACTION_INCLUDE
# include <xrpl/tx/transactors/voting/BallotCreate.h>
#endif
TRANSACTION(ttBALLOT_CREATE, 103, BallotCreate,
Delegation::NotDelegable,
featureConfidentialVoting,
NoPriv,
({
{sfMPTokenIssuanceID, SoeOptional},
{sfDomainID, SoeOptional},
{sfDigest, SoeRequired},
{sfURI, SoeOptional},
{sfOptionCount, SoeRequired},
{sfTallyPublicKey, SoeRequired},
{sfAuditorEncryptionKey, SoeOptional},
{sfOpenTime, SoeRequired},
{sfCloseTime, SoeRequired},
{sfZKProof, SoeRequired},
}))

/** This transaction type casts an encrypted vote on a Ballot. */
#if TRANSACTION_INCLUDE
# include <xrpl/tx/transactors/voting/BallotCastVote.h>
#endif
TRANSACTION(ttBALLOT_CAST_VOTE, 104, BallotCastVote,
Delegation::NotDelegable,
featureConfidentialVoting,
NoPriv,
({
{sfBallotID, SoeRequired},
{sfEncryptedVotes, SoeRequired},
{sfAuditorEncryptedVotes, SoeOptional},
{sfVoterPublicKey, SoeOptional},
{sfVoterEncryptedVotes, SoeOptional},
{sfZKProof, SoeRequired},
{sfBlindingFactor, SoeRequired},
{sfCredentialIDs, SoeOptional},
}))

/** This transaction type publishes the verifiable results of a Ballot. */
#if TRANSACTION_INCLUDE
# include <xrpl/tx/transactors/voting/BallotFinalize.h>
#endif
TRANSACTION(ttBALLOT_FINALIZE, 105, BallotFinalize,
Delegation::NotDelegable,
featureConfidentialVoting,
NoPriv,
({
{sfBallotID, SoeRequired},
{sfResults, SoeRequired},
{sfZKProof, SoeRequired},
}))

/** This transaction type deletes a Ballot or a BallotVote object. */
#if TRANSACTION_INCLUDE
# include <xrpl/tx/transactors/voting/BallotDelete.h>
#endif
TRANSACTION(ttBALLOT_DELETE, 106, BallotDelete,
Delegation::NotDelegable,
featureConfidentialVoting,
NoPriv,
({
{sfBallotID, 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
1 change: 1 addition & 0 deletions include/xrpl/protocol/jss.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ JSS(avg_bps_recv); // out: Peers
JSS(avg_bps_sent); // out: Peers
JSS(balance); // out: AccountLines
JSS(balances); // out: GatewayBalances
JSS(ballot_id); // in: LedgerEntry
JSS(base); // out: LogLevel
JSS(base_asset); // in: get_aggregate_price
JSS(base_fee); // out: NetworkOPs
Expand Down
Loading