Skip to main content

Coin Shuffling & Privacy Subsystem

The Shamwari Coin Shuffling & Privacy Subsystem (nxt.shuffling) provides a protocol-native, decentralized non-custodial coin mixing and account identity anonymization framework built directly into the core Shamwari ledger engine.

By executing coin shuffling directly within nxt.shuffling and managing automated client daemon participation via nxt.shuffling.Shuffler—rather than relying on centralized mixers, trusted intermediaries, or external virtual machine smart contracts—Shamwari achieves zero-counterparty risk, mathematically provable transaction unlinkability, post-quantum key transition, and robust blame management for malicious or non-responsive participants across BetaChains.


Core Capabilities & Architecture

  • Protocol-Native Non-Custodial Anonymization: Shuffling transactions run natively inside the ledger core (nxt.shuffling), eliminating central mixer fees, reentrancy vulnerabilities, and custodial theft risks.
  • Post-Quantum Recipient Key Decoupling: Integrates hybrid post-quantum keypairs (CRYSTALS-Kyber and CRYSTALS-Dilithium via ShamwariQKP), outputting unlinked funds to fresh, un-published recipient public keys (recipientPublicKey).
  • Automated Shuffler Client Engine (nxt.shuffling.Shuffler): Node-level daemon that automatically tracks shuffling state transitions, registers accounts, executes key exchanges/shuffles, verifies stage validity, and submits transaction attachments without manual user intervention.
  • Multi-Stage Mix State Machine: Operates across six distinct stages—REGISTRATION, PROCESSING, VERIFICATION, BLAME, DONE, and CANCELLED—to guarantee participant consensus and early deterministic fault detection.
  • Strict Recipient Integrity Safeguards: Enforces strict checks requiring recipient accounts to be brand-new (unregistered on-chain) to prevent address re-use and cross-chain transaction graph analysis.
  • Fault Tolerance & Resilient Re-Broadcasting: Includes a self-healing background retry engine (failedTransaction) that re-broadcasts transiently rejected shuffling attachments during block application cycles.

Shuffling Lifecycle & Stage Architecture

A coin shuffling operation progresses through a deterministic, multi-stage state machine driven by ShufflingHome event triggers and processed automatically by active Shuffler daemons:

┌───────────────────────────────────────────────┐
│ Shuffling Created / Issuer │
└───────────────────────┬───────────────────────┘


┌───────────────────────────────────────┐
│ REGISTRATION │
│ Participants join (submitRegister) │
└───────┬───────────────┬───────────────┘
│ │
Participant Quorum Met / │ │ Timeout / Cancellation
Full Registration │ │
▼ ▼
┌───────────────┐ ┌───────────────────────┐
│ PROCESSING │ │ CANCELLED │
│ Assignee Shift│ └───────────────────────┘
└───────┬───────┘

All Participants Shuffle │ Blame Triggered
& Pass Encrypted Inputs │ (Malicious/No-Show)
▼ ▼
┌───────────────┐ ┌───────────────────────┐
│ VERIFICATION │──────>│ BLAME │
└───────┬───────┘ └───────────────────────┘

All Signatures Validated │

┌───────────────┐
│ DONE │
└───────────────┘

Shuffling Stage Descriptions

Stage EnumFunctional PurposeAutomated Shuffler Action (Shuffler)
REGISTRATIONInitial pooling phase where accounts join the shuffling instance.Non-issuer participant daemons evaluate eligibility and invoke submitRegister().
PROCESSINGSequential decryption and permutation phase assigned to participant sequence.The assigned account (assigneeAccountId) shuffles key payloads and submits submitProcess().
VERIFICATIONOutput verification where participants validate final target recipient addresses.Every participant daemon verifies output hashes via verify() and signs the final state.
BLAMEFault identification protocol triggered upon non-compliance or bad data.Participants isolate failing keys, initiate cancel(), and attribute blame to offending accounts.
DONESuccessful completion; funds distributed to recipient accounts.Schedules cleanup expiration (SHUFFLER_EXPIRATION_DELAY_BLOCKS) and stops daemon.
CANCELLEDAborted shuffling sequence; locked funds unlocked and returned to participants.Schedules cleanup expiration (SHUFFLER_EXPIRATION_DELAY_BLOCKS) and releases resources.

