segwit support added

This commit is contained in:
OutCast3k 2017-09-10 13:18:31 +00:00
parent d5fe5ea828
commit 6c480a1102
5 changed files with 384 additions and 72 deletions

View file

@ -1,7 +1,7 @@
coinbin coinbin
======= =======
A Open Source Browser Based Bitcoin Wallet. Version 1.2 beta by OutCast3k A Open Source Browser Based Bitcoin Wallet. Version 1.3 beta by OutCast3k
Live version available at http://coinb.in/ or http://4zpinp6gdkjfplhk.onion Live version available at http://coinb.in/ or http://4zpinp6gdkjfplhk.onion
@ -28,5 +28,6 @@ Coinb.in supports a number of key features such as:
- HD (bip32) support - HD (bip32) support
- Supports altcoins such as litecoin - Supports altcoins such as litecoin
- Replace by fee (RBF) Support - Replace by fee (RBF) Support
- Segwit support
Donate to 1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg to see more development! Donate to 1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg to see more development!

View file

@ -58,7 +58,8 @@
<li class="dropdown"> <li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-plus"></span> New<b class="caret"></b></a> <a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-plus"></span> New<b class="caret"></b></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="#newAddress" data-toggle="tab">New Address</a></li> <li><a href="#newAddress" data-toggle="tab">Address</a></li>
<li><a href="#newSegWit" data-toggle="tab">SegWit Address</a></li>
<li><a href="#newMultiSig" data-toggle="tab">MultiSig Address</a></li> <li><a href="#newMultiSig" data-toggle="tab">MultiSig Address</a></li>
<li><a href="#newTimeLocked" data-toggle="tab">Time Locked Address</a></li> <li><a href="#newTimeLocked" data-toggle="tab">Time Locked Address</a></li>
<li><a href="#newHDaddress" data-toggle="tab">HD Address</a></li> <li><a href="#newHDaddress" data-toggle="tab">HD Address</a></li>
@ -123,7 +124,7 @@
<div class="col-md-4"> <div class="col-md-4">
<h3><span class="glyphicon glyphicon-globe"></span> Addresses</h3> <h3><span class="glyphicon glyphicon-globe"></span> Addresses</h3>
<p>We support <a href="#newAddress">regular addresses</a> but also <a href="#newMultiSig">multisig</a> and stealth, and access to your own private keys!</p> <p>We support <a href="#newAddress">regular addresses</a>, <a href="#newMultiSig">multisig</a>, <a href="#newSegWit">segwit</a> and stealth all with access to your own private keys!</p>
</div> </div>
<div class="col-md-4"> <div class="col-md-4">
@ -306,6 +307,47 @@
<br> <br>
</div> </div>
<div class="tab-pane tab-content" id="newSegWit">
<h2>New SegWit Address <small> Smaller &amp; Faster Transactions</small></h2>
<p>Any keys used you will need to manually store safely as they will be needed later to redeem the bitcoins.</p>
<label>SegWit Address (Share)</label>
<div class="input-group">
<input id="newSegWitAddress" type="text" class="form-control address" value="" readonly>
<span class="input-group-btn">
<button class="qrcodeBtn btn btn-default" type="button" data-toggle="modal" data-target="#modalQrcode"><span class="glyphicon glyphicon-qrcode"></span></button>
</span>
</div>
<label>RedeemScript</label>
<input id="newSegWitRedeemScript" type="text" class="form-control" readonly>
<label>Public key</label>
<input id="newSegWitPubKey" type="text" class="form-control" readonly>
<label>Private key (WIF key)</label>
<div class="input-group">
<input id="newSegWitPrivKey" type="password" class="form-control" value="" readonly>
<span class="input-group-btn">
<button class="showKey btn btn-default" type="button">Show</button>
</span>
</div>
<h3>Address Options</h3>
<p>You can use the advanced options below to generate different kind of keys and addresses.</p>
<div class="checkbox">
<label><input type="checkbox" id="newSegWitBrainwallet" class="checkbox-inline"> Custom Seed or Brain Wallet</label>
<input type="text" class="form-control hidden" id="brainwalletSegWit">
</div>
<input type="button" class="btn btn-primary" value="Generate" id="newSegWitKeysBtn">
<br>
</div>
<div class="tab-pane tab-content" id="newMultiSig"> <div class="tab-pane tab-content" id="newMultiSig">
<h2>New Multisig Address <small>Secure multisig address</small></h2> <h2>New Multisig Address <small>Secure multisig address</small></h2>
@ -497,7 +539,7 @@
<h2>Transaction <small>Create a new transaction</small></h2> <h2>Transaction <small>Create a new transaction</small></h2>
<p>Use this page to create a raw transaction</p> <p>Use this page to create a raw transaction</p>
<b>Address, WIF key or Multisig Redeem Script</b>: <b>Address, WIF key or Redeem Script</b>:
<div class="input-group"> <div class="input-group">
<span class="input-group-btn"> <span class="input-group-btn">
<button class="btn btn-info qrcodeScanner" type="button" data-toggle="modal" data-target="#modalQrcodeScanner" forward-result="#redeemFrom"><span class="glyphicon glyphicon-camera"></span></button> <button class="btn btn-info qrcodeScanner" type="button" data-toggle="modal" data-target="#modalQrcodeScanner" forward-result="#redeemFrom"><span class="glyphicon glyphicon-camera"></span></button>
@ -679,6 +721,7 @@
<br> <br>
<div class="hidden verifyData" id="verifyRsData"> <div class="hidden verifyData" id="verifyRsData">
<h4>Redeem Script</h4> <h4>Redeem Script</h4>
<p><span style="float:right"><a href="javascript:;" target="_blank" class="verifyLink" title="Link to this page"><span class="glyphicon glyphicon-link"></span></a></span>The above redeem script has been decoded</p> <p><span style="float:right"><a href="javascript:;" target="_blank" class="verifyLink" title="Link to this page"><span class="glyphicon glyphicon-link"></span></a></span>The above redeem script has been decoded</p>
@ -694,6 +737,7 @@
</div> </div>
</div> </div>
</div> </div>
<label>Required Signatures</label> <label>Required Signatures</label>
<p class="signaturesRequired">?</p> <p class="signaturesRequired">?</p>
<label>Signatures Required from</label> <label>Signatures Required from</label>
@ -701,9 +745,25 @@
<tbody> <tbody>
</tbody> </tbody>
</table> </table>
<br>
</div> </div>
<div class="hidden" id="verifyRsDataHodl"> <div class="hidden verifyData" id="verifyRsDataSegWit">
<label>Segwit Address</label>
<div class="row">
<div class="col-lg-6">
<div class="input-group">
<input type="text" class="form-control address segWitAddress" value="" readonly>
<span class="input-group-btn">
<button class="qrcodeBtn btn btn-default" type="button" data-toggle="modal" data-target="#modalQrcode"><span class="glyphicon glyphicon-qrcode"></span></button>
</span>
</div>
</div>
</div>
<br>
</div>
<div class="hidden verifyData" id="verifyRsDataHodl">
<label>Hodl Address</label> <label>Hodl Address</label>
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
@ -736,8 +796,6 @@
</div> </div>
</div> </div>
</div> </div>
<br>
</div> </div>
</div> </div>
@ -747,6 +805,7 @@
<div><b>Version</b>: <span class="transactionVersion"></span></div> <div><b>Version</b>: <span class="transactionVersion"></span></div>
<div><b>Transaction Size</b>: <span class="transactionSize"></span></div> <div><b>Transaction Size</b>: <span class="transactionSize"></span></div>
<div><b>Lock time</b>: <span class="transactionLockTime"></span></div> <div><b>Lock time</b>: <span class="transactionLockTime"></span></div>
<div class="transactionSegWit"><b>SegWit</b>: True</div>
<div class="transactionRBF"><b>RBF</b>: This is a <a href="https://en.bitcoin.it/wiki/Transaction_replacement">replace by fee</a> transaction!</div> <div class="transactionRBF"><b>RBF</b>: This is a <a href="https://en.bitcoin.it/wiki/Transaction_replacement">replace by fee</a> transaction!</div>
<hr> <hr>
@ -774,6 +833,7 @@
</table> </table>
</div> </div>
<div class="hidden verifyData" id="verifyPrivKey"> <div class="hidden verifyData" id="verifyPrivKey">
<h4>WIF key</h4> <h4>WIF key</h4>
<p>The above wif key has been decoded</p> <p>The above wif key has been decoded</p>
@ -883,6 +943,7 @@
<input type="button" value="Submit" class="btn btn-primary" id="verifyBtn"> <input type="button" value="Submit" class="btn btn-primary" id="verifyBtn">
<br> <br>
</div> </div>
<div class="tab-pane tab-content" id="sign"> <div class="tab-pane tab-content" id="sign">
@ -975,7 +1036,7 @@
<div class="tab-pane tab-content" id="about"> <div class="tab-pane tab-content" id="about">
<h2>About <small>open source bitcoin wallet</small></h2> <h2>About <small>open source bitcoin wallet</small></h2>
<p>Version 1.2</p> <p>Version 1.3</p>
<p>Compatible with bitcoin-qt</p> <p>Compatible with bitcoin-qt</p>
<p>Github <a href="https://github.com/OutCast3k/coinbin/">https://github.com/OutCast3k/coinbin/</a></p> <p>Github <a href="https://github.com/OutCast3k/coinbin/">https://github.com/OutCast3k/coinbin/</a></p>
<p>TOR <a href="http://4zpinp6gdkjfplhk.onion">4zpinp6gdkjfplhk.onion</a></p> <p>TOR <a href="http://4zpinp6gdkjfplhk.onion">4zpinp6gdkjfplhk.onion</a></p>
@ -987,6 +1048,8 @@
<p>Coinb.in is run and funded by the generosity of others in terms of <a href="https://github.com/OutCast3k/coinbin/graphs/contributors" target="_blank">development</a> and hosting.</p> <p>Coinb.in is run and funded by the generosity of others in terms of <a href="https://github.com/OutCast3k/coinbin/graphs/contributors" target="_blank">development</a> and hosting.</p>
<h3>Privacy</h3> <h3>Privacy</h3>
<p>Coinb.in beleives strongly in privacy, not only do we support the use of TOR, the site does not collect and store IP or transaction data via our servers nor do we store your bitcoins private key. We do route traffic via cloudflare using an SSL certificate.</p> <p>Coinb.in beleives strongly in privacy, not only do we support the use of TOR, the site does not collect and store IP or transaction data via our servers nor do we store your bitcoins private key. We do route traffic via cloudflare using an SSL certificate.</p>
<h3>Support</h3>
<p>We recommend that you first check our <a href="https://status.coinb.in/" target="_blank">service status</a> page, if the problem persists you can contact us by emailing support{at}coinb.in.</p>
<h3>Donate</h3> <h3>Donate</h3>
<p>Please donate to <a href="bitcoin:1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg">1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg</a> if you found this project useful or want to see more features!</p> <p>Please donate to <a href="bitcoin:1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg">1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg</a> if you found this project useful or want to see more features!</p>
</div> </div>
@ -1105,7 +1168,7 @@
<div id="footer"> <div id="footer">
<div class="container text-right"> <div class="container text-right">
<p class="text-muted">Version 1.2</p> <p class="text-muted">Version 1.3</p>
</div> </div>
</div> </div>

