Adding multisig bech32 signing
This commit is contained in:
parent
9dd075757e
commit
6f9f44c82e
199
lib_btc.js
199
lib_btc.js
@ -299,11 +299,12 @@
|
||||
/* other vars */
|
||||
coinjs.developer = '33tht1bKDgZVxb39MnZsWa8oxHXHvUYE4G'; //bitcoin
|
||||
|
||||
/* bit(coinb.in) api vars */
|
||||
/* bit(coinb.in) api vars
|
||||
coinjs.hostname = ((document.location.hostname.split(".")[(document.location.hostname.split(".")).length - 1]) == 'onion') ? 'coinbin3ravkwb24f7rmxx6w3snkjw45jhs5lxbh3yfeg3vpt6janwqd.onion' : 'coinb.in';
|
||||
coinjs.host = ('https:' == document.location.protocol ? 'https://' : 'http://') + coinjs.hostname + '/api/';
|
||||
coinjs.uid = '1';
|
||||
coinjs.key = '12345678901234567890123456789012';
|
||||
*/
|
||||
|
||||
/* start of address functions */
|
||||
|
||||
@ -339,7 +340,7 @@
|
||||
x += (document.getElementById("entropybucket")) ? document.getElementById("entropybucket").innerHTML : '';
|
||||
x += x + '' + x;
|
||||
var r = x;
|
||||
for (i = 0; i < (x).length / 25; i++) {
|
||||
for (let i = 0; i < (x).length / 25; i++) {
|
||||
r = Crypto.SHA256(r.concat(x));
|
||||
}
|
||||
var checkrBigInt = new BigInteger(r);
|
||||
@ -444,18 +445,19 @@
|
||||
}
|
||||
|
||||
//Return a Bech32 address for the multisig. Format is same as above
|
||||
coinjs.pubkeys2MultisigAddressBech32 = function (pubkeys, required){
|
||||
var t1,t2,t3;
|
||||
t1 = coinjs.pubkeys2MultisigAddress(pubkeys, required);
|
||||
t2 = Crypto.SHA256(Crypto.util.hexToBytes(t1.redeemScript));
|
||||
t3 = btc_api.encodeBech32(t2,0,"bc");
|
||||
coinjs.pubkeys2MultisigAddressBech32 = function (pubkeys, required) {
|
||||
var r = coinjs.pubkeys2MultisigAddress(pubkeys, required);
|
||||
var program = Crypto.SHA256(Crypto.util.hexToBytes(r.redeemScript), {
|
||||
asBytes: true
|
||||
});
|
||||
var address = coinjs.bech32_encode(coinjs.bech32.hrp, [coinjs.bech32.version].concat(coinjs.bech32_convert(program, 8, 5, true)));
|
||||
return {
|
||||
'address': t3,
|
||||
'redeemScript': t1.redeemScript,
|
||||
'size': t1.size
|
||||
'address': address,
|
||||
'redeemScript': r.redeemScript,
|
||||
'size': r.size
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/* new time locked address, provide the pubkey and time necessary to unlock the funds.
|
||||
when time is greater than 500000000, it should be a unix timestamp (seconds since epoch),
|
||||
otherwise it should be the block height required before this transaction can be released.
|
||||
@ -544,20 +546,19 @@
|
||||
'redeemscript': Crypto.util.bytesToHex(program)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
coinjs.multisigBech32Address = function (raw_redeemscript) {
|
||||
var t1,t2;
|
||||
|
||||
t1 = Crypto.SHA256(Crypto.util.hexToBytes(raw_redeemscript));
|
||||
t2 = btc_api.encodeBech32(t1,0,"bc");
|
||||
|
||||
var program = Crypto.SHA256(Crypto.util.hexToBytes(raw_redeemscript), {
|
||||
asBytes: true
|
||||
});
|
||||
var address = coinjs.bech32_encode(coinjs.bech32.hrp, [coinjs.bech32.version].concat(coinjs.bech32_convert(program, 8, 5, true)));
|
||||
return {
|
||||
'address': t2,
|
||||
'address': address,
|
||||
'type': 'multisigBech32',
|
||||
'redeemscript': t1
|
||||
'redeemscript': Crypto.util.bytesToHex(program)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/* extract the redeemscript from a bech32 address */
|
||||
coinjs.bech32redeemscript = function (address) {
|
||||
var r = false;
|
||||
@ -568,7 +569,7 @@
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/* provide a privkey and return an WIF */
|
||||
coinjs.privkey2wif = function (h) {
|
||||
var r = Crypto.util.hexToBytes(h);
|
||||
@ -626,6 +627,7 @@
|
||||
};
|
||||
}
|
||||
|
||||
/* decode or validate an address and return the hash */
|
||||
coinjs.addressDecode = function (addr) {
|
||||
try {
|
||||
var bytes = coinjs.base58decode(addr);
|
||||
@ -647,9 +649,9 @@
|
||||
|
||||
} else if (o.version == coinjs.multisig) { // multisig address
|
||||
o.type = 'multisig';
|
||||
|
||||
|
||||
} else if (o.version == coinjs.multisigBech32) { // multisigBech32 added
|
||||
o.type = 'multisigBech32';
|
||||
o.type = 'multisigBech32';
|
||||
|
||||
} else if (o.version == coinjs.priv) { // wifkey
|
||||
o.type = 'wifkey';
|
||||
@ -690,13 +692,13 @@
|
||||
throw "Invalid checksum";
|
||||
}
|
||||
} catch (e) {
|
||||
bech32rs = coinjs.bech32redeemscript(addr);
|
||||
if (bech32rs.length == 40) {
|
||||
let bech32rs = coinjs.bech32redeemscript(addr);
|
||||
if (bech32rs && bech32rs.length == 40) {
|
||||
return {
|
||||
'type': 'bech32',
|
||||
'redeemscript': bech32rs
|
||||
};
|
||||
} else if (bech32rs.length == 64 ) {
|
||||
} else if (bech32rs && bech32rs.length == 64) {
|
||||
return {
|
||||
'type': 'multisigBech32',
|
||||
'redeemscript': bech32rs
|
||||
@ -1345,7 +1347,7 @@
|
||||
var rs = Crypto.util.bytesToHex(s.buffer);
|
||||
r.redeemscript = rs;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
// console.log(e);
|
||||
@ -1353,12 +1355,12 @@
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/* create output script to spend */
|
||||
r.spendToScript = function (address) {
|
||||
var addr = coinjs.addressDecode(address);
|
||||
var s = coinjs.script();
|
||||
if (addr.type == "bech32") {
|
||||
if (addr.type == "bech32" || addr.type == "multisigBech32") {
|
||||
s.writeOp(0);
|
||||
s.writeBytes(Crypto.util.hexToBytes(addr.redeemscript));
|
||||
} else if (addr.version == coinjs.multisig) { // multisig address
|
||||
@ -1690,7 +1692,7 @@
|
||||
|
||||
// start redeem script check
|
||||
var extract = this.extractScriptKey(index);
|
||||
if (extract['type'] != 'segwit') {
|
||||
if (extract['type'] != 'segwit' && extract['type'] != 'multisig_bech32') {
|
||||
return {
|
||||
'result': 0,
|
||||
'fail': 'redeemscript',
|
||||
@ -1861,7 +1863,7 @@
|
||||
} 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
|
||||
var sigcount = 0;
|
||||
for (i = 1; i < this.ins[index].script.chunks.length - 1; i++) {
|
||||
for (let i = 1; i < this.ins[index].script.chunks.length - 1; i++) {
|
||||
if (this.ins[index].script.chunks[i] != 0) {
|
||||
sigcount++;
|
||||
}
|
||||
@ -1881,6 +1883,25 @@
|
||||
'signatures': 0,
|
||||
'script': Crypto.util.bytesToHex(this.ins[index].script.buffer)
|
||||
};
|
||||
} else if (this.ins[index].script.chunks[0] >= 80 && this.ins[index].script.chunks[this.ins[index].script.chunks.length - 3] == 174 && this.ins[index].script.chunks[this.ins[index].script.chunks.length - 2] == 0) { //OP_CHECKMULTISIG_BECH32
|
||||
let last_index = this.ins[index].script.chunks.length - 1;
|
||||
let rs = Crypto.util.bytesToHex(this.ins[index].script.buffer.slice(0, this.ins[index].script.buffer.length - 2 - this.ins[index].script.chunks[last_index].length))
|
||||
var sigcount, req_sigs = this.ins[index].script.chunks[0] - 80;
|
||||
var value = - 1;
|
||||
if ((this.ins[index].script.chunks[last_index]) && this.ins[index].script.chunks[last_index].length == 8) {
|
||||
value = coinjs.bytesToNum(this.ins[index].script.chunks[last_index]); // value found encoded in transaction (THIS IS NON STANDARD)
|
||||
}
|
||||
if (!this.witness[index])
|
||||
sigcount = 0;
|
||||
else
|
||||
sigcount = this.witness[index].length - 2;
|
||||
return {
|
||||
'type': 'multisig_bech32',
|
||||
'signed': sigcount >= req_sigs ? 'true' : 'false',
|
||||
'signatures': sigcount,
|
||||
'script': rs,
|
||||
'value': value
|
||||
};
|
||||
} else if (this.ins[index].script.chunks.length == 0) {
|
||||
// empty
|
||||
//bech32 witness check
|
||||
@ -2064,6 +2085,36 @@
|
||||
return true;
|
||||
}
|
||||
|
||||
r.signmultisig_bech32 = function (index, wif, sigHashType, redeemScript) {
|
||||
var shType = sigHashType || 1;
|
||||
var wif2 = coinjs.wif2pubkey(wif);
|
||||
|
||||
let decode_rs = coinjs.script().decodeRedeemScriptBech32(redeemScript);
|
||||
var txhash = this.transactionHashSegWitV0(index, shType);
|
||||
console.debug(txhash, decode_rs.pubkeys,wif2['pubkey'])
|
||||
if (txhash.result == 1 && decode_rs.pubkeys.includes(wif2['pubkey'])) {
|
||||
var segwitHash = Crypto.util.hexToBytes(txhash.hash);
|
||||
var signature = this.transactionSig(index, wif, shType, segwitHash);
|
||||
|
||||
if (!coinjs.isArray(this.witness)) {
|
||||
this.witness = new Array(this.ins.length);
|
||||
this.witness.fill([]);
|
||||
}
|
||||
|
||||
if (!coinjs.isArray(this.witness[index]) || !this.witness[index].length)
|
||||
this.witness[index] = [0, redeemScript];
|
||||
console.debug(this.witness[index])
|
||||
this.witness[index].splice(this.witness[index].length - 1, 0, signature);
|
||||
console.debug(this.witness[index])
|
||||
if (this.witness[index].length - 2 >= decode_rs.signaturesRequired) { // TODO Case:FULLY_SIGNED
|
||||
// remove any non standard data we store, i.e. input value
|
||||
var script = coinjs.script();
|
||||
this.ins[index].script = script; //TODO: check if hash of redeemScript or something else is required instead
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* sign a multisig input */
|
||||
r.signmultisig = function (index, wif, sigHashType) {
|
||||
|
||||
@ -2104,8 +2155,8 @@
|
||||
|
||||
s.writeOp(0);
|
||||
|
||||
for (x in pubkeyList) {
|
||||
for (y in sigsList) {
|
||||
for (let x in pubkeyList) {
|
||||
for (let y in sigsList) {
|
||||
this.ins[index].script.buffer = redeemScript;
|
||||
sighash = Crypto.util.hexToBytes(this.transactionHash(index, sigsList[y].slice(-1)[0] * 1));
|
||||
if (coinjs.verifySignature(sighash, sigsList[y], pubkeyList[x])) {
|
||||
@ -2203,6 +2254,7 @@
|
||||
var w2a = coinjs.wif2address(wif);
|
||||
var script = coinjs.script();
|
||||
var pubkeyHash = script.pubkeyHash(w2a['address']);
|
||||
console.debug(d);
|
||||
|
||||
if (((d['type'] == 'scriptpubkey' && d['script'] == Crypto.util.bytesToHex(pubkeyHash.buffer)) || d['type'] == 'empty') && d['signed'] == "false") {
|
||||
this.signinput(i, wif, shType);
|
||||
@ -2213,6 +2265,9 @@
|
||||
} else if (d['type'] == 'multisig') {
|
||||
this.signmultisig(i, wif, shType);
|
||||
|
||||
} else if (d['type'] == 'multisig_bech32' && d['signed'] == "false") {
|
||||
this.signmultisig_bech32(i, wif, shType, d['script']);
|
||||
|
||||
} else if (d['type'] == 'segwit') {
|
||||
this.signsegwit(i, wif, shType);
|
||||
|
||||
@ -2676,14 +2731,14 @@
|
||||
return result.join('');
|
||||
}
|
||||
|
||||
coinjs.getTransactionHash = function (transaction_in_hex,changeOutputEndianess) {
|
||||
coinjs.getTransactionHash = function (transaction_in_hex, changeOutputEndianess) {
|
||||
var x1, x2, x3, x4, x5;
|
||||
x1 = Crypto.util.hexToBytes(transaction_in_hex);
|
||||
x2 = Crypto.SHA256(x1);
|
||||
x3 = Crypto.util.hexToBytes(x2);
|
||||
x4 = Crypto.SHA256(x3);
|
||||
x5 = coinjs.changeEndianness(x4);
|
||||
if (changeOutputEndianess == true) { x5 = x5 } else if ((typeof changeOutputEndianess == 'undefined') || (changeOutputEndianess == false) ){ x5 = x4 };
|
||||
if (changeOutputEndianess == true) { x5 = x5 } else if ((typeof changeOutputEndianess == 'undefined') || (changeOutputEndianess == false)) { x5 = x4 };
|
||||
return x5;
|
||||
}
|
||||
|
||||
@ -2713,72 +2768,74 @@
|
||||
|
||||
return coinjs.verifySignature(h1, s1, p2);
|
||||
}
|
||||
|
||||
coinjs.generateBitcoinSignature = function (private_key,hash,sighash_type_int = 1){
|
||||
|
||||
coinjs.generateBitcoinSignature = function (private_key, hash, sighash_type_int = 1) {
|
||||
var wif, tx1;
|
||||
if (private_key.length < 60) { wif = private_key } else { wif = coinjs.privkey2wif(private_key) };
|
||||
if (private_key.length < 60) { wif = private_key } else { wif = coinjs.privkey2wif(private_key) };
|
||||
tx1 = coinjs.transaction();
|
||||
return tx1.transactionSigNoIndex(wif,sighash_type_int,hash);
|
||||
return tx1.transactionSigNoIndex(wif, sighash_type_int, hash);
|
||||
}
|
||||
|
||||
coinjs.dSHA256 = function(data){
|
||||
var t1,t2,t3 ;
|
||||
t1= Crypto.SHA256(Crypto.util.hexToBytes(data));
|
||||
t2= Crypto.util.hexToBytes(t1);
|
||||
t3= Crypto.SHA256(t2);
|
||||
coinjs.dSHA256 = function (data) {
|
||||
var t1, t2, t3;
|
||||
t1 = Crypto.SHA256(Crypto.util.hexToBytes(data));
|
||||
t2 = Crypto.util.hexToBytes(t1);
|
||||
t3 = Crypto.SHA256(t2);
|
||||
return t3;
|
||||
}
|
||||
|
||||
coinjs.fromBitcoinAmountFormat = function (data){
|
||||
var x1,x2,x3;
|
||||
coinjs.fromBitcoinAmountFormat = function (data) {
|
||||
var x1, x2, x3;
|
||||
x1 = coinjs.changeEndianness(data);
|
||||
x2 = parseInt(x1,16);
|
||||
x3 = x2/(10**8);
|
||||
x2 = parseInt(x1, 16);
|
||||
x3 = x2 / (10 ** 8);
|
||||
return x3;
|
||||
}
|
||||
|
||||
|
||||
coinjs.toBitcoinAmountFormat = function (countBitcoin) {
|
||||
var t2,t3,t4,t5;
|
||||
t2 = countBitcoin*10**8;
|
||||
var t2, t3, t4, t5;
|
||||
t2 = countBitcoin * 10 ** 8;
|
||||
t3 = t2.toString(16);
|
||||
t4 = coinjs.changeEndianness(t3);
|
||||
t5 = t4.padEnd(16,"0");
|
||||
t5 = t4.padEnd(16, "0");
|
||||
return t5;
|
||||
}
|
||||
|
||||
coinjs.scriptcodeCreatorBasic = function (scriptpubkey){
|
||||
var t1,t2,t3,t4;
|
||||
if (scriptpubkey.substr(0,4) == "0014"){
|
||||
//Scriptpubkey case
|
||||
t1 = scriptpubkey.slice(2);
|
||||
t2 = "1976a9" + t1 + "88ac"; } else {
|
||||
//Redeemscript case
|
||||
t3 = (scriptpubkey.length)/2;
|
||||
t4 = t3.toString(16);
|
||||
t2 = t4 + scriptpubkey;
|
||||
}
|
||||
|
||||
coinjs.scriptcodeCreatorBasic = function (scriptpubkey) {
|
||||
var t1, t2, t3, t4;
|
||||
if (scriptpubkey.substr(0, 4) == "0014") {
|
||||
//Scriptpubkey case
|
||||
t1 = scriptpubkey.slice(2);
|
||||
t2 = "1976a9" + t1 + "88ac";
|
||||
} else {
|
||||
//Redeemscript case
|
||||
t3 = (scriptpubkey.length) / 2;
|
||||
t4 = t3.toString(16);
|
||||
t2 = t4 + scriptpubkey;
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
coinjs.ripemd160sha256 = function (data) {
|
||||
var t1,t2;
|
||||
|
||||
t1 = ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(data), {asBytes: true}), {asBytes: true});
|
||||
coinjs.ripemd160sha256 = function (data) {
|
||||
var t1, t2;
|
||||
|
||||
t1 = ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(data), { asBytes: true }), { asBytes: true });
|
||||
t2 = Crypto.util.bytesToHex(t1)
|
||||
return t2;
|
||||
}
|
||||
|
||||
|
||||
coinjs.random = function (length) {
|
||||
var r = "";
|
||||
var l = length || 25;
|
||||
var chars = "!$%^&*()_+{}:@~?><|\./;'#][=-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
|
||||
for (x = 0; x < l; x++) {
|
||||
r += chars.charAt(Math.floor(Math.random() * 62));
|
||||
for (let x = 0; x < l; x++) {
|
||||
r += chars.charAt(Math.floor(securedMathRandom() * 62));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
})(typeof global !== "undefined" ? global : window);
|
||||
|
||||
(function (EXPORTS) { //btc_api v1.0.6
|
||||
|
||||
Loading…
Reference in New Issue
Block a user