bitcoinjs / bitcoinjs-lib

A javascript Bitcoin library for node.js and browsers.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How can I add derivation (or any other way to make the address be a new one each time)?

5vx opened this issue · comments

I have this relatively simple API route set up on my React website generating a BIP-32 P2WPKH Bitcoin payment address derived from a certain public key. Thing is, it generates the same address every time. I'm aware that's the intended behavior, but how can I make it generate a different one each time (all the while still being derived from the same public key)?

If possible, I don't exactly want to do this using a private key / seed since I'm planning to run this on a serverless host, and not locally.

Looked around in the documentation and couldn't find a concise answer to this. The only lead I found was the randomKey function using ECPair, but that doesn't really accomplish what I'm trying to do here.

import { NextRequest } from 'next/server';
import * as bitcoinjs from 'bitcoinjs-lib'
import * as crypto from 'crypto';

const yourpubkey = Buffer.from('removed key', 'hex');
const network = bitcoinjs.networks.bitcoin; 

export async function GET(request: NextRequest) {
    try {
        const payment = bitcoinjs.payments.p2wpkh({ pubkey: yourpubkey, network }).address;
        return new Response(payment, { status: 200 });
    } catch (error) {
        return new Response('Error.', { status: 500 });
    }
}

You need to hold some sort of state counter.

Your BIP32 idea was fine, but you need to derive 0 on the first request, then 1 on the 2nd request, then 2 on the 3rd request etc etc etc.

Do you have the original BIP32 code? I can tell you where to add the extra derive numbers, then you just need to think of how to store that "last generated number" state. (database, redis, sqlite, file, etc.)

Do you have the original BIP32 code

Sorry, do you mean the master public key/zpub?

Do you have the original BIP32 code? I can tell you where to add the extra derive numbers, then you just need to think of how to store that "last generated number" state. (database, redis, sqlite, file, etc.)

I was under the impression it could be something like a randomly generated number, does it have to be incremental?

Sorry, do you mean the master public key/zpub?

No. You said you tried BIP32. That means you wrote source code that generates the key using BIP32. I would like to see that source code.

does it have to be incremental?

You can choose any number you want, but you need to be able to recover it.

It's easier to use sequential numbers and just store 1 number in the database ("the last number we used") instead of storing every single number you have used up until this point. (This also requires a collision check in the database if you do it this way)

Edit: Think about it this way: let's say you generate 1645365158 for the first user and 1283118333 for the second user, and they make their deposits etc.

Then 5 days later, you go to generate a new number for a new user... if you don't remember 1645365158 and 1283118333 then what happens if you accidentally generate the same 1283118333 again? You won't know that this is bad, and your application will not throw an error or retry to generate another number.

Then 5 days later, you go to generate a new number for a new user... if you don't remember 1645365158 and 1283118333 then what happens if you accidentally generate the same 1283118333 again? You won't know that this is bad, and your application will not throw an error or retry to generate another number.

To be clear, I'm not generating a wallet for an user or anything like that. The way it works is the API generates a new address, belonging to my wallet, every time. It's meant to be for one-time payments to me.

To be clear, I'm not generating a wallet for an user or anything like that. The way it works is the API generates a new address, belonging to my wallet, every time. It's meant to be for one-time payments to me.

It doesn't matter whether it's a user or yourself...

Think about it...

  1. You store 0 state anywhere.
  2. You derive the address at 1283118333 and once you show the sender the address at 1283118333 your app forgets 1283118333 because it stores 0 state.
  3. You wait a few days, because you don't need to send any bitcoin.
  4. 3 days later you want to send bitcoin... your wallet has your private seed............ and that's it.
  5. How do you recover the private key at index 1283118333 if you don't know the number? Just brute force and try every single number?... that's going to take years.

To be clear, I'm not generating a wallet for an user or anything like that. The way it works is the API generates a new address, belonging to my wallet, every time. It's meant to be for one-time payments to me.

It doesn't matter whether it's a user or yourself...

Think about it...

  1. You store 0 state anywhere.
  2. You derive the address at 1283118333 and once you show the sender the address at 1283118333 your app forgets 1283118333 because it stores 0 state.
  3. You wait a few days, because you don't need to send any bitcoin.
  4. 3 days later you want to send bitcoin... your wallet has your private seed............ and that's it.
  5. How do you recover the private key at index 1283118333 if you don't know the number? Just brute force and try every single number?... that's going to take years.

I'm kind of a bitcoin noob (trying to learn more though). I was under the impression receiving addresses don't have private keys, and only wallets do? I am linking it to an existing wallet (whose public key I am inputting as the yourpubkey constant, not an entirely new wallet that is being generated there on the fly.

What you are proposing will not work.

I was under the impression receiving addresses don't have private keys, and only wallets do?

That is incorrect. The below explanation is how wallets actually work.

Pre-bip32 wallets:

  1. Generate random 256 bit private key
  2. Calculate public key from private key
  3. Calculate address from public key
  4. Show sender your address
  5. Repeat as necessary, your "wallet file" contains every single private key you have generated until now, you can't forget to save this or else you will lose money. (if someone sends BTC to address A but you didn't save private key A you can not recover those BTC)

Post-bip32 wallets (which usually also include BIP39 recovery phrases):

  1. Generate a BIP39 recovery seed
  2. Calculate the BIP32 master private key from the recovery seed
  3. Calculate the wallet's master public key from the master private key and your path derivation BIP (44, 49, 84, etc)
  4. Store the master public key wherever you need to generate multiple addresses for your wallet.
  5. Generate public keys from the master public key using x/y paths where x is 0 for receiving addresses and 1 is for change addresses. y is sequential (starting from 0)
  6. Every time the user clicks "generate new address" you increase the wallet file's "last y used" number and if the next number is 6 then you derive public key 0/6, calculate the public key, then the address
  7. Repeat as necessary, the wallet file only needs to save either the BIP39 recovery seed or the BIP32 master private key, and it needs to store "the last address generated" index.
  8. When recovering any BTC sent to 0/6 you will take the master private key, the path derivation BIP's root, and the sub path (0/6 in our example) and recover the private key of the public key we generated in the earlier step. That private key is used for signing.