> ## 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/silent

> JavaScript SDK for receiving Bitcoin privately with silent payments

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

<Note>
  **Built by the community** - Special thanks to [Ruben
  Somsen](https://x.com/SomsenRuben) and [Josie Bake](https://x.com/josibake)
  for their groundbreaking work on BIP-352.
</Note>

## Installation

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

Import the SDK:

```javascript theme={null}
const shakesco = require("@shakesco/silent");
const {
  KeyGeneration,
  SilentPaymentDestination,
  SilentPaymentBuilder,
  ECPrivateInfo,
  Network,
  BitcoinScriptOutput,
  bip32,
  bip39,
} = shakesco;
```

***

## Integration Workflow

<Steps>
  <Step title="Generate silent payment address">
    Create a reusable address for receiving private payments
  </Step>

  <Step title="Create destination address">
    Generate a one-time taproot address for each payment
  </Step>

  <Step title="Scan for incoming funds">
    Detect payments without exposing spending keys
  </Step>

  <Step title="Spend received funds">Derive private keys and move Bitcoin</Step>
</Steps>

***

## Step 1: Generate Silent Payment Address

Choose your key generation method based on your use case:

<Tabs>
  <Tab title="From Private Keys (Recommended)">
    **Best for:** Non-wallet applications where users control their keys

    ```javascript theme={null}
    const b_scan = ""; // Scan private key
    const b_spend = ""; // Spend private key

    const keys = KeyGeneration.fromPrivateKeys({
      b_scan: b_scan,
      b_spend: b_spend,
      network: "testnet",
    });

    const silentPaymentAddress = keys.toAddress();
    console.log(silentPaymentAddress);
    ```

    <Tip>
      **Pro tip:** Make users sign a message, then derive `b_scan` and `b_spend` from the [ECDSA signature](https://cryptobook.nakov.com/digital-signatures/ecdsa-sign-verify-messages#ecdsa-sign):

      * Use `r` as `b_scan`
      * Use `s` as `b_spend` (or vice versa)

      This ensures cryptographically secure randomness without storing additional keys.
    </Tip>
  </Tab>

  <Tab title="From Mnemonic (Wallets)">
    **Best for:** Wallet providers managing user funds

    ```javascript theme={null}
    const mnemonic = ""; // 12, 15, or 24 word phrase
    const keys = KeyGeneration.fromMnemonic(mnemonic);
    const silentPaymentAddress = keys.toAddress();
    console.log(silentPaymentAddress);
    ```

    <Accordion title="Alternative: From HD key directly">
      ```javascript theme={null}
      const seed = bip39.mnemonicToSeedSync(mnemonic);
      const node = bip32.fromSeed(seed);
      const keys = KeyGeneration.fromHd(node);
      const silentPaymentAddress = keys.toAddress();
      ```
    </Accordion>
  </Tab>
</Tabs>

<Warning>
  If not using the signature-derived method, ensure you're using a
  **cryptographically secure random number generator** for `b_scan` and
  `b_spend`.
</Warning>

### Create a Change Address

**Critical for privacy:** Never send change to a public address after making silent payments.

```javascript theme={null}
const keys = KeyGeneration.fromPrivateKeys({
  b_scan: b_scan,
  b_spend: b_spend,
  network: "testnet",
});

// Always use label 0 for change (per BIP-352 spec)
const changeSilentPaymentAddress = keys.toLabeledSilentPaymentAddress(0);
console.log(changeSilentPaymentAddress.toAddress());
```

<Accordion title="Why this matters">
  **Scenario:** You send 10 silent payments to friends, then send change to your public address.

  **Result:** You've exposed:

  * ❌ Your own private transaction history
  * ❌ Your friends' payment patterns
  * ❌ Links between all 10 transactions

  **Solution:** Always use a labeled silent payment address for change.

  Reference: [BIP-352 Labels for Change](https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki#labels_for_change)
</Accordion>

***

## Step 2: Create Destination Address

Generate a unique taproot address for the payment:

```javascript theme={null}
// Parse recipient's silent payment address
const addressPubKeys = KeyGeneration.fromAddress(silentPaymentAddress);

// Your UTXO details
const vinOutpoints = [
  {
    txid: "367e24cac43a7d77621ceb1cbc1cf4a7719fc81b05b07b38f99b043f4e8b95dc",
    index: 1,
  },
];

const pubkeys = [
  "025c471f0e7d30d6f9095058bbaedaf13e1de67dbfcbe8328e6378d2a3bfb5cfd0",
];

const UTXOPrivatekey = ""; // Your UTXO private key

// Build the destination
const builder = new SilentPaymentBuilder({
  vinOutpoints: vinOutpoints,
  pubkeys: pubkeys,
}).createOutputs(
  [
    new ECPrivateInfo(
      UTXOPrivatekey,
      false // Set true if output is from taproot
    ),
  ],
  [
    new SilentPaymentDestination({
      amount: 1000, // Satoshis (1 BTC = 100,000,000 sats)
      network: Network.Testnet,
      version: 0,
      scanPubkey: addressPubKeys.B_scan,
      spendPubkey: addressPubKeys.B_spend,
    }),
  ]
);

// Get the destination taproot address
const destinationAddress = builder[silentPaymentAddress][0];
console.log("Send 1000 sats to:", destinationAddress);
```

<Info>
  **What you need:**

  <ul>
    <li>UTXO transaction ID and output index</li>
    <li>UTXO private key</li>
    <li>Amount in satoshis</li>
    <li>Recipient's scan and spend public keys (`B_scan`, `B_spend`)</li>
  </ul>
</Info>

***

## Step 3: Scan for Incoming Funds

<Warning>
  **Scanning trade-off:** This is the main drawback of silent payments - you
  must scan the blockchain to detect incoming transactions.
</Warning>

Check if a transaction belongs to you:

```javascript theme={null}
const vinOutpoints = [
  {
    txid: "367e24cac43a7d77621ceb1cbc1cf4a7719fc81b05b07b38f99b043f4e8b95dc",
    index: 1,
  },
];

const pubkeys = [
  "025c471f0e7d30d6f9095058bbaedaf13e1de67dbfcbe8328e6378d2a3bfb5cfd0",
];

const search = new SilentPaymentBuilder({
  vinOutpoints: vinOutpoints,
  pubkeys: pubkeys,
  network: Network.Testnet,
}).scanOutputs(
  keys.b_scan, // Your scan private key
  keys.B_spend, // Your spend public key
  [
    new BitcoinScriptOutput(
      "5120fdcb28bcea339a5d36d0c00a3e110b837bf1151be9e7ac9a8544e18b2f63307d",
      BigInt(1000)
    ),
  ]
);

const foundOutput =
  search[builder[keys.toAddress()][0].address.pubkey.toString("hex")].output;
console.log(foundOutput);
```

If the output matches the taproot address → it's yours! 🎉

<Accordion title="What you need for scanning">
  * Transaction input's `txid` and `output_index`
  * Public key from the output
  * Script and amount from the taproot address

  Learn more: [BIP-352 Scanning](https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki#scanning-silent-payment-eligible-transactions)
</Accordion>

***

## Step 4: Spend the Funds

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

```javascript theme={null}
const vinOutpoints = [
  {
    txid: "367e24cac43a7d77621ceb1cbc1cf4a7719fc81b05b07b38f99b043f4e8b95dc",
    index: 1,
  },
];

const pubkeys = [
  "025c471f0e7d30d6f9095058bbaedaf13e1de67dbfcbe8328e6378d2a3bfb5cfd0",
];

const private_key = new SilentPaymentBuilder({
  vinOutpoints: vinOutpoints,
  pubkeys: pubkeys,
}).spendOutputs(keys.b_scan, keys.b_spend);

console.log("Private key:", private_key);
```

<Tip>
  Use this private key with
  [bitcoinjs-lib](https://github.com/bitcoinjs/bitcoinjs-lib) to build and sign
  your taproot transaction.
</Tip>

***

## That's It

You've successfully implemented Bitcoin silent payments. Your users can now:

* ✅ Share a single address for all payments
* ✅ Receive Bitcoin privately
* ✅ Maintain transaction unlinkability
* ✅ Avoid notification transaction fees

***

## Additional Resources

<CardGroup cols={2}>
  <Card title="BIP-352 Specification" icon="book" href="https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki">
    Complete technical specification
  </Card>

  <Card title="bitcoinjs-lib" icon="code-branch" href="https://github.com/bitcoinjs/bitcoinjs-lib">
    Build Bitcoin transactions in JavaScript
  </Card>

  <Card title="Silent Payments Explained" icon="graduation-cap" href="https://silentpayments.xyz/docs/explained/">
    Protocol deep dive
  </Card>

  <Card title="ECDSA Signatures" icon="signature" href="https://cryptobook.nakov.com/digital-signatures/ecdsa-sign-verify-messages">
    Learn about signature-based key derivation
  </Card>
</CardGroup>
