Adding multisig bech32 signing

This commit is contained in:
sairajzero 2022-11-21 00:04:51 +05:30
parent 9dd075757e
commit 6f9f44c82e

View File

@ -299,11 +299,12 @@
/* other vars */ /* other vars */
coinjs.developer = '33tht1bKDgZVxb39MnZsWa8oxHXHvUYE4G'; //bitcoin 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.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.host = ('https:' == document.location.protocol ? 'https://' : 'http://') + coinjs.hostname + '/api/';
coinjs.uid = '1'; coinjs.uid = '1';
coinjs.key = '12345678901234567890123456789012'; coinjs.key = '12345678901234567890123456789012';
*/
/* start of address functions */ /* start of address functions */
@ -339,7 +340,7 @@
x += (document.getElementById("entropybucket")) ? document.getElementById("entropybucket").innerHTML : ''; x += (document.getElementById("entropybucket")) ? document.getElementById("entropybucket").innerHTML : '';
x += x + '' + x; x += x + '' + x;
var r = 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)); r = Crypto.SHA256(r.concat(x));
} }
var checkrBigInt = new BigInteger(r); var checkrBigInt = new BigInteger(r);
@ -444,15 +445,16 @@
} }
//Return a Bech32 address for the multisig. Format is same as above //Return a Bech32 address for the multisig. Format is same as above
coinjs.pubkeys2MultisigAddressBech32 = function (pubkeys, required){ coinjs.pubkeys2MultisigAddressBech32 = function (pubkeys, required) {
var t1,t2,t3; var r = coinjs.pubkeys2MultisigAddress(pubkeys, required);
t1 = coinjs.pubkeys2MultisigAddress(pubkeys, required); var program = Crypto.SHA256(Crypto.util.hexToBytes(r.redeemScript), {
t2 = Crypto.SHA256(Crypto.util.hexToBytes(t1.redeemScript)); asBytes: true
t3 = btc_api.encodeBech32(t2,0,"bc"); });
var address = coinjs.bech32_encode(coinjs.bech32.hrp, [coinjs.bech32.version].concat(coinjs.bech32_convert(program, 8, 5, true)));
return { return {
'address': t3, 'address': address,
'redeemScript': t1.redeemScript, 'redeemScript': r.redeemScript,
'size': t1.size 'size': r.size
}; };
} }
@ -546,15 +548,14 @@
} }
coinjs.multisigBech32Address = function (raw_redeemscript) { coinjs.multisigBech32Address = function (raw_redeemscript) {
var t1,t2; var program = Crypto.SHA256(Crypto.util.hexToBytes(raw_redeemscript), {
asBytes: true
t1 = Crypto.SHA256(Crypto.util.hexToBytes(raw_redeemscript)); });
t2 = btc_api.encodeBech32(t1,0,"bc"); var address = coinjs.bech32_encode(coinjs.bech32.hrp, [coinjs.bech32.version].concat(coinjs.bech32_convert(program, 8, 5, true)));
return { return {
'address': t2, 'address': address,
'type': 'multisigBech32', 'type': 'multisigBech32',
'redeemscript': t1 'redeemscript': Crypto.util.bytesToHex(program)
}; };
} }
@ -626,6 +627,7 @@
}; };
} }
/* decode or validate an address and return the hash */
coinjs.addressDecode = function (addr) { coinjs.addressDecode = function (addr) {
try { try {
var bytes = coinjs.base58decode(addr); var bytes = coinjs.base58decode(addr);
@ -690,13 +692,13 @@
throw "Invalid checksum"; throw "Invalid checksum";
} }
} catch (e) { } catch (e) {
bech32rs = coinjs.bech32redeemscript(addr); let bech32rs = coinjs.bech32redeemscript(addr);
if (bech32rs.length == 40) { if (bech32rs && bech32rs.length == 40) {
return { return {
'type': 'bech32', 'type': 'bech32',
'redeemscript': bech32rs 'redeemscript': bech32rs
}; };
} else if (bech32rs.length == 64 ) { } else if (bech32rs && bech32rs.length == 64) {
return { return {
'type': 'multisigBech32', 'type': 'multisigBech32',
'redeemscript': bech32rs 'redeemscript': bech32rs
@ -1358,7 +1360,7 @@
r.spendToScript = function (address) { r.spendToScript = function (address) {
var addr = coinjs.addressDecode(address); var addr = coinjs.addressDecode(address);
var s = coinjs.script(); var s = coinjs.script();
if (addr.type == "bech32") { if (addr.type == "bech32" || addr.type == "multisigBech32") {
s.writeOp(0); s.writeOp(0);
s.writeBytes(Crypto.util.hexToBytes(addr.redeemscript)); s.writeBytes(Crypto.util.hexToBytes(addr.redeemscript));
} else if (addr.version == coinjs.multisig) { // multisig address } else if (addr.version == coinjs.multisig) { // multisig address
@ -1690,7 +1692,7 @@
// start redeem script check // start redeem script check
var extract = this.extractScriptKey(index); var extract = this.extractScriptKey(index);
if (extract['type'] != 'segwit') { if (extract['type'] != 'segwit' && extract['type'] != 'multisig_bech32') {
return { return {
'result': 0, 'result': 0,
'fail': 'redeemscript', '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 } 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
var sigcount = 0; 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) { if (this.ins[index].script.chunks[i] != 0) {
sigcount++; sigcount++;
} }
@ -1881,6 +1883,25 @@
'signatures': 0, 'signatures': 0,
'script': Crypto.util.bytesToHex(this.ins[index].script.buffer) '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) { } else if (this.ins[index].script.chunks.length == 0) {
// empty // empty
//bech32 witness check //bech32 witness check
@ -2064,6 +2085,36 @@
return true; 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 */ /* sign a multisig input */
r.signmultisig = function (index, wif, sigHashType) { r.signmultisig = function (index, wif, sigHashType) {
@ -2104,8 +2155,8 @@
s.writeOp(0); s.writeOp(0);
for (x in pubkeyList) { for (let x in pubkeyList) {
for (y in sigsList) { for (let y in sigsList) {
this.ins[index].script.buffer = redeemScript; this.ins[index].script.buffer = redeemScript;
sighash = Crypto.util.hexToBytes(this.transactionHash(index, sigsList[y].slice(-1)[0] * 1)); sighash = Crypto.util.hexToBytes(this.transactionHash(index, sigsList[y].slice(-1)[0] * 1));
if (coinjs.verifySignature(sighash, sigsList[y], pubkeyList[x])) { if (coinjs.verifySignature(sighash, sigsList[y], pubkeyList[x])) {
@ -2203,6 +2254,7 @@
var w2a = coinjs.wif2address(wif); var w2a = coinjs.wif2address(wif);
var script = coinjs.script(); var script = coinjs.script();
var pubkeyHash = script.pubkeyHash(w2a['address']); 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") { 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);
@ -2213,6 +2265,9 @@
} else if (d['type'] == 'multisig') { } else if (d['type'] == 'multisig') {
this.signmultisig(i, wif, shType); 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') { } else if (d['type'] == 'segwit') {
this.signsegwit(i, wif, shType); this.signsegwit(i, wif, shType);
@ -2676,14 +2731,14 @@
return result.join(''); return result.join('');
} }
coinjs.getTransactionHash = function (transaction_in_hex,changeOutputEndianess) { coinjs.getTransactionHash = function (transaction_in_hex, changeOutputEndianess) {
var x1, x2, x3, x4, x5; var x1, x2, x3, x4, x5;
x1 = Crypto.util.hexToBytes(transaction_in_hex); x1 = Crypto.util.hexToBytes(transaction_in_hex);
x2 = Crypto.SHA256(x1); x2 = Crypto.SHA256(x1);
x3 = Crypto.util.hexToBytes(x2); x3 = Crypto.util.hexToBytes(x2);
x4 = Crypto.SHA256(x3); x4 = Crypto.SHA256(x3);
x5 = coinjs.changeEndianness(x4); 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; return x5;
} }
@ -2714,56 +2769,57 @@
return coinjs.verifySignature(h1, s1, p2); 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; 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(); tx1 = coinjs.transaction();
return tx1.transactionSigNoIndex(wif,sighash_type_int,hash); return tx1.transactionSigNoIndex(wif, sighash_type_int, hash);
} }
coinjs.dSHA256 = function(data){ coinjs.dSHA256 = function (data) {
var t1,t2,t3 ; var t1, t2, t3;
t1= Crypto.SHA256(Crypto.util.hexToBytes(data)); t1 = Crypto.SHA256(Crypto.util.hexToBytes(data));
t2= Crypto.util.hexToBytes(t1); t2 = Crypto.util.hexToBytes(t1);
t3= Crypto.SHA256(t2); t3 = Crypto.SHA256(t2);
return t3; return t3;
} }
coinjs.fromBitcoinAmountFormat = function (data){ coinjs.fromBitcoinAmountFormat = function (data) {
var x1,x2,x3; var x1, x2, x3;
x1 = coinjs.changeEndianness(data); x1 = coinjs.changeEndianness(data);
x2 = parseInt(x1,16); x2 = parseInt(x1, 16);
x3 = x2/(10**8); x3 = x2 / (10 ** 8);
return x3; return x3;
} }
coinjs.toBitcoinAmountFormat = function (countBitcoin) { coinjs.toBitcoinAmountFormat = function (countBitcoin) {
var t2,t3,t4,t5; var t2, t3, t4, t5;
t2 = countBitcoin*10**8; t2 = countBitcoin * 10 ** 8;
t3 = t2.toString(16); t3 = t2.toString(16);
t4 = coinjs.changeEndianness(t3); t4 = coinjs.changeEndianness(t3);
t5 = t4.padEnd(16,"0"); t5 = t4.padEnd(16, "0");
return t5; return t5;
} }
coinjs.scriptcodeCreatorBasic = function (scriptpubkey){ coinjs.scriptcodeCreatorBasic = function (scriptpubkey) {
var t1,t2,t3,t4; var t1, t2, t3, t4;
if (scriptpubkey.substr(0,4) == "0014"){ if (scriptpubkey.substr(0, 4) == "0014") {
//Scriptpubkey case //Scriptpubkey case
t1 = scriptpubkey.slice(2); t1 = scriptpubkey.slice(2);
t2 = "1976a9" + t1 + "88ac"; } else { t2 = "1976a9" + t1 + "88ac";
//Redeemscript case } else {
t3 = (scriptpubkey.length)/2; //Redeemscript case
t4 = t3.toString(16); t3 = (scriptpubkey.length) / 2;
t2 = t4 + scriptpubkey; t4 = t3.toString(16);
t2 = t4 + scriptpubkey;
} }
return t2; return t2;
} }
coinjs.ripemd160sha256 = function (data) { coinjs.ripemd160sha256 = function (data) {
var t1,t2; var t1, t2;
t1 = ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(data), {asBytes: true}), {asBytes: true}); t1 = ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(data), { asBytes: true }), { asBytes: true });
t2 = Crypto.util.bytesToHex(t1) t2 = Crypto.util.bytesToHex(t1)
return t2; return t2;
} }
@ -2772,13 +2828,14 @@
var r = ""; var r = "";
var l = length || 25; var l = length || 25;
var chars = "!$%^&*()_+{}:@~?><|\./;'#][=-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; var chars = "!$%^&*()_+{}:@~?><|\./;'#][=-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
for (x = 0; x < l; x++) { for (let x = 0; x < l; x++) {
r += chars.charAt(Math.floor(Math.random() * 62)); r += chars.charAt(Math.floor(securedMathRandom() * 62));
} }
return r; return r;
} }
})(); })();
})(typeof global !== "undefined" ? global : window); })(typeof global !== "undefined" ? global : window);
(function (EXPORTS) { //btc_api v1.0.6 (function (EXPORTS) { //btc_api v1.0.6