> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shakesco.com/llms.txt
> Use this file to discover all available pages before exploring further.

# @shakesco/private

> JavaScript SDK for building privacy-preserving transfers

<span style={{display:"none"}}>For the complete documentation index, see [llms.txt](/llms.txt).</span>

<Note>
  **Built on the shoulders of giants** - Special thanks to [Umbra
  Cash](https://app.umbra.cash/) for pioneering stealth payment infrastructure.
</Note>

## What You'll Build

The `@shakesco/private` SDK lets you implement truly private crypto transactions. No one except the sender and receiver can link the payment to the recipient's known address.

<CardGroup cols={2}>
  <Card title="How It Works" icon="book-open" href="https://app.umbra.cash/faq#how-does-it-work-technical">
    Deep dive into stealth address cryptography
  </Card>

  <Card title="EIP-5564 Standard" icon="file-code" href="https://eips.ethereum.org/EIPS/eip-5564">
    Read the official Ethereum proposal
  </Card>
</CardGroup>

***

## Installation

```bash theme={null}
npm i @shakesco/private
```

Import the SDK components:

```javascript theme={null}
const shakesco = require("@shakesco/private");
const { KeyPair, RandomNumber, StealthKeyRegistry, utils } = shakesco;
const { IsUsersFunds, generateKeyPair, prepareSend } = shakesco;
```

<Warning>
  **Security Note:** This implementation assumes a single private key secures
  your wallet and that you're signing the same message hash. Multi-sig or
  threshold signatures require a different approach.
</Warning>

***

## Complete Integration Workflow

### Step 1: Check for Existing Stealth Keys

Before sending private transactions, verify if the recipient has registered stealth keys in the [Umbra registry](https://github.com/ScopeLift/umbra-protocol):

```javascript theme={null}
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const registry = new StealthKeyRegistry(provider);
const recipientId = "0x...."; // User's address

const { spendingPublicKey, viewingPublicKey } =
  await registry.getStealthKeys(recipientId);

if (!spendingPublicKey) {
  console.log("User needs to register stealth keys first");
}
```

<Accordion title="What are spending and viewing keys?">
  **Spending Keys** (`spendingPublicKey`)

  * Used to generate stealth addresses where funds are sent
  * Only the recipient can derive the private key to spend from these addresses

  **Viewing Keys** (`viewingPublicKey`)

  * Allow scanning for incoming private transactions
  * Can detect payments without exposing spending ability
  * Safe to use for monitoring wallets

  This separation means you can check for payments without risking your funds.
</Accordion>

***

### Step 2: Register Stealth Keys

If the user hasn't registered, you'll need to generate and register their key pairs.

<Tabs>
  <Tab title="Smart Wallets (ERC-4337)">
    For account abstraction wallets, register via a contract call:

    ```javascript theme={null}
    const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
    const signer = new ethers.Wallet(process.env.PRIV_KEY, provider);
    const signature = await signer.signMessage(messageHash);

    // Generate deterministic key pairs from signature
    const { spendingKeyPair, viewingKeyPair } = await generateKeyPair(signature);

    const registry = new StealthKeyRegistry(provider);
    const { spendingPrefix, spendingPubKeyX, viewingPrefix, viewingPubKeyX } =
      await registry.setSmartStealthKeys(
        spendingKeyPair.publicKeyHex,
        viewingKeyPair.publicKeyHex
      );
    ```

    Then execute the registration via your smart wallet:

    ```javascript theme={null}
    const calldata = accountABI.encodeFunctionData("execute", [
      "0x31fe56609C65Cd0C510E7125f051D440424D38f3",
      0,
      stealthABI.encodeFunctionData("setStealthKeys", [
        spendingPrefix,
        spendingPubKeyX,
        viewingPrefix,
        viewingPubKeyX,
      ]),
    ]);
    ```

    <Tip>
      Storing the `viewingKeyPair.privateKeyHex` for users is acceptable - it only enables transaction scanning, not spending. This lets you build features like automatic payment detection.
    </Tip>
  </Tab>

  <Tab title="EOAs (Regular Wallets)">
    For standard Ethereum wallets, register directly:

    ```javascript theme={null}
    const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
    const { spendingKeyPair, viewingKeyPair } = await generateKeyPair(setupSig);

    const registry = new StealthKeyRegistry(provider);
    const { spendingPrefix, spendingPubKeyX, viewingPrefix, viewingPubKeyX } =
      await registry.SetEOAStealthKeys(
        spendingKeyPair.publicKeyHex,
        viewingKeyPair.publicKeyHex
      );
    ```
  </Tab>
</Tabs>

***

### Step 3: Generate Stealth Address for Payment

Ready to send a private transaction? Generate a one-time stealth address:

```javascript theme={null}
const payee = "0x..."; // Recipient's address
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);

const { stealthKeyPair, pubKeyXCoordinate, encrypted } = await prepareSend(
  payee,
  provider
);

console.log(stealthKeyPair.address); // ← Send funds HERE
console.log(pubKeyXCoordinate); // ← Share with recipient
console.log(encrypted.ciphertext); // ← Share with recipient
```

<Steps>
  <Step title="Send funds to the stealth address">
    Transfer crypto to `stealthKeyPair.address` - this is a brand new address
    only the recipient can control
  </Step>

  <Step title="Publish announcement data">
    The recipient needs `pubKeyXCoordinate` and `encrypted.ciphertext` to prove
    ownership and spend the funds
  </Step>
</Steps>

***

### Step 4: Announce the Payment

<Warning>
  **Critical:** Without the announcement data, the recipient cannot access their
  funds!
</Warning>

Emit this event from your private transaction contract:

```solidity theme={null}
event Announcement(
  address indexed receiver,    // Stealth address
  uint256 amount,
  address indexed tokenAddress,
  bytes32 pkx,                 // pubKeyXCoordinate
  bytes32 ciphertext           // encrypted.ciphertext
);
```

<Accordion title="How recipients discover payments">
  Recipients scan the blockchain for `Announcement` events. Use indexing services for efficient scanning:

  * **[The Graph](https://thegraph.com/)** - Decentralized indexing protocol
  * **[Moralis](https://moralis.io/)** - Web3 data APIs
  * **Custom indexer** - Query RPC nodes directly (slower)

  These services let recipients quickly find all announcements directed to their registered keys.
</Accordion>

***

### Step 5: Scan for Incoming Funds

Recipients check if an announcement belongs to them:

```javascript theme={null}
IsUsersFunds(
  object.announcements[i],
  provider,
  secret, // Viewing private key
  sender
).then((data) => {
  if (data.isForUser) {
    // 🎉 This payment is for you!
    console.log("Amount:", data.amount);
    console.log("Token:", data.tokenAddress);
    console.log("Stealth address:", data.stealthAddress);
  }
});
```

***

### Step 6: Spend the Private Funds

Once you've confirmed funds belong to you, derive the private key to spend them:

```javascript theme={null}
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const signer = new ethers.Wallet(process.env.PRIV_KEY, provider);
const signature = await signer.signMessage(messageHash);

// Regenerate your key pairs (deterministic from signature)
const { spendingKeyPair, viewingKeyPair } = await generateKeyPair(signature);

// Decrypt the random number used to generate the stealth address
const payload = {
  ephemeralPublicKey: uncompressedPubKey,
  ciphertext: ciphertext,
};

const random = await viewingKeyPair.decrypt(payload);

// Compute the stealth address private key
const stealthPrivateKey = KeyPair.computeStealthPrivateKey(
  spendingKeyPair.privateKeyHex,
  random
);

// Now spend the funds!
const wallet = new ethers.Wallet(stealthPrivateKey, provider);
const txResponse = await wallet.sendTransaction({
  value: ethers.parseEther(value),
  to: destinationAddress,
});

await txResponse.wait();
console.log("✅ Private funds successfully transferred!");
```

***

## What's Next?

<Info>
  While stealth addresses provide strong privacy today, **zero-knowledge
  proofs** will eventually offer even better solutions. Until then, stealth
  payments are the best way to bring privacy to Ethereum transactions.
</Info>

***

## Additional Resources

<CardGroup cols={2}>
  <Card title="Umbra Protocol Docs" icon="book" href="https://app.umbra.cash/faq">
    Learn from the pioneers of stealth payments
  </Card>

  <Card title="EIP-5564 Discussion" icon="comments" href="https://ethereum-magicians.org/t/eip-5564-stealth-addresses/10614">
    Join the Ethereum community conversation
  </Card>

  <Card title="GitHub Repository" icon="github" href="https://github.com/shakesco/shakesco-private">
    View source code and contribute
  </Card>
</CardGroup>