View file

@ -98,9 +98,9 @@
} }
/* provide a public key and return address */ /* provide a public key and return address */
coinjs.pubkey2address = function(h){ coinjs.pubkey2address = function(h, byte){
var r = ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(h), {asBytes: true})); var r = ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(h), {asBytes: true}));
r.unshift(coinjs.pub); r.unshift(byte || coinjs.pub);
var hash = Crypto.SHA256(Crypto.SHA256(r, {asBytes: true}), {asBytes: true}); var hash = Crypto.SHA256(Crypto.SHA256(r, {asBytes: true}), {asBytes: true});
var checksum = hash.slice(0, 4); var checksum = hash.slice(0, 4);
return coinjs.base58encode(r.concat(checksum)); return coinjs.base58encode(r.concat(checksum));
@ -165,6 +165,19 @@
return {'address':address, 'redeemScript':redeemScript}; return {'address':address, 'redeemScript':redeemScript};
} }
/* create a new segwit address */
coinjs.segwitAddress = function(pubkey){
var keyhash = [0x00,0x14].concat(ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(pubkey), {asBytes: true}), {asBytes: true}));
var x = ripemd160(Crypto.SHA256(keyhash, {asBytes: true}), {asBytes: true});
x.unshift(coinjs.multisig);
var r = x;
r = Crypto.SHA256(Crypto.SHA256(r, {asBytes: true}), {asBytes: true});
var checksum = r.slice(0,4);
var address = coinjs.base58encode(x.concat(checksum));
return {'address':address, 'type':'segwit', 'redeemscript':Crypto.util.bytesToHex(keyhash)};
}
/* provide a privkey and return an WIF */ /* provide a privkey and return an WIF */
coinjs.privkey2wif = function(h){ coinjs.privkey2wif = function(h){
var r = Crypto.util.hexToBytes(h); var r = Crypto.util.hexToBytes(h);
@ -683,6 +696,13 @@
var multi = coinjs.pubkeys2MultisigAddress(pubkeys, r.signaturesRequired); var multi = coinjs.pubkeys2MultisigAddress(pubkeys, r.signaturesRequired);
r.address = multi['address']; r.address = multi['address'];
r.type = 'multisig__'; // using __ for now to differentiat from the other object .type == "multisig" r.type = 'multisig__'; // using __ for now to differentiat from the other object .type == "multisig"
} else if((s.chunks.length==2) && (s.buffer[0] == 0 && s.buffer[1] == 20)){ // SEGWIT
r = {};
r.type = "segwit__";
var rs = Crypto.util.bytesToHex(s.buffer);
r.address = coinjs.pubkey2address(rs, coinjs.multisig);
r.redeemscript = rs;
} else if(s.chunks.length == 5 && s.chunks[1] == 177 && s.chunks[2] == 117 && s.chunks[4] == 172){ } else if(s.chunks.length == 5 && s.chunks[1] == 177 && s.chunks[2] == 117 && s.chunks[4] == 172){
// ^ <unlocktime> OP_CHECKLOCKTIMEVERIFY OP_DROP <pubkey> OP_CHECKSIG ^ // ^ <unlocktime> OP_CHECKLOCKTIMEVERIFY OP_DROP <pubkey> OP_CHECKSIG ^
r = {} r = {}
@ -772,6 +792,7 @@
r.lock_time = 0; r.lock_time = 0;
r.ins = []; r.ins = [];
r.outs = []; r.outs = [];
r.witness = [];
r.timestamp = null; r.timestamp = null;
r.block = null; r.block = null;
@ -990,6 +1011,100 @@
} }
} }
/* generate a segwit transaction hash to sign from a transaction input */
r.transactionHashSegWitV0 = function(index, sigHashType){
/*
Notice: coinb.in by default, deals with segwit transactions in a non-standard way.
Segwit transactions require that input values are included in the transaction hash.
To save wasting resources and potentially slowing down this service, we include the amount with the
redeem script to generate the transaction hash and remove it after its signed.
*/
// start redeem script check
var extract = this.extractScriptKey(index);
if(extract['type'] != 'segwit'){
return {'result':0, 'fail':'redeemscript', 'response':'redeemscript missing or not valid for segwit'};
}
var scriptcode = Crypto.util.hexToBytes(extract['script']);
if(scriptcode[0] != 0){
return {'result':0, 'fail':'scriptcode', 'response':'redeemscript is not valid'};
}
if(extract['value'] == -1){
return {'result':0, 'fail':'value', 'response':'unable to generate a valid segwit hash without a value'};
}
// end of redeem script check
scriptcode = scriptcode.slice(1);
scriptcode.unshift(25, 118, 169);
scriptcode.push(136, 172);
var value = coinjs.numToBytes(extract['value'], 8);
// start
var zero = coinjs.numToBytes(0, 32);
var version = coinjs.numToBytes(parseInt(this.version), 4);
var bufferTmp = [];
if(!(sigHashType >= 80)){ // not sighash anyonecanpay
for(var i = 0; i < this.ins.length; i++){
bufferTmp = bufferTmp.concat(Crypto.util.hexToBytes(this.ins[i].outpoint.hash).reverse());
bufferTmp = bufferTmp.concat(coinjs.numToBytes(this.ins[i].outpoint.index, 4));
}
}
var hashPrevouts = bufferTmp.length >= 1 ? Crypto.SHA256(Crypto.SHA256(bufferTmp, {asBytes: true}), {asBytes: true}) : zero;
var bufferTmp = [];
if(!(sigHashType >= 80) && sigHashType != 2 && sigHashType != 3){ // not sighash anyonecanpay & single & none
for(var i = 0; i < this.ins.length; i++){
bufferTmp = bufferTmp.concat(coinjs.numToBytes(this.ins[i].sequence, 4));
}
}
var hashSequence = bufferTmp.length >= 1 ? Crypto.SHA256(Crypto.SHA256(bufferTmp, {asBytes: true}), {asBytes: true}) : zero;
var outpoint = Crypto.util.hexToBytes(this.ins[index].outpoint.hash).reverse();
outpoint = outpoint.concat(coinjs.numToBytes(this.ins[index].outpoint.index, 4));
var nsequence = coinjs.numToBytes(this.ins[index].sequence, 4);
var hashOutputs = zero;
var bufferTmp = [];
if(sigHashType != 2 && sigHashType != 3){ // not sighash single & none
for(var i = 0; i < this.outs.length; i++ ){
bufferTmp = bufferTmp.concat(coinjs.numToBytes(this.outs[i].value, 8));
bufferTmp = bufferTmp.concat(coinjs.numToVarInt(this.outs[i].script.buffer.length));
bufferTmp = bufferTmp.concat(this.outs[i].script.buffer);
}
hashOutputs = Crypto.SHA256(Crypto.SHA256(bufferTmp, {asBytes: true}), {asBytes: true});
} else if ((sigHashType == 2) && index < this.outs.length){ // is sighash single
bufferTmp = bufferTmp.concat(coinjs.numToBytes(this.outs[index].value, 8));
bufferTmp = bufferTmp.concat(coinjs.numToVarInt(this.outs[i].script.buffer.length));
bufferTmp = bufferTmp.concat(this.outs[index].script.buffer);
hashOutputs = Crypto.SHA256(Crypto.SHA256(bufferTmp, {asBytes: true}), {asBytes: true});
}
var locktime = coinjs.numToBytes(this.lock_time, 4);
var sighash = coinjs.numToBytes(sigHashType, 4);
var buffer = [];
buffer = buffer.concat(version);
buffer = buffer.concat(hashPrevouts);
buffer = buffer.concat(hashSequence);
buffer = buffer.concat(outpoint);
buffer = buffer.concat(scriptcode);
buffer = buffer.concat(value);
buffer = buffer.concat(nsequence);
buffer = buffer.concat(hashOutputs);
buffer = buffer.concat(locktime);
buffer = buffer.concat(sighash);
var hash = Crypto.SHA256(buffer, {asBytes: true});
return {'result':1,'hash':Crypto.util.bytesToHex(Crypto.SHA256(hash, {asBytes: true})), 'response':'hash generated'};
}
/* extract the scriptSig, used in the transactionHash() function */ /* extract the scriptSig, used in the transactionHash() function */
r.extractScriptKey = function(index) { r.extractScriptKey = function(index) {
if(this.ins[index]){ if(this.ins[index]){
@ -1005,6 +1120,15 @@
} else if(this.ins[index].script.chunks.length == 5 && this.ins[index].script.chunks[1] == 177){//OP_CHECKLOCKTIMEVERIFY } else if(this.ins[index].script.chunks.length == 5 && this.ins[index].script.chunks[1] == 177){//OP_CHECKLOCKTIMEVERIFY
// hodl script (not signed) // hodl script (not signed)
return {'type':'hodl', 'signed':'false', 'signatures': 0, 'script': Crypto.util.bytesToHex(this.ins[index].script.buffer)}; return {'type':'hodl', 'signed':'false', 'signatures': 0, 'script': Crypto.util.bytesToHex(this.ins[index].script.buffer)};
} else if((this.ins[index].script.chunks.length <= 3 && this.ins[index].script.chunks.length > 0) && this.ins[index].script.chunks[0].length == 22 && this.ins[index].script.chunks[0][0] == 0){
// segwit script
var signed = ((this.witness[index]) && this.witness[index].length==2) ? 'true' : 'false';
var sigs = (signed == 'true') ? 1 : 0;
var value = -1; // no value found
if((this.ins[index].script.chunks[2]) && this.ins[index].script.chunks[2].length==8){
value = coinjs.bytesToNum(this.ins[index].script.chunks[2]); // value found encoded in transaction (THIS IS NON STANDARD)
}
return {'type':'segwit', 'signed':signed, 'signatures': sigs, 'script': Crypto.util.bytesToHex(this.ins[index].script.chunks[0]), 'value': value};
} else if (this.ins[index].script.chunks[0]==0 && this.ins[index].script.chunks[this.ins[index].script.chunks.length-1][this.ins[index].script.chunks[this.ins[index].script.chunks.length-1].length-1]==174) { // OP_CHECKMULTISIG } else if (this.ins[index].script.chunks[0]==0 && this.ins[index].script.chunks[this.ins[index].script.chunks.length-1][this.ins[index].script.chunks[this.ins[index].script.chunks.length-1].length-1]==174) { // OP_CHECKMULTISIG
// multisig script, with signature(s) included // multisig script, with signature(s) included
return {'type':'multisig', 'signed':'true', 'signatures':this.ins[index].script.chunks.length-2, 'script': Crypto.util.bytesToHex(this.ins[index].script.chunks[this.ins[index].script.chunks.length-1])}; return {'type':'multisig', 'signed':'true', 'signatures':this.ins[index].script.chunks.length-2, 'script': Crypto.util.bytesToHex(this.ins[index].script.chunks[this.ins[index].script.chunks.length-1])};
@ -1024,7 +1148,7 @@
} }
/* generate a signature from a transaction hash */ /* generate a signature from a transaction hash */
r.transactionSig = function(index, wif, sigHashType){ r.transactionSig = function(index, wif, sigHashType, txhash){
function serializeSig(r, s) { function serializeSig(r, s) {
var rBa = r.toByteArraySigned(); var rBa = r.toByteArraySigned();
@ -1046,7 +1170,7 @@
} }
var shType = sigHashType || 1; var shType = sigHashType || 1;
var hash = Crypto.util.hexToBytes(this.transactionHash(index, shType)); var hash = txhash || Crypto.util.hexToBytes(this.transactionHash(index, shType));
if(hash){ if(hash){
var curve = EllipticCurve.getSECCurveByName("secp256k1"); var curve = EllipticCurve.getSECCurveByName("secp256k1");
@ -1220,6 +1344,42 @@
return true; return true;
} }
/* sign segwit input */
r.signsegwit = function(index, wif, sigHashType){
var shType = sigHashType || 1;
var wif2 = coinjs.wif2pubkey(wif);
var segwit = coinjs.segwitAddress(wif2['pubkey']);
if(segwit['redeemscript'] == Crypto.util.bytesToHex(this.ins[index].script.chunks[0])){
var txhash = this.transactionHashSegWitV0(index, shType);
if(txhash.result == 1){
var segwitHash = Crypto.util.hexToBytes(txhash.hash);
var signature = this.transactionSig(index, wif, shType, segwitHash);
// remove any non standard data we store, i.e. input value
var script = coinjs.script();
script.writeBytes(this.ins[index].script.chunks[0]);
this.ins[index].script = script;
this.witness.push([signature, wif2['pubkey']]);
/* reorder witness data */
var witness_order = [];
for(var i = 0; i < this.ins.length; i++){
for(var y = 0; y < this.witness.length; y++){
var sw = coinjs.segwitAddress(this.witness[y][1]);
if(sw['redeemscript'] == Crypto.util.bytesToHex(this.ins[i].script.chunks[0])){
witness_order.push(this.witness[y]);
}
}
}
this.witness = witness_order;
}
}
return true;
}
/* sign inputs */ /* sign inputs */
r.sign = function(wif, sigHashType){ r.sign = function(wif, sigHashType){
var shType = sigHashType || 1; var shType = sigHashType || 1;
@ -1232,10 +1392,16 @@
if(((d['type'] == 'scriptpubkey' && d['script']==Crypto.util.bytesToHex(pubkeyHash.buffer)) || d['type'] == 'empty') && d['signed'] == "false"){ if(((d['type'] == 'scriptpubkey' && d['script']==Crypto.util.bytesToHex(pubkeyHash.buffer)) || d['type'] == 'empty') && d['signed'] == "false"){
this.signinput(i, wif, shType); this.signinput(i, wif, shType);
} else if (d['type'] == 'hodl' && d['signed'] == "false") { } else if (d['type'] == 'hodl' && d['signed'] == "false") {
this.signhodl(i, wif, shType); this.signhodl(i, wif, shType);
} else if (d['type'] == 'multisig') { } else if (d['type'] == 'multisig') {
this.signmultisig(i, wif, shType); this.signmultisig(i, wif, shType);
} else if (d['type'] == 'segwit') {
this.signsegwit(i, wif, shType);
} else { } else {
// could not sign // could not sign
} }
@ -1247,8 +1413,12 @@
r.serialize = function(){ r.serialize = function(){
var buffer = []; var buffer = [];
buffer = buffer.concat(coinjs.numToBytes(parseInt(this.version),4)); buffer = buffer.concat(coinjs.numToBytes(parseInt(this.version),4));
buffer = buffer.concat(coinjs.numToVarInt(this.ins.length));
if(this.witness.length>=1){
buffer = buffer.concat([0x00, 0x01]);
}
buffer = buffer.concat(coinjs.numToVarInt(this.ins.length));
for (var i = 0; i < this.ins.length; i++) { for (var i = 0; i < this.ins.length; i++) {
var txin = this.ins[i]; var txin = this.ins[i];
buffer = buffer.concat(Crypto.util.hexToBytes(txin.outpoint.hash).reverse()); buffer = buffer.concat(Crypto.util.hexToBytes(txin.outpoint.hash).reverse());
@ -1268,6 +1438,16 @@
buffer = buffer.concat(scriptBytes); buffer = buffer.concat(scriptBytes);
} }
if(this.witness.length>=1){
for(var i = 0; i < this.witness.length; i++){
buffer = buffer.concat(coinjs.numToVarInt(this.witness[i].length));
for(var x = 0; x < this.witness[i].length; x++){
buffer = buffer.concat(coinjs.numToVarInt(Crypto.util.hexToBytes(this.witness[i][x]).length));
buffer = buffer.concat(Crypto.util.hexToBytes(this.witness[i][x]));
}
}
}
buffer = buffer.concat(coinjs.numToBytes(parseInt(this.lock_time),4)); buffer = buffer.concat(coinjs.numToBytes(parseInt(this.lock_time),4));
return Crypto.util.bytesToHex(buffer); return Crypto.util.bytesToHex(buffer);
} }
@ -1279,6 +1459,8 @@
} }
var pos = 0; var pos = 0;
var witness = false;
var readAsInt = function(bytes) { var readAsInt = function(bytes) {
if (bytes == 0) return 0; if (bytes == 0) return 0;
pos++; pos++;
@ -1304,8 +1486,15 @@
} }
var obj = new coinjs.transaction(); var obj = new coinjs.transaction();
obj.version = readAsInt(4); obj.version = readAsInt(4);
if(buffer[pos] == 0x00 && buffer[pos+1] == 0x01){
// segwit transaction
witness = true;
obj.witness = [];
pos += 2;
}
var ins = readVarInt(); var ins = readVarInt();
for (var i = 0; i < ins; i++) { for (var i = 0; i < ins; i++) {
obj.ins.push({ obj.ins.push({
@ -1326,6 +1515,21 @@
}); });
} }
if(witness == true){
for (i = 0; i < ins; ++i) {
var count = readVarInt();
var vector = [];
for(var y = 0; y < count; y++){
var slice = readVarInt();
pos += slice;
if(!coinjs.isArray(obj.witness[i])){
obj.witness[i] = [];
}
obj.witness[i].push(Crypto.util.bytesToHex(buffer.slice(pos - slice, pos)));
}
}
}
obj.lock_time = readAsInt(4); obj.lock_time = readAsInt(4);
return obj; return obj;
} }

View file

@ -281,6 +281,14 @@ $(document).ready(function() {
} }
}); });
$("#newSegWitBrainwallet").click(function(){
if($(this).is(":checked")){
$("#brainwalletSegWit").removeClass("hidden");
} else {
$("#brainwalletSegWit").addClass("hidden");
}
});
$("#encryptKey").click(function(){ $("#encryptKey").click(function(){
if($(this).is(":checked")){ if($(this).is(":checked")){
$("#aes256passform").removeClass("hidden"); $("#aes256passform").removeClass("hidden");
@ -289,6 +297,21 @@ $(document).ready(function() {
} }
}); });
/* new -> segwit code */
$("#newSegWitKeysBtn").click(function(){
var compressed = coinjs.compressed;
coinjs.compressed = true;
var s = ($("#newSegWitBrainwallet").is(":checked")) ? $("#brainwalletSegWit").val() : null;
var coin = coinjs.newKeys(s);
var sw = coinjs.segwitAddress(coin.pubkey);
$("#newSegWitAddress").val(sw.address);
$("#newSegWitRedeemScript").val(sw.redeemscript);
$("#newSegWitPubKey").val(coin.pubkey);
$("#newSegWitPrivKey").val(coin.wif);
coinjs.compressed = compressed;
});
/* new -> multisig code */ /* new -> multisig code */
$("#newMultiSigAddress").click(function(){ $("#newMultiSigAddress").click(function(){
@ -810,6 +833,15 @@ $(document).ready(function() {
$("#inputs .txId:last").val(txid); $("#inputs .txId:last").val(txid);
$("#inputs .txIdN:last").val(n); $("#inputs .txIdN:last").val(n);
$("#inputs .txIdAmount:last").val(amount); $("#inputs .txIdAmount:last").val(amount);
if(script.match(/^00/) && script.length==44){
s = coinjs.script();
s.writeBytes(Crypto.util.hexToBytes(script));
s.writeOp(0);
s.writeBytes(coinjs.numToBytes((amount*100000000).toFixed(0), 8));
script = Crypto.util.bytesToHex(s.buffer);
}
$("#inputs .txIdScript:last").val(script); $("#inputs .txIdScript:last").val(script);
} }
} }
@ -1277,6 +1309,9 @@ $(document).ready(function() {
if(decode){ if(decode){
$("#verifyRsDataMultisig").addClass('hidden'); $("#verifyRsDataMultisig").addClass('hidden');
$("#verifyRsDataHodl").addClass('hidden'); $("#verifyRsDataHodl").addClass('hidden');
$("#verifyRsDataSegWit").addClass('hidden');
$("#verifyRsData").addClass("hidden");
if(decode.type == "multisig__") { if(decode.type == "multisig__") {
$("#verifyRsDataMultisig .multisigAddress").val(decode['address']); $("#verifyRsDataMultisig .multisigAddress").val(decode['address']);
@ -1291,6 +1326,11 @@ $(document).ready(function() {
$("#verifyRsDataMultisig").removeClass('hidden'); $("#verifyRsDataMultisig").removeClass('hidden');
$(".verifyLink").attr('href','?verify='+$("#verifyScript").val()); $(".verifyLink").attr('href','?verify='+$("#verifyScript").val());
return true; return true;
} else if(decode.type == "segwit__"){
$("#verifyRsData").removeClass("hidden");
$("#verifyRsDataSegWit .segWitAddress").val(decode['address']);
$("#verifyRsDataSegWit").removeClass('hidden');
return true;
} else if(decode.type == "hodl__") { } else if(decode.type == "hodl__") {
var d = $("#verifyRsDataHodl .date").data("DateTimePicker"); var d = $("#verifyRsDataHodl .date").data("DateTimePicker");
$("#verifyRsDataHodl .address").val(decode['address']); $("#verifyRsDataHodl .address").val(decode['address']);
@ -1314,6 +1354,10 @@ $(document).ready(function() {
$("#verifyTransactionData .transactionSize").html(decode.size()+' <i>bytes</i>'); $("#verifyTransactionData .transactionSize").html(decode.size()+' <i>bytes</i>');
$("#verifyTransactionData .transactionLockTime").html(decode['lock_time']); $("#verifyTransactionData .transactionLockTime").html(decode['lock_time']);
$("#verifyTransactionData .transactionRBF").hide(); $("#verifyTransactionData .transactionRBF").hide();
$("#verifyTransactionData .transactionSegWit").hide();
if (decode.witness.length>=1) {
$("#verifyTransactionData .transactionSegWit").show();
}
$("#verifyTransactionData").removeClass("hidden"); $("#verifyTransactionData").removeClass("hidden");
$("#verifyTransactionData tbody").html(""); $("#verifyTransactionData tbody").html("");
@ -1324,7 +1368,7 @@ $(document).ready(function() {
h += '<td><input class="form-control" type="text" value="'+o.outpoint.hash+'" readonly></td>'; h += '<td><input class="form-control" type="text" value="'+o.outpoint.hash+'" readonly></td>';
h += '<td class="col-xs-1">'+o.outpoint.index+'</td>'; h += '<td class="col-xs-1">'+o.outpoint.index+'</td>';
h += '<td class="col-xs-2"><input class="form-control" type="text" value="'+Crypto.util.bytesToHex(o.script.buffer)+'" readonly></td>'; h += '<td class="col-xs-2"><input class="form-control" type="text" value="'+Crypto.util.bytesToHex(o.script.buffer)+'" readonly></td>';
h += '<td class="col-xs-1"> <span class="glyphicon glyphicon-'+((s.signed=='true')?'ok':'remove')+'-circle"></span>'; h += '<td class="col-xs-1"> <span class="glyphicon glyphicon-'+((s.signed=='true' || (decode.witness[i] && decode.witness[i].length==2))?'ok':'remove')+'-circle"></span>';
if(s['type']=='multisig' && s['signatures']>=1){ if(s['type']=='multisig' && s['signatures']>=1){
h += ' '+s['signatures']; h += ' '+s['signatures'];
} }

10
sha1sum
View file

@ -1,9 +1,9 @@
---- Version 1.2 2017.03.14 ---- ---- Version 1.3 2017.09.10 ----
77e4519962e2f6a9fc93342137dbb31c33b76b04 ./js/aes.js 77e4519962e2f6a9fc93342137dbb31c33b76b04 ./js/aes.js
3a09a8fc0cfe828b57fc798d668234d0490ee1a6 ./js/bootstrap-datetimepicker.min.js 3a09a8fc0cfe828b57fc798d668234d0490ee1a6 ./js/bootstrap-datetimepicker.min.js
253711c6d825de55a8360552573be950da180614 ./js/bootstrap.min.js 253711c6d825de55a8360552573be950da180614 ./js/bootstrap.min.js
00aaf959783209cd348a746542b3e32bcdf333e3 ./js/coinbin.js b98f718f0400fada4e0f15471031f92ce31e2b83 ./js/coinbin.js
f23a41e5bf56b98790c68502feae569459a60341 ./js/coin.js 3e7b9b1a30412f827d4709a53014d0b6f06103f0 ./js/coin.js
988565bc2cb402d63ed5c5fd7ff47c4278efc2c5 ./js/collapse.js 988565bc2cb402d63ed5c5fd7ff47c4278efc2c5 ./js/collapse.js
9ba5ede3d7f9d4c8fd623395f196adfdcf7e970f ./js/crypto-min.js 9ba5ede3d7f9d4c8fd623395f196adfdcf7e970f ./js/crypto-min.js
f7c09f2f5a721371e7d478050119f7e2d58e3ef9 ./js/crypto-sha256-hmac.js f7c09f2f5a721371e7d478050119f7e2d58e3ef9 ./js/crypto-sha256-hmac.js
@ -29,5 +29,5 @@ ca35b697d99cae4d1b60f2d60fcd37771987eb07 ./fonts/glyphicons-halflings-regular.w
de51a8494180a6db074af2dee2383f0a363c5b08 ./fonts/glyphicons-halflings-regular.svg de51a8494180a6db074af2dee2383f0a363c5b08 ./fonts/glyphicons-halflings-regular.svg
278e49a86e634da6f2a02f3b47dd9d2a8f26210f ./fonts/glyphicons-halflings-regular.woff 278e49a86e634da6f2a02f3b47dd9d2a8f26210f ./fonts/glyphicons-halflings-regular.woff
44bc1850f570972267b169ae18f1cb06b611ffa2 ./fonts/glyphicons-halflings-regular.ttf 44bc1850f570972267b169ae18f1cb06b611ffa2 ./fonts/glyphicons-halflings-regular.ttf
b4d3a33913a0877684909f7edf8b79bf9192b0a7 ./README.md d8a324a13501cd5705dc26b945fc8088f00907ae ./README.md
5bf3ba82a7c8c798f129d9fcaffb8161095e308c ./index.html da6e4cbb4a168a3583086e0997c8c678a7a80925 ./index.html