walletbeat icon indicating copy to clipboard operation
walletbeat copied to clipboard

Wallet attribute: Stealth address support

Open polymutex opened this issue 10 months ago • 0 comments

I am working on an attribute for private transaction support, and looking for feedback as to whether a wallet's implementation of stealth addresses protects the privacy of the user. At a high level, we want to ensure:

  • Receiving funds under stealth addresses should not allow any third-party to learn the fact that multiple such addresses belong to the same user. This is tricky, due to the difficulties of enumerating and scanning multiple addresses onchain without tipping off the RPC provider that these addresses belong to the same user. However, it is kind of the whole point of stealth addresses, so it can't be ignored.
  • Sending to a stealth address doesn't cause anyone but the sender and the recipient (i.e. no third party) to learn more than one of the following pieces of information:
    • Sender's identity
    • Sender's IP
    • Receiver's identity
    • Receiver's IP
    • Receiver's newly-generated receiving address
  • Spending funds that were sent to stealth addresses is tricky in the same way that UTXO-like coin control is. Wallets that support spending funds sent to stealth addresses need to allow the user to have some control over which (set of) stealth addresses funds may be spent from.

Here's the schema I have come up with:

import { WithRef } from '@/schema/reference';

/** Support for private transactions. */
export interface TransactionPrivacy {
  /** Support for stealth addresses. */
  stealthAddresses: StealthAddressSupport;
}

/** Support for stealth addresses. */
export type StealthAddressSupport =
  | {
      /** Level of support for stealth address. */
      support: 'NOT_SUPPORTED';
    }
  | {
      support: 'SENDING_ONLY';

      /** Info about how the wallet supports sending to stealth addresses. */
      sending: WithRef<StealthAddressSendingSupport>;
    }
  | {
      support: 'RECEIVING_ONLY';

      /** Info about how the wallet supports receiving funds using stealth addresses. */
      receiving: WithRef<StealthAddressReceivingSupport>;
    }
  | {
      support: 'SENDING_AND_RECEIVING';
      sending: WithRef<StealthAddressSendingSupport>;
      receiving: WithRef<StealthAddressReceivingSupport>;

      /** Info about how the wallet supports spending funds that were sent to stealth addresses. */
      spending: WithRef<StealthAddressSpendingSupport>;
    };

/**
 * Info about how the wallet supports sending to stealth addresses.
 *
 * Goal: No third party should learn more than one piece of information below.
 */
export interface StealthAddressSendingSupport {
  /** Does a third-party learn a username that belongs to the recipient? */
  thirdPartyLearnsRecipientUsername: boolean;

  /** Does a third-party learn an address from the recipient? */
  thirdPartyLearnsRecipientAddress: boolean;

  /** Does a third-party learn a username that belongs to the sender? */
  thirdPartyLearnsSenderUsername: boolean;

  /** Does a third-party learn an address from the sender? */
  thirdPartyLearnsSenderAddress: boolean;

  /** Does a third-party learn the sender's IP address? */
  thirdPartyLearnsSenderIp: boolean;
}

/**
 * Info about how the wallet supports receiving funds using stealth addresses.
 *
 * Goal: No third party should learn a correlation between one receiving
 * address and anything else (another receiving address, or recipient IP).
 */
export interface StealthAddressReceivingSupport {
  /** Whether a third-party is given a private key allowing them to view all of a user's stealth addresses. */
  thirdPartyLearnsPrivateViewKey: boolean;

  /** When generating a new stealth address, does a third-party learn this address? */
  thirdPartyLearnsNewlyGeneratedAddress: boolean;

  /** Can a third-party learn at least one previously-generated stealth address at any point? */
  thirdPartyLearnsPreviouslyGeneratedAddress:
    | 'NONE'
    | 'SINGLE_ADDRESS'
    | 'MULTIPLE_ADDRESSES_AT_ONCE'
    | 'MULTIPLE_ADDRESSES_CLOSE_IN_TIME';

  /** Can a third-party learn the recipient's IP address? */
  thirdPartyLearnsRecipientIp: boolean;
}

/**
 * Info about how the wallet supports spending funds that were sent to stealth addresses.
 *
 * Goal: The user should be able to understand and control whether they are
 * associating funds between multiple receiving addresses when spending them,
 * as this creates a permanent record of association between these addresses.
 */
export type StealthAddressSpendingSupport =
  | {
      /** Can the wallet spend funds that were sent to stealth addresses? */
      userCanSpendPrivateFunds: 'NOT_SUPPORTED';
    }
  | {
      /** Can the wallet spend funds that were sent to stealth addresses? */
      userCanSpendPrivateFunds: 'SUPPORTED';

      /** When spending funds sent to stealth addresses, can the user control which stealth addresses funds come from? */
      coinControl:
        | {
            /**
             * Support for selecting the receiving addresses from which funds are being spent.
             *
             * Goal: The user should have at least one way to control which addresses funds
             * are being spent from.
             */
            support: 'OPTIONAL' | 'EXPLICIT';

            /** Support for spending funds from only a single stealth address at a time. */
            oneAddressOnly: boolean;

            /** Support for selecting individual addresses from which funds are being spent. */
            byIndividualAddress: boolean;

            /** Support for selecting labeled sets of addresses from which funds are being spent. */
            byLabeledSets: boolean;
          }
        | {
            support: 'NO';
          };
    };

polymutex avatar Feb 15 '25 02:02 polymutex