Automated Shuffler Execution Engine (nxt.shuffling.Shuffler)

The Shuffler class acts as an automated background agent running on node instances. Once initiated by an account owner, it monitors the ledger for relevant shuffling events and constructs the required cryptographic proofs and transaction attachments.

1. Shuffler Instance Parameters

ParameterTypeOperational Role
betaChainBetaChainTarget BetaChain context hosting the active shuffling pool.
accountIdlong64-bit account identifier of the participant.
shamwariQKPShamwariQKPHybrid post-quantum keypair supplying signing and key-encapsulation functions.
recipientPublicKeyShamwariPublicKeyFresh, previously unused public key where shuffled funds will be delivered.
shufflingFullHashbyte[]32-byte cryptographic hash uniquely identifying the targeted shuffling instance.
feeRateQNTPerFXTlongDynamic transaction fee rate allocated for automated attachment submissions.
failedTransactionTransactionTransient transaction reference held for automatic re-broadcasting upon failure.

Operational Safeguards & Exception Hierarchy

To preserve network efficiency, protect privacy guarantees, and defend against denial-of-service (DoS) attacks, Shuffler.addOrGetShuffler() enforces strict operational guards prior to instantiation:

┌───────────────────────────────────┐
│ Shuffler Add Request Received │
└─────────────────┬─────────────────┘


┌───────────────────────────────────┐
│ Node Shuffler Capacity Check │
│ (Count <= MAX_SHUFFLERS Limit) │
└─────────────────┬─────────────────┘


┌───────────────────────────────────┐
│ Fresh Recipient Verification │
│ (Account.getAccount(key) == null)│
└─────────────────┬─────────────────┘


┌───────────────────────────────────┐
│ Account Control Policy Check │
│ (!contains(PHASING_ONLY) Control)│
└─────────────────┬─────────────────┘


┌───────────────────────────────────┐
│ Shuffler Daemon Activated │
└───────────────────────────────────┘

Key Security Safeguards

  1. Node Shuffler Cap (ShufflerLimitException): Prevents a single node from exceeding resource thresholds. The aggregate active shufflers across all mappings cannot exceed MAX_SHUFFLERS: ShufflersactiveMAX_SHUFFLERS=Nxt.getIntProperty("nxt.maxNumberOfShufflers")\sum \text{Shufflers}_{\text{active}} \le \text{MAX\_SHUFFLERS} = \text{Nxt.getIntProperty}("nxt.maxNumberOfShufflers")

  2. Fresh Recipient Account Rule (InvalidRecipientException): To prevent linkability and graph analysis, the output recipientPublicKey must not belong to an existing on-chain account: Account.getAccount(recipientPublicKey)==null\text{Account.getAccount}(recipientPublicKey) == \text{null} If an account with history or balance already exists for recipientPublicKey, initialization fails immediately.

  3. Recipient Uniqueness Guard (InvalidRecipientException): No two active shuffler daemons running on the node may share the same recipient account identifier: getRecipientShuffler(AccountId(recipientPublicKey))==null\text{getRecipientShuffler}(\text{AccountId}(recipientPublicKey)) == \text{null}

  4. Phasing Control Restriction (ControlledAccountException): Accounts subject to mandatory transaction phasing control (Account.ControlType.PHASING_ONLY) are prohibited from running automated shuffler daemons, as their outgoing attachments require deferred multi-signature approvals incompatible with real-time shuffling rounds.


Mathematical Mechanics & Expiration Logic

1. Participant Quorum Bounds

A shuffling instance operates with a bounded number of participants (NN), defined between network protocol limits and the specific shuffling parameter:

2NConstants.MAX_NUMBER_OF_SHUFFLING_PARTICIPANTS2 \le N \le \text{Constants.MAX\_NUMBER\_OF\_SHUFFLING\_PARTICIPANTS}

ActiveParticipantsshuffling.getParticipantCount()\text{ActiveParticipants} \le \text{shuffling.getParticipantCount}()

2. Expiration Delay Calculation

When a shuffling sequence reaches a terminal state (DONE or CANCELLED), the background daemon schedules automatic memory cleanup and listener unregistration at a target block height (Heightexpire\text{Height}_{\text{expire}}):

