npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@shakesco/silent

v1.0.5

Published

Bitcoin Silent Payments

Downloads

66

Readme

@shakesco/silent

special credit to Ruben Somsen and Josi Bake

Install

To get started, install the package with your package manager.

npm i @shakesco/silent

After installing:

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

Generate Silent Payment address

This will generate the silent payment address. It prepares a receiver to receive silent payments. You can generate a silent payment address in three ways:

Private Keys

If you are not a wallet provider, use this method. More specifically, you can make the user sign a message and then derive b_scan and b_spend from the resulting signature (Use r as b_scan and s as b_spend or vice versa).

⚠️ If you are not using this method, ensure that a cryptographically secure random number generator is being used.

function main() {
    const b_scan = "";
    const b_spend = "";
    const keys = KeyGeneration.fromPrivateKeys({
    b_scan: b_scan,
    b_spend: b_spend,
    network: "testnet",
    });
    const silentPaymentAddress = keys.toAddress();
    console.log(silentPaymentAddress); // Silent payment address
}
Mnemonic and HD Key

If you are a wallet provider, use this method.

function main() {
  const mnemonic = ""; // 12, 15, 24 word phrase
  const keys = KeyGeneration.fromMnemonic(mnemonic);
  const silentPaymentAddress = keys.toAddress();
  console.log(silentPaymentAddress);

// const seed = bip39.mnemonicToSeedSync(mnemonic);
// const node = bip32.fromSeed(seed);
// const keys = KeyGeneration.fromHd(node);
// const silentPaymentAddress = keys.toAddress();
// console.log(silentPaymentAddress);
}

Create a change address

Create a change silent payment address that won't break privacy. Consider a scenario where you have sent 10 silent payments to friends and have sent the change to your public address. In this case, you would have compromised not only your private transactions but also those of your friends. So, let's create a change address:

function main() {
    const b_scan = "";
    const b_spend = "";
    const keys = KeyGeneration.fromPrivateKeys({
    b_scan: b_scan,
    b_spend: b_spend,
    network: "testnet",
    });
    const changeSilentPaymentAddress = keys.toLabeledSilentPaymentAddress(0); //should always be zero!(https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki#labels_for_change)
    console.log(changeSilentPaymentAddress.toAddress()); // change silent payment address
}

Create a taproot address destination

Here is where you create a destination address for the user to send to a newly generated Taproot address, derived from the receiver's silent payment address generated above. You will need:

  1. The Unspent Transaction Output(UTXO) of the user, hash and output_index.
  2. The private key of the UTXO in 1 above.
  3. Amount the user wants to send. Should be in satoshis(1 BTC = 1006 satoshis)
  4. Finally, the public keys of the 2 secret shares, B_scan and B_spend
function main() {
    const addressPubKeys = KeyGeneration.fromAddress(silentPaymentAddress);
    const vinOutpoints = [
    {
        txid: "367e24cac43a7d77621ceb1cbc1cf4a7719fc81b05b07b38f99b043f4e8b95dc",
        index: 1,
    },
    ];

    const pubkeys = [
    "025c471f0e7d30d6f9095058bbaedaf13e1de67dbfcbe8328e6378d2a3bfb5cfd0",
    ];
    const UTXOPrivatekey = "";
    const builder = new SilentPaymentBuilder({
    vinOutpoints: vinOutpoints,
    pubkeys: pubkeys,
    }).createOutputs(
    [
        new ECPrivateInfo(
        UTXOPrivatekey,
        false // If the output is from a taproot address
        ),
    ],
    [
        new SilentPaymentDestination({
        amount: 1000,
        network: Network.Testnet,
        version: 0,
        scanPubkey: addressPubKeys.B_scan,
        spendPubkey: addressPubKeys.B_spend,
        }),
    ]
    );
    console.log(builder[silentPaymentAddress][0]); // Access the taproot address and send 1000 satoshis
}

Scan for funds

Scanning for funds is a drawback of silent payments. So below is how you can check if a certain transaction belongs to a user. You will need:

  1. The transaction input's tx_hash and output_index.
  2. Public key outputted.
  3. Script and amount from the outputted taproot address

For more info, go here

function main() {
    const vinOutpoints = [
    {
        txid: "367e24cac43a7d77621ceb1cbc1cf4a7719fc81b05b07b38f99b043f4e8b95dc",
        index: 1,
    },
    ];

    const pubkeys = [
    "025c471f0e7d30d6f9095058bbaedaf13e1de67dbfcbe8328e6378d2a3bfb5cfd0",
    ];
    const search = new SilentPaymentBuilder({
    vinOutpoints: vinOutpoints,
    pubkeys: pubkeys,
    network: Network.Testnet,
    }).scanOutputs(keys.b_scan, keys.B_spend, [
    new BitcoinScriptOutput(
        "5120fdcb28bcea339a5d36d0c00a3e110b837bf1151be9e7ac9a8544e18b2f63307d",
        BigInt(1000)
    ),
    ]);

    console.log(
    search[builder[keys.toAddress()][0].address.pubkey.toString("hex")].output
    );
}

If the address above matches the taproot address from the output in the transaction, it belongs to the user.

Spend funds

If the funds belong to the user, they can spend like so:

First, you will need:

  1. The transaction input's tx_hash and output_index.
  2. Public key outputted.
  3. Receiver's spend and scan private keys.
function main() {
     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); // use this to build a taproot transaction with bitcoinjs: https://github.com/bitcoinjs/bitcoinjs-lib
}

The receiver can use private_key to spend the funds!

Thats it! 🎊🎊🎊

Contribute

If you love what we do to progress privacy, contribute to further development