/** * Note Encryption Module * * Implements AES-256-GCM encryption for Railgun transaction notes. * This is used to encrypt the change note in partial unshield transactions. * * For partial unshield (01x02 circuit): * - Output 1: Unshield (no ciphertext needed - recipient is public address) * - Output 2: Change note (requires commitmentCiphertext for receiver to decrypt) * * The commitmentCiphertext allows the receiver (self in case of change) to: * 1. Discover the note when scanning the blockchain * 2. Decrypt the note details (value, token, random) * 3. Spend the note in future transactions */ import type { ViewingKeyPair } from './key-derivation'; /** * Output type enum (matches @railgun-community/engine) */ export declare enum OutputType { Transfer = 0, BroadcasterFee = 1, Change = 2 } /** * Structure for the commitment ciphertext that goes into boundParams * This matches the Solidity struct in the Railgun contract */ export interface CommitmentCiphertext { ciphertext: [string, string, string, string]; blindedSenderViewingKey: string; blindedReceiverViewingKey: string; annotationData: string; memo: string; } /** * Parameters for encrypting a change note */ export interface EncryptChangeNoteParams { noteRandom: string; noteValue: bigint; tokenHash: string; senderMasterPublicKey: bigint; receiverMasterPublicKey: bigint; senderViewingPrivateKey: Uint8Array; receiverViewingPublicKey: Uint8Array; memoText?: string; } /** * Generate a random sender random value (15 bytes) * This is used for blinding the sender address */ export declare function generateSenderRandom(): string; /** * Generate a random note random value (16 bytes) */ export declare function generateNoteRandom(): string; /** * Encrypt a change note for a partial unshield transaction * * This creates the commitmentCiphertext structure needed for the change note. * The encryption uses: * 1. Blinded viewing keys (for key agreement) * 2. ECDH shared secret (for AES key derivation) * 3. AES-256-GCM encryption (for the note data) * * @param params - Encryption parameters * @returns CommitmentCiphertext ready for boundParams */ export declare function encryptChangeNote(params: EncryptChangeNoteParams): Promise; /** * Create commitmentCiphertext for a change note in partial unshield * * This is a simplified version that uses the same wallet for sender and receiver * (since the change goes back to self). * * @param changeNoteRandom - Random value for the change note (16 bytes hex) * @param changeNoteValue - Value of the change note in wei * @param tokenHash - Token hash (32 bytes) * @param masterPublicKey - User's master public key * @param viewingKeyPair - User's viewing key pair * @returns Array with single CommitmentCiphertext for the change note */ export declare function createChangeNoteCommitmentCiphertext(changeNoteRandom: string, changeNoteValue: bigint, tokenHash: string, masterPublicKey: bigint, viewingKeyPair: ViewingKeyPair): Promise; /** * Format a random bigint value as a 16-byte hex string for note encryption * * The change note random used in the commitment should match the random * used for encryption. The random is stored as a bigint but needs to be * formatted as a 16-byte hex string (32 chars without 0x prefix) for encryption. * * @param random - The random value as bigint (e.g., from generateSecureRandom()) * @returns 16-byte hex string (32 chars) without 0x prefix */ export declare function formatNoteRandomForEncryption(random: bigint): string; /** * Generate a secure 16-byte random value as a hex string * This matches the format expected by TransactNote */ export declare function generateNoteRandomHex(): string; /** * Decrypted change note data */ export interface DecryptedChangeNote { masterPublicKey: bigint; tokenHash: string; random: bigint; value: bigint; } /** * Decrypt a change note from its ciphertext * * This reverses the encryption done by encryptChangeNote(). * Used to discover change notes from partial unshield transactions. * * Like Railgun engine, we try BOTH blinded keys: * - blindedSenderViewingKey: for notes we're receiving * - blindedReceiverViewingKey: for notes we sent (to track our own sends) * * @param ciphertext - The 4 ciphertext fields [iv+tag, data0, data1, data2] * @param blindedSenderViewingKey - The blinded SENDER viewing key * @param viewingPrivateKey - Our viewing private key * @param blindedReceiverViewingKey - Optional blinded RECEIVER viewing key (try both) * @param memo - The memo field from the event (4th encrypted block). AES-GCM tag * covers all 4 encrypted blocks, so this MUST be included for decryption. * @returns Decrypted note data or null if decryption fails */ export declare function decryptChangeNote(ciphertext: [string, string, string, string], blindedSenderViewingKey: string, viewingPrivateKey: Uint8Array, blindedReceiverViewingKey?: string, memo?: string): Promise;