Heightexpire=CurrentBlockHeight+Constants.SHUFFLER_EXPIRATION_DELAY_BLOCKS\text{Height}_{\text{expire}} = \text{CurrentBlockHeight} + \text{Constants.SHUFFLER\_EXPIRATION\_DELAY\_BLOCKS}

The block application listener (AFTER_BLOCK_APPLY) evaluates expiration sets at every block:

IsExpired(shuffling)    Heightcurrent==Heightexpire\text{IsExpired}(shuffling) \iff \text{Height}_{\text{current}} == \text{Height}_{\text{expire}}

Upon expiration, the internal shufflingsMap removes the registered hash, emitting Event.SHUFFLER_STOPPED.


Lifecycle Event Matrix & Listener Architecture

Shuffler registers listeners on ShufflingHome and BlockchainProcessor to automate state transitions:

System SubmoduleListened EventInternal Operational Handler
ShufflingHomeSHUFFLING_CREATEDEvaluates new shuffling instance; non-issuer accounts submit registration (submitRegister).
ShufflingHomeSHUFFLING_PROCESSING_ASSIGNEDDetects when the local account is chosen as assigneeAccountId; executes vector permutation (submitProcess).
ShufflingHomeSHUFFLING_PROCESSING_FINISHEDTriggers output verification across all participants (verify).
ShufflingHomeSHUFFLING_BLAME_STARTEDInitiates fault localization sequence (cancel) to expose non-compliant nodes.
ShufflingHomeSHUFFLING_DONESchedules expiration block cleanup via scheduleExpiration().
ShufflingHomeSHUFFLING_CANCELLEDSchedules expiration block cleanup via scheduleExpiration().
BlockchainProcessorAFTER_BLOCK_APPLYPurges expired shufflers matching the current block height.
BlockchainProcessorAFTER_BLOCK_ACCEPTAttempts automatic re-broadcasting of cached failedTransaction instances.
BlockchainProcessorRESCAN_BEGINImmediately stops all running shuffler daemons (stopAllShufflers) to protect state consistency during chain rescans.

Resilience & Failed Transaction Engine

In peer-to-peer network environments, temporary validation errors or unconfirmed memory pool congestion can cause transaction broadcast rejections. Shuffler implements a self-healing retry mechanism:

// Logic from Shuffler static initializer
BlockchainProcessorImpl.getInstance().addListener(block ->
shufflingsMap.values().forEach(shufflerMap ->
shufflerMap.values().forEach(shuffler -> {
if (shuffler.failedTransaction != null) {
try {
TransactionProcessorImpl.getInstance().broadcast(shuffler.failedTransaction);
shuffler.failedTransaction = null;
shuffler.failureCause = null;
} catch (NxtException.ValidationException ignore) {
// Retry deferred to next block confirmation cycle
}
}
})
), BlockchainProcessor.Event.AFTER_BLOCK_ACCEPT
);

When an automated submission fails, the failedTransaction and failureCause references are retained. At each accepted block (AFTER_BLOCK_ACCEPT), the node automatically re-attempts broadcasting, ensuring participant daemons do not stall active shuffling pools due to transient network drops.


APIDescription
ShufflingCreateCreate shuffle
ShufflingRegisterRegister for shuffle
ShufflingProcessProcess shuffle
ShufflingVerifyVerify shuffle
ShufflingCancelCancel shuffle
GetShufflingGet shuffle info
GetShufflingParticipantsGet participants
GetAllShufflingsList all shuffles
GetAccountShufflingsGet account shuffles
GetAssignedShufflingsGet assigned shuffles
GetHoldingShufflingsGet holding shuffles
StartShufflerStart shuffler daemon
StopShufflerStop shuffler daemon

Primary Institutional & Commercial Use Cases

  • Post-Quantum Account Anonymization: Users move funds from legacy or public addresses into fresh post-quantum keypairs without leaving a traceable transaction graph on-chain.
  • Enterprise Treasury Privacy: Financial institutions shuffle internal operational funds before disbursing payroll or vendor payments, masking commercial liquidities from public inspection.
  • Merchant Payment Privacy: Point-of-sale vendors receive shuffled settlement outputs, preventing third-party observers from tracking daily sales volumes or customer payment histories.
  • Cross-Chain Liquidity Anonymization: Integrates with monetary system currencies (CURRENCY) and custom assets (TOTEM), allowing users to break ownership links prior to executing cross-chain atomic swaps.