Skip to content

Commit f87b5b0

Browse files
committed
feat: initial commit
1 parent a2f52f2 commit f87b5b0

File tree

1 file changed

+91
-0
lines changed

1 file changed

+91
-0
lines changed
+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import BIP32Factory from 'bip32';
2+
import * as ecc from 'tiny-secp256k1';
3+
import { describe, it } from 'mocha';
4+
5+
import { regtestUtils } from './_regtest';
6+
import * as bitcoin from '../..';
7+
import { toXOnly } from '../../src/psbt/bip371';
8+
9+
const rng = require('randombytes');
10+
const regtest = regtestUtils.network;
11+
bitcoin.initEccLib(ecc);
12+
const bip32 = BIP32Factory(ecc);
13+
14+
describe('bitcoinjs-lib (silent payments)', () => {
15+
it('can create (and broadcast via 3PBP) a simple silent payment', async () => {
16+
const { senderKeyPair, receiverKeyPair, sharedSecret } = initParticipants();
17+
// this is what the sender sees/scans
18+
const silentPublicKey = toXOnly(receiverKeyPair.publicKey);
19+
20+
// the input being spent
21+
const { output: p2wpkhOutput } = bitcoin.payments.p2wpkh({
22+
pubkey: senderKeyPair.publicKey,
23+
network: regtest,
24+
});
25+
26+
// amount from faucet
27+
const amount = 42e4;
28+
// amount to send
29+
const sendAmount = amount - 1e4;
30+
// get faucet
31+
const unspent = await regtestUtils.faucetComplex(p2wpkhOutput!, amount);
32+
33+
const psbt = new bitcoin.Psbt({ network: regtest });
34+
psbt.addInput({
35+
hash: unspent.txId,
36+
index: 0,
37+
witnessUtxo: { value: amount, script: p2wpkhOutput! },
38+
});
39+
40+
// destination
41+
const { address } = bitcoin.payments.p2tr({
42+
internalPubkey: silentPublicKey,
43+
hash: sharedSecret,
44+
network: regtest,
45+
});
46+
psbt.addOutput({ value: sendAmount, address: address! });
47+
48+
psbt.signInput(0, senderKeyPair);
49+
50+
psbt.finalizeAllInputs();
51+
const tx = psbt.extractTransaction();
52+
const rawTx = tx.toBuffer();
53+
54+
const hex = rawTx.toString('hex');
55+
56+
await regtestUtils.broadcast(hex);
57+
await regtestUtils.verify({
58+
txId: tx.getId(),
59+
address: address!,
60+
vout: 0,
61+
value: sendAmount,
62+
});
63+
});
64+
});
65+
66+
function initParticipants() {
67+
const receiverKeyPair = bip32.fromSeed(rng(64), regtest);
68+
const senderKeyPair = bip32.fromSeed(rng(64), regtest);
69+
70+
71+
const senderSharedSecret = ecc.pointMultiply(
72+
receiverKeyPair.publicKey,
73+
senderKeyPair.privateKey!,
74+
);
75+
76+
const receiverSharedSecred = ecc.pointMultiply(
77+
senderKeyPair.publicKey,
78+
receiverKeyPair.privateKey!,
79+
);
80+
81+
if (!toBuffer(receiverSharedSecred!).equals(toBuffer(senderSharedSecret!)))
82+
throw new Error('Shared secret missmatch.');
83+
84+
return {
85+
receiverKeyPair,
86+
senderKeyPair,
87+
sharedSecret: toXOnly(Buffer.from(receiverSharedSecred!)),
88+
};
89+
}
90+
91+
const toBuffer = (a: Uint8Array) => Buffer.from(a);

0 commit comments

Comments
 (0)