bitgo & securing bitcoin with p2sh
DESCRIPTION
This talk was presented at the SF Bitcoin Dev meetup on March 3, 2014. It's a pretty low level talk, and we covered many topics from how transaction signing works, how scripts work, how multi-signature transactions work, what are standard transactions, what are P2SH transactions, and finally, how to use the early BitGo APIs to do your own P2SH wallet creation and transaction signing. If you wish to use the BitGo APIs, please contact me.TRANSCRIPT
Securing Bitcoin With P2SH
● Mike Belshe● CTO / Co-Founder of BitGo. Startup Addict.● Early Chrome Engineer● Co-creator of SPDY, becoming HTTP/2.0● Co-founder of Lookout Software, email
search.
Who Am I?
Agenda
Part 1: The Theory● Signatures - how
do they work?○ Inputs & Outputs○ Script Pub Key○ Script Signature
● The P2SH Overlay
Part 2: The Code● BitGo APIs
○ HTTP Service○ JavaScript library
● Let’s create a P2SH address!
● Let’s create a transaction
Part 1: The Theory
Anatomy of a Transaction
Transaction
● Version● # of Inputs● List of inputs● # of Outputs● List of outputs● Lock time
Input #2
Input #1
Output #1
Anatomy of An Output
Output
● Value (in Satoshis)● ScriptPub
½ of the Script“Deposit Script”
Anatomy of An Input
Input
● txHash of input● Output index● Script Signature
½ of the Script“Withdrawal Script”
Transaction Chain
Transaction #a1111
Inputs: None
Output #0: 50 BTC
Transaction #b2222
Input #0: #a1111:0
Output #0: 25 BTCOutput #1: 25 BTC
Transaction #c3333
Input #0: #b2222:1
Output #0: 5 BTCOutput #1: 20 BTC
Transaction #d4444
Input #0: #b2222:0Input #1: #c3333:1
Output #0: 35 BTCOutput #1: 10 BTC
Unspents
Anatomy of A Transaction Script
Script Signature (from the new transaction)
Script Pub Key(from the old transaction)
Transaction #a1111
Inputs: None
Output #0: 50 BTC
Transaction #b2222
Input #0: #a1111:0
Output #0: 25 BTCOutput #1: 25 BTC
Script
1. Take Script Pub Key from the output to spend
2. Append it to Script Signature from input in spending transaction
3. Use this as a stack of commands to run as a script
What Does A Script Look Like?● Scripting language is
complicated● Scripts can be large and
expensive to run● Not turing complete● bitcoind does not
implement the full language○ Rely on “standard
transactions”
Sampling of Script OP CODES
OP_0, OP_FALSE Push 0 onto stack
OP_PUSHDATA[1-4] Push a number of bytes on stack
OP_DUP Duplicate top of stack
OP_IFDUP If top of stack is not zero, duplicate it
OP_NUMEQUAL Returns 1 if the numbers are equal
OP_SHA256 Hash the contents of the stack with SHA-256
OP_RIPEMD160 Hash the contents of the stack with RIPEMD-160
OP_CHECKSIG Hash the transaction inputs/outputs; the sig must be a valid for the given pub key
etc Overall, there are < 100 op codes
Standard Transaction Types & ScriptPub
Pay to PubKey● old● used in coinbase.<PubKey>OP_CHECKSIG
Pay to PubKey Hash● Common form
OP_DUP
OP_HASH160
<PubKeyHash>
OP_EQUALVERIFY
OP_CHECKSIG
MultiSig M of N● (BIP 11)
<m>
<PubKey>
…
<PubKey>
<n>
<OP_CHECKMULTISIG>
The Need For P2SH
● Existing “Standard Transactions” require the transaction creator to specify the ScriptPub portion of the script
● Wanted a way to let the receiver specify the script.○ Faster adoption of new formats (like BIP11: M of N)○ Applies to all transactions at an address
Welcome Pay-to-Script-Hash (BIP16)
Deposit Script (ScriptPub) is a Fixed Format:
OP_HASH160
<ScriptHash>
OP_EQUAL
Withdrawal Script (ScriptSig) contains a new Script:
<Signature>
<Serialized Script>
P2SH Details
● Adoption accepted in April 2012.● Was controversial because the script is a bit
of a “bolt on”○ New address type (BIP13): 32JnPkrXfNZByp5tgi4YxAVMi649Cjfnds
● Provided simple, 20-byte addresses like our existing ones
BitGo: P2SH & M-of-N magic
● P2SH gives the “Withdrawal Script” back to the receiver, rather than the sender.
● Multi-Sig gives us multi-factor bitcoin
● Now we can create a safe storage for bitcoin using the web: https://www.bitgo.com/p2sh_safe_address
Part 2: The Code
● Of course we’re using BitGo APIs!
● BitGo APIs are still evolving, version 0.9
● If you want to use these APIs contact me.
Disclosures and Disclaimers
2-Part SDK: Service + Browser
● Browser API is Javascript○ Other client-side APIs will work
● Service API is HTTP
JavaScript API
● Modified Bitcoinjs-lib w/ Multi-Sig support
● https://github.com/BitGo/bitcoinjs-lib
Bitcoin. Address ECKey Transaction
Bitcoin.Addressvar stdAddress = ‘1MyxBcAfzNze2aY3ggLEvroKJBZXDgAmc’;
var p2shAddress = ‘32JnPkrXfNZByp5tgi4YxAVMi649Cjfnds’;
assert(Bitcoin.Address.verify(stdAddress), true);
assert(Bitcoin.Address.verify(p2shAddress), true);
var address;
try {
address = new Bitcoin.Address(stdAddress);
assert(address.isP2SHAddress() === false);} catch (e) {
console.log(‘Invalid Address: ‘ + e);}
Bitcoin.Util// Arrays to/from Hex Strings
Bitcoin.Util.bytesToHex() / hexToBytes()
// double-SHA256
Bitcoin.Util.dsha()
// A solid PRNG; with browser entropy from mouse/keyboard
Bitcoin.Util.randomBytes()
Bitcoin.ECKeyvar key = new Bitcoin.ECKey();
// Get the bitcoin address for this key
key.getBitcoinAddress().toString()
// Get the public key
key.getPub(); // as a byte array
key.getPubKeyHex(); // as a hex string
// Get string format for private key
key.getWalletImportFormat();
Bitcoin.Transaction - Create// Create a transaction
// Input is the outputIndex of inputTx
// Output is valueInSatoshis to outputAddress.
function createTx(inputTx, outputIndex, valueInSatoshis, outputAddress) {
var tx = new Bitcoin.Transaction();
tx.addInput(new Bitcoin.TransactionIn( {
outpoint: { hash: inputTx.getHash(), index: outputIndex },
script: inputTx.script,
sequence: 4294967295 }) );
tx.addOuput(outputAddress, valueInSatoshis);
return tx;
}
Bitcoin.Transaction - Sign// Sign a transaction
function signTx(tx, redeemScript, signingKey) {
var key = new Bitcoin.ECKey(signingKey);
try {
tx.signWithMultiSigScript(
[key],
Crypto.util.hexToBytes(redeemScript)
);
} catch (e) {
// deal with error ... }
return tx;
}
Simple enough.
But what the heck is a redeemScript?
We’ll come back to this after we checkout the service APIs.
Service API
● Authenticate User
● Create Multi-Sig Wallets
● Find Unspents
● Sign & Send Transactions
User LoginMethod: POST
URL: api/v1/user/login/local
curl --cookie cookies.txt --cookie-jar cookies.txt --header 'Content-Type: application/json' --data-binary '{"email": "[email protected]", "password": "<redacted>"}' https://www.bitgo.com/api/v1/user/signup/local
{"user":
{"id":"5314b981196d448052000088",
"name":{
"first":"",
"last":"",
"full":"[email protected]"
},
// etc
}
Create Multi-Sig WalletMethod: POST
URL: /api/v1/addresses/bitcoin
curl --cookie cookies.txt --cookie-jar cookies.txt --header 'Content-Type: application/json' --data-binary '{"private": {"m":2, "n":3, "userPubKey": "[insert key here]", "backupPubKey": "[insert key here]", "userPrivKey": "x"}}' https://www.bitgo.com/api/v1/addresses/bitcoin
{"id":"2Mx7XSW3s36Em89jCegL75AZ3iDRLKMFXi6",
"type":"bitcoin",
"watch":true,
"private":{
"userPrivKey":"x",
"redeemScript":"5241045ccd… … … "
},
"spendingAccount":true,
"isActive":true,
"accountType":"safe",
"pendingBalance":0,
"availableBalance":0,
"balance":0,
"unconfirmedTransactions":[]
}
UnspentsMethod: GET
URL: /api/v1/transactions/unspents/bitcoin/<address>
curl --cookie cookies.txt --cookie-jar cookies.txt https://www.bitgo.com/api/v1/transactions/unspents/bitcoin/3LbPcRnHdGHqQnhjc2VMGZVbh8LfrGQCy6
{
"unspents":[
{
"tx_hash": "e6f8057a1693b58101… … … ",
"tx_output_n":0,
"value":9005778,
"raw":"0100000001bfe62… … … "
}
]
}
Sign TransactionMethod: POST
URL: /api/v1/transactions/bitcoin
curl --cookie cookies.txt --cookie-jar cookies.txt --header 'Content-Type: application/json' --data-binary '{"tx":"<hex encoded transaction here"}' https://www.bitgo.com/api/v1/transaction/bitcoin
{
transaction: “<hex encoded, fully signed transaction”
}
finem