segwit support added
This commit is contained in:
parent
d5fe5ea828
commit
6c480a1102
5 changed files with 384 additions and 72 deletions
|
@ -1,7 +1,7 @@
|
|||
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
|
||||
|
||||
|
@ -28,5 +28,6 @@ Coinb.in supports a number of key features such as:
|
|||
- HD (bip32) support
|
||||
- Supports altcoins such as litecoin
|
||||
- Replace by fee (RBF) Support
|
||||
- Segwit support
|
||||
|
||||
Donate to 1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg to see more development!
|
||||
|
|
173
index.html
173
index.html
|
@ -58,7 +58,8 @@
|
|||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-plus"></span> New<b class="caret"></b></a>
|
||||
<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="#newTimeLocked" data-toggle="tab">Time Locked Address</a></li>
|
||||
<li><a href="#newHDaddress" data-toggle="tab">HD Address</a></li>
|
||||
|
@ -123,7 +124,7 @@
|
|||
|
||||
<div class="col-md-4">
|
||||
<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 class="col-md-4">
|
||||
|
@ -306,6 +307,47 @@
|
|||
<br>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane tab-content" id="newSegWit">
|
||||
<h2>New SegWit Address <small> Smaller & 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">
|
||||
<h2>New Multisig Address <small>Secure multisig address</small></h2>
|
||||
|
||||
|
@ -497,7 +539,7 @@
|
|||
<h2>Transaction <small>Create a new transaction</small></h2>
|
||||
<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">
|
||||
<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>
|
||||
|
@ -679,66 +721,82 @@
|
|||
<br>
|
||||
|
||||
<div class="hidden verifyData" id="verifyRsData">
|
||||
|
||||
<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>
|
||||
|
||||
<div class="hidden" id="verifyRsDataMultisig">
|
||||
<label>Multi Signature Address</label>
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control address multisigAddress" 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>
|
||||
<label>Multi Signature Address</label>
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control address multisigAddress" 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>
|
||||
</div>
|
||||
<label>Required Signatures</label>
|
||||
<p class="signaturesRequired">?</p>
|
||||
<label>Signatures Required from</label>
|
||||
<table class="table table-striped table-hover">
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="hidden" id="verifyRsDataHodl">
|
||||
<label>Hodl Address</label>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="input-group">
|
||||
<input 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>
|
||||
</div>
|
||||
</div>
|
||||
<label>Required Signatures</label>
|
||||
<p class="signaturesRequired">?</p>
|
||||
<label>Signatures Required from</label>
|
||||
<table class="table table-striped table-hover">
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
|
||||
<label>Required Signature</label>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control address pubkey" 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>
|
||||
<div class="hidden verifyData" id="verifyRsDataHodl">
|
||||
<label>Hodl Address</label>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="input-group">
|
||||
<input 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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label>Unlock Time</label>
|
||||
<div class="row">
|
||||
<div class='col-md-4'>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control date" value="" readonly>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<label>Required Signature</label>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control address pubkey" 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>
|
||||
<label>Unlock Time</label>
|
||||
<div class="row">
|
||||
<div class='col-md-4'>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control date" value="" readonly>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hidden verifyData" id="verifyTransactionData">
|
||||
|
@ -747,6 +805,7 @@
|
|||
<div><b>Version</b>: <span class="transactionVersion"></span></div>
|
||||
<div><b>Transaction Size</b>: <span class="transactionSize"></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>
|
||||
|
||||
<hr>
|
||||
|
@ -774,6 +833,7 @@
|
|||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="hidden verifyData" id="verifyPrivKey">
|
||||
<h4>WIF key</h4>
|
||||
<p>The above wif key has been decoded</p>
|
||||
|
@ -883,6 +943,7 @@
|
|||
|
||||
<input type="button" value="Submit" class="btn btn-primary" id="verifyBtn">
|
||||
<br>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="tab-pane tab-content" id="sign">
|
||||
|
@ -975,7 +1036,7 @@
|
|||
|
||||
<div class="tab-pane tab-content" id="about">
|
||||
<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>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>
|
||||
|
@ -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>
|
||||
<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>
|
||||
<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>
|
||||
<p>Please donate to <a href="bitcoin:1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg">1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg</a> if you found this project useful or want to see more features!</p>
|
||||
</div>
|
||||
|
@ -1105,7 +1168,7 @@
|
|||
|
||||
<div id="footer">
|
||||
<div class="container text-right">
|
||||
<p class="text-muted">Version 1.2</p>
|
||||
<p class="text-muted">Version 1.3</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
220
js/coin.js
220
js/coin.js
|
@ -98,9 +98,9 @@
|
|||
}
|
||||
|
||||
/* 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}));
|
||||
r.unshift(coinjs.pub);
|
||||
r.unshift(byte || coinjs.pub);
|
||||
var hash = Crypto.SHA256(Crypto.SHA256(r, {asBytes: true}), {asBytes: true});
|
||||
var checksum = hash.slice(0, 4);
|
||||
return coinjs.base58encode(r.concat(checksum));
|
||||
|
@ -165,6 +165,19 @@
|
|||
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 */
|
||||
coinjs.privkey2wif = function(h){
|
||||
var r = Crypto.util.hexToBytes(h);
|
||||
|
@ -683,6 +696,13 @@
|
|||
var multi = coinjs.pubkeys2MultisigAddress(pubkeys, r.signaturesRequired);
|
||||
r.address = multi['address'];
|
||||
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){
|
||||
// ^ <unlocktime> OP_CHECKLOCKTIMEVERIFY OP_DROP <pubkey> OP_CHECKSIG ^
|
||||
r = {}
|
||||
|
@ -772,6 +792,7 @@
|
|||
r.lock_time = 0;
|
||||
r.ins = [];
|
||||
r.outs = [];
|
||||
r.witness = [];
|
||||
r.timestamp = null;
|
||||
r.block = null;
|
||||
|
||||
|
@ -955,8 +976,8 @@
|
|||
|
||||
for (var i = 0; i < clone.ins.length; i++) {
|
||||
if(index!=i){
|
||||
clone.ins[i].sequence = 0;
|
||||
}
|
||||
clone.ins[i].sequence = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (shType >= 128){
|
||||
|
@ -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 */
|
||||
r.extractScriptKey = function(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
|
||||
// hodl script (not signed)
|
||||
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
|
||||
// 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])};
|
||||
|
@ -1024,7 +1148,7 @@
|
|||
}
|
||||
|
||||
/* generate a signature from a transaction hash */
|
||||
r.transactionSig = function(index, wif, sigHashType){
|
||||
r.transactionSig = function(index, wif, sigHashType, txhash){
|
||||
|
||||
function serializeSig(r, s) {
|
||||
var rBa = r.toByteArraySigned();
|
||||
|
@ -1046,7 +1170,7 @@
|
|||
}
|
||||
|
||||
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){
|
||||
var curve = EllipticCurve.getSECCurveByName("secp256k1");
|
||||
|
@ -1220,6 +1344,42 @@
|
|||
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 */
|
||||
r.sign = function(wif, sigHashType){
|
||||
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"){
|
||||
this.signinput(i, wif, shType);
|
||||
|
||||
} else if (d['type'] == 'hodl' && d['signed'] == "false") {
|
||||
this.signhodl(i, wif, shType);
|
||||
|
||||
} else if (d['type'] == 'multisig') {
|
||||
this.signmultisig(i, wif, shType);
|
||||
|
||||
} else if (d['type'] == 'segwit') {
|
||||
this.signsegwit(i, wif, shType);
|
||||
|
||||
} else {
|
||||
// could not sign
|
||||
}
|
||||
|
@ -1247,8 +1413,12 @@
|
|||
r.serialize = function(){
|
||||
var buffer = [];
|
||||
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++) {
|
||||
var txin = this.ins[i];
|
||||
buffer = buffer.concat(Crypto.util.hexToBytes(txin.outpoint.hash).reverse());
|
||||
|
@ -1268,6 +1438,16 @@
|
|||
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));
|
||||
return Crypto.util.bytesToHex(buffer);
|
||||
}
|
||||
|
@ -1279,6 +1459,8 @@
|
|||
}
|
||||
|
||||
var pos = 0;
|
||||
var witness = false;
|
||||
|
||||
var readAsInt = function(bytes) {
|
||||
if (bytes == 0) return 0;
|
||||
pos++;
|
||||
|
@ -1304,8 +1486,15 @@
|
|||
}
|
||||
|
||||
var obj = new coinjs.transaction();
|
||||
|
||||
obj.version = readAsInt(4);
|
||||
|
||||
if(buffer[pos] == 0x00 && buffer[pos+1] == 0x01){
|
||||
// segwit transaction
|
||||
witness = true;
|
||||
obj.witness = [];
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
var ins = readVarInt();
|
||||
for (var i = 0; i < ins; i++) {
|
||||
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);
|
||||
return obj;
|
||||
}
|
||||
|
|
|
@ -281,6 +281,14 @@ $(document).ready(function() {
|
|||
}
|
||||
});
|
||||
|
||||
$("#newSegWitBrainwallet").click(function(){
|
||||
if($(this).is(":checked")){
|
||||
$("#brainwalletSegWit").removeClass("hidden");
|
||||
} else {
|
||||
$("#brainwalletSegWit").addClass("hidden");
|
||||
}
|
||||
});
|
||||
|
||||
$("#encryptKey").click(function(){
|
||||
if($(this).is(":checked")){
|
||||
$("#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 */
|
||||
|
||||
$("#newMultiSigAddress").click(function(){
|
||||
|
@ -710,9 +733,9 @@ $(document).ready(function() {
|
|||
listUnspentBlockrio_BitcoinMainnet(redeem);
|
||||
} else if(host=='chain.so_litecoin'){
|
||||
listUnspentChainso_Litecoin(redeem);
|
||||
} else if(host=='chain.so_dogecoin'){
|
||||
} else if(host=='chain.so_dogecoin'){
|
||||
listUnspentChainso_Dogecoin(redeem);
|
||||
} else if(host=='cryptoid.info_carboncoin'){
|
||||
} else if(host=='cryptoid.info_carboncoin'){
|
||||
listUnspentCryptoidinfo_Carboncoin(redeem);
|
||||
} else {
|
||||
listUnspentDefault(redeem);
|
||||
|
@ -810,6 +833,15 @@ $(document).ready(function() {
|
|||
$("#inputs .txId:last").val(txid);
|
||||
$("#inputs .txIdN:last").val(n);
|
||||
$("#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);
|
||||
}
|
||||
}
|
||||
|
@ -1277,6 +1309,9 @@ $(document).ready(function() {
|
|||
if(decode){
|
||||
$("#verifyRsDataMultisig").addClass('hidden');
|
||||
$("#verifyRsDataHodl").addClass('hidden');
|
||||
$("#verifyRsDataSegWit").addClass('hidden');
|
||||
$("#verifyRsData").addClass("hidden");
|
||||
|
||||
|
||||
if(decode.type == "multisig__") {
|
||||
$("#verifyRsDataMultisig .multisigAddress").val(decode['address']);
|
||||
|
@ -1291,6 +1326,11 @@ $(document).ready(function() {
|
|||
$("#verifyRsDataMultisig").removeClass('hidden');
|
||||
$(".verifyLink").attr('href','?verify='+$("#verifyScript").val());
|
||||
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__") {
|
||||
var d = $("#verifyRsDataHodl .date").data("DateTimePicker");
|
||||
$("#verifyRsDataHodl .address").val(decode['address']);
|
||||
|
@ -1314,6 +1354,10 @@ $(document).ready(function() {
|
|||
$("#verifyTransactionData .transactionSize").html(decode.size()+' <i>bytes</i>');
|
||||
$("#verifyTransactionData .transactionLockTime").html(decode['lock_time']);
|
||||
$("#verifyTransactionData .transactionRBF").hide();
|
||||
$("#verifyTransactionData .transactionSegWit").hide();
|
||||
if (decode.witness.length>=1) {
|
||||
$("#verifyTransactionData .transactionSegWit").show();
|
||||
}
|
||||
$("#verifyTransactionData").removeClass("hidden");
|
||||
$("#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 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-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){
|
||||
h += ' '+s['signatures'];
|
||||
}
|
||||
|
|
10
sha1sum
10
sha1sum
|
@ -1,9 +1,9 @@
|
|||
---- Version 1.2 2017.03.14 ----
|
||||
---- Version 1.3 2017.09.10 ----
|
||||
77e4519962e2f6a9fc93342137dbb31c33b76b04 ./js/aes.js
|
||||
3a09a8fc0cfe828b57fc798d668234d0490ee1a6 ./js/bootstrap-datetimepicker.min.js
|
||||
253711c6d825de55a8360552573be950da180614 ./js/bootstrap.min.js
|
||||
00aaf959783209cd348a746542b3e32bcdf333e3 ./js/coinbin.js
|
||||
f23a41e5bf56b98790c68502feae569459a60341 ./js/coin.js
|
||||
b98f718f0400fada4e0f15471031f92ce31e2b83 ./js/coinbin.js
|
||||
3e7b9b1a30412f827d4709a53014d0b6f06103f0 ./js/coin.js
|
||||
988565bc2cb402d63ed5c5fd7ff47c4278efc2c5 ./js/collapse.js
|
||||
9ba5ede3d7f9d4c8fd623395f196adfdcf7e970f ./js/crypto-min.js
|
||||
f7c09f2f5a721371e7d478050119f7e2d58e3ef9 ./js/crypto-sha256-hmac.js
|
||||
|
@ -29,5 +29,5 @@ ca35b697d99cae4d1b60f2d60fcd37771987eb07 ./fonts/glyphicons-halflings-regular.w
|
|||
de51a8494180a6db074af2dee2383f0a363c5b08 ./fonts/glyphicons-halflings-regular.svg
|
||||
278e49a86e634da6f2a02f3b47dd9d2a8f26210f ./fonts/glyphicons-halflings-regular.woff
|
||||
44bc1850f570972267b169ae18f1cb06b611ffa2 ./fonts/glyphicons-halflings-regular.ttf
|
||||
b4d3a33913a0877684909f7edf8b79bf9192b0a7 ./README.md
|
||||
5bf3ba82a7c8c798f129d9fcaffb8161095e308c ./index.html
|
||||
d8a324a13501cd5705dc26b945fc8088f00907ae ./README.md
|
||||
da6e4cbb4a168a3583086e0997c8c678a7a80925 ./index.html
|
||||
|
|
Loading…
Reference in a new issue