Skip to content

Instantly share code, notes, and snippets.


Jeremy Spilman jspilman

View GitHub Profile
jspilman / Stealth Payments
Last active Aug 19, 2017
Working implementation of stealth payments in Bitcoin using OP_RETURN! See TxID: 6e8576d6f65947b249a19402b6359c5a490abf67d50869a18518ccae41f94419 on Test NeT
View Stealth Payments
// BIP32 Wallet
byte[] entropy = Util.DoubleSHA256(Encoding.ASCII.GetBytes("Stealth Address"));
HdNode wallet = HdNode.Create(entropy, mainNet: false).GetSecretChild(0);
// A TxID on Test-Net with 1BTC in Vout[1], spendable by wallet/0'/0'
byte[] unspentPubKey = wallet.GetSecretChild(0, 0).PublicKey;
byte[] unspentPrivKey = wallet.GetSecretChild(0, 0).PrivateKey;
string unspentAddr = Util.PubKeyToAddress(unspentPubKey, mainNet: false);
byte[] unspentTxId = Util.HexToBytes("4b8fd9c4f5cb233c687e3e883f7c284f9abc2698dd08f1ec6770f488a27a9704");
TxOut unspentTxOut = TxOut.PayToPubKeyHash(Util.Amount("1"), unspentPubKey);
View Payment Protocol Security
Payment Protocol uses X.509 certs to sign a Payment Request. This allows wallets to display meta-data from the cert
to the payer instead of the address, which should make it easier to verify where money is being sent, and prevent
an attacker from changing an address displayed to a user so that coins are sent to the wrong place.
The difficulty is that Payment Requests must be generated live, and therefore the cert used to sign those requests
must also be live, exposing the cert to theft similar to a hot wallet. The question... is there a way to sign something
once, offline, which verifies the address belongs to the payee?
1) Given a root or intermediate certificate 'parent' cert which is kept offline, and a child certificate of 'parent'
which is kept hot on the payment server.
jspilman / PaymentChannel.cs
Last active Jun 30, 2021
Proof of Concept for Payment Channels
View PaymentChannel.cs
// 0) User and AP negotiate how much to escrow, who pays the fees, and how far in the future nLockTime
// will be set (how long user’s funds will be tied if AP doesn’t close the channel)
long apUnspent = Util.Amount("0.27");
long userUnspent = Util.Amount("6.123");
long escrowAmount = Util.Amount("5");
long payerFee = 0;
long apFee = Util.Amount(".0005");
long userChange = userUnspent - escrowAmount - payerFee;
long apChange = apUnspent - apFee;
View gist:5287991

Secure Wallet Extensions through Payment Protocol

The first rule of fight club is... 'Never trust a private key to a third party.'

Jeremy Spilman (
April 2, 2013
DRAFT v0.3