From 7757ac3239ac8c49313270c76b460fa331fcbe30 Mon Sep 17 00:00:00 2001 From: sairaj mote Date: Tue, 9 Jan 2024 03:32:50 +0530 Subject: [PATCH] Adding tor API support --- btcOperator.js | 99 +++++++++++++++++++++++++++++------------ btcOperator.min.js | 1 + compactIDB.min.js | 1 + floBlockchainAPI.js | 20 ++++++++- floBlockchainAPI.min.js | 1 + floCloudAPI.min.js | 1 + floCrypto.min.js | 1 + floDapps.min.js | 1 + floTokenAPI.js | 52 ++++++++++++++++------ floTokenAPI.min.js | 1 + lib.min.js | 57 ++++++++++++++++++++++++ 11 files changed, 192 insertions(+), 43 deletions(-) create mode 100644 btcOperator.min.js create mode 100644 compactIDB.min.js create mode 100644 floBlockchainAPI.min.js create mode 100644 floCloudAPI.min.js create mode 100644 floCrypto.min.js create mode 100644 floDapps.min.js create mode 100644 floTokenAPI.min.js create mode 100644 lib.min.js diff --git a/btcOperator.js b/btcOperator.js index 3f2c571..0e7301e 100644 --- a/btcOperator.js +++ b/btcOperator.js @@ -1,4 +1,4 @@ -(function (EXPORTS) { //btcOperator v1.2.7 +(function (EXPORTS) { //btcOperator v1.2.8 /* BTC Crypto and API Operator */ const btcOperator = EXPORTS; const SATOSHI_IN_BTC = 1e8; @@ -22,6 +22,7 @@ try { const response = await fetch(url, { method: 'POST', + mode: 'no-cors', headers: { 'Content-Type': 'application/json' }, @@ -56,7 +57,7 @@ }, async broadcast({ rawTxHex, url }) { try { - const result = await post(`${url || this.url}txs/push`, { tx: rawTxHex }) + const result = await post(`${url || this.url}pushtx`, { tx: rawTxHex }) return result.hash } catch (e) { throw e @@ -78,16 +79,19 @@ latestBlock() { return fetch_api(`blocks/tip/height`, { url: this.url }) }, - // tx({ txid, url }) { - // return fetch_api(`tx/${txid}`, { url: url || this.url }) - // .then(result => formatTx(result)) - // }, - // txHex({ txid, url }) { - // return fetch_api(`tx/${txid}/hex`, { url: url || this.url, asText: true }) - // }, - // txs({ addr, before, after, url }) { - // return fetch_api(`address/${addr}/txs${before ? `?before=${before}` : ''}${after ? `?after=${after}` : ''}`, { url: url || this.url }) - // }, + tx({ txid, url }) { + return fetch_api(`tx/${txid}`, { url: url || this.url }) + .then(result => formatTx(result)) + }, + txHex({ txid, url }) { + return fetch_api(`tx/${txid}/hex`, { url: url || this.url, asText: true }) + }, + txs({ addr, url, ...args }) { + let queryParams = Object.entries(args).map(([key, value]) => `${key}=${value}`).join('&') + if (queryParams) + queryParams = '?' + queryParams + return fetch_api(`address/${addr}/txs${queryParams}`, { url: url || this.url }) + }, async block({ id, url }) { // if id is hex string then it is block hash try { @@ -114,17 +118,20 @@ latestBlock() { return fetch_api(`blocks/tip/height`, { url: this.url }) }, - // tx({ txid }) { - // return fetch_api(`tx/${txid}`, { url: this.url }) - // .then(result => formatTx(result)) + tx({ txid }) { + return fetch_api(`tx/${txid}`, { url: this.url }) + .then(result => formatTx(result)) - // }, - // txHex({ txid }) { - // return fetch_api(`tx/${txid}/hex`, { url: this.url, asText: true }) - // }, - // txs({ addr, before, after }) { - // return fetch_api(`address/${addr}/txs${before ? `?before=${before}` : ''}${after ? `?after=${after}` : ''}`, { url: this.url }) - // }, + }, + txHex({ txid }) { + return fetch_api(`tx/${txid}/hex`, { url: this.url, asText: true }) + }, + txs({ addr, ...args }) { + let queryParams = Object.entries(args).map(([key, value]) => `${key}=${value}`).join('&') + if (queryParams) + queryParams = '?' + queryParams + return fetch_api(`address/${addr}/txs${queryParams}`, { url: this.url }) + }, async block({ id }) { // if id is hex string then it is block hash try { @@ -159,8 +166,11 @@ txHex({ txid }) { return fetch_api(`rawtx/${txid}?format=hex`, { url: this.url, asText: true }) }, - txs({ addr, before, after }) { - return fetch_api(`rawaddr/${addr}${before ? `?before=${before}` : ''}${after ? `?after=${after}` : ''}`, { url: this.url }) + txs({ addr, ...args }) { + let queryParams = Object.entries(args).map(([key, value]) => `${key}=${value}`).join('&') + if (queryParams) + queryParams = '?' + queryParams + return fetch_api(`rawaddr/${addr}${queryParams}`, { url: this.url }) .then(result => result.txs) }, latestBlock() { @@ -196,6 +206,43 @@ } } + }, + { + url: 'https://coinb.in/api/?uid=1&key=12345678901234567890123456789012&setmodule=bitcoin&request=sendrawtransaction', + name: 'Coinb.in', + broadcast({ rawTxHex }) { + return new Promise((resolve, reject) => { + fetch(this.url, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + body: "rawtx=" + rawTxHex + }).then(response => { + console.log(response) + response.text().then(resultText => { + let r = resultText.match(/.*<\/result>/); + if (!r) + reject(resultText); + else { + r = r.pop().replace('', '').replace('', ''); + if (r == '1') { + let txid = resultText.match(/.*<\/txid>/).pop().replace('', '').replace('', ''); + resolve(txid); + } else if (r == '0') { + let error + if (resultText.includes('')) { + error = resultText.match(/.*<\/message>/).pop().replace('', '').replace('', ''); + } else { + error = resultText.match(/.*<\/response>/).pop().replace('', '').replace('', ''); + } + reject(decodeURIComponent(error.replace(/\+/g, " "))); + } else reject(resultText); + } + }).catch(error => reject(error)) + }).catch(error => reject(error)) + }); + } } ] @@ -309,10 +356,6 @@ console.error(error) APIs[index].coolDownTime = new Date().getTime() + 1000 * 60 * 10; // 10 minutes return multiApi(fnName, { index: index + 1, ...args }); - if (error.code && [301, 429, 404].includes(error.code)) { - } else { - throw error.message || error; - } } }; diff --git a/btcOperator.min.js b/btcOperator.min.js new file mode 100644 index 0000000..9429bb7 --- /dev/null +++ b/btcOperator.min.js @@ -0,0 +1 @@ +!function(EXPORTS){const btcOperator="object"===typeof module?module.exports:window.btcOperator={},util=btcOperator.util={};util.Sat_to_BTC=value=>parseFloat((value/1e8).toFixed(8)),util.BTC_to_Sat=value=>parseInt(1e8*value);const checkIfTor=btcOperator.checkIfTor=()=>fetch("https://check.torproject.org/api/ip",{mode:"no-cors"}).then((response=>response.json())).then((result=>result.IsTor)).catch((error=>!1));let isTor=!1;async function post(url,data,{asText:asText=!1}={}){try{const response=await fetch(url,{method:"POST",mode:"no-cors",headers:{"Content-Type":"application/json"},body:JSON.stringify(data)});if(response.ok)return asText?await response.text():await response.json();throw response}catch(e){throw e}}checkIfTor().then((result=>isTor=result));const APIs=btcOperator.APIs=[{url:"https://api.blockcypher.com/v1/btc/main/",name:"Blockcypher",balance({addr:addr}){return fetch_api(`addrs/${addr}/balance`,{url:this.url}).then((result=>util.Sat_to_BTC(result.balance)))},async block({id:id}){try{let block=await fetch_api(`blocks/${id}`,{url:this.url});return formatBlock(block)}catch(e){console.log(e)}},async broadcast({rawTxHex:rawTxHex,url:url}){try{return(await post(`${url||this.url}pushtx`,{tx:rawTxHex})).hash}catch(e){throw e}}},{url:"https://blockstream.info/api/",name:"Blockstream",hasOnion:!0,onionUrl:"http://explorerzydxu5ecjrkwceayqybizmpjjznk5izmitf2modhcusuqlid.onion/api/",balance({addr:addr,url:url}){return fetch_api(`address/${addr}/utxo`,{url:url||this.url}).then((result=>{const balance=result.reduce(((t,u)=>t+u.value),0);return util.Sat_to_BTC(balance)}))},latestBlock(){return fetch_api("blocks/tip/height",{url:this.url})},tx({txid:txid,url:url}){return fetch_api(`tx/${txid}`,{url:url||this.url}).then((result=>formatTx(result)))},txHex({txid:txid,url:url}){return fetch_api(`tx/${txid}/hex`,{url:url||this.url,asText:!0})},txs({addr:addr,url:url,...args}){let queryParams=Object.entries(args).map((([key,value])=>`${key}=${value}`)).join("&");return queryParams&&(queryParams="?"+queryParams),fetch_api(`address/${addr}/txs${queryParams}`,{url:url||this.url})},async block({id:id,url:url}){try{let blockHash=id;/^[0-9a-f]{64}$/i.test(id)||(blockHash=await fetch_api(`block-height/${id}`,{url:url||this.url,asText:!0}));const block=await fetch_api(`block/${blockHash}`,{url:url||this.url});return formatBlock(block)}catch(e){throw e}},async broadcast({rawTxHex:rawTxHex,url:url}){return post(`${url||this.url}tx`,{tx:rawTxHex},{asText:!0})}},{url:"https://mempool.space/api/",name:"Mempool",balance({addr:addr}){return fetch_api(`address/${addr}`,{url:this.url}).then((result=>util.Sat_to_BTC(result.chain_stats.funded_txo_sum-result.chain_stats.spent_txo_sum)))},latestBlock(){return fetch_api("blocks/tip/height",{url:this.url})},tx({txid:txid}){return fetch_api(`tx/${txid}`,{url:this.url}).then((result=>formatTx(result)))},txHex({txid:txid}){return fetch_api(`tx/${txid}/hex`,{url:this.url,asText:!0})},txs({addr:addr,...args}){let queryParams=Object.entries(args).map((([key,value])=>`${key}=${value}`)).join("&");return queryParams&&(queryParams="?"+queryParams),fetch_api(`address/${addr}/txs${queryParams}`,{url:this.url})},async block({id:id}){try{let blockHash=id;/^[0-9a-f]{64}$/i.test(id)||(blockHash=await fetch_api(`block-height/${id}`,{url:this.url,asText:!0}));const block=await fetch_api(`block/${blockHash}`,{url:this.url});return formatBlock(block)}catch(e){throw e}},async broadcast({rawTxHex:rawTxHex,url:url}){return post(`${url||this.url}tx`,{tx:rawTxHex},{asText:!0})}},{url:"https://blockchain.info/",name:"Blockchain",balance({addr:addr}){return fetch_api(`q/addressbalance/${addr}`,{url:this.url}).then((result=>util.Sat_to_BTC(result)))},unspent({addr:addr,allowUnconfirmedUtxos:allowUnconfirmedUtxos=!1}){return fetch_api(`unspent?active=${addr}`,{url:this.url}).then((result=>formatUtxos(result.unspent_outputs,allowUnconfirmedUtxos)))},tx({txid:txid}){return fetch_api(`rawtx/${txid}`,{url:this.url}).then((result=>formatTx(result)))},txHex({txid:txid}){return fetch_api(`rawtx/${txid}?format=hex`,{url:this.url,asText:!0})},txs({addr:addr,...args}){let queryParams=Object.entries(args).map((([key,value])=>`${key}=${value}`)).join("&");return queryParams&&(queryParams="?"+queryParams),fetch_api(`rawaddr/${addr}${queryParams}`,{url:this.url}).then((result=>result.txs))},latestBlock(){return fetch_api("q/getblockcount",{url:this.url})},async block({id:id}){try{let block;if(/^[0-9a-f]{64}$/i.test(id))block=await fetch_api(`rawblock/${id}`,{url:this.url});else{block=(await fetch_api(`block-height/${id}?format=json`,{url:this.url})).blocks[0]}return formatBlock(block)}catch(e){throw e}},async blockTxs({id:id}){try{let block;if(/^[0-9a-f]{64}$/i.test(id))block=await fetch_api(`rawblock/${id}`,{url:this.url});else{block=(await fetch_api(`block-height/${id}?format=json`,{url:this.url})).blocks[0]}return block.tx}catch(e){}}},{url:"https://coinb.in/api/?uid=1&key=12345678901234567890123456789012&setmodule=bitcoin&request=sendrawtransaction",name:"Coinb.in",broadcast({rawTxHex:rawTxHex}){return new Promise(((resolve,reject)=>{fetch(this.url,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:"rawtx="+rawTxHex}).then((response=>{console.log(response),response.text().then((resultText=>{let r=resultText.match(/.*<\/result>/);if(r)if(r=r.pop().replace("","").replace("",""),"1"==r){let txid=resultText.match(/.*<\/txid>/).pop().replace("","").replace("","");resolve(txid)}else if("0"==r){let error;error=resultText.includes("")?resultText.match(/.*<\/message>/).pop().replace("","").replace("",""):resultText.match(/.*<\/response>/).pop().replace("","").replace("",""),reject(decodeURIComponent(error.replace(/\+/g," ")))}else reject(resultText);else reject(resultText)})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))}}];btcOperator.util.format={};const formatBlock=btcOperator.util.format.block=async block=>{try{const{height:height,hash:hash,id:id,time:time,timestamp:timestamp,mrkl_root:mrkl_root,merkle_root:merkle_root,prev_block:prev_block,next_block:next_block,size:size}=block,details={height:height,hash:hash||id,time:1e3*(time||timestamp),merkle_root:merkle_root||mrkl_root,size:size};return prev_block&&(details.prev_block=prev_block),next_block&&(details.next_block=next_block[0]),details}catch(e){throw e}},formatUtxos=btcOperator.util.format.utxos=async(utxos,allowUnconfirmedUtxos=!1)=>{try{if(!allowUnconfirmedUtxos&&!utxos||!Array.isArray(utxos))throw{message:"No utxos found",code:1e3};return utxos.map((utxo=>{const{tx_hash:tx_hash,tx_hash_big_endian:tx_hash_big_endian,txid:txid,tx_output_n:tx_output_n,vout:vout,value:value,script:script,confirmations:confirmations,status:{confirmed:confirmed}={}}=utxo;return{confirmations:confirmations||confirmed,tx_hash_big_endian:tx_hash_big_endian||tx_hash||txid,tx_output_n:tx_output_n||vout,value:value,script:script}}))}catch(e){throw e}},formatTx=btcOperator.util.format.tx=async tx=>{try{let{txid:txid,hash:hash,time:time,block_height:block_height,fee:fee,fees:fees,received:received,confirmed:confirmed,size:size,double_spend:double_spend,block_hash:block_hash,confirmations:confirmations,status:{block_height:statusBlockHeight,block_hash:statusBlockHash,block_time:block_time}={}}=tx;if((block_height||statusBlockHeight)&&void 0===confirmations||null===confirmations){confirmations=await multiApi("latestBlock")-(block_height||statusBlockHeight)}const inputs=tx.vin||tx.inputs,outputs=tx.vout||tx.outputs||tx.out;return{hash:hash||txid,size:size,fee:fee||fees,double_spend:double_spend,time:1e3*time||new Date(confirmed||received).getTime()||1e3*block_time||Date.now(),block_height:block_height||statusBlockHeight,block_hash:block_hash||statusBlockHash,confirmations:confirmations,inputs:inputs.map((input=>({index:input.n||input.output_index||input.vout,prev_out:{addr:input.prev_out?.addr||input.addresses?.[0]||input.prev_out?.address||input.addr||input.prevout.scriptpubkey_address,value:input.prev_out?.value||input.output_value||input.prevout.value}}))),out:outputs.map((output=>({addr:output.scriptpubkey_address||output.addresses?.[0]||output.scriptpubkey_address||output.addr,value:output.value||output.scriptpubkey_value})))}}catch(e){throw e}},multiApi=btcOperator.multiApi=async(fnName,{index:index=0,...args}={})=>{try{let triedOnion=!1;for(;index(new Date).getTime()))return await APIs[index][fnName](args);index+=1}if(isTor&&!triedOnion)for(triedOnion=!0,index=0;index(new Date).getTime()))return await multiApi(fnName,{index:index+1,...args,url:APIs[index].onionUrl});index+=1}throw"No API available"}catch(error){return console.error(error),APIs[index].coolDownTime=(new Date).getTime()+6e5,multiApi(fnName,{index:index+1,...args})}};const fetch_api=btcOperator.fetch=function(api,{asText:asText=!1,url:url="https://blockchain.info/"}={}){return new Promise(((resolve,reject)=>{console.debug(url+api),fetch(url+api).then((response=>{response.ok?(asText?response.text():response.json()).then((result=>resolve(result))).catch((error=>reject(error))):response.json().then((result=>reject(result))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))};const broadcastTx=btcOperator.broadcastTx=rawTxHex=>new Promise(((resolve,reject)=>{console.log("txHex:",rawTxHex);fetch("https://coinb.in/api/?uid=1&key=12345678901234567890123456789012&setmodule=bitcoin&request=sendrawtransaction",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:"rawtx="+rawTxHex}).then((response=>{console.log(response),response.text().then((resultText=>{let r=resultText.match(/.*<\/result>/);if(r)if(r=r.pop().replace("","").replace("",""),"1"==r){let txid=resultText.match(/.*<\/txid>/).pop().replace("","").replace("","");resolve(txid)}else if("0"==r){let error;error=resultText.includes("")?resultText.match(/.*<\/message>/).pop().replace("","").replace("",""):resultText.match(/.*<\/response>/).pop().replace("","").replace("",""),reject(decodeURIComponent(error.replace(/\+/g," ")))}else reject(resultText);else reject(resultText)})).catch((error=>reject(error)))})).catch((error=>reject(error)))}));Object.defineProperties(btcOperator,{newKeys:{get:()=>{let r=coinjs.newKeys();return r.segwitAddress=coinjs.segwitAddress(r.pubkey).address,r.bech32Address=coinjs.bech32Address(r.pubkey).address,r}},pubkey:{value:key=>key.length>=66?key:64==key.length?coinjs.newPubkey(key):coinjs.wif2pubkey(key).pubkey},address:{value:(key,prefix=void 0)=>coinjs.pubkey2address(btcOperator.pubkey(key),prefix)},segwitAddress:{value:key=>coinjs.segwitAddress(btcOperator.pubkey(key)).address},bech32Address:{value:key=>coinjs.bech32Address(btcOperator.pubkey(key)).address},bech32mAddress:{value:key=>segwit_addr.encode("bc",1,key)}}),coinjs.compressed=!0;const verifyKey=btcOperator.verifyKey=function(addr,key){if(addr&&key)switch(coinjs.addressDecode(addr).type){case"standard":return btcOperator.address(key)===addr;case"multisig":return btcOperator.segwitAddress(key)===addr;case"bech32":return btcOperator.bech32Address(key)===addr;case"bech32m":return btcOperator.bech32mAddress(key)===addr;default:return null}},validateAddress=btcOperator.validateAddress=function(addr){if(!addr)return;let type=coinjs.addressDecode(addr).type;return!!["standard","multisig","bech32","multisigBech32","bech32m"].includes(type)&&type};btcOperator.multiSigAddress=function(pubKeys,minRequired,bech32=!0){if(!Array.isArray(pubKeys))throw"pubKeys must be an array of public keys";if(pubKeys.lengthnew Promise(((resolve,reject)=>{if(!validateAddress(addr))return reject("Invalid address");multiApi("balance",{addr:addr}).then((result=>resolve(result))).catch((error=>reject(error)))}));const BASE_INPUT_SIZE=41,LEGACY_INPUT_SIZE=107,BECH32_INPUT_SIZE=27,BECH32_MULTISIG_INPUT_SIZE=35,SEGWIT_INPUT_SIZE=59,MULTISIG_INPUT_SIZE_ES=351,BASE_OUTPUT_SIZE=9,LEGACY_OUTPUT_SIZE=25,BECH32_OUTPUT_SIZE=23,BECH32_MULTISIG_OUTPUT_SIZE=34,SEGWIT_OUTPUT_SIZE=23;function _redeemScript(addr,key){let decode=coinjs.addressDecode(addr);switch(decode.type){case"standard":return!1;case"multisig":return key?coinjs.segwitAddress(btcOperator.pubkey(key)).redeemscript:null;case"bech32":case"'multisigBech32":return decode.redeemscript;case"bech32m":return decode.outstring;default:return null}}function _sizePerOutput(addr){switch(coinjs.addressDecode(addr).type){case"standard":return BASE_OUTPUT_SIZE+LEGACY_OUTPUT_SIZE;case"bech32":return BASE_OUTPUT_SIZE+BECH32_OUTPUT_SIZE;case"multisigBech32":return BASE_OUTPUT_SIZE+BECH32_MULTISIG_OUTPUT_SIZE;case"multisig":return BASE_OUTPUT_SIZE+SEGWIT_OUTPUT_SIZE;case"bech32m":return BASE_OUTPUT_SIZE+BECH32M_OUTPUT_SIZE;default:return null}}function validateTxParameters(parameters){let invalids=[];if(parameters.senders&&(Array.isArray(parameters.senders)||(parameters.senders=[parameters.senders]),parameters.senders.forEach((id=>validateAddress(id)?null:invalids.push(id))),invalids.length))throw"Invalid senders:"+invalids;if(parameters.privkeys){if(Array.isArray(parameters.privkeys)||(parameters.privkeys=[parameters.privkeys]),parameters.senders.length!=parameters.privkeys.length)throw"Array length for senders and privkeys should be equal";if(parameters.senders.forEach(((id,i)=>{let key=parameters.privkeys[i];verifyKey(id,key)||invalids.push(id),64===key.length&&(parameters.privkeys[i]=coinjs.privkey2wif(key))})),invalids.length)throw"Invalid private key for address:"+invalids}if(Array.isArray(parameters.receivers)||(parameters.receivers=[parameters.receivers]),parameters.receivers.forEach((id=>validateAddress(id)?null:invalids.push(id))),invalids.length)throw"Invalid receivers:"+invalids;if(parameters.change_address&&!validateAddress(parameters.change_address))throw"Invalid change_address:"+parameters.change_address;if(("number"!=typeof parameters.fee||parameters.fee<=0)&&null!==parameters.fee)throw"Invalid fee:"+parameters.fee;if(Array.isArray(parameters.amounts)||(parameters.amounts=[parameters.amounts]),parameters.receivers.length!=parameters.amounts.length)throw"Array length for receivers and amounts should be equal";if(parameters.amounts.forEach((a=>"number"!=typeof a||a<=0?invalids.push(a):null)),invalids.length)throw"Invalid amounts:"+invalids;return parameters}BECH32M_OUTPUT_SIZE=35,btcOperator._redeemScript=_redeemScript,btcOperator.validateTxParameters=validateTxParameters;const createTransaction=btcOperator.createTransaction=({senders:senders,redeemScripts:redeemScripts,receivers:receivers,amounts:amounts,fee:fee,change_address:change_address,fee_from_receiver:fee_from_receiver,allowUnconfirmedUtxos:allowUnconfirmedUtxos=!1,sendingTx:sendingTx=!1,hasInsufficientBalance:hasInsufficientBalance=!1})=>new Promise(((resolve,reject)=>{let total_amount=parseFloat(amounts.reduce(((t,a)=>t+a),0).toFixed(8));const tx=coinjs.transaction();let output_size=addOutputs(tx,receivers,amounts,change_address);addInputs(tx,senders,redeemScripts,total_amount,fee,output_size,fee_from_receiver,allowUnconfirmedUtxos).then((result=>{if(result.change_amount>0&&result.change_amount>result.fee&&(tx.outs[tx.outs.length-1].value=util.BTC_to_Sat(result.change_amount)),fee_from_receiver){let fee_remaining=util.BTC_to_Sat(result.fee);for(let i=0;i0;i++)fee_remaining0)return reject("Send amount is less than fee")}let filtered_outputs=[],dust_value=0;tx.outs.forEach((o=>o.value>=546?filtered_outputs.push(o):dust_value+=o.value)),tx.outs=filtered_outputs,result.fee+=util.Sat_to_BTC(dust_value),result.output_size=output_size,result.output_amount=total_amount-(fee_from_receiver?result.fee:0),result.total_size=12+output_size+result.input_size,result.transaction=tx,sendingTx&&result.hasOwnProperty("hasInsufficientBalance")&&result.hasInsufficientBalance?reject({message:"Insufficient balance",...result}):resolve(result)})).catch((error=>reject(error)))}));function addInputs(tx,senders,redeemScripts,total_amount,fee,output_size,fee_from_receiver,allowUnconfirmedUtxos=!1){return new Promise(((resolve,reject)=>{null!==fee?addUTXOs(tx,senders,redeemScripts,fee_from_receiver?total_amount:total_amount+fee,!1,{allowUnconfirmedUtxos:allowUnconfirmedUtxos}).then((result=>{result.fee=fee,resolve(result)})).catch((error=>reject(error))):new Promise(((resolve,reject)=>{fetch("https://api.blockchain.info/mempool/fees").then((response=>{response.ok?response.json().then((result=>resolve(util.Sat_to_BTC(result.regular)))).catch((error=>reject(error))):reject(response)})).catch((error=>reject(error)))})).then((fee_rate=>{let net_fee=12*fee_rate;net_fee+=output_size*fee_rate,(fee_from_receiver?addUTXOs(tx,senders,redeemScripts,total_amount,!1,{allowUnconfirmedUtxos:allowUnconfirmedUtxos}):addUTXOs(tx,senders,redeemScripts,total_amount+net_fee,fee_rate,{allowUnconfirmedUtxos:allowUnconfirmedUtxos})).then((result=>{result.fee=parseFloat((net_fee+result.input_size*fee_rate).toFixed(8)),result.fee_rate=fee_rate,resolve(result)})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))}function addUTXOs(tx,senders,redeemScripts,required_amount,fee_rate,rec_args={allowUnconfirmedUtxos:!1}){return new Promise(((resolve,reject)=>{if(required_amount=parseFloat(required_amount.toFixed(8)),void 0===rec_args.n&&(rec_args.n=0,rec_args.input_size=0,rec_args.input_amount=0),required_amount<=0)return resolve({input_size:rec_args.input_size,input_amount:rec_args.input_amount,change_amount:-1*required_amount});if(rec_args.n>=senders.length)return resolve({hasInsufficientBalance:!0,input_size:rec_args.input_size,input_amount:rec_args.input_amount,change_amount:-1*required_amount});let addr=senders[rec_args.n],rs=redeemScripts[rec_args.n],addr_type=coinjs.addressDecode(addr).type,size_per_input=function(addr,rs){switch(coinjs.addressDecode(addr).type){case"standard":return BASE_INPUT_SIZE+LEGACY_INPUT_SIZE;case"bech32":return BASE_INPUT_SIZE+BECH32_INPUT_SIZE;case"multisigBech32":return BASE_INPUT_SIZE+BECH32_MULTISIG_INPUT_SIZE;case"multisig":switch(coinjs.script().decodeRedeemScript(rs).type){case"segwit__":return BASE_INPUT_SIZE+SEGWIT_INPUT_SIZE;case"multisig__":return BASE_INPUT_SIZE+MULTISIG_INPUT_SIZE_ES;default:return null}default:return null}}(addr,rs);multiApi("unspent",{addr:addr,allowUnconfirmedUtxos:rec_args.allowUnconfirmedUtxos}).then((utxos=>{for(let i=0;i0;i++){if(1===utxos.length&&rec_args.allowUnconfirmedUtxos)console.log("allowing unconfirmed utxos");else if(!utxos[i].confirmations)continue;var script;if(rs&&rs.length)if(rs.match(/^00/)&&44==rs.length||40==rs.length&&rs.match(/^[a-f0-9]+$/gi)||"multisigBech32"===addr_type){let s=coinjs.script();s.writeBytes(Crypto.util.hexToBytes(rs)),s.writeOp(0),s.writeBytes(coinjs.numToBytes(utxos[i].value.toFixed(0),8)),script=Crypto.util.bytesToHex(s.buffer)}else script=rs;else script=utxos[i].script;tx.addinput(utxos[i].tx_hash_big_endian,utxos[i].tx_output_n,script,4294967293),rec_args.input_size+=size_per_input,rec_args.input_amount+=util.Sat_to_BTC(utxos[i].value),required_amount-=util.Sat_to_BTC(utxos[i].value),fee_rate&&(required_amount+=size_per_input*fee_rate)}rec_args.n+=1,addUTXOs(tx,senders,redeemScripts,required_amount,fee_rate,rec_args).then((result=>resolve(result))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))}function addOutputs(tx,receivers,amounts,change_address){let size=0;for(let i in receivers)tx.addoutput(receivers[i],amounts[i]),size+=_sizePerOutput(receivers[i]);return tx.addoutput(change_address,0),size+=_sizePerOutput(change_address),size}function tx_fetch_for_editing(tx){return new Promise(((resolve,reject)=>{"string"==typeof tx&&/^[0-9a-f]{64}$/i.test(tx)?getTx.hex(tx).then((txhex=>resolve(deserializeTx(txhex)))).catch((error=>reject(error))):resolve(deserializeTx(tx))}))}btcOperator.addInputs=addInputs,btcOperator.addUTXOs=addUTXOs,btcOperator.addOutputs=addOutputs,btcOperator.tx_fetch_for_editing=tx_fetch_for_editing;btcOperator.extractLastHexStrings=function(arr){const result=[];for(let i=0;i0){const lastHexString=innerArray[innerArray.length-1];result.push(lastHexString)}}return result};btcOperator.editFee=function(tx_hex,new_fee,private_keys,change_only=!0){return new Promise(((resolve,reject)=>{Array.isArray(private_keys)||(private_keys=[private_keys]),tx_fetch_for_editing(tx_hex).then((tx=>{parseTransaction(tx).then((tx_parsed=>{if(tx_parsed.fee>=new_fee)return reject("Fees can only be increased");var edit_output_address=new Set;!0===change_only?tx_parsed.inputs.forEach((inp=>edit_output_address.add(inp.address))):!1===change_only?tx_parsed.outputs.forEach((out=>edit_output_address.add(out.address))):"string"==typeof change_only?edit_output_address.add(change_only):Array.isArray(change_only)&&change_only.forEach((id=>edit_output_address.add(id)));let inc_fee=util.BTC_to_Sat(new_fee-tx_parsed.fee);if(inc_fee<219)return reject("Insufficient additional fee. Minimum increment: 219");for(let i=tx.outs.length-1;i>=0&&inc_fee>0;i--)if(edit_output_address.has(tx_parsed.outputs[i].address)){let current_value=tx.outs[i].value;current_value instanceof BigInteger&&(current_value=current_value.intValue()),current_value>inc_fee?(tx.outs[i].value=current_value-inc_fee,inc_fee=0):(inc_fee-=current_value,tx.outs[i].value=0)}if(inc_fee>0){let max_possible_fee=util.BTC_to_Sat(new_fee)-inc_fee;return reject(`Insufficient output values to increase fee. Maximum fee possible: ${util.Sat_to_BTC(max_possible_fee)}`)}tx.outs=tx.outs.filter((o=>o.value>=546));let wif_keys=[];for(let i in tx.ins){var addr=tx_parsed.inputs[i].address,value=util.BTC_to_Sat(tx_parsed.inputs[i].value);let addr_decode=coinjs.addressDecode(addr);var privKey=private_keys.find((pk=>verifyKey(addr,pk)));if(!privKey)return reject(`Private key missing for ${addr}`);const rs=_redeemScript(addr,privKey);var script;if(!1===rs?wif_keys.unshift(privKey):wif_keys.push(privKey),rs&&rs.length)if(rs.match(/^00/)&&44==rs.length||40==rs.length&&rs.match(/^[a-f0-9]+$/gi)||"multisigBech32"===addr_decode.type){let s=coinjs.script();s.writeBytes(Crypto.util.hexToBytes(rs)),s.writeOp(0),s.writeBytes(coinjs.numToBytes(value.toFixed(0),8)),script=Crypto.util.bytesToHex(s.buffer)}else script=rs;else{let s=coinjs.script();s.writeOp(118),s.writeOp(169),s.writeBytes(addr_decode.bytes),s.writeOp(136),s.writeOp(172),script=Crypto.util.bytesToHex(s.buffer)}tx.ins[i].script=coinjs.script(script)}tx.witness=!1,console.debug("Unsigned:",tx.serialize()),new Set(wif_keys).forEach((key=>tx.sign(key,1))),resolve(tx.serialize())})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},btcOperator.editFee_corewallet=function(tx_hex,new_fee,private_keys,change_only=!0){return new Promise(((resolve,reject)=>{Array.isArray(private_keys)||(private_keys=[private_keys]),tx_fetch_for_editing(tx_hex).then((tx=>{parseTransaction(tx).then((tx_parsed=>{if(tx_parsed.fee>=new_fee)return reject("Fees can only be increased");var edit_output_address=new Set;!0===change_only?tx_parsed.inputs.forEach((inp=>edit_output_address.add(inp.address))):!1===change_only?tx_parsed.outputs.forEach((out=>edit_output_address.add(out.address))):"string"==typeof change_only?edit_output_address.add(change_only):Array.isArray(change_only)&&change_only.forEach((id=>edit_output_address.add(id)));let inc_fee=util.BTC_to_Sat(new_fee-tx_parsed.fee);if(inc_fee<219)return reject("Insufficient additional fee. Minimum increment: 219");for(let i=tx.outs.length-1;i>=0&&inc_fee>0;i--)if(edit_output_address.has(tx_parsed.outputs[i].address)){let current_value=tx.outs[i].value;current_value instanceof BigInteger&&(current_value=current_value.intValue()),current_value>inc_fee?(tx.outs[i].value=current_value-inc_fee,inc_fee=0):(inc_fee-=current_value,tx.outs[i].value=0)}if(inc_fee>0){let max_possible_fee=util.BTC_to_Sat(new_fee)-inc_fee;return reject(`Insufficient output values to increase fee. Maximum fee possible: ${util.Sat_to_BTC(max_possible_fee)}`)}tx.outs=tx.outs.filter((o=>o.value>=546));let wif_keys=[],witness_position=0;for(let i in tx.ins){var addr=tx_parsed.inputs[i].address,value=util.BTC_to_Sat(tx_parsed.inputs[i].value);let addr_decode=coinjs.addressDecode(addr);var privKey=private_keys.find((pk=>verifyKey(addr,pk)));if(!privKey)return reject(`Private key missing for ${addr}`);const rs=_redeemScript(addr,privKey);var script;if(!1===rs?wif_keys.unshift(privKey):wif_keys.push(privKey),rs&&rs.length)if(rs.match(/^00/)&&44==rs.length||40==rs.length&&rs.match(/^[a-f0-9]+$/gi)){let s=coinjs.script();s.writeBytes(Crypto.util.hexToBytes(rs)),s.writeOp(0),s.writeBytes(coinjs.numToBytes(value.toFixed(0),8)),script=Crypto.util.bytesToHex(s.buffer),"bech32"==addr_decode&&(witness_position+=1)}else if("multisigBech32"===addr_decode.type){let redeemScript=btcOperator.extractLastHexStrings(tx.witness)[witness_position];witness_position+=1;let s=coinjs.script();s.writeBytes(Crypto.util.hexToBytes(redeemScript)),s.writeOp(0),s.writeBytes(coinjs.numToBytes(value.toFixed(0),8)),script=Crypto.util.bytesToHex(s.buffer)}else script=rs;else{let s=coinjs.script();s.writeOp(118),s.writeOp(169),s.writeBytes(addr_decode.bytes),s.writeOp(136),s.writeOp(172),script=Crypto.util.bytesToHex(s.buffer)}tx.ins[i].script=coinjs.script(script)}tx.witness=!1,console.debug("Unsigned:",tx.serialize()),new Set(wif_keys).forEach((key=>tx.sign(key,1))),btcOperator.checkSigned(tx)?resolve(tx.serialize()):reject("All private keys not present")})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},btcOperator.sendTx=function(senders,privkeys,receivers,amounts,fee=null,options={}){return options.sendingTx=!0,new Promise(((resolve,reject)=>{createSignedTx(senders,privkeys,receivers,amounts,fee,options).then((result=>{broadcastTx(result.transaction.serialize()).then((txid=>resolve(txid))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))};const createSignedTx=btcOperator.createSignedTx=function(senders,privkeys,receivers,amounts,fee=null,options={}){return new Promise(((resolve,reject)=>{try{({senders:senders,privkeys:privkeys,receivers:receivers,amounts:amounts}=validateTxParameters({senders:senders,privkeys:privkeys,receivers:receivers,amounts:amounts,fee:fee,...options}))}catch(e){return reject(e)}let redeemScripts=[],wif_keys=[];for(let i in senders){let rs=_redeemScript(senders[i],privkeys[i]);redeemScripts.push(rs),!1===rs?wif_keys.unshift(privkeys[i]):wif_keys.push(privkeys[i])}if(redeemScripts.includes(null))return reject("Unable to get redeem-script");createTransaction({senders:senders,redeemScripts:redeemScripts,receivers:receivers,amounts:amounts,fee:fee,change_address:options.change_address||senders[0],...options}).then((result=>{let tx=result.transaction;console.debug("Unsigned:",tx.serialize()),new Set(wif_keys).forEach((key=>tx.sign(key,1))),console.debug("Signed:",tx.serialize()),resolve(result)})).catch((error=>reject(error)))}))};btcOperator.createTx=function(senders,receivers,amounts,fee=null,options={allowUnconfirmedUtxos:!1}){return new Promise(((resolve,reject)=>{try{({senders:senders,receivers:receivers,amounts:amounts}=validateTxParameters({senders:senders,receivers:receivers,amounts:amounts,fee:fee,change_address:options.change_address}))}catch(e){return reject(e)}let redeemScripts=senders.map((id=>_redeemScript(id)));if(redeemScripts.includes(null))return reject("Unable to get redeem-script");createTransaction({senders:senders,redeemScripts:redeemScripts,receivers:receivers,amounts:amounts,fee:fee,change_address:options.change_address||senders[0],...options}).then((result=>{result.tx_hex=result.transaction.serialize(),delete result.transaction,resolve(result)})).catch((error=>reject(error)))}))},btcOperator.createMultiSigTx=function(sender,redeemScript,receivers,amounts,fee=null,options={}){return new Promise(((resolve,reject)=>{let addr_type=validateAddress(sender);if(!["multisig","multisigBech32"].includes(addr_type))return reject("Invalid sender (multisig):"+sender);{let script=coinjs.script(),decode="multisig"==addr_type?script.decodeRedeemScript(redeemScript):script.decodeRedeemScriptBech32(redeemScript);if(!decode||decode.address!==sender)return reject("Invalid redeem-script")}try{({receivers:receivers,amounts:amounts}=validateTxParameters({receivers:receivers,amounts:amounts,fee:fee,change_address:options.change_address}))}catch(e){return reject(e)}createTransaction({senders:[sender],redeemScripts:[redeemScript],receivers:receivers,amounts:amounts,fee:fee,change_address:options.change_address||sender,...options}).then((result=>{result.tx_hex=result.transaction.serialize(),delete result.transaction,resolve(result)})).catch((error=>reject(error)))}))};const deserializeTx=btcOperator.deserializeTx=function(tx){if("string"==typeof tx||Array.isArray(tx))try{tx=coinjs.transaction().deserialize(tx)}catch{throw"Invalid transaction hex"}else if("object"!=typeof tx||"function"!=typeof tx.sign)throw"Invalid transaction object";return tx};btcOperator.signTx=function(tx,privkeys,sighashtype=1){tx=deserializeTx(tx),Array.isArray(privkeys)||(privkeys=[privkeys]);for(let i in privkeys)64===privkeys[i].length&&(privkeys[i]=coinjs.privkey2wif(privkeys[i]));return new Set(privkeys).forEach((key=>tx.sign(key,sighashtype))),tx.serialize()};const checkSigned=btcOperator.checkSigned=function(tx,bool=!0){tx=deserializeTx(tx);let n=[];for(let i in tx.ins){var s=tx.extractScriptKey(i);if("multisig"!==s.type&&"multisig_bech32"!==s.type)n.push("true"==s.signed||tx.witness[i]&&2==tx.witness[i].length);else{var rs=coinjs.script().decodeRedeemScript(s.script);let x={s:s.signatures,r:rs.signaturesRequired,t:rs.pubkeys.length};if(x.r>x.t)throw"signaturesRequired is more than publicKeys";x.s!0!==x)).length:n};btcOperator.checkIfSameTx=function(tx1,tx2){if(tx1=deserializeTx(tx1),tx2=deserializeTx(tx2),tx1.ins.length!==tx2.ins.length||tx1.outs.length!==tx2.outs.length)return!1;for(let i=0;inew Promise(((resolve,reject)=>{multiApi("tx",{txid:txid}).then((result=>resolve(result.out[i]))).catch((error=>reject(error)))})),parseTransaction=btcOperator.parseTransaction=function(tx){return new Promise(((resolve,reject)=>{tx=deserializeTx(tx);let result={},promises=[];for(let i=0;i{result.inputs=inputs.map((inp=>Object({address:inp.addr,value:util.Sat_to_BTC(inp.value)})));let signed=checkSigned(tx,!1);result.inputs.forEach(((inp,i)=>inp.signed=signed[i])),result.outputs=tx.outs.map((out=>{var address;switch(out.script.chunks[0]){case 0:address=util.encodeBech32(Crypto.util.bytesToHex(out.script.chunks[1]),coinjs.bech32.version,coinjs.bech32.hrp);break;case 169:address=util.encodeLegacy(Crypto.util.bytesToHex(out.script.chunks[1]),coinjs.multisig);break;case 118:address=util.encodeLegacy(Crypto.util.bytesToHex(out.script.chunks[2]),coinjs.pub)}return{address:address,value:util.Sat_to_BTC(out.value)}})),result.total_input=parseFloat(result.inputs.reduce(((a,inp)=>a+inp.value),0).toFixed(8)),result.total_output=parseFloat(result.outputs.reduce(((a,out)=>a+out.value),0).toFixed(8)),result.fee=parseFloat((result.total_input-result.total_output).toFixed(8)),resolve(result)})).catch((error=>reject(error)))}))};btcOperator.transactionID=function(tx){tx=deserializeTx(tx);let clone=coinjs.clone(tx);clone.witness=null;let raw_bytes=Crypto.util.hexToBytes(clone.serialize()),txid=Crypto.SHA256(Crypto.SHA256(raw_bytes,{asBytes:!0}),{asBytes:!0}).reverse();return Crypto.util.bytesToHex(txid)};const getTx=btcOperator.getTx=txid=>new Promise((async(resolve,reject)=>{try{const result=await multiApi("tx",{txid:txid});resolve({confirmations:result.confirmations,block:result.block_height,txid:result.hash,time:result.time,size:result.size,fee:util.Sat_to_BTC(result.fee),inputs:result.inputs.map((i=>Object({address:i.prev_out.addr,value:util.Sat_to_BTC(i.prev_out.value)}))),total_input_value:util.Sat_to_BTC(result.inputs.reduce(((a,i)=>a+i.prev_out.value),0)),outputs:result.out.map((o=>Object({address:o.addr,value:util.Sat_to_BTC(o.value)}))),total_output_value:util.Sat_to_BTC(result.out.reduce(((a,o)=>a+o.value),0))})}catch(error){reject(error)}})).catch((error=>reject(error)));getTx.hex=btcOperator.getTx.hex=txid=>multiApi("txHex",{txid:txid}),btcOperator.getAddressData=address=>new Promise(((resolve,reject)=>{Promise.all([multiApi("balance",{addr:address}),multiApi("txs",{addr:address})]).then((([balance,txs])=>{const parsedTxs=txs.map((tx=>function(tx,addressOfTx){const{txid:txid,hash:hash,time:time,block_height:block_height,inputs:inputs,outputs:outputs,out:out,vin:vin,vout:vout,fee:fee,fees:fees,received:received,confirmed:confirmed,status:{block_height:statusBlockHeight,block_time:block_time}={}}=tx;let parsedTx={txid:hash||txid,time:1e3*time||new Date(confirmed||received).getTime()||1e3*block_time||Date.now(),block:block_height||statusBlockHeight,tx_senders:{}};(inputs||vin).forEach((i=>{const address=i.prev_out?.addr||i.addresses?.[0]||i.prev_out?.address||i.addr||i.prevout.scriptpubkey_address,value=i.prev_out?.value||i.output_value||i.value||i.prevout.value;address in parsedTx.tx_senders?parsedTx.tx_senders[address]+=value:parsedTx.tx_senders[address]=value})),parsedTx.tx_input_value=0;for(let senderAddr in parsedTx.tx_senders){let val=parsedTx.tx_senders[senderAddr];parsedTx.tx_senders[senderAddr]=util.Sat_to_BTC(val),parsedTx.tx_input_value+=val}parsedTx.tx_input_value=util.Sat_to_BTC(parsedTx.tx_input_value),parsedTx.tx_receivers={},(outputs||out||vout).forEach((o=>{const address=o.scriptpubkey_address||o.addresses?.[0]||o.scriptpubkey_address||o.addr,value=o.value||o.scriptpubkey_value;address in parsedTx.tx_receivers?parsedTx.tx_receivers[address]+=value:parsedTx.tx_receivers[address]=value})),parsedTx.tx_output_value=0;for(let receiverAddr in parsedTx.tx_receivers){let val=parsedTx.tx_receivers[receiverAddr];parsedTx.tx_receivers[receiverAddr]=util.Sat_to_BTC(val),parsedTx.tx_output_value+=val}return parsedTx.tx_output_value=util.Sat_to_BTC(parsedTx.tx_output_value),parsedTx.tx_fee=util.Sat_to_BTC(fee||fees||parsedTx.tx_input_value-parsedTx.tx_output_value),1===Object.keys(parsedTx.tx_receivers).length&&1===Object.keys(parsedTx.tx_senders).length&&Object.keys(parsedTx.tx_senders)[0]===Object.keys(parsedTx.tx_receivers)[0]?(parsedTx.type="self",parsedTx.amount=parsedTx.tx_receivers[addressOfTx],parsedTx.address=addressOfTx):addressOfTx in parsedTx.tx_senders&&Object.keys(parsedTx.tx_receivers).some((addr=>addr!==addressOfTx))?(parsedTx.type="out",parsedTx.receiver=Object.keys(parsedTx.tx_receivers).filter((addr=>addr!=addressOfTx)),parsedTx.amount=parsedTx.receiver.reduce(((t,addr)=>t+parsedTx.tx_receivers[addr]),0)+parsedTx.tx_fee):(parsedTx.type="in",parsedTx.sender=Object.keys(parsedTx.tx_senders).filter((addr=>addr!=addressOfTx)),parsedTx.amount=parsedTx.tx_receivers[addressOfTx]),parsedTx}(tx,address)));resolve({address:address,balance:balance,txs:parsedTxs})})).catch((error=>reject(error)))})),btcOperator.getBlock=block=>new Promise(((resolve,reject)=>{fetch_api(`rawblock/${block}`).then((result=>resolve({height:result.height,hash:result.hash,merkle_root:result.mrkl_root,prev_block:result.prev_block,next_block:result.next_block[0],size:result.size,time:1e3*result.time,txs:result.tx.map((t=>Object({fee:t.fee,size:t.size,inputs:t.inputs.map((i=>Object({address:i.prev_out.addr,value:util.Sat_to_BTC(i.prev_out.value)}))),total_input_value:util.Sat_to_BTC(t.inputs.reduce(((a,i)=>a+i.prev_out.value),0)),outputs:t.out.map((o=>Object({address:o.addr,value:util.Sat_to_BTC(o.value)}))),total_output_value:util.Sat_to_BTC(t.out.reduce(((a,o)=>a+o.value),0))})))}))).catch((error=>reject(error)))}))}(); \ No newline at end of file diff --git a/compactIDB.min.js b/compactIDB.min.js new file mode 100644 index 0000000..db21c75 --- /dev/null +++ b/compactIDB.min.js @@ -0,0 +1 @@ +!function(EXPORTS){"use strict";const compactIDB=window.compactIDB={};var defaultDB;const indexedDB=window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB,IDBKeyRange=(window.IDBTransaction||window.webkitIDBTransaction||window.msIDBTransaction,window.IDBKeyRange||window.webkitIDBKeyRange||window.msIDBKeyRange);if(!indexedDB)return void console.error("Your browser doesn't support a stable version of IndexedDB.");function upgradeDB(dbName,createList=null,deleteList=null){return new Promise(((resolve,reject)=>{(function(dbName=defaultDB){return new Promise(((resolve,reject)=>{openDB(dbName).then((db=>{resolve(db.version),db.close()})).catch((error=>reject(error)))}))})(dbName).then((version=>{var idb=indexedDB.open(dbName,version+1);idb.onerror=event=>reject("Error in opening IndexedDB"),idb.onupgradeneeded=event=>{let db=event.target.result;if(createList instanceof Object){if(Array.isArray(createList)){let tmp={};createList.forEach((o=>tmp[o]={})),createList=tmp}for(let o in createList){let obs=db.createObjectStore(o,createList[o].options||{});if(createList[o].indexes instanceof Object)for(let i in createList[o].indexes)obs.createIndex(i,i,createList[o].indexes||{})}}Array.isArray(deleteList)&&deleteList.forEach((o=>db.deleteObjectStore(o))),resolve("Database upgraded")},idb.onsuccess=event=>event.target.result.close()})).catch((error=>reject(error)))}))}compactIDB.setDefaultDB=dbName=>defaultDB=dbName,Object.defineProperty(compactIDB,"default",{get:()=>defaultDB,set:dbName=>defaultDB=dbName}),compactIDB.initDB=function(dbName,objectStores={}){return new Promise(((resolve,reject)=>{if(!(objectStores instanceof Object))return reject("ObjectStores must be an object or array");defaultDB=defaultDB||dbName;var idb=indexedDB.open(dbName);idb.onerror=event=>reject("Error in opening IndexedDB"),idb.onsuccess=event=>{var db=event.target.result;let cList=Object.values(db.objectStoreNames);var obs={},a_obs={},d_obs=[];if(Array.isArray(objectStores))objectStores.forEach((o=>obs[o]={}));else obs=objectStores;let nList=Object.keys(obs);for(let o of nList)cList.includes(o)||(a_obs[o]=obs[o]);for(let o of cList)nList.includes(o)||d_obs.push(o);Object.keys(a_obs).length||d_obs.length?upgradeDB(dbName,a_obs,d_obs).then((result=>resolve(result))).catch((error=>reject(error))):resolve("Initiated IndexedDB"),db.close()}}))};const openDB=compactIDB.openDB=function(dbName=defaultDB){return new Promise(((resolve,reject)=>{var idb=indexedDB.open(dbName);idb.onerror=event=>reject("Error in opening IndexedDB"),idb.onupgradeneeded=event=>{event.target.result.close(),deleteDB(dbName).then((_=>null)).catch((_=>null)).finally((_=>reject("Datebase not found")))},idb.onsuccess=event=>resolve(event.target.result)}))},deleteDB=compactIDB.deleteDB=function(dbName=defaultDB){return new Promise(((resolve,reject)=>{var deleteReq=indexedDB.deleteDatabase(dbName);deleteReq.onerror=event=>reject("Error deleting database!"),deleteReq.onsuccess=event=>resolve("Database deleted successfully")}))};compactIDB.writeData=function(obsName,data,key=!1,dbName=defaultDB){return new Promise(((resolve,reject)=>{openDB(dbName).then((db=>{var obs=db.transaction(obsName,"readwrite").objectStore(obsName);let writeReq=key?obs.put(data,key):obs.put(data);writeReq.onsuccess=evt=>resolve("Write data Successful"),writeReq.onerror=evt=>reject(`Write data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`),db.close()})).catch((error=>reject(error)))}))},compactIDB.addData=function(obsName,data,key=!1,dbName=defaultDB){return new Promise(((resolve,reject)=>{openDB(dbName).then((db=>{var obs=db.transaction(obsName,"readwrite").objectStore(obsName);let addReq=key?obs.add(data,key):obs.add(data);addReq.onsuccess=evt=>resolve("Add data successful"),addReq.onerror=evt=>reject(`Add data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`),db.close()})).catch((error=>reject(error)))}))},compactIDB.removeData=function(obsName,key,dbName=defaultDB){return new Promise(((resolve,reject)=>{openDB(dbName).then((db=>{let delReq=db.transaction(obsName,"readwrite").objectStore(obsName).delete(key);delReq.onsuccess=evt=>resolve(`Removed Data ${key}`),delReq.onerror=evt=>reject(`Remove data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`),db.close()})).catch((error=>reject(error)))}))},compactIDB.clearData=function(obsName,dbName=defaultDB){return new Promise(((resolve,reject)=>{openDB(dbName).then((db=>{let clearReq=db.transaction(obsName,"readwrite").objectStore(obsName).clear();clearReq.onsuccess=evt=>resolve("Clear data Successful"),clearReq.onerror=evt=>reject("Clear data Unsuccessful"),db.close()})).catch((error=>reject(error)))}))},compactIDB.readData=function(obsName,key,dbName=defaultDB){return new Promise(((resolve,reject)=>{openDB(dbName).then((db=>{let getReq=db.transaction(obsName,"readonly").objectStore(obsName).get(key);getReq.onsuccess=evt=>resolve(evt.target.result),getReq.onerror=evt=>reject(`Read data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`),db.close()})).catch((error=>reject(error)))}))},compactIDB.readAllData=function(obsName,dbName=defaultDB){return new Promise(((resolve,reject)=>{openDB(dbName).then((db=>{var obs=db.transaction(obsName,"readonly").objectStore(obsName),tmpResult={};let curReq=obs.openCursor();curReq.onsuccess=evt=>{var cursor=evt.target.result;cursor?(tmpResult[cursor.primaryKey]=cursor.value,cursor.continue()):resolve(tmpResult)},curReq.onerror=evt=>reject(`Read-All data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`),db.close()})).catch((error=>reject(error)))}))},compactIDB.searchData=function(obsName,options={},dbName=defaultDB){return options.lowerKey=options.atKey||options.lowerKey||0,options.upperKey=options.atKey||options.upperKey||!1,options.patternEval=options.patternEval||((k,v)=>!0),options.limit=options.limit||!1,options.reverse=options.reverse||!1,options.lastOnly=options.lastOnly||!1,new Promise(((resolve,reject)=>{openDB(dbName).then((db=>{var obs=db.transaction(obsName,"readonly").objectStore(obsName),filteredResult={};let curReq=obs.openCursor(options.upperKey?IDBKeyRange.bound(options.lowerKey,options.upperKey):IDBKeyRange.lowerBound(options.lowerKey),options.lastOnly||options.reverse?"prev":"next");curReq.onsuccess=evt=>{var cursor=evt.target.result;if(!cursor||options.limit&&options.limit<=Object.keys(filteredResult).length)return resolve(filteredResult);options.patternEval(cursor.primaryKey,cursor.value)?(filteredResult[cursor.primaryKey]=cursor.value,options.lastOnly?resolve(filteredResult):cursor.continue()):cursor.continue()},curReq.onerror=evt=>reject(`Search unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`),db.close()})).catch((error=>reject(error)))}))}}(); \ No newline at end of file diff --git a/floBlockchainAPI.js b/floBlockchainAPI.js index 467d8fb..135e7d3 100644 --- a/floBlockchainAPI.js +++ b/floBlockchainAPI.js @@ -1,4 +1,4 @@ -(function (EXPORTS) { //floBlockchainAPI v3.0.1b +(function (EXPORTS) { //floBlockchainAPI v3.1.1 /* FLO Blockchain Operator to send/receive data from blockchain using API calls via FLO Blockbook*/ 'use strict'; const floBlockchainAPI = EXPORTS; @@ -17,6 +17,22 @@ const SATOSHI_IN_BTC = 1e8; const isUndefined = val => typeof val === 'undefined'; + const checkIfTor = floBlockchainAPI.checkIfTor = () => { + return fetch('https://check.torproject.org/api/ip', { + mode: 'no-cors' + }) + .then(response => response.json()) + .then(result => result.IsTor) + .catch(error => false) + } + let isTor = false; + checkIfTor().then(result => { + isTor = result + if (isTor) { + DEFAULT.apiURL.FLO.push('http://vl7ni6byqx7rbub5hypxtod5dbfeuhoj5r5exuyl44pspqh2gasjj4qd.onion:9166/') + DEFAULT.apiURL.FLO_TEST.push('http://omwkzk6bd6zuragdqsrhdyzgxzre7yx4vzrou4vzftintzc2dmagp6qd.onion:15017/') + } + }); const util = floBlockchainAPI.util = {}; @@ -1041,4 +1057,4 @@ }) } -})('object' === typeof module ? module.exports : window.floBlockchainAPI = {}); +})('object' === typeof module ? module.exports : window.floBlockchainAPI = {}); \ No newline at end of file diff --git a/floBlockchainAPI.min.js b/floBlockchainAPI.min.js new file mode 100644 index 0000000..e4f2786 --- /dev/null +++ b/floBlockchainAPI.min.js @@ -0,0 +1 @@ +!function(EXPORTS){"use strict";const floBlockchainAPI="object"===typeof module?module.exports:window.floBlockchainAPI={},DEFAULT={blockchain:floGlobals.blockchain,apiURL:{FLO:["https://blockbook.ranchimall.net/"],FLO_TEST:["https://blockbook-testnet.ranchimall.net/"]},sendAmt:3e-4,fee:2e-4,minChangeAmt:2e-4,receiverID:floGlobals.adminID},isUndefined=val=>void 0===val,checkIfTor=floBlockchainAPI.checkIfTor=()=>fetch("https://check.torproject.org/api/ip",{mode:"no-cors"}).then((response=>response.json())).then((result=>result.IsTor)).catch((error=>!1));let isTor=!1;checkIfTor().then((result=>{isTor=result,isTor&&(DEFAULT.apiURL.FLO.push("http://vl7ni6byqx7rbub5hypxtod5dbfeuhoj5r5exuyl44pspqh2gasjj4qd.onion:9166/"),DEFAULT.apiURL.FLO_TEST.push("http://omwkzk6bd6zuragdqsrhdyzgxzre7yx4vzrou4vzftintzc2dmagp6qd.onion:15017/"))}));const util=floBlockchainAPI.util={};util.Sat_to_FLO=value=>parseFloat((value/1e8).toFixed(8)),util.FLO_to_Sat=value=>parseInt(1e8*value),util.toFixed=value=>parseFloat(value.toFixed(8)),Object.defineProperties(floBlockchainAPI,{sendAmt:{get:()=>DEFAULT.sendAmt,set:amt=>isNaN(amt)?null:DEFAULT.sendAmt=amt},fee:{get:()=>DEFAULT.fee,set:fee=>isNaN(fee)?null:DEFAULT.fee=fee},defaultReceiver:{get:()=>DEFAULT.receiverID,set:floID=>DEFAULT.receiverID=floID},blockchain:{get:()=>DEFAULT.blockchain}}),floGlobals.sendAmt&&(floBlockchainAPI.sendAmt=floGlobals.sendAmt),floGlobals.fee&&(floBlockchainAPI.fee=floGlobals.fee),Object.defineProperties(floGlobals,{sendAmt:{get:()=>DEFAULT.sendAmt,set:amt=>isNaN(amt)?null:DEFAULT.sendAmt=amt},fee:{get:()=>DEFAULT.fee,set:fee=>isNaN(fee)?null:DEFAULT.fee=fee}});const allServerList=new Set(floGlobals.apiURL&&floGlobals.apiURL[DEFAULT.blockchain]?floGlobals.apiURL[DEFAULT.blockchain]:DEFAULT.apiURL[DEFAULT.blockchain]);var serverList=Array.from(allServerList),curPos=floCrypto.randInt(0,serverList.length-1);function fetch_retry(apicall,rm_node){return new Promise(((resolve,reject)=>{let i=serverList.indexOf(rm_node);-1!=i&&serverList.splice(i,1),curPos=floCrypto.randInt(0,serverList.length-1),fetch_api(apicall,!1).then((result=>resolve(result))).catch((error=>reject(error)))}))}function fetch_api(apicall,ic=!0){return new Promise(((resolve,reject)=>{if(0===serverList.length)ic?(serverList=Array.from(allServerList),curPos=floCrypto.randInt(0,serverList.length-1),fetch_api(apicall,!1).then((result=>resolve(result))).catch((error=>reject(error)))):reject("No FLO blockbook server working");else{let serverURL=serverList[curPos];fetch(serverURL+apicall).then((response=>{response.ok?response.json().then((data=>resolve(data))):fetch_retry(apicall,serverURL).then((result=>resolve(result))).catch((error=>reject(error)))})).catch((error=>{fetch_retry(apicall,serverURL).then((result=>resolve(result))).catch((error=>reject(error)))}))}}))}Object.defineProperties(floBlockchainAPI,{serverList:{get:()=>Array.from(serverList)},current_server:{get:()=>serverList[curPos]}});const promisedAPI=floBlockchainAPI.promisedAPI=floBlockchainAPI.fetch=function(apicall,query_params=void 0){return new Promise(((resolve,reject)=>{isUndefined(query_params)||(apicall+="?"+new URLSearchParams(JSON.parse(JSON.stringify(query_params))).toString()),fetch_api(apicall).then((result=>resolve(result))).catch((error=>reject(error)))}))},getBalance=floBlockchainAPI.getBalance=function(addr){return new Promise(((resolve,reject)=>{promisedAPI(`api/address/${addr}`,{details:"basic"}).then((result=>resolve(result.balance))).catch((error=>reject(error)))}))};const getUTXOs=address=>new Promise(((resolve,reject)=>{promisedAPI(`api/utxo/${address}`,{confirmed:!0}).then((utxos=>{let scriptPubKey=function(address){var tx=bitjs.transaction();tx.addoutput(address,0);let outputBuffer=tx.outputs.pop().script;return Crypto.util.bytesToHex(outputBuffer)}(address);utxos.forEach((u=>u.scriptPubKey=scriptPubKey)),resolve(utxos)})).catch((error=>reject(error)))})),createTx=function(senderAddr,receiverAddr,sendAmt,floData="",strict_utxo=!0){return new Promise(((resolve,reject)=>floCrypto.validateASCII(floData)?floCrypto.validateFloID(senderAddr,!0)?floCrypto.validateFloID(receiverAddr)?"number"!=typeof sendAmt||sendAmt<=0?reject(`Invalid sendAmt : ${sendAmt}`):void getBalance(senderAddr).then((balance=>{var fee=DEFAULT.fee;if(balance{for(var trx=bitjs.transaction(),utxoAmt=0,i=utxos.length-1;i>=0&&utxoAmtDEFAULT.minChangeAmt&&trx.addoutput(senderAddr,change),trx.addflodata(floData.replace(/\n/g," ")),resolve(trx)}})).catch((error=>reject(error)))})).catch((error=>reject(error))):reject(`Invalid address : ${receiverAddr}`):reject(`Invalid address : ${senderAddr}`):reject("Invalid FLO_Data: only printable ASCII characters are allowed")))};floBlockchainAPI.createTx=function(senderAddr,receiverAddr,sendAmt,floData="",strict_utxo=!0){return new Promise(((resolve,reject)=>{createTx(senderAddr,receiverAddr,sendAmt,floData,strict_utxo).then((trx=>resolve(trx.serialize()))).catch((error=>reject(error)))}))};const sendTx=floBlockchainAPI.sendTx=function(senderAddr,receiverAddr,sendAmt,privKey,floData="",strict_utxo=!0){return new Promise(((resolve,reject)=>floCrypto.validateFloID(senderAddr,!0)?privKey.length<1||!floCrypto.verifyPrivKey(privKey,senderAddr)?reject("Invalid Private key!"):void createTx(senderAddr,receiverAddr,sendAmt,floData,strict_utxo).then((trx=>{var signedTxHash=trx.sign(privKey,1);broadcastTx(signedTxHash).then((txid=>resolve(txid))).catch((error=>reject(error)))})).catch((error=>reject(error))):reject(`Invalid address : ${senderAddr}`)))};floBlockchainAPI.writeData=function(senderAddr,data,privKey,receiverAddr=DEFAULT.receiverID,options={}){let strict_utxo=!1!==options.strict_utxo,sendAmt=isNaN(options.sendAmt)?DEFAULT.sendAmt:options.sendAmt;return new Promise(((resolve,reject)=>{"string"!=typeof data&&(data=JSON.stringify(data)),sendTx(senderAddr,receiverAddr,sendAmt,privKey,data,strict_utxo).then((txid=>resolve(txid))).catch((error=>reject(error)))}))},floBlockchainAPI.mergeUTXOs=function(floID,privKey,floData=""){return new Promise(((resolve,reject)=>{if(!floCrypto.validateFloID(floID,!0))return reject("Invalid floID");if(!floCrypto.verifyPrivKey(privKey,floID))return reject("Invalid Private Key");if(!floCrypto.validateASCII(floData))return reject("Invalid FLO_Data: only printable ASCII characters are allowed");var trx=bitjs.transaction(),utxoAmt=0,fee=DEFAULT.fee;getUTXOs(floID).then((utxos=>{for(var i=utxos.length-1;i>=0;i--)utxos[i].confirmations&&(trx.addinput(utxos[i].txid,utxos[i].vout,utxos[i].scriptPubKey),utxoAmt+=utxos[i].amount);trx.addoutput(floID,utxoAmt-fee),trx.addflodata(floData.replace(/\n/g," "));var signedTxHash=trx.sign(privKey,1);broadcastTx(signedTxHash).then((txid=>resolve(txid))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},floBlockchainAPI.splitUTXOs=function(floID,privKey,count,floData=""){return new Promise(((resolve,reject)=>{if(!floCrypto.validateFloID(floID,!0))return reject("Invalid floID");if(!floCrypto.verifyPrivKey(privKey,floID))return reject("Invalid Private Key");if(!floCrypto.validateASCII(floData))return reject("Invalid FLO_Data: only printable ASCII characters are allowed");var fee=DEFAULT.fee,splitAmt=DEFAULT.sendAmt+fee,totalAmt=splitAmt*count;getBalance(floID).then((balance=>{var fee=DEFAULT.fee;if(balance{var trx=bitjs.transaction(),utxoAmt=0;for(let i=utxos.length-1;i>=0&&utxoAmtDEFAULT.minChangeAmt&&trx.addoutput(floID,change),trx.addflodata(floData.replace(/\n/g," "));var signedTxHash=trx.sign(privKey,1);broadcastTx(signedTxHash).then((txid=>resolve(txid))).catch((error=>reject(error)))}})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},floBlockchainAPI.writeDataMultiple=function(senderPrivKeys,data,receivers=[DEFAULT.receiverID],options={}){return new Promise(((resolve,reject)=>{if(!Array.isArray(senderPrivKeys))return reject("Invalid senderPrivKeys: SenderPrivKeys must be Array");if(!1===options.preserveRatio){let tmp={},amount=DEFAULT.sendAmt*receivers.length/senderPrivKeys.length;senderPrivKeys.forEach((key=>tmp[key]=amount)),senderPrivKeys=tmp}if(!Array.isArray(receivers))return reject("Invalid receivers: Receivers must be Array");{let tmp={},amount=options.sendAmt||DEFAULT.sendAmt;receivers.forEach((floID=>tmp[floID]=amount)),receivers=tmp}"string"!=typeof data&&(data=JSON.stringify(data)),sendTxMultiple(senderPrivKeys,receivers,data).then((txid=>resolve(txid))).catch((error=>reject(error)))}))};const sendTxMultiple=floBlockchainAPI.sendTxMultiple=function(senderPrivKeys,receivers,floData=""){return new Promise(((resolve,reject)=>{if(!floCrypto.validateASCII(floData))return reject("Invalid FLO_Data: only printable ASCII characters are allowed");let preserveRatio,senders={};try{let invalids={InvalidSenderPrivKeys:[],InvalidSenderAmountFor:[],InvalidReceiverIDs:[],InvalidReceiveAmountFor:[]},inputVal=0,outputVal=0;if(Array.isArray(senderPrivKeys))senderPrivKeys.forEach((key=>{try{if(key){let floID=floCrypto.getFloID(key);senders[floID]={wif:key}}else invalids.InvalidSenderPrivKeys.push(key)}catch(error){invalids.InvalidSenderPrivKeys.push(key)}})),preserveRatio=!0;else{for(let key in senderPrivKeys)try{if(key){"number"!=typeof senderPrivKeys[key]||senderPrivKeys[key]<=0?invalids.InvalidSenderAmountFor.push(key):inputVal+=senderPrivKeys[key];let floID=floCrypto.getFloID(key);senders[floID]={wif:key,coins:senderPrivKeys[key]}}else invalids.InvalidSenderPrivKeys.push(key)}catch(error){invalids.InvalidSenderPrivKeys.push(key)}preserveRatio=!1}for(let floID in receivers)floCrypto.validateFloID(floID)||invalids.InvalidReceiverIDs.push(floID),"number"!=typeof receivers[floID]||receivers[floID]<=0?invalids.InvalidReceiveAmountFor.push(floID):outputVal+=receivers[floID];for(let i in invalids)invalids[i].length||delete invalids[i];if(Object.keys(invalids).length)return reject(invalids);if(!preserveRatio&&inputVal!=outputVal)return reject(`Input Amount (${inputVal}) not equal to Output Amount (${outputVal})`)}catch(error){return reject(error)}let promises=[];for(let floID in senders)promises.push(getBalance(floID));Promise.all(promises).then((results=>{let totalBalance=0,totalFee=DEFAULT.fee,balance={};if(!preserveRatio)var dividedFee=totalFee/Object.keys(senders).length;let insufficient=[];for(let floID in senders)balance[floID]=parseFloat(results.shift()),(isNaN(balance[floID])||preserveRatio&&balance[floID]<=totalFee||!preserveRatio&&balance[floID]{var trx=bitjs.transaction();for(let floID in senders){let sendAmt,utxos=results.shift();if(preserveRatio){let ratio=balance[floID]/totalBalance;sendAmt=totalSendAmt*ratio}else sendAmt=senders[floID].coins+dividedFee;let utxoAmt=0;for(let i=utxos.length-1;i>=0&&utxoAmt0&&trx.addoutput(floID,change)}for(let floID in receivers)trx.addoutput(floID,receivers[floID]);trx.addflodata(floData.replace(/\n/g," "));for(let floID in senders)trx.sign(senders[floID].wif,1);var signedTxHash=trx.serialize();broadcastTx(signedTxHash).then((txid=>resolve(txid))).catch((error=>reject(error)))})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},createMultisigTx=function(redeemScript,receivers,amounts,floData="",strict_utxo=!0){return new Promise(((resolve,reject)=>{var multisig=floCrypto.decodeRedeemScript(redeemScript);if(!multisig)return reject("Invalid redeemScript");var senderAddr=multisig.address;if(!floCrypto.validateFloID(senderAddr))return reject(`Invalid multisig : ${senderAddr}`);if(!floCrypto.validateASCII(floData))return reject("Invalid FLO_Data: only printable ASCII characters are allowed");Array.isArray(receivers)||(receivers=[receivers]);for(let r of receivers)if(!floCrypto.validateFloID(r))return reject(`Invalid address : ${r}`);if(Array.isArray(amounts)||(amounts=[amounts]),amounts.length!=receivers.length)return reject("Receivers and amounts have different length");var sendAmt=0;for(let a of amounts){if("number"!=typeof a||a<=0)return reject(`Invalid amount : ${a}`);sendAmt+=a}getBalance(senderAddr).then((balance=>{var fee=DEFAULT.fee;if(balance{for(var trx=bitjs.transaction(),utxoAmt=0,i=utxos.length-1;i>=0&&utxoAmtDEFAULT.minChangeAmt&&trx.addoutput(senderAddr,change),trx.addflodata(floData.replace(/\n/g," ")),resolve(trx)}})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))};floBlockchainAPI.createMultisigTx=function(redeemScript,receivers,amounts,floData="",strict_utxo=!0){return new Promise(((resolve,reject)=>{createMultisigTx(redeemScript,receivers,amounts,floData,strict_utxo).then((trx=>resolve(trx.serialize()))).catch((error=>reject(error)))}))};const sendMultisigTx=floBlockchainAPI.sendMultisigTx=function(redeemScript,privateKeys,receivers,amounts,floData="",strict_utxo=!0){return new Promise(((resolve,reject)=>{var multisig=floCrypto.decodeRedeemScript(redeemScript);if(!multisig)return reject("Invalid redeemScript");if(privateKeys.length{for(let pk of privateKeys)trx.sign(pk,1);var signedTxHash=trx.serialize();broadcastTx(signedTxHash).then((txid=>resolve(txid))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))};function deserializeTx(tx){if("string"==typeof tx||Array.isArray(tx))try{tx=bitjs.transaction(tx)}catch{throw"Invalid transaction hex"}else if("object"!=typeof tx||"function"!=typeof tx.sign)throw"Invalid transaction object";return tx}floBlockchainAPI.writeMultisigData=function(redeemScript,data,privatekeys,receiverAddr=DEFAULT.receiverID,options={}){let strict_utxo=!1!==options.strict_utxo,sendAmt=isNaN(options.sendAmt)?DEFAULT.sendAmt:options.sendAmt;return new Promise(((resolve,reject)=>{if(!floCrypto.validateFloID(receiverAddr))return reject(`Invalid receiver: ${receiverAddr}`);sendMultisigTx(redeemScript,privatekeys,receiverAddr,sendAmt,data,strict_utxo).then((txid=>resolve(txid))).catch((error=>reject(error)))}))},floBlockchainAPI.signTx=function(tx,privateKey,sighashtype=1){if(!floCrypto.getFloID(privateKey))throw"Invalid Private key";return(tx=deserializeTx(tx)).sign(privateKey,sighashtype)};const checkSigned=floBlockchainAPI.checkSigned=function(tx,bool=!0){tx=deserializeTx(tx);let n=[];for(let i=0;ix.t)throw"signaturesRequired is more than publicKeys";x.s!0!==x)).length:n};floBlockchainAPI.checkIfSameTx=function(tx1,tx2){if(tx1=deserializeTx(tx1),tx2=deserializeTx(tx2),tx1.inputs.length!==tx2.inputs.length||tx1.outputs.length!==tx2.outputs.length)return!1;if(tx1.floData!==tx2.floData)return!1;for(let i=0;inew Promise(((resolve,reject)=>{promisedAPI(`api/tx/${txid}`).then((result=>resolve(result.vout[i]))).catch((error=>reject(error)))}));function getOutputAddress(outscript){var bytes,version;switch(outscript[0]){case 118:bytes=outscript.slice(3,outscript.length-2),version=bitjs.pub;break;case 169:bytes=outscript.slice(2,outscript.length-1),version=bitjs.multisig;break;default:return}bytes.unshift(version);var checksum=Crypto.SHA256(Crypto.SHA256(bytes,{asBytes:!0}),{asBytes:!0}).slice(0,4);return bitjs.Base58.encode(bytes.concat(checksum))}floBlockchainAPI.parseTransaction=function(tx){return new Promise(((resolve,reject)=>{tx=deserializeTx(tx);let result={},promises=[];for(let i=0;i{result.inputs=inputs.map((inp=>Object({address:inp.scriptPubKey.addresses[0],value:parseFloat(inp.value)})));let signed=checkSigned(tx,!1);result.inputs.forEach(((inp,i)=>inp.signed=signed[i])),result.outputs=tx.outputs.map((out=>Object({address:getOutputAddress(out.script),value:util.Sat_to_FLO(out.value)}))),result.total_input=parseFloat(result.inputs.reduce(((a,inp)=>a+inp.value),0).toFixed(8)),result.total_output=parseFloat(result.outputs.reduce(((a,out)=>a+out.value),0).toFixed(8)),result.fee=parseFloat((result.total_input-result.total_output).toFixed(8)),result.floData=tx.floData,resolve(result)})).catch((error=>reject(error)))}))};const broadcastTx=floBlockchainAPI.broadcastTx=function(signedTxHash){return new Promise(((resolve,reject)=>{if(signedTxHash.length<1)return reject("Empty Transaction Data");promisedAPI("/api/sendtx/"+signedTxHash).then((response=>resolve(response.result))).catch((error=>reject(error)))}))},getTx=floBlockchainAPI.getTx=function(txid){return new Promise(((resolve,reject)=>{promisedAPI(`api/tx/${txid}`).then((response=>resolve(response))).catch((error=>reject(error)))}))},waitForConfirmation=floBlockchainAPI.waitForConfirmation=function(txid,max_retry=-1,retry_timeout=20){return new Promise(((resolve,reject)=>{setTimeout((function(){getTx(txid).then((tx=>tx?tx.confirmations?resolve(tx):0===max_retry?reject("Waiting timeout: tx still not confirmed"):void waitForConfirmation(txid,max_retry=max_retry<0?-1:max_retry-1,retry_timeout).then((result=>resolve(result))).catch((error=>reject(error))):reject("Transaction not found"))).catch((error=>reject(error)))}),1e3*retry_timeout)}))},readTxs=floBlockchainAPI.readTxs=function(addr,options={}){return new Promise(((resolve,reject)=>{let query_params={details:"txs"};!isUndefined(options.page)&&Number.isInteger(options.page)&&(query_params.page=options.page),!isUndefined(options.pageSize)&&Number.isInteger(options.pageSize)&&(query_params.pageSize=options.pageSize),options.confirmed&&(query_params.confirmed=!0),promisedAPI(`api/address/${addr}`,query_params).then((response=>{Array.isArray(response.txs)||(response.txs=[]),resolve(response)})).catch((error=>reject(error)))}))};function readAllTxs_oldSupport(addr,options,ignoreOld=0,cacheTotal=0){return new Promise(((resolve,reject)=>{readTxs(addr,options).then((response=>{cacheTotal+=response.txs.length;let n_remaining=response.txApperances-cacheTotal;if(n_remainingresolve(response.txs.concat(result)))).catch((error=>reject(error))))})).catch((error=>reject(error)))}))}function readAllTxs_new(addr,options,lastItem){return new Promise(((resolve,reject)=>{readTxs(addr,options).then((response=>{let i=response.txs.findIndex((t=>t.txid===lastItem));-1!=i?resolve(response.txs.slice(0,i)):response.page==response.totalPages?resolve(response.txs):(options.page=response.page+1,readAllTxs_new(addr,options,lastItem).then((result=>resolve(response.txs.concat(result)))).catch((error=>reject(error))))})).catch((error=>reject(error)))}))}const readAllTxs=floBlockchainAPI.readAllTxs=function(addr,options={}){return new Promise(((resolve,reject)=>{Number.isInteger(options.ignoreOld)?readAllTxs_oldSupport(addr,options,options.ignoreOld).then((txs=>{let last_tx=txs.find((t=>t.confirmations>0)),new_lastItem=last_tx?last_tx.txid:options.ignoreOld;resolve({lastItem:new_lastItem,items:txs})})).catch((error=>reject(error))):readAllTxs_new(addr,options,options.after).then((txs=>{let last_tx=txs.find((t=>t.confirmations>0)),new_lastItem=last_tx?last_tx.txid:options.after;resolve({lastItem:new_lastItem,items:txs})})).catch((error=>reject(error)))}))};floBlockchainAPI.readData=function(addr,options={}){return new Promise(((resolve,reject)=>{let query_options={};query_options.confirmed=!!isUndefined(options.confirmed)||options.confirmed,isUndefined(options.after)?isUndefined(options.ignoreOld)||(query_options.ignoreOld=options.ignoreOld):query_options.after=options.after,readAllTxs(addr,query_options).then((response=>{"string"==typeof options.senders&&(options.senders=[options.senders]),"string"==typeof options.receivers&&(options.receivers=[options.receivers]);const filteredData=response.items.filter((tx=>{if(!tx.confirmations)return!1;if(options.sentOnly&&!tx.vin.some((vin=>vin.addresses[0]===addr)))return!1;if(Array.isArray(options.senders)&&!tx.vin.some((vin=>options.senders.includes(vin.addresses[0]))))return!1;if(options.receivedOnly&&!tx.vout.some((vout=>vout.scriptPubKey.addresses[0]===addr)))return!1;if(Array.isArray(options.receivers)&&!tx.vout.some((vout=>options.receivers.includes(vout.scriptPubKey.addresses[0]))))return!1;if(options.pattern)try{let jsonContent=JSON.parse(tx.floData);if(!Object.keys(jsonContent).includes(options.pattern))return!1}catch{return!1}return!(options.filter&&!options.filter(tx.floData))})).map((tx=>options.tx?{txid:tx.txid,time:tx.time,blockheight:tx.blockheight,senders:new Set(tx.vin.map((v=>v.addresses[0]))),receivers:new Set(tx.vout.map((v=>v.scriptPubKey.addresses[0]))),data:tx.floData}:tx.floData)),result={lastItem:response.lastItem};options.tx?result.items=filteredData:result.data=filteredData,resolve(result)})).catch((error=>reject(error)))}))};const getLatestData=floBlockchainAPI.getLatestData=function(addr,caseFn,options={}){return new Promise(((resolve,reject)=>{let new_lastItem,query_options={};query_options.confirmed=!!isUndefined(options.confirmed)||options.confirmed,isUndefined(options.page)||(query_options.page=options.page),readTxs(addr,query_options).then((response=>{if(!new_lastItem){let last_tx=response.items.find((t=>t.confirmations>0));last_tx&&(new_lastItem=last_tx.txid)}"string"==typeof options.senders&&(options.senders=[options.senders]),"string"==typeof options.receivers&&(options.receivers=[options.receivers]);let i_after=response.txs.findIndex((t=>t.txid===options.after));-1!=i_after&&response.items.splice(i_after);var item=response.items.find((tx=>!!tx.confirmations&&(!(options.sentOnly&&!tx.vin.some((vin=>vin.addresses[0]===addr)))&&(!(Array.isArray(options.senders)&&!tx.vin.some((vin=>options.senders.includes(vin.addresses[0]))))&&(!(options.receivedOnly&&!tx.vout.some((vout=>vout.scriptPubKey.addresses[0]===addr)))&&(!(Array.isArray(options.receivers)&&!tx.vout.some((vout=>options.receivers.includes(vout.scriptPubKey.addresses[0]))))&&!!caseFn(tx.floData)))))));if(!isUndefined(item)){const result={lastItem:new_lastItem||item.txid};return options.tx?result.item={txid:item.txid,time:item.time,blockheight:item.blockheight,senders:new Set(item.vin.map((v=>v.addresses[0]))),receivers:new Set(item.vout.map((v=>v.scriptPubKey.addresses[0]))),data:item.floData}:result.data=item.floData,resolve(result)}response.page==response.totalPages||-1!=i_after?resolve({lastItem:new_lastItem||options.after}):(options.page=response.page+1,getLatestData(addr,caseFn,options).then((result=>resolve(result))).catch((error=>reject(error))))})).catch((error=>reject(error)))}))}}(); \ No newline at end of file diff --git a/floCloudAPI.min.js b/floCloudAPI.min.js new file mode 100644 index 0000000..84fe9f4 --- /dev/null +++ b/floCloudAPI.min.js @@ -0,0 +1 @@ +!function(EXPORTS){"use strict";const floCloudAPI="object"===typeof module?module.exports:window.floCloudAPI={},DEFAULT={blockchainPrefix:35,SNStorageID:floGlobals.SNStorageID||"FNaN9McoBAEFUjkRmNQRYLmBF8SpS7Tgfk",adminID:floGlobals.adminID,application:floGlobals.application,SNStorageName:"SuperNodeStorage",callback:(d,e)=>console.debug(d,e)};var user_id,user_public,user_private,aes_key,appObjects,generalData,lastVC;function user(id,priv){if(!priv||!id)return user.clear();let pub=floCrypto.getPubKeyHex(priv);if(!pub||!floCrypto.verifyPubKey(pub,id))return user.clear();let n=floCrypto.randInt(12,20);return aes_key=floCrypto.randString(n),user_private=Crypto.AES.encrypt(priv,aes_key),user_public=pub,user_id=id}Object.defineProperties(user,{id:{get:()=>{if(!user_id)throw"User not set";return user_id}},public:{get:()=>{if(!user_public)throw"User not set";return user_public}},sign:{value:msg=>{if(!user_private)throw"User not set";return floCrypto.signData(msg,Crypto.AES.decrypt(user_private,aes_key))}},clear:{value:()=>user_id=user_public=user_private=aes_key=void 0}}),Object.defineProperties(floCloudAPI,{SNStorageID:{get:()=>DEFAULT.SNStorageID},SNStorageName:{get:()=>DEFAULT.SNStorageName},adminID:{get:()=>DEFAULT.adminID},application:{get:()=>DEFAULT.application},user:{get:()=>user}}),Object.defineProperties(floGlobals,{appObjects:{get:()=>appObjects,set:obj=>appObjects=obj},generalData:{get:()=>generalData,set:data=>generalData=data},generalDataset:{value:(type,options={})=>generalData[filterKey(type,options)]},lastVC:{get:()=>lastVC,set:vc=>lastVC=vc}});var kBucket,supernodes={};Object.defineProperty(floCloudAPI,"nodes",{get:()=>JSON.parse(JSON.stringify(supernodes))});const K_Bucket=floCloudAPI.K_Bucket=function(masterID,nodeList){const decodeID=floID=>{let k=bitjs.Base58.decode(floID);k.shift(),k.splice(-4,4);let decodedId=Crypto.util.bytesToHex(k),nodeIdBytes=new BigInteger(decodedId,16).toByteArrayUnsigned();return new Uint8Array(nodeIdBytes)},_KB=new BuildKBucket({localNodeId:decodeID(masterID)});nodeList.forEach((id=>_KB.add({id:decodeID(id),floID:id})));const _CO=nodeList.map((id=>[_KB.distance(_KB.localNodeId,decodeID(id)),id])).sort(((a,b)=>a[0]-b[0])).map((a=>a[1]));Object.defineProperty(this,"tree",{get:()=>_KB}),Object.defineProperty(this,"list",{get:()=>Array.from(_CO)}),this.isNode=floID=>_CO.includes(floID),this.innerNodes=function(id1,id2){if(!_CO.includes(id1)||!_CO.includes(id2))throw Error("Given nodes are not supernode");let iNodes=[];for(let i=_CO.indexOf(id1)+1;_CO[i]!=id2;i++)i<_CO.length?iNodes.push(_CO[i]):i=-1;return iNodes},this.outterNodes=function(id1,id2){if(!_CO.includes(id1)||!_CO.includes(id2))throw Error("Given nodes are not supernode");let oNodes=[];for(let i=_CO.indexOf(id2)+1;_CO[i]!=id1;i++)i<_CO.length?oNodes.push(_CO[i]):i=-1;return oNodes},this.prevNode=function(id,N=1){let n=N||_CO.length;if(!_CO.includes(id))throw Error("Given node is not supernode");let pNodes=[];for(let i=0,j=_CO.indexOf(id)-1;i-1?pNodes[i++]=_CO[j]:j=_CO.length;return 1==N?pNodes[0]:pNodes},this.nextNode=function(id,N=1){let n=N||_CO.length;if(!_CO.includes(id))throw Error("Given node is not supernode");n||(n=_CO.length);let nNodes=[];for(let i=0,j=_CO.indexOf(id)+1;ik.floID));return 1==N?cNodes[0]:cNodes}};floCloudAPI.init=function(nodes){return new Promise(((resolve,reject)=>{try{supernodes=nodes,kBucket=new K_Bucket(DEFAULT.SNStorageID,Object.keys(supernodes)),resolve("Cloud init successful")}catch(error){reject(error)}}))},Object.defineProperty(floCloudAPI,"kBucket",{get:()=>kBucket});const _inactive=new Set;function ws_activeConnect(snID,reverse=!1){return new Promise(((resolve,reject)=>{if(_inactive.size===kBucket.list.length)return reject("Cloud offline");snID in supernodes||(snID=kBucket.closestNode(proxyID(snID))),function(snID){return new Promise(((resolve,reject)=>{if(!(snID in supernodes))return reject(`${snID} is not a supernode`);if(_inactive.has(snID))return reject(`${snID} is not active`);var wsConn=new WebSocket("wss://"+supernodes[snID].uri+"/");wsConn.onopen=evt=>resolve(wsConn),wsConn.onerror=evt=>{_inactive.add(snID),reject(`${snID} is unavailable`)}}))}(snID).then((node=>resolve(node))).catch((error=>{if(reverse)var nxtNode=kBucket.prevNode(snID);else nxtNode=kBucket.nextNode(snID);ws_activeConnect(nxtNode,reverse).then((node=>resolve(node))).catch((error=>reject(error)))}))}))}function fetch_ActiveAPI(snID,data,reverse=!1){return new Promise(((resolve,reject)=>{if(_inactive.size===kBucket.list.length)return reject("Cloud offline");snID in supernodes||(snID=kBucket.closestNode(proxyID(snID))),function(snID,data){return new Promise(((resolve,reject)=>{if(_inactive.has(snID))return reject(`${snID} is not active`);let fetcher,sn_url="https://"+supernodes[snID].uri;"string"==typeof data?fetcher=fetch(sn_url+"?"+data):"object"==typeof data&&"POST"===data.method&&(fetcher=fetch(sn_url,data)),fetcher.then((response=>{response.ok||400===response.status||500===response.status?resolve(response):reject(response)})).catch((error=>reject(error)))}))}(snID,data).then((result=>resolve(result))).catch((error=>{if(_inactive.add(snID),reverse)var nxtNode=kBucket.prevNode(snID);else nxtNode=kBucket.nextNode(snID);fetch_ActiveAPI(nxtNode,data,reverse).then((result=>resolve(result))).catch((error=>reject(error)))}))}))}function singleRequest(floID,data_obj,method="POST"){return new Promise(((resolve,reject)=>{let data;data="POST"===method?{method:"POST",body:JSON.stringify(data_obj)}:new URLSearchParams(JSON.parse(JSON.stringify(data_obj))).toString(),fetch_ActiveAPI(floID,data).then((response=>{response.ok?response.json().then((result=>resolve(result))).catch((error=>reject(error))):response.text().then((result=>reject(response.status+": "+result))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))}const _liveRequest={};function liveRequest(floID,request,callback){const filterData=void 0!==request.status?data=>{if(request.status)return data;{let filtered={};for(let i in data)request.trackList.includes(i)&&(filtered[i]=data[i]);return filtered}}:data=>{data=objectifier(data);let filtered={},proxy=proxyID(request.receiverID),r=request;for(let v in data){let d=data[v];r.atVectorClock&&r.atVectorClock!=v||!(r.atVectorClock||!r.lowerVectorClock||r.lowerVectorClock<=v)||!(r.atVectorClock||!r.upperVectorClock||r.upperVectorClock>=v)||r.afterTime&&!(r.afterTime{ws_activeConnect(floID).then((node=>{let randID=floCrypto.randString(5);node.send(JSON.stringify(request)),node.onmessage=evt=>{let d=null,e=null;try{d=filterData(JSON.parse(evt.data))}catch(error){e=evt.data}finally{callback(d,e)}},_liveRequest[randID]=node,_liveRequest[randID].request=request,resolve(randID)})).catch((error=>reject(error)))}))}Object.defineProperty(floCloudAPI,"liveRequest",{get:()=>_liveRequest}),Object.defineProperty(floCloudAPI,"inactive",{get:()=>_inactive});const util=floCloudAPI.util={},encodeMessage=util.encodeMessage=function(message){return btoa(unescape(encodeURIComponent(JSON.stringify(message))))},decodeMessage=util.decodeMessage=function(message){return JSON.parse(decodeURIComponent(escape(atob(message))))},filterKey=util.filterKey=function(type,options={}){return type+(options.comment?":"+options.comment:"")+"|"+(options.group||options.receiverID||DEFAULT.adminID)+"|"+(options.application||DEFAULT.application)},proxyID=util.proxyID=function(address){if(address){var bytes;if(33==address.length||34==address.length){let decode=bitjs.Base58.decode(address);bytes=decode.slice(0,decode.length-4);let checksum=decode.slice(decode.length-4),hash=Crypto.SHA256(Crypto.SHA256(bytes,{asBytes:!0}),{asBytes:!0});hash[0]!=checksum[0]||hash[1]!=checksum[1]||hash[2]!=checksum[2]||hash[3]!=checksum[3]?bytes=void 0:bytes.shift()}else if(42==address.length||62==address.length){if("function"!=typeof coinjs)throw"library missing (lib_btc.js)";let decode=coinjs.bech32_decode(address);decode&&((bytes=decode.data).shift(),bytes=coinjs.bech32_convert(bytes,5,8,!1),62==address.length&&(bytes=coinjs.bech32_convert(bytes,5,8,!1)))}else 66==address.length&&(bytes=ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(address),{asBytes:!0})));if(bytes){bytes.unshift(DEFAULT.blockchainPrefix);let hash=Crypto.SHA256(Crypto.SHA256(bytes,{asBytes:!0}),{asBytes:!0});return bitjs.Base58.encode(bytes.concat(hash.slice(0,4)))}throw"Invalid address: "+address}},lastCommit={};function updateObject(objectName,dataSet){try{console.log(dataSet);let vcList=Object.keys(dataSet).sort();for(let vc of vcList)if(!(vclastVC[fk]&&(lastVC[fk]=dataSet[vc].log_time);compactIDB.writeData("lastVC",lastVC[fk],fk),compactIDB.writeData("generalData",generalData[fk],fk)}catch(error){console.error(error)}}function objectifier(data){return Array.isArray(data)||(data=[data]),Object.fromEntries(data.map((d=>(d.message=decodeMessage(d.message),[d.vectorClock,d]))))}Object.defineProperty(lastCommit,"get",{value:objName=>JSON.parse(lastCommit[objName])}),Object.defineProperty(lastCommit,"set",{value:objName=>lastCommit[objName]=JSON.stringify(appObjects[objName])}),floCloudAPI.setStatus=function(options={}){return new Promise(((resolve,reject)=>{let callback=options.callback instanceof Function?options.callback:DEFAULT.callback;var request={floID:user.id,application:options.application||DEFAULT.application,time:Date.now(),status:!0,pubKey:user.public};let hashcontent=["time","application","floID"].map((d=>request[d])).join("|");request.sign=user.sign(hashcontent),liveRequest(options.refID||DEFAULT.adminID,request,callback).then((result=>resolve(result))).catch((error=>reject(error)))}))},floCloudAPI.requestStatus=function(trackList,options={}){return new Promise(((resolve,reject)=>{Array.isArray(trackList)||(trackList=[trackList]);let callback=options.callback instanceof Function?options.callback:DEFAULT.callback,request={status:!1,application:options.application||DEFAULT.application,trackList:trackList};liveRequest(options.refID||DEFAULT.adminID,request,callback).then((result=>resolve(result))).catch((error=>reject(error)))}))};const sendApplicationData=floCloudAPI.sendApplicationData=function(message,type,options={}){return new Promise(((resolve,reject)=>{var data={senderID:user.id,receiverID:options.receiverID||DEFAULT.adminID,pubKey:user.public,message:encodeMessage(message),time:Date.now(),application:options.application||DEFAULT.application,type:type,comment:options.comment||""};let hashcontent=["receiverID","time","application","type","message","comment"].map((d=>data[d])).join("|");data.sign=user.sign(hashcontent),singleRequest(data.receiverID,data).then((result=>resolve(result))).catch((error=>reject(error)))}))},requestApplicationData=floCloudAPI.requestApplicationData=function(type,options={}){return new Promise(((resolve,reject)=>{var request={receiverID:options.receiverID||DEFAULT.adminID,senderID:options.senderID||void 0,application:options.application||DEFAULT.application,type:type,comment:options.comment||void 0,lowerVectorClock:options.lowerVectorClock||void 0,upperVectorClock:options.upperVectorClock||void 0,atVectorClock:options.atVectorClock||void 0,afterTime:options.afterTime||void 0,mostRecent:options.mostRecent||void 0};options.callback instanceof Function?liveRequest(request.receiverID,request,options.callback).then((result=>resolve(result))).catch((error=>reject(error))):("POST"===options.method&&(request={time:Date.now(),request:request}),singleRequest(request.receiverID,request,options.method||"GET").then((data=>resolve(data))).catch((error=>reject(error))))}))};floCloudAPI.editApplicationData=function(vectorClock,comment_edit,options={}){return new Promise(((resolve,reject)=>{let req_options=Object.assign({},options);req_options.atVectorClock=vectorClock,requestApplicationData(void 0,req_options).then((result=>{if(!result.length)return reject("Data not found");let data=result[0];if(data.senderID!==user.id)return reject("Only sender can edit comment");data.comment=comment_edit;let hashcontent=["receiverID","time","application","type","message","comment"].map((d=>data[d])).join("|"),re_sign=user.sign(hashcontent);var request={receiverID:options.receiverID||DEFAULT.adminID,requestorID:user.id,pubKey:user.public,time:Date.now(),vectorClock:vectorClock,edit:comment_edit,re_sign:re_sign};let request_hash=["time","vectorClock","edit","re_sign"].map((d=>request[d])).join("|");request.sign=user.sign(request_hash),singleRequest(request.receiverID,request).then((result=>resolve(result))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},floCloudAPI.tagApplicationData=function(vectorClock,tag,options={}){return new Promise(((resolve,reject)=>{if(!floGlobals.subAdmins.includes(user.id))return reject("Only subAdmins can tag data");var request={receiverID:options.receiverID||DEFAULT.adminID,requestorID:user.id,pubKey:user.public,time:Date.now(),vectorClock:vectorClock,tag:tag};let hashcontent=["time","vectorClock","tag"].map((d=>request[d])).join("|");request.sign=user.sign(hashcontent),singleRequest(request.receiverID,request).then((result=>resolve(result))).catch((error=>reject(error)))}))},floCloudAPI.noteApplicationData=function(vectorClock,note,options={}){return new Promise(((resolve,reject)=>{var request={receiverID:options.receiverID||DEFAULT.adminID,requestorID:user.id,pubKey:user.public,time:Date.now(),vectorClock:vectorClock,note:note};let hashcontent=["time","vectorClock","note"].map((d=>request[d])).join("|");request.sign=user.sign(hashcontent),singleRequest(request.receiverID,request).then((result=>resolve(result))).catch((error=>reject(error)))}))},floCloudAPI.sendGeneralData=function(message,type,options={}){return new Promise(((resolve,reject)=>{if(options.encrypt){let encryptionKey=!0===options.encrypt?floGlobals.settings.encryptionKey:options.encrypt;message=floCrypto.encryptData(JSON.stringify(message),encryptionKey)}sendApplicationData(message,type,options).then((result=>resolve(result))).catch((error=>reject(error)))}))},floCloudAPI.requestGeneralData=function(type,options={}){return new Promise(((resolve,reject)=>{var fk=filterKey(type,options);if(lastVC[fk]=parseInt(lastVC[fk])||0,options.afterTime=options.afterTime||lastVC[fk],options.callback instanceof Function){let new_options=Object.create(options);new_options.callback=(d,e)=>{storeGeneral(fk,d),options.callback(d,e)},requestApplicationData(type,new_options).then((result=>resolve(result))).catch((error=>reject(error)))}else requestApplicationData(type,options).then((dataSet=>{storeGeneral(fk,objectifier(dataSet)),resolve(dataSet)})).catch((error=>reject(error)))}))},floCloudAPI.requestObjectData=function(objectName,options={}){return new Promise(((resolve,reject)=>{options.lowerVectorClock=options.lowerVectorClock||lastVC[objectName]+1,options.senderID=[!1,null].includes(options.senderID)?null:options.senderID||floGlobals.subAdmins,options.mostRecent=!0,options.comment="RESET";let callback=null;if(options.callback instanceof Function){let old_callback=options.callback;callback=(d,e)=>{updateObject(objectName,d),old_callback(d,e)},delete options.callback}requestApplicationData(objectName,options).then((dataSet=>{if(updateObject(objectName,objectifier(dataSet)),delete options.comment,options.lowerVectorClock=lastVC[objectName]+1,delete options.mostRecent,callback){let new_options=Object.create(options);new_options.callback=callback,requestApplicationData(objectName,new_options).then((result=>resolve(result))).catch((error=>reject(error)))}else requestApplicationData(objectName,options).then((dataSet=>{updateObject(objectName,objectifier(dataSet)),resolve(appObjects[objectName])})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},floCloudAPI.closeRequest=function(requestID){return new Promise(((resolve,reject)=>{let conn=_liveRequest[requestID];if(!conn)return reject("Request not found");conn.onclose=evt=>{delete _liveRequest[requestID],resolve("Request connection closed")},conn.close()}))},floCloudAPI.resetObjectData=function(objectName,options={}){return new Promise(((resolve,reject)=>{let message={reset:appObjects[objectName]};options.comment="RESET",sendApplicationData(message,objectName,options).then((result=>{lastCommit.set(objectName),resolve(result)})).catch((error=>reject(error)))}))},floCloudAPI.updateObjectData=function(objectName,options={}){return new Promise(((resolve,reject)=>{let message={diff:diff.find(lastCommit.get(objectName),appObjects[objectName])};options.comment="UPDATE",sendApplicationData(message,objectName,options).then((result=>{lastCommit.set(objectName),resolve(result)})).catch((error=>reject(error)))}))},floCloudAPI.uploadFile=function(fileBlob,type,options={}){return new Promise(((resolve,reject)=>{if(!(fileBlob instanceof File||fileBlob instanceof Blob))return reject("file must be instance of File/Blob");fileBlob.arrayBuffer().then((arraybuf=>{let file_data={type:fileBlob.type,name:fileBlob.name};if(file_data.content=Crypto.util.bytesToBase64(new Uint8Array(arraybuf)),options.encrypt){let encryptionKey=!0===options.encrypt?floGlobals.settings.encryptionKey:options.encrypt;file_data=floCrypto.encryptData(JSON.stringify(file_data),encryptionKey)}sendApplicationData(file_data,type,options).then((({vectorClock:vectorClock,receiverID:receiverID,type:type,application:application})=>resolve({vectorClock:vectorClock,receiverID:receiverID,type:type,application:application}))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},floCloudAPI.downloadFile=function(vectorClock,options={}){return new Promise(((resolve,reject)=>{options.atVectorClock=vectorClock,requestApplicationData(options.type,options).then((result=>{if(!result.length)return reject("File not found");result=result[0];try{let file_data=decodeMessage(result.message);if(file_data instanceof Object&&"secret"in file_data){if(!options.decrypt)return reject("Data is encrypted");let decryptionKey=!0===options.decrypt?Crypto.AES.decrypt(user_private,aes_key):options.decrypt;Array.isArray(decryptionKey)||(decryptionKey=[decryptionKey]);let flag=!1;for(let key of decryptionKey)try{let tmp=floCrypto.decryptData(file_data,key);file_data=JSON.parse(tmp),flag=!0;break}catch(error){}if(!flag)return reject("Unable to decrypt file: Invalid private key")}let arraybuf=new Uint8Array(Crypto.util.base64ToBytes(file_data.content));result.file=new File([arraybuf],file_data.name,{type:file_data.type}),resolve(result)}catch(error){console.error(error),reject("Data is not a file")}})).catch((error=>reject(error)))}))};var diff=function(){const isDate=d=>d instanceof Date,isEmpty=o=>0===Object.keys(o).length,isObject=o=>null!=o&&"object"==typeof o,properObject=o=>isObject(o)&&!o.hasOwnProperty?{...o}:o,updatedDiff=(lhs,rhs)=>{if(lhs===rhs)return{};if(!isObject(lhs)||!isObject(rhs))return rhs;const l=properObject(lhs),r=properObject(rhs);return isDate(l)||isDate(r)?l.valueOf()==r.valueOf()?{}:r:Object.keys(r).reduce(((acc,key)=>{if(l.hasOwnProperty(key)){const difference=updatedDiff(l[key],r[key]);return isObject(difference)&&isEmpty(difference)&&!isDate(difference)?acc:{...acc,[key]:difference}}return acc}),{})},addedDiff=(lhs,rhs)=>{if(lhs===rhs||!isObject(lhs)||!isObject(rhs))return{};const l=properObject(lhs),r=properObject(rhs);return Object.keys(r).reduce(((acc,key)=>{if(l.hasOwnProperty(key)){const difference=addedDiff(l[key],r[key]);return isObject(difference)&&isEmpty(difference)?acc:{...acc,[key]:difference}}return{...acc,[key]:r[key]}}),{})},deletedDiff=(lhs,rhs)=>{if(lhs===rhs||!isObject(lhs)||!isObject(rhs))return{};const l=properObject(lhs),r=properObject(rhs);return Object.keys(l).reduce(((acc,key)=>{if(r.hasOwnProperty(key)){const difference=deletedDiff(l[key],r[key]);return isObject(difference)&&isEmpty(difference)?acc:{...acc,[key]:difference}}return{...acc,[key]:null}}),{})},mergeRecursive=(obj1,obj2,deleteMode=!1)=>{for(var p in obj2)try{obj2[p].constructor==Object?obj1[p]=mergeRecursive(obj1[p],obj2[p],deleteMode):Array.isArray(obj2[p])?obj2[p].length<1?obj1[p]=obj2[p]:obj1[p]=mergeRecursive(obj1[p],obj2[p],deleteMode):obj1[p]=deleteMode&&null===obj2[p]?void 0:obj2[p]}catch(e){obj1[p]=deleteMode&&null===obj2[p]?void 0:obj2[p]}return obj1},cleanse=obj=>(Object.keys(obj).forEach((key=>{var value=obj[key];"object"==typeof value&&null!==value?obj[key]=cleanse(value):void 0===value&&delete obj[key]})),Array.isArray(obj)&&(obj=obj.filter((v=>void 0!==v))),obj);return{find:(lhs,rhs)=>({added:addedDiff(lhs,rhs),deleted:deletedDiff(lhs,rhs),updated:updatedDiff(lhs,rhs)}),merge:(obj,diff)=>(0!==Object.keys(diff.updated).length&&(obj=mergeRecursive(obj,diff.updated)),0!==Object.keys(diff.deleted).length&&(obj=mergeRecursive(obj,diff.deleted,!0),obj=cleanse(obj)),0!==Object.keys(diff.added).length&&(obj=mergeRecursive(obj,diff.added)),obj)}}()}(); \ No newline at end of file diff --git a/floCrypto.min.js b/floCrypto.min.js new file mode 100644 index 0000000..bb25e14 --- /dev/null +++ b/floCrypto.min.js @@ -0,0 +1 @@ +!function(EXPORTS){"use strict";const floCrypto="object"===typeof module?module.exports:window.floCrypto={},p=BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F",16),ecparams=EllipticCurve.getSECCurveByName("secp256k1"),ascii_alternatives="‘ '\n’ '\n“ \"\n” \"\n– --\n— ---\n≥ >=\n≤ <=\n≠ !=\n× *\n÷ /\n← <-\n→ ->\n↔ <->\n⇒ =>\n⇐ <=\n⇔ <=>",exponent1=()=>p.add(BigInteger.ONE).divide(BigInteger("4"));function getUncompressedPublicKey(compressedPublicKey){let pubKeyBytes=Crypto.util.hexToBytes(compressedPublicKey);let prefix_modulus=pubKeyBytes.shift()%2;pubKeyBytes.unshift(0);let x=new BigInteger(pubKeyBytes),xDecimalValue=x.toString(),y=function(x){let exp=exponent1();return x.modPow(BigInteger("3"),p).add(BigInteger("7")).mod(p).modPow(exp,p)}(x),yDecimalValue=y.toString();return prefix_modulus!==y.mod(BigInteger("2")).toString()%2&&(yDecimalValue=y.negate().mod(p).toString()),{x:xDecimalValue,y:yDecimalValue}}coinjs.compressed=!0,floCrypto.randInt=function(min,max){return min=Math.ceil(min),max=Math.floor(max),Math.floor(securedMathRandom()*(max-min+1))+min},floCrypto.randString=function(length,alphaNumeric=!0){for(var result="",characters=alphaNumeric?"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789":"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_+-./*?@#&$<>=[]{}():",i=0;igenerateNewID()},hashID:{value:str=>{let bytes=ripemd160(Crypto.SHA256(str,{asBytes:!0}),{asBytes:!0});bytes.unshift(bitjs.pub);var checksum=Crypto.SHA256(Crypto.SHA256(bytes,{asBytes:!0}),{asBytes:!0}).slice(0,4);return bitjs.Base58.encode(bytes.concat(checksum))}},tmpID:{get:()=>{let bytes=Crypto.util.randomBytes(20);bytes.unshift(bitjs.pub);var checksum=Crypto.SHA256(Crypto.SHA256(bytes,{asBytes:!0}),{asBytes:!0}).slice(0,4);return bitjs.Base58.encode(bytes.concat(checksum))}}}),floCrypto.getPubKeyHex=function(privateKeyHex){if(!privateKeyHex)return null;var key=new Bitcoin.ECKey(privateKeyHex);return null==key.priv?null:(key.setCompressed(!0),key.getPubKeyHex())},floCrypto.getFloID=function(keyHex){if(!keyHex)return null;try{var key=new Bitcoin.ECKey(keyHex);return null==key.priv&&key.setPub(keyHex),key.getBitcoinAddress()}catch{return null}},floCrypto.getAddress=function(privateKeyHex,strict=!1){if(!privateKeyHex)return;var key=new Bitcoin.ECKey(privateKeyHex);if(null==key.priv)return null;key.setCompressed(!0);let pubKey=key.getPubKeyHex();switch(bitjs.Base58.decode(privateKeyHex)[0]){case coinjs.priv:return coinjs.bech32Address(pubKey).address;case bitjs.priv:return bitjs.pubkey2address(pubKey);default:return!strict&&bitjs.pubkey2address(pubKey)}},floCrypto.verifyPrivKey=function(privateKeyHex,pubKey_floID,isfloID=!0){if(!privateKeyHex||!pubKey_floID)return!1;try{var key=new Bitcoin.ECKey(privateKeyHex);return null!=key.priv&&(key.setCompressed(!0),!(!isfloID||pubKey_floID!=key.getBitcoinAddress())||!isfloID&&pubKey_floID.toUpperCase()==key.getPubKeyHex().toUpperCase())}catch{return null}},floCrypto.getMultisigAddress=function(publicKeyList,requiredSignatures){if(!Array.isArray(publicKeyList)||!publicKeyList.length)return null;if(!Number.isInteger(requiredSignatures)||requiredSignatures<1||requiredSignatures>publicKeyList.length)return null;try{return bitjs.pubkeys2multisig(publicKeyList,requiredSignatures)}catch{return null}},floCrypto.decodeRedeemScript=function(redeemScript){try{return bitjs.transaction().decodeRedeemScript(redeemScript)}catch{return null}},floCrypto.validateFloID=function(floID,regularOnly=!1){if(!floID)return!1;try{let addr=new Bitcoin.Address(floID);return!regularOnly||addr.version==Bitcoin.Address.standardVersion}catch{return!1}},floCrypto.validateAddr=function(address,std=!0,bech=!0){let raw=decodeAddress(address);return!!raw&&(void 0!==raw.version?0!=std&&!!(!0===std||!Array.isArray(std)&&std===raw.version||Array.isArray(std)&&std.includes(raw.version)):void 0!==raw.bech_version&&(!1!==bech&&!!(!0===bech||!Array.isArray(bech)&&bech===raw.bech_version||Array.isArray(bech)&&bech.includes(raw.bech_version))))},floCrypto.verifyPubKey=function(pubKeyHex,address){let raw=decodeAddress(address);if(!raw)return;let pub_hash=Crypto.util.bytesToHex(ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(pubKeyHex),{asBytes:!0})));return void 0!==raw.bech_version&&32==raw.bytes.length&&(raw.hex=Crypto.util.bytesToHex(ripemd160(raw.bytes,{asBytes:!0}))),pub_hash===raw.hex},floCrypto.toFloID=function(address,options=null){if(!address)return;let raw=decodeAddress(address);if(!raw)return;if(options){if(!(void 0===raw.version||options.std&&options.std.includes(raw.version)))return;if(!(void 0===raw.bech_version||options.bech&&options.bech.includes(raw.bech_version)))return}raw.bytes.unshift(bitjs.pub);let hash=Crypto.SHA256(Crypto.SHA256(raw.bytes,{asBytes:!0}),{asBytes:!0});return bitjs.Base58.encode(raw.bytes.concat(hash.slice(0,4)))},floCrypto.rawToFloID=function(raw_bytes){if("string"==typeof raw_bytes&&(raw_bytes=Crypto.util.hexToBytes(raw_bytes)),20!=raw_bytes.length)return null;raw_bytes.unshift(bitjs.pub);let hash=Crypto.SHA256(Crypto.SHA256(raw_bytes,{asBytes:!0}),{asBytes:!0});return bitjs.Base58.encode(raw_bytes.concat(hash.slice(0,4)))},floCrypto.toMultisigFloID=function(address,options=null){if(!address)return;let raw=decodeAddress(address);if(!raw)return;if(options){if(!(void 0===raw.version||options.std&&options.std.includes(raw.version)))return;if(!(void 0===raw.bech_version||options.bech&&options.bech.includes(raw.bech_version)))return}if(void 0!==raw.bech_version){if(32!=raw.bytes.length)return;raw.bytes=ripemd160(raw.bytes,{asBytes:!0})}raw.bytes.unshift(bitjs.multisig);let hash=Crypto.SHA256(Crypto.SHA256(raw.bytes,{asBytes:!0}),{asBytes:!0});return bitjs.Base58.encode(raw.bytes.concat(hash.slice(0,4)))},floCrypto.isSameAddr=function(addr1,addr2){if(!addr1||!addr2)return;let raw1=decodeAddress(addr1),raw2=decodeAddress(addr2);return!(!raw1||!raw2)&&(void 0!==raw1.bech_version&&32==raw1.bytes.length&&(raw1.hex=Crypto.util.bytesToHex(ripemd160(raw1.bytes,{asBytes:!0}))),void 0!==raw2.bech_version&&32==raw2.bytes.length&&(raw2.hex=Crypto.util.bytesToHex(ripemd160(raw2.bytes,{asBytes:!0}))),raw1.hex===raw2.hex)};const decodeAddress=floCrypto.decodeAddr=function(address){if(address){if(33==address.length||34==address.length){let decode=bitjs.Base58.decode(address),bytes=decode.slice(0,decode.length-4),checksum=decode.slice(decode.length-4),hash=Crypto.SHA256(Crypto.SHA256(bytes,{asBytes:!0}),{asBytes:!0});return hash[0]!=checksum[0]||hash[1]!=checksum[1]||hash[2]!=checksum[2]||hash[3]!=checksum[3]?null:{version:bytes.shift(),hex:Crypto.util.bytesToHex(bytes),bytes:bytes}}if(42==address.length||62==address.length){let decode=coinjs.bech32_decode(address);if(decode){let bytes=decode.data,bech_version=bytes.shift();return bytes=coinjs.bech32_convert(bytes,5,8,!1),{bech_version:bech_version,hrp:decode.hrp,hex:Crypto.util.bytesToHex(bytes),bytes:bytes}}return null}}};floCrypto.createShamirsSecretShares=function(str,total_shares,threshold_limit){try{if(str.length>0){var strHex=shamirSecretShare.str2hex(str);return shamirSecretShare.share(strHex,total_shares,threshold_limit)}return!1}catch{return!1}};const retrieveShamirSecret=floCrypto.retrieveShamirSecret=function(sharesArray){try{if(sharesArray.length>0){var comb=shamirSecretShare.combine(sharesArray.slice(0,sharesArray.length));return comb=shamirSecretShare.hex2str(comb)}return!1}catch{return!1}};floCrypto.verifyShamirsSecret=function(sharesArray,str){return str?retrieveShamirSecret(sharesArray)===str:null};const validateASCII=floCrypto.validateASCII=function(string,bool=!0){if("string"!=typeof string)return null;if(bool){let x;for(let i=0;i127)return!1;return!0}{let x,invalids={};for(let i=0;i127)&&(x in invalids?invalids[string[i]].push(i):invalids[string[i]]=[i]);return!Object.keys(invalids).length||invalids}};floCrypto.convertToASCII=function(string,mode="soft-remove"){let chars=validateASCII(string,!1);if(!0===chars)return string;if(null===chars)return null;let convertor,result=string,refAlt={};if(ascii_alternatives.split("\n").forEach((a=>refAlt[a[0]]=a.slice(2))),"hard-unicode"===(mode=mode.toLowerCase()))convertor=c=>`\\u${("000"+c.charCodeAt().toString(16)).slice(-4)}`;else if("soft-unicode"===mode)convertor=c=>refAlt[c]||`\\u${("000"+c.charCodeAt().toString(16)).slice(-4)}`;else if("hard-remove"===mode)convertor=c=>"";else{if("soft-remove"!==mode)return null;convertor=c=>refAlt[c]||""}for(let c in chars)result=result.replaceAll(c,convertor(c));return result},floCrypto.revertUnicode=function(string){return string.replace(/\\u[\dA-F]{4}/gi,(m=>String.fromCharCode(parseInt(m.replace(/\\u/g,""),16))))}}(); \ No newline at end of file diff --git a/floDapps.min.js b/floDapps.min.js new file mode 100644 index 0000000..152132c --- /dev/null +++ b/floDapps.min.js @@ -0,0 +1 @@ +!function(EXPORTS){"use strict";const floDapps="object"===typeof module?module.exports:window.floDapps={},DEFAULT={root:"floDapps",application:floGlobals.application,adminID:floGlobals.adminID};var user_priv_raw,aes_key,user_priv_wrap;Object.defineProperties(floDapps,{application:{get:()=>DEFAULT.application},adminID:{get:()=>DEFAULT.adminID},root:{get:()=>DEFAULT.root}});const raw_user={get private(){if(!user_priv_raw)throw"User not logged in";return Crypto.AES.decrypt(user_priv_raw,aes_key)}};var user_id,user_public,user_private;const user=floDapps.user={get id(){if(!user_id)throw"User not logged in";return user_id},get public(){if(!user_public)throw"User not logged in";return user_public},get private(){if(user_private)return user_private instanceof Function?user_private():Crypto.AES.decrypt(user_private,aes_key);throw"User not logged in"},sign:message=>floCrypto.signData(message,raw_user.private),decrypt:data=>floCrypto.decryptData(data,raw_user.private),encipher:message=>Crypto.AES.encrypt(message,raw_user.private),decipher:data=>Crypto.AES.decrypt(data,raw_user.private),get db_name(){return"floDapps#"+floCrypto.toFloID(user.id)},lock(){user_private=user_priv_wrap},async unlock(){await user.private===raw_user.private&&(user_private=user_priv_raw)},get_contact(id){if(!user.contacts)throw"Contacts not available";if(user.contacts[id])return user.contacts[id];{let id_raw=floCrypto.decodeAddr(id).hex;for(let i in user.contacts)if(floCrypto.decodeAddr(i).hex==id_raw)return user.contacts[i]}},get_pubKey(id){if(!user.pubKeys)throw"Contacts not available";if(user.pubKeys[id])return user.pubKeys[id];{let id_raw=floCrypto.decodeAddr(id).hex;for(let i in user.pubKeys)if(floCrypto.decodeAddr(i).hex==id_raw)return user.pubKeys[i]}},clear(){user_id=user_public=user_private=void 0,user_priv_raw=aes_key=void 0,delete user.contacts,delete user.pubKeys,delete user.messages}};var subAdmins,trustedIDs,settings;function initIndexedDB(){return new Promise(((resolve,reject)=>{var obs_a={credentials:{},subAdmins:{},trustedIDs:{},settings:{},appObjects:{},generalData:{},lastVC:{}};initIndexedDB.appObs=initIndexedDB.appObs||{};for(let o in initIndexedDB.appObs)o in obs_a||(obs_a[o]=initIndexedDB.appObs[o]);Promise.all([compactIDB.initDB(DEFAULT.application,obs_a),compactIDB.initDB(DEFAULT.root,{lastTx:{},supernodes:{}})]).then((result=>{compactIDB.setDefaultDB(DEFAULT.application),resolve("IndexedDB App Storage Initated Successfully")})).catch((error=>reject(error)))}))}Object.defineProperties(window,{myFloID:{get:()=>{try{return user.id}catch{return}}},myUserID:{get:()=>{try{return user.id}catch{return}}},myPubKey:{get:()=>{try{return user.public}catch{return}}},myPrivKey:{get:()=>{try{return user.private}catch{return}}}}),Object.defineProperties(floGlobals,{subAdmins:{get:()=>subAdmins},trustedIDs:{get:()=>trustedIDs},settings:{get:()=>settings},contacts:{get:()=>user.contacts},pubKeys:{get:()=>user.pubKeys},messages:{get:()=>user.messages}});const startUpOptions={cloud:!0,app_config:!0};floDapps.startUpOptions={set app_config(val){!0!==val&&!1!==val||(startUpOptions.app_config=val)},get app_config(){return startUpOptions.app_config},set cloud(val){!0!==val&&!1!==val||(startUpOptions.cloud=val)},get cloud(){return startUpOptions.cloud}};const startUpFunctions=[];startUpFunctions.push((function(){return new Promise(((resolve,reject)=>{if(!startUpOptions.cloud)return resolve("No cloud for this app");const CLOUD_KEY="floCloudAPI#"+floCloudAPI.SNStorageID;compactIDB.readData("lastTx",CLOUD_KEY,DEFAULT.root).then((lastTx=>{var query_options={sentOnly:!0,pattern:floCloudAPI.SNStorageName};"number"==typeof lastTx?query_options.ignoreOld=lastTx:"string"==typeof lastTx&&(query_options.after=lastTx),floBlockchainAPI.readData(floCloudAPI.SNStorageID,query_options).then((result=>{compactIDB.readData("supernodes",CLOUD_KEY,DEFAULT.root).then((nodes=>{nodes=nodes||{};for(var i=result.data.length-1;i>=0;i--){var content=JSON.parse(result.data[i])[floCloudAPI.SNStorageName];for(let sn in content.removeNodes)delete nodes[sn];for(let sn in content.newNodes)nodes[sn]=content.newNodes[sn];for(let sn in content.updateNodes)sn in nodes&&(nodes[sn].uri=content.updateNodes[sn])}Promise.all([compactIDB.writeData("lastTx",result.lastItem,CLOUD_KEY,DEFAULT.root),compactIDB.writeData("supernodes",nodes,CLOUD_KEY,DEFAULT.root)]).then((_=>{floCloudAPI.init(nodes).then((result=>resolve("Loaded Supernode list\n"+result))).catch((error=>reject(error)))})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))})).catch((error=>reject(error)))}))})),startUpFunctions.push((function(){return new Promise(((resolve,reject)=>{if(!startUpOptions.app_config)return resolve("No configs for this app");compactIDB.readData("lastTx",`${DEFAULT.application}|${DEFAULT.adminID}`,DEFAULT.root).then((lastTx=>{var query_options={sentOnly:!0,pattern:DEFAULT.application};"number"==typeof lastTx?query_options.ignoreOld=lastTx:"string"==typeof lastTx&&(query_options.after=lastTx),floBlockchainAPI.readData(DEFAULT.adminID,query_options).then((result=>{for(var i=result.data.length-1;i>=0;i--){var content=JSON.parse(result.data[i])[DEFAULT.application];if(content&&"object"==typeof content){if(Array.isArray(content.removeSubAdmin))for(var j=0;j{subAdmins=Object.keys(result),compactIDB.readAllData("trustedIDs").then((result=>{trustedIDs=Object.keys(result),compactIDB.readAllData("settings").then((result=>{settings=result,resolve("Read app configuration from blockchain")}))}))}))}))})).catch((error=>reject(error)))}))})),startUpFunctions.push((function(){return new Promise(((resolve,reject)=>{if(!startUpOptions.cloud)return resolve("No cloud for this app");for(var loadData=["appObjects","generalData","lastVC"],promises=[],i=0;i{for(var i=0;ireject(error)))}))}));var keyInput=type=>new Promise(((resolve,reject)=>{let inputVal=prompt(`Enter ${type}: `);null===inputVal?reject(null):resolve(inputVal)}));function getCredentials(){const writeSharesToIDB=(shares,i=0,resultIndexes=[])=>new Promise((resolve=>{if(i>=shares.length)return resolve(resultIndexes);var n=floCrypto.randInt(0,1e5);compactIDB.addData("credentials",shares[i],n).then((res=>{resultIndexes.push(n),writeSharesToIDB(shares,i+1,resultIndexes).then((result=>resolve(result)))})).catch((error=>{writeSharesToIDB(shares,i,resultIndexes).then((result=>resolve(result)))}))})),getPrivateKeyCredentials=()=>new Promise(((resolve,reject)=>{var privKey,indexArr=localStorage.getItem(`${DEFAULT.application}#privKey`);indexArr?(indexArr=>new Promise(((resolve,reject)=>{for(var promises=[],i=0;i{var secret=floCrypto.retrieveShamirSecret(shares);secret?resolve(secret):reject("Shares are insufficient or incorrect")})).catch((error=>{clearCredentials(),location.reload()}))})))(JSON.parse(indexArr)).then((result=>resolve(result))).catch((error=>reject(error))):keyInput("PRIVATE_KEY").then((result=>{if(!result)return reject("Empty Private Key");var floID=floCrypto.getFloID(result);if(!floID||!floCrypto.validateFloID(floID))return reject("Invalid Private Key");privKey=result})).catch((error=>{console.log(error,"Generating Random Keys"),privKey=floCrypto.generateNewID().privKey})).finally((_=>{if(privKey){var threshold=floCrypto.randInt(10,20),shares=floCrypto.createShamirsSecretShares(privKey,threshold,threshold);writeSharesToIDB(shares).then((resultIndexes=>{localStorage.setItem(`${DEFAULT.application}#privKey`,JSON.stringify(resultIndexes));var randomPrivKey=floCrypto.generateNewID().privKey,randomThreshold=floCrypto.randInt(10,20),randomShares=floCrypto.createShamirsSecretShares(randomPrivKey,randomThreshold,randomThreshold);writeSharesToIDB(randomShares),resolve(privKey)}))}}))})),checkIfPinRequired=key=>new Promise(((resolve,reject)=>{52==key.length?resolve(key):keyInput("PIN/Password").then((pwd=>{try{let privKey=Crypto.AES.decrypt(key,pwd);resolve(privKey)}catch(error){reject("Access Denied: Incorrect PIN/Password")}})).catch((error=>reject("Access Denied: PIN/Password required")))}));return new Promise(((resolve,reject)=>{getPrivateKeyCredentials().then((key=>{checkIfPinRequired(key).then((privKey=>{try{user_public=floCrypto.getPubKeyHex(privKey),user_id=floCrypto.getAddress(privKey),startUpOptions.cloud&&floCloudAPI.user(user_id,privKey),user_priv_wrap=()=>checkIfPinRequired(key);let n=floCrypto.randInt(12,20);aes_key=floCrypto.randString(n),user_priv_raw=Crypto.AES.encrypt(privKey,aes_key),user_private=user_priv_wrap,resolve("Login Credentials loaded successful")}catch(error){console.log(error),reject("Corrupted Private Key")}})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))}var startUpLog=(status,log)=>status?console.log(log):console.error(log);const callStartUpFunction=i=>new Promise(((resolve,reject)=>{startUpFunctions[i]().then((result=>{callStartUpFunction.completed+=1,startUpLog(!0,`${result}\nCompleted ${callStartUpFunction.completed}/${callStartUpFunction.total} Startup functions`),resolve(!0)})).catch((error=>{callStartUpFunction.failed+=1,startUpLog(!1,`${error}\nFailed ${callStartUpFunction.failed}/${callStartUpFunction.total} Startup functions`),reject(!1)}))}));var _midFunction;const callAndLog=p=>new Promise(((res,rej)=>{p.then((r=>{startUpLog(!0,r),res(r)})).catch((e=>{startUpLog(!1,e),rej(e)}))}));floDapps.launchStartUp=function(){return new Promise(((resolve,reject)=>{initIndexedDB().then((log=>{console.log(log),callStartUpFunction.total=startUpFunctions.length,callStartUpFunction.completed=0,callStartUpFunction.failed=0;let p1=new Promise(((res,rej)=>{Promise.all(startUpFunctions.map(((f,i)=>callStartUpFunction(i)))).then((r=>{callAndLog(new Promise(((res,rej)=>{_midFunction instanceof Function?_midFunction().then((r=>res("Mid startup function completed"))).catch((e=>rej("Mid startup function failed"))):res("No mid startup function")}))).then((r=>res(!0))).catch((e=>rej(!1)))}))})),p2=new Promise(((res,rej)=>{callAndLog(getCredentials()).then((r=>{callAndLog(new Promise(((resolve,reject)=>{compactIDB.initDB(user.db_name,{contacts:{},pubKeys:{},messages:{}}).then((result=>{resolve("UserDB Initated Successfully")})).catch((error=>reject("Init userDB failed")))}))).then((r=>{callAndLog(new Promise(((resolve,reject)=>{for(var loadData=["contacts","pubKeys","messages"],promises=[],i=0;i{for(var i=0;ireject("Load userDB failed")))}))).then((r=>res(!0))).catch((e=>rej(!1)))})).catch((e=>rej(!1)))})).catch((e=>rej(!1)))}));Promise.all([p1,p2]).then((r=>resolve("App Startup finished successful"))).catch((e=>reject("App Startup failed")))})).catch((error=>{startUpLog(!1,error),reject("App database initiation failed")}))}))},floDapps.addStartUpFunction=fn=>fn instanceof Function&&!startUpFunctions.includes(fn)&&startUpFunctions.push(fn),floDapps.setMidStartup=fn=>fn instanceof Function&&(_midFunction=fn),floDapps.setCustomStartupLogger=fn=>fn instanceof Function&&(startUpLog=fn),floDapps.setCustomPrivKeyInput=fn=>fn instanceof Function&&(keyInput=fn),floDapps.setAppObjectStores=appObs=>initIndexedDB.appObs=appObs,floDapps.storeContact=function(floID,name){return new Promise(((resolve,reject)=>{if(!floCrypto.validateAddr(floID))return reject("Invalid floID!");compactIDB.writeData("contacts",name,floID,user.db_name).then((result=>{user.contacts[floID]=name,resolve("Contact stored")})).catch((error=>reject(error)))}))},floDapps.storePubKey=function(floID,pubKey){return new Promise(((resolve,reject)=>floID in user.pubKeys?resolve("pubKey already stored"):floCrypto.validateAddr(floID)?floCrypto.verifyPubKey(pubKey,floID)?void compactIDB.writeData("pubKeys",pubKey,floID,user.db_name).then((result=>{user.pubKeys[floID]=pubKey,resolve("pubKey stored")})).catch((error=>reject(error))):reject("Incorrect pubKey"):reject("Invalid floID!")))},floDapps.sendMessage=function(floID,message){return new Promise(((resolve,reject)=>{let options={receiverID:floID,application:DEFAULT.root,comment:DEFAULT.application};floID in user.pubKeys&&(message=floCrypto.encryptData(JSON.stringify(message),user.pubKeys[floID])),floCloudAPI.sendApplicationData(message,"Message",options).then((result=>resolve(result))).catch((error=>reject(error)))}))},floDapps.requestInbox=function(callback){return new Promise(((resolve,reject)=>{let lastVC=Object.keys(user.messages).sort().pop(),options={receiverID:user.id,application:DEFAULT.root,lowerVectorClock:lastVC+1},privKey=raw_user.private;options.callback=(d,e)=>{for(let v in d){try{d[v].message instanceof Object&&"secret"in d[v].message&&(d[v].message=floCrypto.decryptData(d[v].message,privKey))}catch(error){}compactIDB.writeData("messages",d[v],v,user.db_name),user.messages[v]=d[v]}callback instanceof Function&&callback(d,e)},floCloudAPI.requestApplicationData("Message",options).then((result=>resolve(result))).catch((error=>reject(error)))}))},floDapps.manageAppConfig=function(adminPrivKey,addList,rmList,settings){return new Promise(((resolve,reject)=>{if(!startUpOptions.app_config)return reject("No configs for this app");if(Array.isArray(addList)&&addList.length||(addList=void 0),Array.isArray(rmList)&&rmList.length||(rmList=void 0),settings&&"object"==typeof settings&&Object.keys(settings).length||(settings=void 0),!addList&&!rmList&&!settings)return reject("No configuration change");var floData={[DEFAULT.application]:{addSubAdmin:addList,removeSubAdmin:rmList,settings:settings}},floID=floCrypto.getFloID(adminPrivKey);floID!=DEFAULT.adminID?reject("Access Denied for Admin privilege"):floBlockchainAPI.writeData(floID,JSON.stringify(floData),adminPrivKey).then((result=>resolve(["Updated App Configuration",result]))).catch((error=>reject(error)))}))},floDapps.manageAppTrustedIDs=function(adminPrivKey,addList,rmList){return new Promise(((resolve,reject)=>{if(!startUpOptions.app_config)return reject("No configs for this app");if(Array.isArray(addList)&&addList.length||(addList=void 0),Array.isArray(rmList)&&rmList.length||(rmList=void 0),!addList&&!rmList)return reject("No change in list");var floData={[DEFAULT.application]:{addTrustedID:addList,removeTrustedID:rmList}},floID=floCrypto.getFloID(adminPrivKey);floID!=DEFAULT.adminID?reject("Access Denied for Admin privilege"):floBlockchainAPI.writeData(floID,JSON.stringify(floData),adminPrivKey).then((result=>resolve(["Updated App Configuration",result]))).catch((error=>reject(error)))}))};const clearCredentials=floDapps.clearCredentials=function(){return new Promise(((resolve,reject)=>{compactIDB.clearData("credentials",DEFAULT.application).then((result=>{localStorage.removeItem(`${DEFAULT.application}#privKey`),user.clear(),resolve("privKey credentials deleted!")})).catch((error=>reject(error)))}))};floDapps.deleteUserData=function(credentials=!1){return new Promise(((resolve,reject)=>{let p=[];p.push(compactIDB.deleteDB(user.db_name)),credentials&&p.push(clearCredentials()),Promise.all(p).then((result=>resolve("User database(local) deleted"))).catch((error=>reject(error)))}))},floDapps.deleteAppData=function(){return new Promise(((resolve,reject)=>{compactIDB.deleteDB(DEFAULT.application).then((result=>{localStorage.removeItem(`${DEFAULT.application}#privKey`),user.clear(),compactIDB.removeData("lastTx",`${DEFAULT.application}|${DEFAULT.adminID}`,DEFAULT.root).then((result=>resolve("App database(local) deleted"))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},floDapps.securePrivKey=function(pwd){return new Promise((async(resolve,reject)=>{let indexArr=localStorage.getItem(`${DEFAULT.application}#privKey`);if(!indexArr)return reject("PrivKey not found");indexArr=JSON.parse(indexArr);let encryptedKey=Crypto.AES.encrypt(await user.private,pwd),threshold=indexArr.length,shares=floCrypto.createShamirsSecretShares(encryptedKey,threshold,threshold),promises=[];for(var i=0;iresolve("Private Key Secured"))).catch((error=>reject(error)))}))},floDapps.verifyPin=function(pin=null){return new Promise(((resolve,reject)=>{var indexArr=localStorage.getItem(`${DEFAULT.application}#privKey`);console.info(indexArr),indexArr||reject("No login credentials found"),function(indexArr){return new Promise(((resolve,reject)=>{for(var promises=[],i=0;i{var secret=floCrypto.retrieveShamirSecret(shares);console.info(shares,secret),secret?resolve(secret):reject("Shares are insufficient or incorrect")})).catch((error=>{clearCredentials(),location.reload()}))}))}(JSON.parse(indexArr)).then((key=>{if(52==key.length)null===pin?resolve("Private key not secured"):reject("Private key not secured");else{if(null===pin)return reject("PIN/Password required");try{Crypto.AES.decrypt(key,pin);resolve("PIN/Password verified")}catch(error){reject("Incorrect PIN/Password")}}})).catch((error=>reject(error)))}))};const getNextGeneralData=floDapps.getNextGeneralData=function(type,vectorClock=null,options={}){var fk=floCloudAPI.util.filterKey(type,options);vectorClock=vectorClock||getNextGeneralData[fk]||"0";var filteredResult={};if(floGlobals.generalData[fk])for(let d in floGlobals.generalData[fk])d>vectorClock&&(filteredResult[d]=JSON.parse(JSON.stringify(floGlobals.generalData[fk][d])));else if(options.comment){let comment=options.comment;delete options.comment;let fk=floCloudAPI.util.filterKey(type,options);for(let d in floGlobals.generalData[fk])d>vectorClock&&floGlobals.generalData[fk][d].comment==comment&&(filteredResult[d]=JSON.parse(JSON.stringify(floGlobals.generalData[fk][d])))}if(options.decrypt){let decryptionKey=!0===options.decrypt?raw_user.private:options.decrypt;Array.isArray(decryptionKey)||(decryptionKey=[decryptionKey]);for(let f in filteredResult){let data=filteredResult[f];try{if(data.message instanceof Object&&"secret"in data.message)for(let key of decryptionKey)try{let tmp=floCrypto.decryptData(data.message,key);data.message=JSON.parse(tmp);break}catch(error){}}catch(error){}}}return getNextGeneralData[fk]=Object.keys(filteredResult).sort().pop(),filteredResult},syncData=floDapps.syncData={};syncData.oldDevice=()=>new Promise(((resolve,reject)=>{let sync={contacts:user.contacts,pubKeys:user.pubKeys,messages:user.messages},message=Crypto.AES.encrypt(JSON.stringify(sync),raw_user.private),options={receiverID:user.id,application:DEFAULT.root};floCloudAPI.sendApplicationData(message,"syncData",options).then((result=>resolve(result))).catch((error=>reject(error)))})),syncData.newDevice=()=>new Promise(((resolve,reject)=>{var options={receiverID:user.id,senderID:user.id,application:DEFAULT.root,mostRecent:!0};floCloudAPI.requestApplicationData("syncData",options).then((response=>{let vc=Object.keys(response).sort().pop(),sync=JSON.parse(Crypto.AES.decrypt(response[vc].message,raw_user.private)),promises=[];["contacts","pubKeys","messages"].forEach((c=>{for(let i in sync[c])key=i,val=sync[c][i],obs=c,promises.push(compactIDB.writeData(obs,val,key,user.db_name)),user[c][i]=sync[c][i];var key,val,obs})),Promise.all(promises).then((results=>resolve("Sync data successful"))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))}(); \ No newline at end of file diff --git a/floTokenAPI.js b/floTokenAPI.js index 2456b88..7215040 100644 --- a/floTokenAPI.js +++ b/floTokenAPI.js @@ -1,16 +1,33 @@ -(function (EXPORTS) { //floTokenAPI v1.0.4a +(function (EXPORTS) { //floTokenAPI v1.1.0a /* Token Operator to send/receive tokens via blockchain using API calls*/ 'use strict'; const tokenAPI = EXPORTS; const DEFAULT = { - apiURL: floGlobals.tokenURL || "https://ranchimallflo.duckdns.org/", + apiURL: [floGlobals.tokenURL || "https://ranchimallflo.ranchimall.net/"], currency: floGlobals.currency || "rupee" } + + const checkIfTor = tokenAPI.checkIfTor = () => { + return fetch('https://check.torproject.org/api/ip', { + mode: 'no-cors' + }) + .then(response => response.json()) + .then(result => result.IsTor) + .catch(error => false) + } + let isTor = false; + checkIfTor().then(result => { + isTor = result + if (isTor) { + DEFAULT.apiURL.push('http://omwkzk6bd6zuragdqsrhdyzgxzre7yx4vzrou4vzftintzc2dmagp6qd.onion:5017/') + } + }); + Object.defineProperties(tokenAPI, { URL: { - get: () => DEFAULT.apiURL + get: () => DEFAULT.apiURL[0], }, currency: { get: () => DEFAULT.currency, @@ -27,29 +44,38 @@ } }); - const fetch_api = tokenAPI.fetch = function (apicall) { + const fetch_api = tokenAPI.fetch = function (apicall, apiURLs = DEFAULT.apiURL) { return new Promise((resolve, reject) => { - console.debug(DEFAULT.apiURL + apicall); - fetch(DEFAULT.apiURL + apicall).then(response => { + if (apiURLs.length === 0) { + reject("No API URLs available"); + return; + } + const currentURL = apiURLs[0]; + console.debug(currentURL + apicall); + fetch(currentURL + apicall).then(response => { if (response.ok) response.json().then(data => resolve(data)); else - reject(response) - }).catch(error => reject(error)) - }) + reject(response); + }).catch(error => { + console.error(`Failed to fetch from ${currentURL}: ${error}`); + // Try the next API URL recursively + fetch_api(apicall, apiURLs.slice(1)).then(resolve).catch(reject); + }); + }); } const getBalance = tokenAPI.getBalance = function (floID, token = DEFAULT.currency) { return new Promise((resolve, reject) => { - fetch_api(`api/v1.0/getFloAddressBalance?token=${token}&floAddress=${floID}`) - .then(result => resolve(result.balance || 0)) + fetch_api(`api/v2/floAddressInfo/${floID}`) + .then(result => resolve(result.floAddressBalances[token]?.balance || 0)) .catch(error => reject(error)) }) } tokenAPI.getTx = function (txID) { return new Promise((resolve, reject) => { - fetch_api(`api/v1.0/getTransactionDetails/${txID}`).then(res => { + fetch_api(`api/v2/transactionDetails/${txID}`).then(res => { if (res.result === "error") reject(res.description); else if (!res.parsedFloData) @@ -143,7 +169,7 @@ tokenAPI.getAllTxs = function (floID, token = DEFAULT.currency) { return new Promise((resolve, reject) => { - fetch_api(`api/v1.0/getFloAddressTransactions?token=${token}&floAddress=${floID}`) + fetch_api(`api/v2/floAddressTransactions/${floID}${token ? `?token=${token}` : ''}`) .then(result => resolve(result)) .catch(error => reject(error)) }) diff --git a/floTokenAPI.min.js b/floTokenAPI.min.js new file mode 100644 index 0000000..a3226ff --- /dev/null +++ b/floTokenAPI.min.js @@ -0,0 +1 @@ +!function(EXPORTS){"use strict";const tokenAPI="object"===typeof module?module.exports:window.floTokenAPI={},DEFAULT={apiURL:[floGlobals.tokenURL||"https://ranchimallflo.ranchimall.net/"],currency:floGlobals.currency||"rupee"},checkIfTor=tokenAPI.checkIfTor=()=>fetch("https://check.torproject.org/api/ip",{mode:"no-cors"}).then((response=>response.json())).then((result=>result.IsTor)).catch((error=>!1));let isTor=!1;checkIfTor().then((result=>{isTor=result,isTor&&DEFAULT.apiURL.push("http://omwkzk6bd6zuragdqsrhdyzgxzre7yx4vzrou4vzftintzc2dmagp6qd.onion:5017/")})),Object.defineProperties(tokenAPI,{URL:{get:()=>DEFAULT.apiURL[0]},currency:{get:()=>DEFAULT.currency,set:currency=>DEFAULT.currency=currency}}),floGlobals.currency&&(tokenAPI.currency=floGlobals.currency),Object.defineProperties(floGlobals,{currency:{get:()=>DEFAULT.currency,set:currency=>DEFAULT.currency=currency}});const fetch_api=tokenAPI.fetch=function(apicall,apiURLs=DEFAULT.apiURL){return new Promise(((resolve,reject)=>{if(0===apiURLs.length)return void reject("No API URLs available");const currentURL=apiURLs[0];console.debug(currentURL+apicall),fetch(currentURL+apicall).then((response=>{response.ok?response.json().then((data=>resolve(data))):reject(response)})).catch((error=>{console.error(`Failed to fetch from ${currentURL}: ${error}`),fetch_api(apicall,apiURLs.slice(1)).then(resolve).catch(reject)}))}))},getBalance=tokenAPI.getBalance=function(floID,token=DEFAULT.currency){return new Promise(((resolve,reject)=>{fetch_api(`api/v2/floAddressInfo/${floID}`).then((result=>resolve(result.floAddressBalances[token]?.balance||0))).catch((error=>reject(error)))}))};function sendTokens_raw(privKey,receiverID,token,amount,utxo,vout,scriptPubKey){return new Promise(((resolve,reject)=>{var trx=bitjs.transaction();trx.addinput(utxo,vout,scriptPubKey),trx.addoutput(receiverID,floBlockchainAPI.sendAmt),trx.addflodata(`send ${amount} ${token}#`);var signedTxHash=trx.sign(privKey,1);floBlockchainAPI.broadcastTx(signedTxHash).then((txid=>resolve([receiverID,txid]))).catch((error=>reject([receiverID,error])))}))}tokenAPI.getTx=function(txID){return new Promise(((resolve,reject)=>{fetch_api(`api/v2/transactionDetails/${txID}`).then((res=>{"error"===res.result?reject(res.description):res.parsedFloData?res.transactionDetails?resolve(res):reject("Data piece (transactionDetails) missing"):reject("Data piece (parsedFloData) missing")})).catch((error=>reject(error)))}))},tokenAPI.sendToken=function(privKey,amount,receiverID,message="",token=DEFAULT.currency,options={}){return new Promise(((resolve,reject)=>{let senderID=floCrypto.getFloID(privKey);if("number"!=typeof amount||isNaN(amount)||amount<=0)return reject("Invalid amount");getBalance(senderID,token).then((bal=>{if(amount>bal)return reject(`Insufficient ${token}# balance`);floBlockchainAPI.writeData(senderID,`send ${amount} ${token}# ${message}`,privKey,receiverID,options).then((txid=>resolve(txid))).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},tokenAPI.bulkTransferTokens=function(sender,privKey,token,receivers){return new Promise(((resolve,reject)=>{if("object"!=typeof receivers)return reject("receivers must be object in format {receiver1: amount1, receiver2:amount2...}");let receiver_list=Object.keys(receivers),amount_list=Object.values(receivers),invalidReceivers=receiver_list.filter((id=>!floCrypto.validateFloID(id))),invalidAmount=amount_list.filter((val=>"number"!=typeof val||val<=0));if(invalidReceivers.length)return reject(`Invalid receivers: ${invalidReceivers}`);if(invalidAmount.length)return reject(`Invalid amounts: ${invalidAmount}`);if(0==receiver_list.length)return reject("Receivers cannot be empty");if(1==receiver_list.length){let receiver=receiver_list[0],amount=amount_list[0];floTokenAPI.sendToken(privKey,amount,receiver,"",token).then((txid=>resolve({success:{[receiver]:txid}}))).catch((error=>reject(error)))}else floTokenAPI.getBalance(sender,token).then((token_balance=>{if(amount_list.reduce(((a,e)=>a+e),0)>token_balance)return reject(`Insufficient ${token}# balance`);floBlockchainAPI.splitUTXOs(sender,privKey,receiver_list.length).then((split_txid=>{floBlockchainAPI.waitForConfirmation(split_txid).then((split_tx=>{var scriptPubKey=split_tx.vout[0].scriptPubKey.hex;let promises=[];for(let i in receiver_list)promises.push(sendTokens_raw(privKey,receiver_list[i],token,amount_list[i],split_txid,i,scriptPubKey));Promise.allSettled(promises).then((results=>{let success=Object.fromEntries(results.filter((r=>"fulfilled"==r.status)).map((r=>r.value))),failed=Object.fromEntries(results.filter((r=>"rejected"==r.status)).map((r=>r.reason)));resolve({success:success,failed:failed})}))})).catch((error=>reject(error)))})).catch((error=>reject(error)))})).catch((error=>reject(error)))}))},tokenAPI.getAllTxs=function(floID,token=DEFAULT.currency){return new Promise(((resolve,reject)=>{fetch_api(`api/v2/floAddressTransactions/${floID}${token?`?token=${token}`:""}`).then((result=>resolve(result))).catch((error=>reject(error)))}))};(tokenAPI.util={}).parseTxData=function(txData){let parsedData={};for(let p in txData.parsedFloData)parsedData[p]=txData.parsedFloData[p];parsedData.sender=txData.transactionDetails.vin[0].addr;for(let vout of txData.transactionDetails.vout)vout.scriptPubKey.addresses[0]!==parsedData.sender&&(parsedData.receiver=vout.scriptPubKey.addresses[0]);return parsedData.time=txData.transactionDetails.time,parsedData}}(); \ No newline at end of file diff --git a/lib.min.js b/lib.min.js new file mode 100644 index 0000000..29687b1 --- /dev/null +++ b/lib.min.js @@ -0,0 +1,57 @@ +!function(GLOBAL){"use strict";GLOBAL.cryptocoin=("undefined"==typeof floGlobals?null:floGlobals.blockchain)||"FLO";const getRandomBytes=function(){if("function"==typeof require){const crypto=require("crypto");return function(buf){var bytes=crypto.randomBytes(buf.length);return buf.set(bytes),buf}}if(GLOBAL.crypto&&GLOBAL.crypto.getRandomValues)return function(buf){return GLOBAL.crypto.getRandomValues(buf)};throw Error("Unable to define getRandomBytes")}();var C,util,charenc,UTF8,Binary,workerUrl,ec,ellipticEncryption,coinjs;GLOBAL.securedMathRandom=function(){if("function"==typeof require){const crypto=require("crypto");return function(){return crypto.randomBytes(4).readUInt32LE()/4294967295}}if(GLOBAL.crypto&&GLOBAL.crypto.getRandomValues)return function(){return GLOBAL.crypto.getRandomValues(new Uint32Array(1))[0]/4294967295};throw Error("Unable to define securedMathRandom")}(),function(){var base64map,util,charenc,Binary,d,k,g,b,a,c,e,Crypto=GLOBAL.Crypto={}; +/*! + * Crypto-JS v2.5.4 Crypto.js + * http://code.google.com/p/crypto-js/ + * Copyright (c) 2009-2013, Jeff Mott. All rights reserved. + * http://code.google.com/p/crypto-js/wiki/License + */base64map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",util=Crypto.util={rotl:function(n,b){return n<>>32-b},rotr:function(n,b){return n<<32-b|n>>>b},endian:function(n){if(n.constructor==Number)return 16711935&util.rotl(n,8)|4278255360&util.rotl(n,24);for(var i=0;i0;n--)bytes.push(Math.floor(256*securedMathRandom()));return bytes},bytesToWords:function(bytes){for(var words=[],i=0,b=0;i>>5]|=(255&bytes[i])<<24-b%32;return words},wordsToBytes:function(words){for(var bytes=[],b=0;b<32*words.length;b+=8)bytes.push(words[b>>>5]>>>24-b%32&255);return bytes},bytesToHex:function(bytes){for(var hex=[],i=0;i>>4).toString(16)),hex.push((15&bytes[i]).toString(16));return hex.join("")},hexToBytes:function(hex){for(var bytes=[],c=0;c>>6*(3-j)&63)):base64.push("=");return base64.join("")},base64ToBytes:function(base64){base64=base64.replace(/[^A-Z0-9+\/]/gi,"");for(var bytes=[],i=0,imod4=0;i>>6-2*imod4);return bytes}},(charenc=Crypto.charenc={}).UTF8={stringToBytes:function(str){return Binary.stringToBytes(unescape(encodeURIComponent(str)))},bytesToString:function(bytes){return decodeURIComponent(escape(Binary.bytesToString(bytes)))}},Binary=charenc.Binary={stringToBytes:function(str){for(var bytes=[],i=0;i>5]|=128<<24-l%32,m[15+(l+64>>>9<<4)]=l;for(var i=0;i>>31}var t=(H0<<5|H0>>>27)+H4+(w[j]>>>0)+(j<20?1518500249+(H1&H2|~H1&H3):j<40?1859775393+(H1^H2^H3):j<60?(H1&H2|H1&H3|H2&H3)-1894007588:(H1^H2^H3)-899497514);H4=H3,H3=H2,H2=H1<<30|H1>>>2,H1=H0,H0=t}H0+=a,H1+=b,H2+=c,H3+=d,H4+=e}return[H0,H1,H2,H3,H4]},SHA1._blocksize=16,SHA1._digestsize=20}(),function(){var C=Crypto,util=C.util,charenc=C.charenc,UTF8=charenc.UTF8,Binary=charenc.Binary;C.HMAC=function(hasher,message,key,options){message.constructor==String&&(message=UTF8.stringToBytes(message)),key.constructor==String&&(key=UTF8.stringToBytes(key)),key.length>4*hasher._blocksize&&(key=hasher(key,{asBytes:!0}));for(var okey=key.slice(0),ikey=key.slice(0),i=0;i<4*hasher._blocksize;i++)okey[i]^=92,ikey[i]^=54;var hmacbytes=hasher(okey.concat(hasher(ikey.concat(message),{asBytes:!0})),{asBytes:!0});return options&&options.asBytes?hmacbytes:options&&options.asString?Binary.bytesToString(hmacbytes):util.bytesToHex(hmacbytes)}}(),k=(d=Crypto).util,g=d.charenc,b=g.UTF8,a=g.Binary,c=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298],e=d.SHA256=function(b,c){var f=k.wordsToBytes(e._sha256(b));return c&&c.asBytes?f:c&&c.asString?a.bytesToString(f):k.bytesToHex(f)},e._sha256=function(a){a.constructor==String&&(a=b.stringToBytes(a));var g,m,r,i,n,o,s,t,h,l,j,e=k.bytesToWords(a),f=8*a.length,d=(a=[1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225],[]);for(e[f>>5]|=128<<24-f%32,e[15+(f+64>>9<<4)]=f,t=0;t>>7)^(l<<14|l>>>18)^l>>>3)+(d[h-7]>>>0)+((j<<15|j>>>17)^(j<<13|j>>>19)^j>>>10)+(d[h-16]>>>0)),j=f&g^f&m^g&m;var u=(f<<30|f>>>2)^(f<<19|f>>>13)^(f<<10|f>>>22);l=(s>>>0)+((i<<26|i>>>6)^(i<<21|i>>>11)^(i<<7|i>>>25))+(i&n^~i&o)+c[h]+(d[h]>>>0),s=o,o=n,n=i,i=r+l>>>0,r=m,m=g,g=f,f=l+(j=u+j)>>>0}a[0]+=f,a[1]+=g,a[2]+=m,a[3]+=r,a[4]+=i,a[5]+=n,a[6]+=o,a[7]+=s}return a},e._blocksize=16,e._digestsize=32,function(){var d=Crypto,k=d.util,g=d.charenc,b=g.UTF8,a=g.Binary;d.HMAC=function(c,e,d,g){e.constructor==String&&(e=b.stringToBytes(e)),d.constructor==String&&(d=b.stringToBytes(d)),d.length>4*c._blocksize&&(d=c(d,{asBytes:!0}));for(var f=d.slice(0),q=(d=d.slice(0),0);q<4*c._blocksize;q++)f[q]^=92,d[q]^=54;return c=c(f.concat(c(d.concat(e),{asBytes:!0})),{asBytes:!0}),g&&g.asBytes?c:g&&g.asString?a.bytesToString(c):k.bytesToHex(c)}}()}(),function(){ +/*! + * Random number generator with ArcFour PRNG + * + * NOTE: For best results, put code like + * + * in your main HTML document. + * + * Copyright Tom Wu, bitaddress.org BSD License. + * http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE + */ +var sr=GLOBAL.SecureRandom=function(){};if(sr.state,sr.pool,sr.pptr,sr.poolCopyOnInit,sr.poolSize=256,sr.prototype.nextBytes=function(ba){var i;if(getRandomBytes&&GLOBAL.Uint8Array)try{var rvBytes=new Uint8Array(ba.length);for(getRandomBytes(rvBytes),i=0;i>8),sr.seedInt8(x>>16),sr.seedInt8(x>>24)},sr.seedInt16=function(x){sr.seedInt8(x),sr.seedInt8(x>>8)},sr.seedInt8=function(x){sr.pool[sr.pptr++]^=255&x,sr.pptr>=sr.poolSize&&(sr.pptr-=sr.poolSize)},sr.ArcFour=function(){function Arcfour(){this.i=0,this.j=0,this.S=new Array}return Arcfour.prototype.init=function(key){var i,j,t;for(i=0;i<256;++i)this.S[i]=i;for(j=0,i=0;i<256;++i)j=j+this.S[i]+key[i%key.length]&255,t=this.S[i],this.S[i]=this.S[j],this.S[j]=t;this.i=0,this.j=0},Arcfour.prototype.next=function(){var t;return this.i=this.i+1&255,this.j=this.j+this.S[this.i]&255,t=this.S[this.i],this.S[this.i]=this.S[this.j],this.S[this.j]=t,this.S[t+this.S[this.i]&255]},new Arcfour},null==sr.pool){var t;if(sr.pool=new Array,sr.pptr=0,getRandomBytes&&GLOBAL.Uint8Array)try{var ua=new Uint8Array(sr.poolSize);for(getRandomBytes(ua),t=0;t>>8,sr.pool[sr.pptr++]=255&t;sr.pptr=Math.floor(sr.poolSize*securedMathRandom()),sr.seedTime();var entropyStr="";entropyStr+=GLOBAL.screen.height*GLOBAL.screen.width*GLOBAL.screen.colorDepth,entropyStr+=GLOBAL.screen.availHeight*GLOBAL.screen.availWidth*GLOBAL.screen.pixelDepth,entropyStr+=(new Date).getTimezoneOffset(),entropyStr+=navigator.userAgent;for(var pluginsStr="",i=0;i>>24)|4278255360&(M_offset_i<<24|M_offset_i>>>8)}var al,bl,cl,dl,el,ar,br,cr,dr,er,t;ar=al=H[0],br=bl=H[1],cr=cl=H[2],dr=dl=H[3],er=el=H[4];for(i=0;i<80;i+=1)t=al+M[offset+zl[i]]|0,t+=i<16?f1(bl,cl,dl)+hl[0]:i<32?f2(bl,cl,dl)+hl[1]:i<48?f3(bl,cl,dl)+hl[2]:i<64?f4(bl,cl,dl)+hl[3]:f5(bl,cl,dl)+hl[4],t=(t=rotl(t|=0,sl[i]))+el|0,al=el,el=dl,dl=rotl(cl,10),cl=bl,bl=t,t=ar+M[offset+zr[i]]|0,t+=i<16?f5(br,cr,dr)+hr[0]:i<32?f4(br,cr,dr)+hr[1]:i<48?f3(br,cr,dr)+hr[2]:i<64?f2(br,cr,dr)+hr[3]:f1(br,cr,dr)+hr[4],t=(t=rotl(t|=0,sr[i]))+er|0,ar=er,er=dr,dr=rotl(cr,10),cr=br,br=t;t=H[1]+cl+dr|0,H[1]=H[2]+dl+er|0,H[2]=H[3]+el+ar|0,H[3]=H[4]+al+br|0,H[4]=H[0]+bl+cr|0,H[0]=t};function f1(x,y,z){return x^y^z}function f2(x,y,z){return x&y|~x&z}function f3(x,y,z){return(x|~y)^z}function f4(x,y,z){return x&z|y&~z}function f5(x,y,z){return x^(y|~z)}function rotl(x,n){return x<>>32-n}GLOBAL.ripemd160=function(message){var H=[1732584193,4023233417,2562383102,271733878,3285377520],m=function(bytes){for(var words=[],i=0,b=0;i>>5]|=bytes[i]<<24-b%32;return words}(message),nBitsLeft=8*message.length,nBitsTotal=8*message.length;m[nBitsLeft>>>5]|=128<<24-nBitsLeft%32,m[14+(nBitsLeft+64>>>9<<4)]=16711935&(nBitsTotal<<8|nBitsTotal>>>24)|4278255360&(nBitsTotal<<24|nBitsTotal>>>8);for(var i=0;i>>24)|4278255360&(H_i<<24|H_i>>>8)}return function(words){for(var bytes=[],b=0;b<32*words.length;b+=8)bytes.push(words[b>>>5]>>>24-b%32&255);return bytes}(H)}}(),function(){ +/*! + * Basic JavaScript BN library - subset useful for RSA encryption. v1.4 + * + * Copyright (c) 2005 Tom Wu + * All Rights Reserved. + * BSD License + * http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE + * + * Copyright Stephan Thomas + * Copyright pointbiz + */ +var dbits,BigInteger=GLOBAL.BigInteger=function BigInteger(a,b,c){if(!(this instanceof BigInteger))return new BigInteger(a,b,c);null!=a&&("number"==typeof a?this.fromNumber(a,b,c):null==b&&"string"!=typeof a?this.fromString(a,256):this.fromString(a,b))};function nbi(){return new BigInteger(null)}"Microsoft Internet Explorer"==navigator.appName?(BigInteger.prototype.am=function(i,x,w,j,c,n){for(var xl=32767&x,xh=x>>15;--n>=0;){var l=32767&this[i],h=this[i++]>>15,m=xh*l+h*xl;c=((l=xl*l+((32767&m)<<15)+w[j]+(1073741823&c))>>>30)+(m>>>15)+xh*h+(c>>>30),w[j++]=1073741823&l}return c},dbits=30):"Netscape"!=navigator.appName?(BigInteger.prototype.am=function(i,x,w,j,c,n){for(;--n>=0;){var v=x*this[i++]+w[j]+c;c=Math.floor(v/67108864),w[j++]=67108863&v}return c},dbits=26):(BigInteger.prototype.am=function(i,x,w,j,c,n){for(var xl=16383&x,xh=x>>14;--n>=0;){var l=16383&this[i],h=this[i++]>>14,m=xh*l+h*xl;c=((l=xl*l+((16383&m)<<14)+w[j]+c)>>28)+(m>>14)+xh*h,w[j++]=268435455&l}return c},dbits=28),BigInteger.prototype.DB=dbits,BigInteger.prototype.DM=(1<>>16)&&(x=t,r+=16),0!=(t=x>>8)&&(x=t,r+=8),0!=(t=x>>4)&&(x=t,r+=4),0!=(t=x>>2)&&(x=t,r+=2),0!=(t=x>>1)&&(x=t,r+=1),r}function lbit(x){if(0==x)return-1;var r=0;return 0==(65535&x)&&(x>>=16,r+=16),0==(255&x)&&(x>>=8,r+=8),0==(15&x)&&(x>>=4,r+=4),0==(3&x)&&(x>>=2,r+=2),0==(1&x)&&++r,r}function cbit(x){for(var r=0;0!=x;)x&=x-1,++r;return r}BigInteger.prototype.copyTo=function(r){for(var i=this.t-1;i>=0;--i)r[i]=this[i];r.t=this.t,r.s=this.s},BigInteger.prototype.fromInt=function(x){this.t=1,this.s=x<0?-1:0,x>0?this[0]=x:x<-1?this[0]=x+this.DV:this.t=0},BigInteger.prototype.fromString=function(s,b){var k;if(16==b)k=4;else if(8==b)k=3;else if(256==b)k=8;else if(2==b)k=1;else if(32==b)k=5;else{if(4!=b)return void this.fromRadix(s,b);k=2}this.t=0,this.s=0;for(var i=s.length,mi=!1,sh=0;--i>=0;){var x=8==k?255&s[i]:intAt(s,i);x<0?"-"==s.charAt(i)&&(mi=!0):(mi=!1,0==sh?this[this.t++]=x:sh+k>this.DB?(this[this.t-1]|=(x&(1<>this.DB-sh):this[this.t-1]|=x<=this.DB&&(sh-=this.DB))}8==k&&0!=(128&s[0])&&(this.s=-1,sh>0&&(this[this.t-1]|=(1<0&&this[this.t-1]==c;)--this.t},BigInteger.prototype.dlShiftTo=function(n,r){var i;for(i=this.t-1;i>=0;--i)r[i+n]=this[i];for(i=n-1;i>=0;--i)r[i]=0;r.t=this.t+n,r.s=this.s},BigInteger.prototype.drShiftTo=function(n,r){for(var i=n;i=0;--i)r[i+ds+1]=this[i]>>cbs|c,c=(this[i]&bm)<=0;--i)r[i]=0;r[ds]=c,r.t=this.t+ds+1,r.s=this.s,r.clamp()},BigInteger.prototype.rShiftTo=function(n,r){r.s=this.s;var ds=Math.floor(n/this.DB);if(ds>=this.t)r.t=0;else{var bs=n%this.DB,cbs=this.DB-bs,bm=(1<>bs;for(var i=ds+1;i>bs;bs>0&&(r[this.t-ds-1]|=(this.s&bm)<>=this.DB;if(a.t>=this.DB;c+=this.s}else{for(c+=this.s;i>=this.DB;c-=a.s}r.s=c<0?-1:0,c<-1?r[i++]=this.DV+c:c>0&&(r[i++]=c),r.t=i,r.clamp()},BigInteger.prototype.multiplyTo=function(a,r){var x=this.abs(),y=a.abs(),i=x.t;for(r.t=i+y.t;--i>=0;)r[i]=0;for(i=0;i=0;)r[i]=0;for(i=0;i=x.DV&&(r[i+x.t]-=x.DV,r[i+x.t+1]=1)}r.t>0&&(r[r.t-1]+=x.am(i,x[i],r,2*i,0,1)),r.s=0,r.clamp()},BigInteger.prototype.divRemTo=function(m,q,r){var pm=m.abs();if(!(pm.t<=0)){var pt=this.abs();if(pt.t0?(pm.lShiftTo(nsh,y),pt.lShiftTo(nsh,r)):(pm.copyTo(y),pt.copyTo(r));var ys=y.t,y0=y[ys-1];if(0!=y0){var yt=y0*(1<1?y[ys-2]>>this.F2:0),d1=this.FV/yt,d2=(1<=0&&(r[r.t++]=1,r.subTo(t,r)),BigInteger.ONE.dlShiftTo(ys,t),t.subTo(y,y);y.t=0;){var qd=r[--i]==y0?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);if((r[i]+=y.am(0,qd,r,j,0,ys))0&&r.rShiftTo(nsh,r),ts<0&&BigInteger.ZERO.subTo(r,r)}}},BigInteger.prototype.invDigit=function(){if(this.t<1)return 0;var x=this[0];if(0==(1&x))return 0;var y=3&x;return(y=(y=(y=(y=y*(2-(15&x)*y)&15)*(2-(255&x)*y)&255)*(2-((65535&x)*y&65535))&65535)*(2-x*y%this.DV)%this.DV)>0?this.DV-y:-y},BigInteger.prototype.isEven=function(){return 0==(this.t>0?1&this[0]:this.s)},BigInteger.prototype.exp=function(e,z){if(e>4294967295||e<1)return BigInteger.ONE;var r=nbi(),r2=nbi(),g=z.convert(this),i=nbits(e)-1;for(g.copyTo(r);--i>=0;)if(z.sqrTo(r,r2),(e&1<0)z.mulTo(r2,g,r);else{var t=r;r=r2,r2=t}return z.revert(r)},BigInteger.prototype.toString=function(b){if(this.s<0)return"-"+this.negate().toString(b);var k;if(16==b)k=4;else if(8==b)k=3;else if(2==b)k=1;else if(32==b)k=5;else{if(4!=b)return this.toRadix(b);k=2}var d,km=(1<0)for(p>p)>0&&(m=!0,r=int2char(d));i>=0;)p>(p+=this.DB-k)):(d=this[i]>>(p-=k)&km,p<=0&&(p+=this.DB,--i)),d>0&&(m=!0),m&&(r+=int2char(d));return m?r:"0"},BigInteger.prototype.negate=function(){var r=nbi();return BigInteger.ZERO.subTo(this,r),r},BigInteger.prototype.abs=function(){return this.s<0?this.negate():this},BigInteger.prototype.compareTo=function(a){var r=this.s-a.s;if(0!=r)return r;var i=this.t;if(0!=(r=i-a.t))return this.s<0?-r:r;for(;--i>=0;)if(0!=(r=this[i]-a[i]))return r;return 0},BigInteger.prototype.bitLength=function(){return this.t<=0?0:this.DB*(this.t-1)+nbits(this[this.t-1]^this.s&this.DM)},BigInteger.prototype.mod=function(a){var r=nbi();return this.abs().divRemTo(a,null,r),this.s<0&&r.compareTo(BigInteger.ZERO)>0&&a.subTo(r,r),r},BigInteger.prototype.modPowInt=function(e,m){var z;return z=e<256||m.isEven()?new Classic(m):new Montgomery(m),this.exp(e,z)},BigInteger.ZERO=nbv(0),BigInteger.ONE=nbv(1);var lowprimes=[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997],lplim=(1<<26)/lowprimes[lowprimes.length-1];function op_and(x,y){return x&y}function op_or(x,y){return x|y}function op_xor(x,y){return x^y}function op_andnot(x,y){return x&~y}BigInteger.prototype.chunkSize=function(r){return Math.floor(Math.LN2*this.DB/Math.log(r))},BigInteger.prototype.toRadix=function(b){if(null==b&&(b=10),0==this.signum()||b<2||b>36)return"0";var cs=this.chunkSize(b),a=Math.pow(b,cs),d=nbv(a),y=nbi(),z=nbi(),r="";for(this.divRemTo(d,y,z);y.signum()>0;)r=(a+z.intValue()).toString(b).substr(1)+r,y.divRemTo(d,y,z);return z.intValue().toString(b)+r},BigInteger.prototype.fromRadix=function(s,b){this.fromInt(0),null==b&&(b=10);for(var cs=this.chunkSize(b),d=Math.pow(b,cs),mi=!1,j=0,w=0,i=0;i=cs&&(this.dMultiply(d),this.dAddOffset(w,0),j=0,w=0))}j>0&&(this.dMultiply(Math.pow(b,j)),this.dAddOffset(w,0)),mi&&BigInteger.ZERO.subTo(this,this)},BigInteger.prototype.fromNumber=function(a,b,c){if("number"==typeof b)if(a<2)this.fromInt(1);else for(this.fromNumber(a,c),this.testBit(a-1)||this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this),this.isEven()&&this.dAddOffset(1,0);!this.isProbablePrime(b);)this.dAddOffset(2,0),this.bitLength()>a&&this.subTo(BigInteger.ONE.shiftLeft(a-1),this);else{var x=new Array,t=7&a;x.length=1+(a>>3),b.nextBytes(x),t>0?x[0]&=(1<>=this.DB;if(a.t>=this.DB;c+=this.s}else{for(c+=this.s;i>=this.DB;c+=a.s}r.s=c<0?-1:0,c>0?r[i++]=c:c<-1&&(r[i++]=this.DV+c),r.t=i,r.clamp()},BigInteger.prototype.dMultiply=function(n){this[this.t]=this.am(0,n-1,this,0,0,this.t),++this.t,this.clamp()},BigInteger.prototype.dAddOffset=function(n,w){if(0!=n){for(;this.t<=w;)this[this.t++]=0;for(this[w]+=n;this[w]>=this.DV;)this[w]-=this.DV,++w>=this.t&&(this[this.t++]=0),++this[w]}},BigInteger.prototype.multiplyLowerTo=function(a,n,r){var j,i=Math.min(this.t+a.t,n);for(r.s=0,r.t=i;i>0;)r[--i]=0;for(j=r.t-this.t;i=0;)r[i]=0;for(i=Math.max(n-this.t,0);i0)if(0==d)r=this[0]%n;else for(var i=this.t-1;i>=0;--i)r=(d*r+this[i])%n;return r},BigInteger.prototype.millerRabin=function(t){var n1=this.subtract(BigInteger.ONE),k=n1.getLowestSetBit();if(k<=0)return!1;var r=n1.shiftRight(k);(t=t+1>>1)>lowprimes.length&&(t=lowprimes.length);for(var a=nbi(),i=0;i>24},BigInteger.prototype.shortValue=function(){return 0==this.t?this.s:this[0]<<16>>16},BigInteger.prototype.signum=function(){return this.s<0?-1:this.t<=0||1==this.t&&this[0]<=0?0:1},BigInteger.prototype.toByteArray=function(){var i=this.t,r=new Array;r[0]=this.s;var d,p=this.DB-i*this.DB%8,k=0;if(i-- >0)for(p>p)!=(this.s&this.DM)>>p&&(r[k++]=d|this.s<=0;)p<8?(d=(this[i]&(1<>(p+=this.DB-8)):(d=this[i]>>(p-=8)&255,p<=0&&(p+=this.DB,--i)),0!=(128&d)&&(d|=-256),0==k&&(128&this.s)!=(128&d)&&++k,(k>0||d!=this.s)&&(r[k++]=d);return r},BigInteger.prototype.equals=function(a){return 0==this.compareTo(a)},BigInteger.prototype.min=function(a){return this.compareTo(a)<0?this:a},BigInteger.prototype.max=function(a){return this.compareTo(a)>0?this:a},BigInteger.prototype.and=function(a){var r=nbi();return this.bitwiseTo(a,op_and,r),r},BigInteger.prototype.or=function(a){var r=nbi();return this.bitwiseTo(a,op_or,r),r},BigInteger.prototype.xor=function(a){var r=nbi();return this.bitwiseTo(a,op_xor,r),r},BigInteger.prototype.andNot=function(a){var r=nbi();return this.bitwiseTo(a,op_andnot,r),r},BigInteger.prototype.not=function(){for(var r=nbi(),i=0;i=this.t?0!=this.s:0!=(this[j]&1<1){var g2=nbi();for(z.sqrTo(g[1],g2);n<=km;)g[n]=nbi(),z.mulTo(g2,g[n-2],g[n]),n+=2}var w,t,j=e.t-1,is1=!0,r2=nbi();for(i=nbits(e[j])-1;j>=0;){for(i>=k1?w=e[j]>>i-k1&km:(w=(e[j]&(1<0&&(w|=e[j-1]>>this.DB+i-k1)),n=k;0==(1&w);)w>>=1,--n;if((i-=n)<0&&(i+=this.DB,--j),is1)g[w].copyTo(r),is1=!1;else{for(;n>1;)z.sqrTo(r,r2),z.sqrTo(r2,r),n-=2;n>0?z.sqrTo(r,r2):(t=r,r=r2,r2=t),z.mulTo(r2,g[w],r)}for(;j>=0&&0==(e[j]&1<=0?(u.subTo(v,u),ac&&a.subTo(c,a),b.subTo(d,b)):(v.subTo(u,v),ac&&c.subTo(a,c),d.subTo(b,d))}if(0!=v.compareTo(BigInteger.ONE))return BigInteger.ZERO;for(;d.compareTo(m)>=0;)d.subTo(m,d);for(;d.signum()<0;)d.addTo(m,d);return d},BigInteger.prototype.pow=function(e){return this.exp(e,new NullExp)},BigInteger.prototype.gcd=function(a){var x=this.s<0?this.negate():this.clone(),y=a.s<0?a.negate():a.clone();if(x.compareTo(y)<0){var t=x;x=y,y=t}var i=x.getLowestSetBit(),g=y.getLowestSetBit();if(g<0)return x;for(i0&&(x.rShiftTo(g,x),y.rShiftTo(g,y));x.signum()>0;)(i=x.getLowestSetBit())>0&&x.rShiftTo(i,x),(i=y.getLowestSetBit())>0&&y.rShiftTo(i,y),x.compareTo(y)>=0?(x.subTo(y,x),x.rShiftTo(1,x)):(y.subTo(x,y),y.rShiftTo(1,y));return g>0&&y.lShiftTo(g,y),y},BigInteger.prototype.isProbablePrime=function(t){var i,x=this.abs();if(1==x.t&&x[0]<=lowprimes[lowprimes.length-1]){for(i=0;i=0?x.mod(this.m):x},Classic.prototype.revert=function(x){return x},Classic.prototype.reduce=function(x){x.divRemTo(this.m,null,x)},Classic.prototype.mulTo=function(x,y,r){x.multiplyTo(y,r),this.reduce(r)},Classic.prototype.sqrTo=function(x,r){x.squareTo(r),this.reduce(r)};var Montgomery=GLOBAL.Montgomery=function(m){this.m=m,this.mp=m.invDigit(),this.mpl=32767&this.mp,this.mph=this.mp>>15,this.um=(1<0&&this.m.subTo(r,r),r},Montgomery.prototype.revert=function(x){var r=nbi();return x.copyTo(r),this.reduce(r),r},Montgomery.prototype.reduce=function(x){for(;x.t<=this.mt2;)x[x.t++]=0;for(var i=0;i>15)*this.mpl&this.um)<<15)&x.DM;for(x[j=i+this.m.t]+=this.m.am(0,u0,x,i,0,this.m.t);x[j]>=x.DV;)x[j]-=x.DV,x[++j]++}x.clamp(),x.drShiftTo(this.m.t,x),x.compareTo(this.m)>=0&&x.subTo(this.m,x)},Montgomery.prototype.mulTo=function(x,y,r){x.multiplyTo(y,r),this.reduce(r)},Montgomery.prototype.sqrTo=function(x,r){x.squareTo(r),this.reduce(r)};var NullExp=GLOBAL.NullExp=function(){};NullExp.prototype.convert=function(x){return x},NullExp.prototype.revert=function(x){return x},NullExp.prototype.mulTo=function(x,y,r){x.multiplyTo(y,r)},NullExp.prototype.sqrTo=function(x,r){x.squareTo(r)};var Barrett=GLOBAL.Barrett=function(m){this.r2=nbi(),this.q3=nbi(),BigInteger.ONE.dlShiftTo(2*m.t,this.r2),this.mu=this.r2.divide(m),this.m=m};Barrett.prototype.convert=function(x){if(x.s<0||x.t>2*this.m.t)return x.mod(this.m);if(x.compareTo(this.m)<0)return x;var r=nbi();return x.copyTo(r),this.reduce(r),r},Barrett.prototype.revert=function(x){return x},Barrett.prototype.reduce=function(x){for(x.drShiftTo(this.m.t-1,this.r2),x.t>this.m.t+1&&(x.t=this.m.t+1,x.clamp()),this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3),this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);x.compareTo(this.r2)<0;)x.dAddOffset(1,this.m.t+1);for(x.subTo(this.r2,x);x.compareTo(this.m)>=0;)x.subTo(this.m,x)},Barrett.prototype.mulTo=function(x,y,r){x.multiplyTo(y,r),this.reduce(r)},Barrett.prototype.sqrTo=function(x,r){x.squareTo(r),this.reduce(r)}}(),(ec=GLOBAL.EllipticCurve=function(){}).FieldElementFp=function(q,x){this.x=x,this.q=q},ec.FieldElementFp.prototype.equals=function(other){return other==this||this.q.equals(other.q)&&this.x.equals(other.x)},ec.FieldElementFp.prototype.toBigInteger=function(){return this.x},ec.FieldElementFp.prototype.negate=function(){return new ec.FieldElementFp(this.q,this.x.negate().mod(this.q))},ec.FieldElementFp.prototype.add=function(b){return new ec.FieldElementFp(this.q,this.x.add(b.toBigInteger()).mod(this.q))},ec.FieldElementFp.prototype.subtract=function(b){return new ec.FieldElementFp(this.q,this.x.subtract(b.toBigInteger()).mod(this.q))},ec.FieldElementFp.prototype.multiply=function(b){return new ec.FieldElementFp(this.q,this.x.multiply(b.toBigInteger()).mod(this.q))},ec.FieldElementFp.prototype.square=function(){return new ec.FieldElementFp(this.q,this.x.square().mod(this.q))},ec.FieldElementFp.prototype.divide=function(b){return new ec.FieldElementFp(this.q,this.x.multiply(b.toBigInteger().modInverse(this.q)).mod(this.q))},ec.FieldElementFp.prototype.getByteLength=function(){return Math.floor((this.toBigInteger().bitLength()+7)/8)},ec.FieldElementFp.prototype.sqrt=function(){if(!this.q.testBit(0))throw new Error("even value of q");if(this.q.testBit(1)){var z=new ec.FieldElementFp(this.q,this.x.modPow(this.q.shiftRight(2).add(BigInteger.ONE),this.q));return z.square().equals(this)?z:null}var qMinusOne=this.q.subtract(BigInteger.ONE),legendreExponent=qMinusOne.shiftRight(1);if(!this.x.modPow(legendreExponent,this.q).equals(BigInteger.ONE))return null;var U,V,k=qMinusOne.shiftRight(2).shiftLeft(1).add(BigInteger.ONE),Q=this.x,fourQ=Q.shiftLeft(2).mod(this.q);do{var P,rand=new SecureRandom;do{P=new BigInteger(this.q.bitLength(),rand)}while(P.compareTo(this.q)>=0||!P.multiply(P).subtract(fourQ).modPow(legendreExponent,this.q).equals(qMinusOne));var result=ec.FieldElementFp.fastLucasSequence(this.q,P,Q,k);if(U=result[0],(V=result[1]).multiply(V).mod(this.q).equals(fourQ))return V.testBit(0)&&(V=V.add(this.q)),V=V.shiftRight(1),new ec.FieldElementFp(this.q,V)}while(U.equals(BigInteger.ONE)||U.equals(qMinusOne));return null}, +/*! + * Crypto-JS 2.5.4 BlockModes.js + * contribution from Simon Greatrix + */ +function(C){var C_pad=C.pad={};function _requiredPadding(cipher,message){var blockSizeInBytes=4*cipher._blocksize;return blockSizeInBytes-message.length%blockSizeInBytes}var _unpadLength=function(cipher,message,alg,padding){var pad=message.pop();if(0==pad)throw new Error("Invalid zero-length padding specified for "+alg+". Wrong cipher specification or key used?");if(pad>4*cipher._blocksize)throw new Error("Invalid padding length of "+pad+" specified for "+alg+". Wrong cipher specification or key used?");for(var i=1;i0;reqd--)message.push(0)},unpad:function(cipher,message){for(;0==message[message.length-1];)message.pop()}},C_pad.iso7816={pad:function(cipher,message){var reqd=_requiredPadding(cipher,message);for(message.push(128);reqd>1;reqd--)message.push(0)},unpad:function(cipher,message){var padLength;for(padLength=4*cipher._blocksize;padLength>0;padLength--){var b=message.pop();if(128==b)return;if(0!=b)throw new Error("ISO-7816 padding byte must be 0, not 0x"+b.toString(16)+". Wrong cipher specification or key used?")}throw new Error("ISO-7816 padded beyond cipher block size. Wrong cipher specification or key used?")}},C_pad.ansix923={pad:function(cipher,message){for(var reqd=_requiredPadding(cipher,message),i=1;i 0 and a power of 2");if(N>2147483647/128/r)throw Error("Parameter N is too large");if(r>2147483647/128/p)throw Error("Parameter r is too large");var PBKDF2_opts={iterations:1,hasher:Crypto.SHA256,asBytes:!0},B=Crypto.PBKDF2(passwd,salt,128*p*r,PBKDF2_opts);try{var i=0,worksDone=0,makeWorker=function(){if(!workerUrl){var blob,code="("+scryptCore.toString()+")()";try{blob=new Blob([code],{type:"text/javascript"})}catch(e){GLOBAL.BlobBuilder=GLOBAL.BlobBuilder||GLOBAL.WebKitBlobBuilder||GLOBAL.MozBlobBuilder||GLOBAL.MSBlobBuilder,(blob=new BlobBuilder).append(code),blob=blob.getBlob("text/javascript")}workerUrl=URL.createObjectURL(blob)}var worker=new Worker(workerUrl);return worker.onmessage=function(event){var Bi=event.data[0],Bslice=event.data[1];worksDone++,i1&&workers[1].postMessage([N,r,p,B,i++])}catch(e){GLOBAL.setTimeout((function(){scryptCore(),callback(Crypto.PBKDF2(passwd,B,dkLen,PBKDF2_opts))}),0)}function scryptCore(){var XY=[],V=[];if(void 0===B)onmessage=function(event){var data=event.data,N=data[0],r=data[1],B=(data[2],data[3]),i=data[4],Bslice=[];arraycopy32(B,128*i*r,Bslice,0,128*r),smix(Bslice,0,r,N,V,XY),postMessage([i,Bslice])};else for(var i=0;i>>32-b}function salsa20_8(B){var i,B32=new Array(32),x=new Array(32);for(i=0;i<16;i++)B32[i]=(255&B[4*i+0])<<0,B32[i]|=(255&B[4*i+1])<<8,B32[i]|=(255&B[4*i+2])<<16,B32[i]|=(255&B[4*i+3])<<24;for(function(src,srcPos,dest,destPos,length){for(;length--;)dest[destPos++]=src[srcPos++]}(B32,0,x,0,16),i=8;i>0;i-=2)x[4]^=R(x[0]+x[12],7),x[8]^=R(x[4]+x[0],9),x[12]^=R(x[8]+x[4],13),x[0]^=R(x[12]+x[8],18),x[9]^=R(x[5]+x[1],7),x[13]^=R(x[9]+x[5],9),x[1]^=R(x[13]+x[9],13),x[5]^=R(x[1]+x[13],18),x[14]^=R(x[10]+x[6],7),x[2]^=R(x[14]+x[10],9),x[6]^=R(x[2]+x[14],13),x[10]^=R(x[6]+x[2],18),x[3]^=R(x[15]+x[11],7),x[7]^=R(x[3]+x[15],9),x[11]^=R(x[7]+x[3],13),x[15]^=R(x[11]+x[7],18),x[1]^=R(x[0]+x[3],7),x[2]^=R(x[1]+x[0],9),x[3]^=R(x[2]+x[1],13),x[0]^=R(x[3]+x[2],18),x[6]^=R(x[5]+x[4],7),x[7]^=R(x[6]+x[5],9),x[4]^=R(x[7]+x[6],13),x[5]^=R(x[4]+x[7],18),x[11]^=R(x[10]+x[9],7),x[8]^=R(x[11]+x[10],9),x[9]^=R(x[8]+x[11],13),x[10]^=R(x[9]+x[8],18),x[12]^=R(x[15]+x[14],7),x[13]^=R(x[12]+x[15],9),x[14]^=R(x[13]+x[12],13),x[15]^=R(x[14]+x[13],18);for(i=0;i<16;++i)B32[i]=x[i]+B32[i];for(i=0;i<16;i++){var bi=4*i;B[bi+0]=B32[i]>>0&255,B[bi+1]=B32[i]>>8&255,B[bi+2]=B32[i]>>16&255,B[bi+3]=B32[i]>>24&255}}function blockxor(S,Si,D,Di,len){for(var i=len>>6;i--;)D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++],D[Di++]^=S[Si++]}function integerify(B,bi,r){var n;return n=(255&B[(bi+=64*(2*r-1))+0])<<0,n|=(255&B[bi+1])<<8,n|=(255&B[bi+2])<<16,n|=(255&B[bi+3])<<24}function arraycopy32(src,srcPos,dest,destPos,length){for(var i=length>>5;i--;)dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++],dest[destPos++]=src[srcPos++]}}}, +/*! + * Crypto-JS v2.5.4 AES.js + * http://code.google.com/p/crypto-js/ + * Copyright (c) 2009-2013, Jeff Mott. All rights reserved. + * http://code.google.com/p/crypto-js/wiki/License + */ +function(){for(var C=Crypto,util=C.util,UTF8=C.charenc.UTF8,SBOX=[99,124,119,123,242,107,111,197,48,1,103,43,254,215,171,118,202,130,201,125,250,89,71,240,173,212,162,175,156,164,114,192,183,253,147,38,54,63,247,204,52,165,229,241,113,216,49,21,4,199,35,195,24,150,5,154,7,18,128,226,235,39,178,117,9,131,44,26,27,110,90,160,82,59,214,179,41,227,47,132,83,209,0,237,32,252,177,91,106,203,190,57,74,76,88,207,208,239,170,251,67,77,51,133,69,249,2,127,80,60,159,168,81,163,64,143,146,157,56,245,188,182,218,33,16,255,243,210,205,12,19,236,95,151,68,23,196,167,126,61,100,93,25,115,96,129,79,220,34,42,144,136,70,238,184,20,222,94,11,219,224,50,58,10,73,6,36,92,194,211,172,98,145,149,228,121,231,200,55,109,141,213,78,169,108,86,244,234,101,122,174,8,186,120,37,46,28,166,180,198,232,221,116,31,75,189,139,138,112,62,181,102,72,3,246,14,97,53,87,185,134,193,29,158,225,248,152,17,105,217,142,148,155,30,135,233,206,85,40,223,140,161,137,13,191,230,66,104,65,153,45,15,176,84,187,22],INVSBOX=[],i=0;i<256;i++)INVSBOX[SBOX[i]]=i;var MULT2=[],MULT3=[],MULT9=[],MULTB=[],MULTD=[],MULTE=[];function xtime(a,b){for(var result=0,i=0;i<8;i++){1&b&&(result^=a);var hiBitSet=128&a;a=a<<1&255,hiBitSet&&(a^=27),b>>>=1}return result}for(i=0;i<256;i++)MULT2[i]=xtime(i,2),MULT3[i]=xtime(i,3),MULT9[i]=xtime(i,9),MULTB[i]=xtime(i,11),MULTD[i]=xtime(i,13),MULTE[i]=xtime(i,14);var keylength,nrounds,keyschedule,RCON=[0,1,2,4,8,16,32,64,128,27,54],state=[[],[],[],[]],AES=C.AES={encrypt:function(message,password,options){var mode=(options=options||{}).mode||new C.mode.OFB;mode.fixOptions&&mode.fixOptions(options);var m=message.constructor==String?UTF8.stringToBytes(message):message,iv=options.iv||util.randomBytes(4*AES._blocksize),k=password.constructor==String?C.PBKDF2(password,iv,32,{asBytes:!0}):password;return AES._init(k),mode.encrypt(AES,m,iv),m=options.iv?m:iv.concat(m),options&&options.asBytes?m:util.bytesToBase64(m)},decrypt:function(ciphertext,password,options){var mode=(options=options||{}).mode||new C.mode.OFB;mode.fixOptions&&mode.fixOptions(options);var c=ciphertext.constructor==String?util.base64ToBytes(ciphertext):ciphertext,iv=options.iv||c.splice(0,4*AES._blocksize),k=password.constructor==String?C.PBKDF2(password,iv,32,{asBytes:!0}):password;return AES._init(k),mode.decrypt(AES,c,iv),options&&options.asBytes?c:UTF8.bytesToString(c)},_blocksize:4,_encryptblock:function(m,offset){for(var row=0;row6&&row%keylength==4&&(temp[0]=SBOX[temp[0]],temp[1]=SBOX[temp[1]],temp[2]=SBOX[temp[2]],temp[3]=SBOX[temp[3]]),keyschedule[row]=[keyschedule[row-keylength][0]^temp[0],keyschedule[row-keylength][1]^temp[1],keyschedule[row-keylength][2]^temp[2],keyschedule[row-keylength][3]^temp[3]]}}}}(),ec.FieldElementFp.fastLucasSequence=function(p,P,Q,k){for(var n=k.bitLength(),s=k.getLowestSetBit(),Uh=BigInteger.ONE,Vl=BigInteger.TWO,Vh=P,Ql=BigInteger.ONE,Qh=BigInteger.ONE,j=n-1;j>=s+1;--j)Ql=Ql.multiply(Qh).mod(p),k.testBit(j)?(Qh=Ql.multiply(Q).mod(p),Uh=Uh.multiply(Vh).mod(p),Vl=Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p),Vh=Vh.multiply(Vh).subtract(Qh.shiftLeft(1)).mod(p)):(Qh=Ql,Uh=Uh.multiply(Vl).subtract(Ql).mod(p),Vh=Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p),Vl=Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p));for(Qh=(Ql=Ql.multiply(Qh).mod(p)).multiply(Q).mod(p),Uh=Uh.multiply(Vl).subtract(Ql).mod(p),Vl=Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p),Ql=Ql.multiply(Qh).mod(p),j=1;j<=s;++j)Uh=Uh.multiply(Vl).mod(p),Vl=Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p),Ql=Ql.multiply(Ql).mod(p);return[Uh,Vl]},ec.PointFp=function(curve,x,y,z,compressed){this.curve=curve,this.x=x,this.y=y,this.z=null==z?BigInteger.ONE:z,this.zinv=null,this.compressed=!!compressed},ec.PointFp.prototype.getX=function(){null==this.zinv&&(this.zinv=this.z.modInverse(this.curve.q));var r=this.x.toBigInteger().multiply(this.zinv);return this.curve.reduce(r),this.curve.fromBigInteger(r)},ec.PointFp.prototype.getY=function(){null==this.zinv&&(this.zinv=this.z.modInverse(this.curve.q));var r=this.y.toBigInteger().multiply(this.zinv);return this.curve.reduce(r),this.curve.fromBigInteger(r)},ec.PointFp.prototype.equals=function(other){return other==this||(this.isInfinity()?other.isInfinity():other.isInfinity()?this.isInfinity():!!other.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(other.z)).mod(this.curve.q).equals(BigInteger.ZERO)&&other.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(other.z)).mod(this.curve.q).equals(BigInteger.ZERO))},ec.PointFp.prototype.isInfinity=function(){return null==this.x&&null==this.y||this.z.equals(BigInteger.ZERO)&&!this.y.toBigInteger().equals(BigInteger.ZERO)},ec.PointFp.prototype.negate=function(){return new ec.PointFp(this.curve,this.x,this.y.negate(),this.z)},ec.PointFp.prototype.add=function(b){if(this.isInfinity())return b;if(b.isInfinity())return this;var u=b.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(b.z)).mod(this.curve.q),v=b.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(b.z)).mod(this.curve.q);if(BigInteger.ZERO.equals(v))return BigInteger.ZERO.equals(u)?this.twice():this.curve.getInfinity();var THREE=new BigInteger("3"),x1=this.x.toBigInteger(),y1=this.y.toBigInteger(),v2=(b.x.toBigInteger(),b.y.toBigInteger(),v.square()),v3=v2.multiply(v),x1v2=x1.multiply(v2),zu2=u.square().multiply(this.z),x3=zu2.subtract(x1v2.shiftLeft(1)).multiply(b.z).subtract(v3).multiply(v).mod(this.curve.q),y3=x1v2.multiply(THREE).multiply(u).subtract(y1.multiply(v3)).subtract(zu2.multiply(u)).multiply(b.z).add(u.multiply(v3)).mod(this.curve.q),z3=v3.multiply(this.z).multiply(b.z).mod(this.curve.q);return new ec.PointFp(this.curve,this.curve.fromBigInteger(x3),this.curve.fromBigInteger(y3),z3)},ec.PointFp.prototype.twice=function(){if(this.isInfinity())return this;if(0==this.y.toBigInteger().signum())return this.curve.getInfinity();var THREE=new BigInteger("3"),x1=this.x.toBigInteger(),y1=this.y.toBigInteger(),y1z1=y1.multiply(this.z),y1sqz1=y1z1.multiply(y1).mod(this.curve.q),a=this.curve.a.toBigInteger(),w=x1.square().multiply(THREE);BigInteger.ZERO.equals(a)||(w=w.add(this.z.square().multiply(a)));var x3=(w=w.mod(this.curve.q)).square().subtract(x1.shiftLeft(3).multiply(y1sqz1)).shiftLeft(1).multiply(y1z1).mod(this.curve.q),y3=w.multiply(THREE).multiply(x1).subtract(y1sqz1.shiftLeft(1)).shiftLeft(2).multiply(y1sqz1).subtract(w.square().multiply(w)).mod(this.curve.q),z3=y1z1.square().multiply(y1z1).shiftLeft(3).mod(this.curve.q);return new ec.PointFp(this.curve,this.curve.fromBigInteger(x3),this.curve.fromBigInteger(y3),z3)},ec.PointFp.prototype.multiply=function(k){if(this.isInfinity())return this;if(0==k.signum())return this.curve.getInfinity();var i,e=k,h=e.multiply(new BigInteger("3")),neg=this.negate(),R=this;for(i=h.bitLength()-2;i>0;--i){R=R.twice();var hBit=h.testBit(i);hBit!=e.testBit(i)&&(R=R.add(hBit?this:neg))}return R},ec.PointFp.prototype.multiplyTwo=function(j,x,k){var i;i=j.bitLength()>k.bitLength()?j.bitLength()-1:k.bitLength()-1;for(var R=this.curve.getInfinity(),both=this.add(x);i>=0;)R=R.twice(),j.testBit(i)?R=k.testBit(i)?R.add(both):R.add(this):k.testBit(i)&&(R=R.add(x)),--i;return R},ec.PointFp.prototype.getEncoded=function(compressed){var x=this.getX().toBigInteger(),y=this.getY().toBigInteger(),enc=ec.integerToBytes(x,32);return compressed?y.isEven()?enc.unshift(2):enc.unshift(3):(enc.unshift(4),enc=enc.concat(ec.integerToBytes(y,32))),enc},ec.PointFp.decodeFrom=function(curve,enc){enc[0];var dataLen=enc.length-1,xBa=enc.slice(1,1+dataLen/2),yBa=enc.slice(1+dataLen/2,1+dataLen);xBa.unshift(0),yBa.unshift(0);var x=new BigInteger(xBa),y=new BigInteger(yBa);return new ec.PointFp(curve,curve.fromBigInteger(x),curve.fromBigInteger(y))},ec.PointFp.prototype.add2D=function(b){if(this.isInfinity())return b;if(b.isInfinity())return this;if(this.x.equals(b.x))return this.y.equals(b.y)?this.twice():this.curve.getInfinity();var x_x=b.x.subtract(this.x),gamma=b.y.subtract(this.y).divide(x_x),x3=gamma.square().subtract(this.x).subtract(b.x),y3=gamma.multiply(this.x.subtract(x3)).subtract(this.y);return new ec.PointFp(this.curve,x3,y3)},ec.PointFp.prototype.twice2D=function(){if(this.isInfinity())return this;if(0==this.y.toBigInteger().signum())return this.curve.getInfinity();var TWO=this.curve.fromBigInteger(BigInteger.valueOf(2)),THREE=this.curve.fromBigInteger(BigInteger.valueOf(3)),gamma=this.x.square().multiply(THREE).add(this.curve.a).divide(this.y.multiply(TWO)),x3=gamma.square().subtract(this.x.multiply(TWO)),y3=gamma.multiply(this.x.subtract(x3)).subtract(this.y);return new ec.PointFp(this.curve,x3,y3)},ec.PointFp.prototype.multiply2D=function(k){if(this.isInfinity())return this;if(0==k.signum())return this.curve.getInfinity();var i,e=k,h=e.multiply(new BigInteger("3")),neg=this.negate(),R=this;for(i=h.bitLength()-2;i>0;--i){R=R.twice();var hBit=h.testBit(i);hBit!=e.testBit(i)&&(R=R.add2D(hBit?this:neg))}return R},ec.PointFp.prototype.isOnCurve=function(){var x=this.getX().toBigInteger(),y=this.getY().toBigInteger(),a=this.curve.getA().toBigInteger(),b=this.curve.getB().toBigInteger(),n=this.curve.getQ(),lhs=y.multiply(y).mod(n),rhs=x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(n);return lhs.equals(rhs)},ec.PointFp.prototype.toString=function(){return"("+this.getX().toBigInteger().toString()+","+this.getY().toBigInteger().toString()+")"},ec.PointFp.prototype.validate=function(){var n=this.curve.getQ();if(this.isInfinity())throw new Error("Point is at infinity.");var x=this.getX().toBigInteger(),y=this.getY().toBigInteger();if(x.compareTo(BigInteger.ONE)<0||x.compareTo(n.subtract(BigInteger.ONE))>0)throw new Error("x coordinate out of bounds");if(y.compareTo(BigInteger.ONE)<0||y.compareTo(n.subtract(BigInteger.ONE))>0)throw new Error("y coordinate out of bounds");if(!this.isOnCurve())throw new Error("Point is not on the curve.");if(this.multiply(n).isInfinity())throw new Error("Point is not a scalar multiple of G.");return!0},ec.CurveFp=function(q,a,b){this.q=q,this.a=this.fromBigInteger(a),this.b=this.fromBigInteger(b),this.infinity=new ec.PointFp(this,null,null),this.reducer=new Barrett(this.q)},ec.CurveFp.prototype.getQ=function(){return this.q},ec.CurveFp.prototype.getA=function(){return this.a},ec.CurveFp.prototype.getB=function(){return this.b},ec.CurveFp.prototype.equals=function(other){return other==this||this.q.equals(other.q)&&this.a.equals(other.a)&&this.b.equals(other.b)},ec.CurveFp.prototype.getInfinity=function(){return this.infinity},ec.CurveFp.prototype.fromBigInteger=function(x){return new ec.FieldElementFp(this.q,x)},ec.CurveFp.prototype.reduce=function(x){this.reducer.reduce(x)},ec.CurveFp.prototype.decodePointHex=function(s){var firstByte=parseInt(s.substr(0,2),16);switch(firstByte){case 0:return this.infinity;case 2:case 3:var yTilde=1&firstByte,xHex=s.substr(2,s.length-2),X1=new BigInteger(xHex,16);return this.decompressPoint(yTilde,X1);case 4:case 6:case 7:var len=(s.length-2)/2,yHex=(xHex=s.substr(2,len),s.substr(len+2,len));return new ec.PointFp(this,this.fromBigInteger(new BigInteger(xHex,16)),this.fromBigInteger(new BigInteger(yHex,16)));default:return null}},ec.CurveFp.prototype.encodePointHex=function(p){if(p.isInfinity())return"00";var xHex=p.getX().toBigInteger().toString(16),yHex=p.getY().toBigInteger().toString(16),oLen=this.getQ().toString(16).length;for(oLen%2!=0&&oLen++;xHex.lengthbytes.length;)bytes.unshift(0);return bytes},ec.X9Parameters=function(curve,g,n,h){this.curve=curve,this.g=g,this.n=n,this.h=h},ec.X9Parameters.prototype.getCurve=function(){return this.curve},ec.X9Parameters.prototype.getG=function(){return this.g},ec.X9Parameters.prototype.getN=function(){return this.n},ec.X9Parameters.prototype.getH=function(){return this.h},ec.secNamedCurves={secp256k1:function(){var p=ec.fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"),a=BigInteger.ZERO,b=ec.fromHex("7"),n=ec.fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"),h=BigInteger.ONE,curve=new ec.CurveFp(p,a,b),G=curve.decodePointHex("0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8");return new ec.X9Parameters(curve,G,n,h)}},ec.getSECCurveByName=function(name){return null==ec.secNamedCurves[name]?null:ec.secNamedCurves[name]()},function(){var bitjs=GLOBAL.bitjs=function(){};bitjs.pub=35,bitjs.priv=163,bitjs.multisig=94,bitjs.compressed=!1,"FLO_TEST"==GLOBAL.cryptocoin&&(bitjs.pub=115,bitjs.priv=163,bitjs.multisig=198),bitjs.privkey2wif=function(h){var r=Crypto.util.hexToBytes(h);1==bitjs.compressed&&r.push(1),r.unshift(bitjs.priv);var checksum=Crypto.SHA256(Crypto.SHA256(r,{asBytes:!0}),{asBytes:!0}).slice(0,4);return B58.encode(r.concat(checksum))},bitjs.wif2privkey=function(wif){var compressed=!1,decode=B58.decode(wif),key=decode.slice(0,decode.length-4);return(key=key.slice(1,key.length)).length>=33&&1==key[key.length-1]&&(key=key.slice(0,key.length-1),compressed=!0),{privkey:Crypto.util.bytesToHex(key),compressed:compressed}},bitjs.wif2pubkey=function(wif){var compressed=bitjs.compressed,r=bitjs.wif2privkey(wif);bitjs.compressed=r.compressed;var pubkey=bitjs.newPubkey(r.privkey);return bitjs.compressed=compressed,{pubkey:pubkey,compressed:r.compressed}},bitjs.wif2address=function(wif){var r=bitjs.wif2pubkey(wif);return{address:bitjs.pubkey2address(r.pubkey),compressed:r.compressed}},bitjs.newPubkey=function(hash){var privateKeyBigInt=BigInteger.fromByteArrayUnsigned(Crypto.util.hexToBytes(hash)),curvePt=EllipticCurve.getSECCurveByName("secp256k1").getG().multiply(privateKeyBigInt),x=curvePt.getX().toBigInteger(),y=curvePt.getY().toBigInteger(),publicKeyBytes=EllipticCurve.integerToBytes(x,32);if((publicKeyBytes=publicKeyBytes.concat(EllipticCurve.integerToBytes(y,32))).unshift(4),1==bitjs.compressed){var publicKeyBytesCompressed=EllipticCurve.integerToBytes(x,32);return y.isEven()?publicKeyBytesCompressed.unshift(2):publicKeyBytesCompressed.unshift(3),Crypto.util.bytesToHex(publicKeyBytesCompressed)}return Crypto.util.bytesToHex(publicKeyBytes)},bitjs.pubkey2address=function(h,byte){var r=ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(h),{asBytes:!0}));r.unshift(byte||bitjs.pub);var checksum=Crypto.SHA256(Crypto.SHA256(r,{asBytes:!0}),{asBytes:!0}).slice(0,4);return B58.encode(r.concat(checksum))},bitjs.pubkeys2multisig=function(pubkeys,required){var s=[];s.push(80+required);for(var i=0;i520)throw Error(`redeemScript size(=${s.length}) too large`);var x=ripemd160(Crypto.SHA256(s,{asBytes:!0}),{asBytes:!0});x.unshift(bitjs.multisig);var r=x,checksum=(r=Crypto.SHA256(Crypto.SHA256(r,{asBytes:!0}),{asBytes:!0})).slice(0,4),redeemScript=Crypto.util.bytesToHex(s);return{address:B58.encode(x.concat(checksum)),redeemScript:redeemScript,size:s.length}},bitjs.transaction=function(tx_data=void 0){var btrx={};return btrx.version=2,btrx.inputs=[],btrx.outputs=[],btrx.locktime=0,btrx.floData="",btrx.addinput=function(txid,index,scriptPubKey,sequence){var o={};return o.outpoint={hash:txid,index:index},o.script=Crypto.util.hexToBytes(scriptPubKey),o.sequence=sequence||(0==btrx.locktime?4294967295:0),this.inputs.push(o)},btrx.addoutput=function(address,value){var o={},buf=[],addr=this.addressDecode(address);return o.value=new BigInteger(""+Math.round(1*value*1e8),10),addr.version===bitjs.pub?(buf.push(118),buf.push(169),(buf=this.writeBytesToScriptBuffer(buf,addr.bytes)).push(136),buf.push(172)):addr.version===bitjs.multisig&&(buf.push(169),(buf=this.writeBytesToScriptBuffer(buf,addr.bytes)).push(135)),o.script=buf,this.outputs.push(o)},btrx.addflodata=function(data){if("string"!=typeof data)throw Error("floData should be String");if(data.length>1040)throw Error("floData Character Limit Exceeded");if(bitjs.strToBytes(data).some((c=>c<32||c>127)))throw Error("floData contains Invalid characters (only ASCII characters allowed");return this.floData=data,this.floData},btrx.addressDecode=function(address){var bytes=B58.decode(address),front=bytes.slice(0,bytes.length-4),back=bytes.slice(bytes.length-4);if(Crypto.SHA256(Crypto.SHA256(front,{asBytes:!0}),{asBytes:!0}).slice(0,4)+""==back+"")return{version:front[0],bytes:front.slice(1)}},btrx.transactionHash=function(index,sigHashType){for(var clone=bitjs.clone(this),shType=sigHashType||1,i=0;i=128)if(clone.inputs=[clone.inputs[index]],129==shType);else if(130==shType)clone.outputs=[];else if(131==shType){clone.outputs.length=index+1;for(i=0;i0&&(s=n.subtract(s));var sig=function(r,s){var rBa=r.toByteArraySigned(),sBa=s.toByteArraySigned(),sequence=[];return sequence.push(2),sequence.push(rBa.length),(sequence=sequence.concat(rBa)).push(2),sequence.push(sBa.length),(sequence=sequence.concat(sBa)).unshift(sequence.length),sequence.unshift(48),sequence}(r,s);return sig.push(parseInt(shType,10)),Crypto.util.bytesToHex(sig)}return!1},btrx.deterministicK=function(wif,hash,badrs){badrs=badrs||0;var key=bitjs.wif2privkey(wif),x=Crypto.util.hexToBytes(key.privkey),N=EllipticCurve.getSECCurveByName("secp256k1").getN(),v=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],k=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];k=Crypto.HMAC(Crypto.SHA256,v.concat([0]).concat(x).concat(hash),k,{asBytes:!0}),v=Crypto.HMAC(Crypto.SHA256,v,k,{asBytes:!0}),k=Crypto.HMAC(Crypto.SHA256,v.concat([1]).concat(x).concat(hash),k,{asBytes:!0}),v=Crypto.HMAC(Crypto.SHA256,v,k,{asBytes:!0});var T=[];T=v=Crypto.HMAC(Crypto.SHA256,v,k,{asBytes:!0});for(var KBigInt=BigInteger.fromByteArrayUnsigned(T),i=0;KBigInt.compareTo(N)>=0||KBigInt.compareTo(BigInteger.ZERO)<=0||i>>8&255)):(buf.push(78),buf.push(255&bytes.length),buf.push(bytes.length>>>8&255),buf.push(bytes.length>>>16&255),buf.push(bytes.length>>>24&255)),buf=buf.concat(bytes)},btrx.parseScript=function(script){var chunks=[],i=0;function readChunk(n){chunks.push(script.slice(i,i+n)),i+=n}for(;i=240&&(opcode=opcode<<8|script[i++]),opcode>0&&opcode<76?readChunk(opcode):76==opcode?readChunk(script[i++]):77==opcode?readChunk(script[i++]<<8|script[i++]):78==opcode?readChunk(script[i++]<<24|script[i++]<<16|script[i++]<<8|script[i++]):chunks.push(opcode),i<0)break}return chunks},btrx.decodeRedeemScript=function(rs){"string"==typeof rs&&(rs=Crypto.util.hexToBytes(rs));var script=this.parseScript(rs);if(!(script[0]>80&&script[script.length-2]>80&&174==script[script.length-1]))throw"Invalid RedeemScript";var r={};r.required=script[0]-80,r.pubkeys=[];for(var i=1;i=80&&174==script[i][script[i].length-1]&&(redeemScript=script[i]))}else redeemScript=script;var pubkeyList=this.decodeRedeemScript(redeemScript).pubkeys,pubkey=bitjs.wif2pubkey(wif).pubkey;if(!pubkeyList.includes(pubkey))return!1;pubkeyList=pubkeyList.map((pub=>Crypto.util.hexToBytes(bitjs.pubkeydecompress(pub))));var shType=sigHashType||1;this.inputs[index].script=redeemScript;var signature=Crypto.util.hexToBytes(this.transactionSig(index,wif,shType));sigsList.push(signature);var buf=[];buf.push(0);for(let x in pubkeyList)for(let y in sigsList){var sighash=Crypto.util.hexToBytes(this.transactionHash(index,1*sigsList[y].slice(-1)[0]));if(bitjs.verifySignature(sighash,sigsList[y],pubkeyList[x])){buf=this.writeBytesToScriptBuffer(buf,sigsList[y]);break}}return buf=this.writeBytesToScriptBuffer(buf,redeemScript),this.inputs[index].script=buf,!0},btrx.sign=function(wif,sigHashType){for(var shType=sigHashType||1,i=0;i=80&&174==script[script.length-1]?{type:"multisig",rs:Array.from(this.inputs[index].script)}:void 0},btrx.serialize=function(){var buffer=[];buffer=(buffer=buffer.concat(bitjs.numToBytes(parseInt(this.version),4))).concat(bitjs.numToVarInt(this.inputs.length));for(var i=0;iString.fromCharCode(b))).join("")}(tx_data),btrx},bitjs.numToBytes=function(num,bytes){return void 0===bytes&&(bytes=8),0==bytes?[]:-1==num?Crypto.util.hexToBytes("ffffffffffffffff"):[num%256].concat(bitjs.numToBytes(Math.floor(num/256),bytes-1))},bitjs.numToByteArray=function(num){return num<=256?[num]:[num%256].concat(bitjs.numToByteArray(Math.floor(num/256)))},bitjs.numToVarInt=function(num){return num<253?[num]:num<65536?[253].concat(bitjs.numToBytes(num,2)):num<4294967296?[254].concat(bitjs.numToBytes(num,4)):[255].concat(bitjs.numToBytes(num,8))},bitjs.bytesToNum=function(bytes){return 0==bytes.length?0:bytes[0]+256*bitjs.bytesToNum(bytes.slice(1))},bitjs.strToBytes=function(str){return str.split("").map((c=>c.charCodeAt(0)))},bitjs.pubkeydecompress=function(pubkey){if("string"==typeof pubkey&&pubkey.match(/^[a-f0-9]+$/i)){var curve=EllipticCurve.getSECCurveByName("secp256k1");try{var pt=curve.curve.decodePointHex(pubkey),x=pt.getX().toBigInteger(),y=pt.getY().toBigInteger(),publicKeyBytes=EllipticCurve.integerToBytes(x,32);return(publicKeyBytes=publicKeyBytes.concat(EllipticCurve.integerToBytes(y,32))).unshift(4),Crypto.util.bytesToHex(publicKeyBytes)}catch(e){return!1}}return!1},bitjs.verifySignature=function(hash,sig,pubkey){return Bitcoin.ECDSA.verify(hash,sig,pubkey)},bitjs.clone=function(obj){if(null==obj||"object"!=typeof obj)return obj;var temp=new obj.constructor;for(var key in obj)obj.hasOwnProperty(key)&&(temp[key]=bitjs.clone(obj[key]));return temp};var B58=bitjs.Base58={alphabet:"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",validRegex:/^[1-9A-HJ-NP-Za-km-z]+$/,base:BigInteger.valueOf(58),encode:function(input){for(var bi=BigInteger.fromByteArrayUnsigned(input),chars=[];bi.compareTo(B58.base)>=0;){var mod=bi.mod(B58.base);chars.unshift(B58.alphabet[mod.intValue()]),bi=bi.subtract(mod).divide(B58.base)}chars.unshift(B58.alphabet[bi.intValue()]);for(var i=0;i=0;i--){var alphaIndex=B58.alphabet.indexOf(input[i]);if(alphaIndex<0)throw"Invalid character";bi=bi.add(BigInteger.valueOf(alphaIndex).multiply(B58.base.pow(input.length-1-i))),"1"==input[i]?leadingZerosNum++:leadingZerosNum=0}for(var bytes=bi.toByteArrayUnsigned();leadingZerosNum-- >0;)bytes.unshift(0);return bytes}}}(),function(){var ecparams,rng,P_OVER_FOUR,ECDSA,Bip38,Bitcoin=GLOBAL.Bitcoin={},B58=Bitcoin.Base58={alphabet:"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",validRegex:/^[1-9A-HJ-NP-Za-km-z]+$/,base:BigInteger.valueOf(58),encode:function(input){for(var bi=BigInteger.fromByteArrayUnsigned(input),chars=[];bi.compareTo(B58.base)>=0;){var mod=bi.mod(B58.base);chars.unshift(B58.alphabet[mod.intValue()]),bi=bi.subtract(mod).divide(B58.base)}chars.unshift(B58.alphabet[bi.intValue()]);for(var i=0;i=0;i--){var alphaIndex=B58.alphabet.indexOf(input[i]);if(alphaIndex<0)throw"Invalid character";bi=bi.add(BigInteger.valueOf(alphaIndex).multiply(B58.base.pow(input.length-1-i))),"1"==input[i]?leadingZerosNum++:leadingZerosNum=0}for(var bytes=bi.toByteArrayUnsigned();leadingZerosNum-- >0;)bytes.unshift(0);return bytes}};Bitcoin.Address=function(bytes){if("string"==typeof bytes){var d=Bitcoin.Address.decodeString(bytes);if(bytes=d.hash,d.version!=Bitcoin.Address.standardVersion&&d.version!=Bitcoin.Address.multisigVersion)throw"Version (prefix) "+d.version+" not supported!";this.version=d.version}else this.version=Bitcoin.Address.standardVersion;this.hash=bytes},Bitcoin.Address.standardVersion=35,Bitcoin.Address.multisigVersion=94,"FLO_TEST"==GLOBAL.cryptocoin&&(Bitcoin.Address.standardVersion=115,Bitcoin.Address.multisigVersion=198),Bitcoin.Address.prototype.toString=function(version=null){var hash=this.hash.slice(0);hash.unshift(null!==version?version:this.version);var checksum=Crypto.SHA256(Crypto.SHA256(hash,{asBytes:!0}),{asBytes:!0}),bytes=hash.concat(checksum.slice(0,4));return Bitcoin.Base58.encode(bytes)},Bitcoin.Address.prototype.getHashBase64=function(){return Crypto.util.bytesToBase64(this.hash)},Bitcoin.Address.decodeString=function(string){var bytes=Bitcoin.Base58.decode(string),hash=bytes.slice(0,21),checksum=Crypto.SHA256(Crypto.SHA256(hash,{asBytes:!0}),{asBytes:!0});if(checksum[0]!=bytes[21]||checksum[1]!=bytes[22]||checksum[2]!=bytes[23]||checksum[3]!=bytes[24])throw"Checksum validation failed!";return{version:hash.shift(),hash:hash}},Bitcoin.ECDSA=(ecparams=EllipticCurve.getSECCurveByName("secp256k1"),rng=new SecureRandom,P_OVER_FOUR=null,ECDSA={getBigRandom:function(limit){return new BigInteger(limit.bitLength(),rng).mod(limit.subtract(BigInteger.ONE)).add(BigInteger.ONE)},sign:function(hash,priv){var d=priv,n=ecparams.getN(),e=BigInteger.fromByteArrayUnsigned(hash);do{var k=ECDSA.getBigRandom(n),r=ecparams.getG().multiply(k).getX().toBigInteger().mod(n)}while(r.compareTo(BigInteger.ZERO)<=0);var s=k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);return ECDSA.serializeSig(r,s)},verify:function(hash,sig,pubkey){var r,s,Q;if(Bitcoin.Util.isArray(sig)){var obj=ECDSA.parseSig(sig);r=obj.r,s=obj.s}else{if("object"!=typeof sig||!sig.r||!sig.s)throw"Invalid value for signature";r=sig.r,s=sig.s}if(pubkey instanceof EllipticCurve.PointFp)Q=pubkey;else{if(!Bitcoin.Util.isArray(pubkey))throw"Invalid format for pubkey value, must be byte array or ec.PointFp";Q=EllipticCurve.PointFp.decodeFrom(ecparams.getCurve(),pubkey)}var e=BigInteger.fromByteArrayUnsigned(hash);return ECDSA.verifyRaw(e,r,s,Q)},verifyRaw:function(e,r,s,Q){var n=ecparams.getN(),G=ecparams.getG();if(r.compareTo(BigInteger.ONE)<0||r.compareTo(n)>=0)return!1;if(s.compareTo(BigInteger.ONE)<0||s.compareTo(n)>=0)return!1;var c=s.modInverse(n),u1=e.multiply(c).mod(n),u2=r.multiply(c).mod(n);return G.multiply(u1).add(Q.multiply(u2)).getX().toBigInteger().mod(n).equals(r)},serializeSig:function(r,s){var rBa=r.toByteArraySigned(),sBa=s.toByteArraySigned(),sequence=[];return sequence.push(2),sequence.push(rBa.length),(sequence=sequence.concat(rBa)).push(2),sequence.push(sBa.length),(sequence=sequence.concat(sBa)).unshift(sequence.length),sequence.unshift(48),sequence},parseSig:function(sig){var cursor;if(48!=sig[0])throw new Error("Signature not a valid DERSequence");if(2!=sig[cursor=2])throw new Error("First element in signature must be a DERInteger");var rBa=sig.slice(cursor+2,cursor+2+sig[cursor+1]);if(2!=sig[cursor+=2+sig[cursor+1]])throw new Error("Second element in signature must be a DERInteger");var sBa=sig.slice(cursor+2,cursor+2+sig[cursor+1]);return cursor+=2+sig[cursor+1],{r:BigInteger.fromByteArrayUnsigned(rBa),s:BigInteger.fromByteArrayUnsigned(sBa)}},parseSigCompact:function(sig){if(65!==sig.length)throw"Signature has the wrong length";var i=sig[0]-27;if(i<0||i>7)throw"Invalid signature type";var n=ecparams.getN();return{r:BigInteger.fromByteArrayUnsigned(sig.slice(1,33)).mod(n),s:BigInteger.fromByteArrayUnsigned(sig.slice(33,65)).mod(n),i:i}},recoverPubKey:function(r,s,hash,i){var isYEven=1&(i&=3),isSecondKey=i>>1,n=ecparams.getN(),G=ecparams.getG(),curve=ecparams.getCurve(),p=curve.getQ(),a=curve.getA().toBigInteger(),b=curve.getB().toBigInteger();P_OVER_FOUR||(P_OVER_FOUR=p.add(BigInteger.ONE).divide(BigInteger.valueOf(4)));var x=isSecondKey?r.add(n):r,beta=x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p).modPow(P_OVER_FOUR,p),y=(beta.isEven(),(beta.isEven()?!isYEven:isYEven)?beta:p.subtract(beta)),R=new EllipticCurve.PointFp(curve,curve.fromBigInteger(x),curve.fromBigInteger(y));R.validate();var e=BigInteger.fromByteArrayUnsigned(hash),eNeg=BigInteger.ZERO.subtract(e).mod(n),rInv=r.modInverse(n),Q=function(P,k,Q,l){for(var m=Math.max(k.bitLength(),l.bitLength()),Z=P.add2D(Q),R=P.curve.getInfinity(),i=m-1;i>=0;--i)(R=R.twice2D()).z=BigInteger.ONE,k.testBit(i)?R=l.testBit(i)?R.add2D(Z):R.add2D(P):l.testBit(i)&&(R=R.add2D(Q));return R}(R,s,G,eNeg).multiply(rInv);if(Q.validate(),!ECDSA.verifyRaw(e,r,s,Q))throw"Pubkey recovery unsuccessful";var pubKey=new Bitcoin.ECKey;return pubKey.pub=Q,pubKey},calcPubkeyRecoveryParam:function(address,r,s,hash){for(var i=0;i<4;i++)try{if(Bitcoin.ECDSA.recoverPubKey(r,s,hash,i).getBitcoinAddress().toString()==address)return i}catch(e){}throw"Unable to find valid recovery factor"}}),Bitcoin.KeyPool=new function(){return this.keyArray=[],this.push=function(item){if(null!=item&&null!=item.priv){var doAdd=!0;for(var index in this.keyArray){var currentItem=this.keyArray[index];if(null!=currentItem&&null!=currentItem.priv&&item.getBitcoinAddress()==currentItem.getBitcoinAddress()){doAdd=!1;break}}doAdd&&this.keyArray.push(item)}},this.reset=function(){this.keyArray=[]},this.getArray=function(){return this.keyArray.slice(0)},this.setArray=function(ka){this.keyArray=ka},this.length=function(){return this.keyArray.length},this.toString=function(){var keyPoolString="# = "+this.length()+"\n",pool=this.getArray();for(var index in pool){var item=pool[index];Bitcoin.Util.hasMethods(item,"getBitcoinAddress","toString")&&null!=item&&(keyPoolString+='"'+item.getBitcoinAddress()+'", "'+item.toString("wif")+'"\n')}return keyPoolString},this},Bitcoin.Bip38Key=((Bip38=function(address,encryptedKey){this.address=address,this.priv=encryptedKey}).prototype.getBitcoinAddress=function(){return this.address},Bip38.prototype.toString=function(){return this.priv},Bip38),Bitcoin.ECKey=function(){var ECDSA=Bitcoin.ECDSA,KeyPool=Bitcoin.KeyPool,ecparams=EllipticCurve.getSECCurveByName("secp256k1"),ECKey=function(input){if(input){if(input instanceof BigInteger)this.priv=input;else if(Bitcoin.Util.isArray(input))this.priv=BigInteger.fromByteArrayUnsigned(input);else if("string"==typeof input){var bytes=null;try{/^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{52}$/.test(input)?(bytes=ECKey.decodeCompressedWalletImportFormat(input),this.compressed=!0):ECKey.isHexFormat(input)&&(bytes=Crypto.util.hexToBytes(input))}catch(exc1){this.setError(exc1)}ECKey.isBase6Format(input)?this.priv=new BigInteger(input,6):null==bytes||32!=bytes.length?this.priv=null:this.priv=BigInteger.fromByteArrayUnsigned(bytes)}}else{var n=ecparams.getN();this.priv=ECDSA.getBigRandom(n)}this.compressed=null==this.compressed?!!ECKey.compressByDefault:this.compressed;try{null!=this.priv&&0==BigInteger.ZERO.compareTo(this.priv)&&this.setError("Error: BigInteger equal to zero.");var rangeLimitBytes=Crypto.util.hexToBytes("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140"),limitBigInt=BigInteger.fromByteArrayUnsigned(rangeLimitBytes);null!=this.priv&&limitBigInt.compareTo(this.priv)<0&&this.setError("Error: BigInteger outside of curve range."),null!=this.priv&&KeyPool.push(this)}catch(exc2){this.setError(exc2)}};return"FLO"==GLOBAL.cryptocoin?ECKey.privateKeyPrefix=163:"FLO_TEST"==GLOBAL.cryptocoin&&(ECKey.privateKeyPrefix=239),ECKey.compressByDefault=!1,ECKey.prototype.setError=function(err){return this.error=err,this.priv=null,this},ECKey.prototype.setCompressed=function(v){return this.compressed=!!v,this.pubPoint&&(this.pubPoint.compressed=this.compressed),this},ECKey.prototype.getPub=function(){return this.compressed?this.pubComp?this.pubComp:this.pubComp=this.getPubPoint().getEncoded(1):this.pubUncomp?this.pubUncomp:this.pubUncomp=this.getPubPoint().getEncoded(0)},ECKey.prototype.getPubPoint=function(){return this.pubPoint||(this.pubPoint=ecparams.getG().multiply(this.priv),this.pubPoint.compressed=this.compressed),this.pubPoint},ECKey.prototype.getPubKeyHex=function(){return this.compressed?this.pubKeyHexComp?this.pubKeyHexComp:this.pubKeyHexComp=Crypto.util.bytesToHex(this.getPub()).toString().toUpperCase():this.pubKeyHexUncomp?this.pubKeyHexUncomp:this.pubKeyHexUncomp=Crypto.util.bytesToHex(this.getPub()).toString().toUpperCase()},ECKey.prototype.getPubKeyHash=function(){return this.compressed?this.pubKeyHashComp?this.pubKeyHashComp:this.pubKeyHashComp=Bitcoin.Util.sha256ripe160(this.getPub()):this.pubKeyHashUncomp?this.pubKeyHashUncomp:this.pubKeyHashUncomp=Bitcoin.Util.sha256ripe160(this.getPub())},ECKey.prototype.getBitcoinAddress=function(){var hash=this.getPubKeyHash();return new Bitcoin.Address(hash).toString()},ECKey.prototype.setPub=function(pub){Bitcoin.Util.isArray(pub)&&(pub=Crypto.util.bytesToHex(pub).toString().toUpperCase());var ecPoint=ecparams.getCurve().decodePointHex(pub);return this.setCompressed(ecPoint.compressed),this.pubPoint=ecPoint,this},ECKey.prototype.getBitcoinWalletImportFormat=function(){var bytes=this.getBitcoinPrivateKeyByteArray();if(null==bytes)return"";bytes.unshift(ECKey.privateKeyPrefix),this.compressed&&bytes.push(1);var checksum=Crypto.SHA256(Crypto.SHA256(bytes,{asBytes:!0}),{asBytes:!0});return bytes=bytes.concat(checksum.slice(0,4)),Bitcoin.Base58.encode(bytes)},ECKey.prototype.getBitcoinHexFormat=function(){return Crypto.util.bytesToHex(this.getBitcoinPrivateKeyByteArray()).toString().toUpperCase()},ECKey.prototype.getBitcoinBase64Format=function(){return Crypto.util.bytesToBase64(this.getBitcoinPrivateKeyByteArray())},ECKey.prototype.getBitcoinPrivateKeyByteArray=function(){if(null==this.priv)return null;for(var bytes=this.priv.toByteArrayUnsigned();bytes.length<32;)bytes.unshift(0);return bytes},ECKey.prototype.toString=function(format){return"base64"==(format=format||"").toString().toLowerCase()||"b64"==format.toString().toLowerCase()?this.getBitcoinBase64Format():"wif"==format.toString().toLowerCase()?this.getBitcoinWalletImportFormat():this.getBitcoinHexFormat()},ECKey.prototype.sign=function(hash){return ECDSA.sign(hash,this.priv)},ECKey.prototype.verify=function(hash,sig){return ECDSA.verify(hash,sig,this.getPub())},ECKey.decodeWalletImportFormat=function(privStr){var bytes=Bitcoin.Base58.decode(privStr),hash=bytes.slice(0,33),checksum=Crypto.SHA256(Crypto.SHA256(hash,{asBytes:!0}),{asBytes:!0});if(checksum[0]!=bytes[33]||checksum[1]!=bytes[34]||checksum[2]!=bytes[35]||checksum[3]!=bytes[36])throw"Checksum validation failed!";hash.shift();return hash},ECKey.decodeCompressedWalletImportFormat=function(privStr){var bytes=Bitcoin.Base58.decode(privStr),hash=bytes.slice(0,34),checksum=Crypto.SHA256(Crypto.SHA256(hash,{asBytes:!0}),{asBytes:!0});if(checksum[0]!=bytes[34]||checksum[1]!=bytes[35]||checksum[2]!=bytes[36]||checksum[3]!=bytes[37])throw"Checksum validation failed!";hash.shift();return hash.pop(),hash},ECKey.isHexFormat=function(key){return key=key.toString(),/^[A-Fa-f0-9]{64}$/.test(key)},ECKey.isWalletImportFormat=function(key){return key=key.toString(),128==ECKey.privateKeyPrefix?/^5[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{50}$/.test(key):/^R[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{50}$/.test(key)},ECKey.isCompressedWalletImportFormat=function(key){return key=key.toString(),128==ECKey.privateKeyPrefix?/^[LK][123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{51}$/.test(key):/^R[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{51}$/.test(key)},ECKey.isBase64Format=function(key){return key=key.toString(),/^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789=+\/]{44}$/.test(key)},ECKey.isBase6Format=function(key){return key=key.toString(),/^[012345]{99}$/.test(key)},ECKey.isMiniFormat=function(key){key=key.toString();var validChars22=/^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21}$/.test(key),validChars26=/^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{25}$/.test(key),validChars30=/^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{29}$/.test(key),testBytes=Crypto.SHA256(key+"?",{asBytes:!0});return(0===testBytes[0]||1===testBytes[0])&&(validChars22||validChars26||validChars30)},ECKey}(),Bitcoin.Util={isArray:Array.isArray||function(o){return"[object Array]"===Object.prototype.toString.call(o)},makeFilledArray:function(len,val){for(var array=[],i=0;i>>8,255&i]:i<=1?[254].concat(Crypto.util.wordsToBytes([i])):[255].concat(Crypto.util.wordsToBytes([i>>>32,i]))},valueToBigInt:function(valueBuffer){return valueBuffer instanceof BigInteger?valueBuffer:BigInteger.fromByteArrayUnsigned(valueBuffer)},formatValue:function(valueBuffer){for(var value=this.valueToBigInt(valueBuffer).toString(),integerPart=value.length>8?value.substr(0,value.length-8):"0",decimalPart=value.length>8?value.substr(value.length-8):value;decimalPart.length<8;)decimalPart="0"+decimalPart;for(decimalPart=decimalPart.replace(/0*$/,"");decimalPart.length<2;)decimalPart+="0";return integerPart+"."+decimalPart},parseValue:function(valueString){for(var valueComp=valueString.split("."),integralPart=valueComp[0],fractionalPart=valueComp[1]||"0";fractionalPart.length<8;)fractionalPart+="0";fractionalPart=fractionalPart.replace(/^0+/g,"");var value=BigInteger.valueOf(parseInt(integralPart));return value=(value=value.multiply(BigInteger.valueOf(1e8))).add(BigInteger.valueOf(parseInt(fractionalPart)))},sha256ripe160:function(data){return ripemd160(Crypto.SHA256(data,{asBytes:!0}),{asBytes:!0})},dsha256:function(data){return Crypto.SHA256(Crypto.SHA256(data,{asBytes:!0}),{asBytes:!0})},hasMethods:function(obj){for(var methodName,i=1;methodName=arguments[i++];)if("function"!=typeof obj[methodName])return!1;return!0}}}(),(ellipticEncryption=GLOBAL.ellipticCurveEncryption=function(){}).rng=new SecureRandom,ellipticEncryption.getCurveParameters=function(curveName){curveName=void 0!==curveName?curveName:"secp256k1";var c=EllipticCurve.getSECCurveByName(curveName),curveDetails={Q:"",A:"",B:"",GX:"",GY:"",N:""};return curveDetails.Q=c.getCurve().getQ().toString(),curveDetails.A=c.getCurve().getA().toBigInteger().toString(),curveDetails.B=c.getCurve().getB().toBigInteger().toString(),curveDetails.GX=c.getG().getX().toBigInteger().toString(),curveDetails.GY=c.getG().getY().toBigInteger().toString(),curveDetails.N=c.getN().toString(),curveDetails},ellipticEncryption.selectedCurve=ellipticEncryption.getCurveParameters("secp256k1"),ellipticEncryption.get_curve=function(){return new EllipticCurve.CurveFp(new BigInteger(this.selectedCurve.Q),new BigInteger(this.selectedCurve.A),new BigInteger(this.selectedCurve.B))},ellipticEncryption.get_G=function(curve){return new EllipticCurve.PointFp(curve,curve.fromBigInteger(new BigInteger(this.selectedCurve.GX)),curve.fromBigInteger(new BigInteger(this.selectedCurve.GY)))},ellipticEncryption.pick_rand=function(){var n=new BigInteger(this.selectedCurve.N),n1=n.subtract(BigInteger.ONE);return new BigInteger(n.bitLength(),this.rng).mod(n1).add(BigInteger.ONE)},ellipticEncryption.senderRandom=function(){return this.pick_rand().toString()},ellipticEncryption.receiverRandom=function(){return this.pick_rand().toString()},ellipticEncryption.senderPublicString=function(senderPrivateKey){var senderKeyECData={},curve=this.get_curve(),G=this.get_G(curve),a=new BigInteger(senderPrivateKey),P=G.multiply(a);return senderKeyECData.XValuePublicString=P.getX().toBigInteger().toString(),senderKeyECData.YValuePublicString=P.getY().toBigInteger().toString(),senderKeyECData},ellipticEncryption.receiverPublicString=function(receiverPublicKey){var receiverKeyECData={},curve=this.get_curve(),G=this.get_G(curve),a=new BigInteger(receiverPublicKey),P=G.multiply(a);return receiverKeyECData.XValuePublicString=P.getX().toBigInteger().toString(),receiverKeyECData.YValuePublicString=P.getY().toBigInteger().toString(),receiverKeyECData},ellipticEncryption.senderSharedKeyDerivation=function(receiverPublicStringXValue,receiverPublicStringYValue,senderPrivateKey){var senderDerivedKey={},curve=this.get_curve(),P=new EllipticCurve.PointFp(curve,curve.fromBigInteger(new BigInteger(receiverPublicStringXValue)),curve.fromBigInteger(new BigInteger(receiverPublicStringYValue))),a=new BigInteger(senderPrivateKey),S=P.multiply(a);return senderDerivedKey.XValue=S.getX().toBigInteger().toString(),senderDerivedKey.YValue=S.getY().toBigInteger().toString(),senderDerivedKey},ellipticEncryption.receiverSharedKeyDerivation=function(senderPublicStringXValue,senderPublicStringYValue,receiverPrivateKey){var receiverDerivedKey={},curve=this.get_curve(),P=new EllipticCurve.PointFp(curve,curve.fromBigInteger(new BigInteger(senderPublicStringXValue)),curve.fromBigInteger(new BigInteger(senderPublicStringYValue))),a=new BigInteger(receiverPrivateKey),S=P.multiply(a);return receiverDerivedKey.XValue=S.getX().toBigInteger().toString(),receiverDerivedKey.YValue=S.getY().toBigInteger().toString(),receiverDerivedKey},function(){function n(a){throw a}var q=null;function s(a,b){this.a=a,this.b=b}function u(a,b){var g,d=[],h=(1<>>5]|=(a.charCodeAt(g/b)&h)<<32-b-g%32;return{value:d,binLen:f}}function x(a){var h,f,b=[],d=a.length;for(0!=d%2&&n("String of HEX type must be in byte increments"),h=0;h>>3]|=f<<24-h%8*4;return{value:b,binLen:4*d}}function B(a){var h,f,g,k,m,b=[],d=0;for(-1===a.search(/^[a-zA-Z0-9=+\/]+$/)&&n("Invalid character in base-64 string"),h=a.indexOf("="),a=a.replace(/\=/g,""),-1!==h&&h1&&"'"==c[c.length-1],child_index=2147483647&parseInt(use_private?c.slice(0,c.length-1):c);use_private&&(child_index+=2147483648);var key=(hdp=hdp.derive(child_index)).keys_extended.privkey&&""!=hdp.keys_extended.privkey?hdp.keys_extended.privkey:hdp.keys_extended.pubkey;hdp=coinjs.hd(key)}return hdp},derive:function(i){i=i||0;var k,key,pubkey,o,blob=Crypto.util.hexToBytes(this.keys.pubkey).concat(coinjs.numToBytes(i,4).reverse()),hash=new jsSHA(Crypto.util.bytesToHex(blob),"HEX").getHMAC(Crypto.util.bytesToHex(r.chain_code),"HEX","SHA-512","HEX"),il=new BigInteger(hash.slice(0,64),16),ir=Crypto.util.hexToBytes(hash.slice(64,128)),ecparams=EllipticCurve.getSECCurveByName("secp256k1");if(ecparams.getCurve(),(o=coinjs.clone(this)).chain_code=ir,o.child_index=i,"private"==this.type)k=il.add(new BigInteger([0].concat(Crypto.util.hexToBytes(this.keys.privkey)))).mod(ecparams.getN()),key=Crypto.util.bytesToHex(k.toByteArrayUnsigned()),pubkey=coinjs.newPubkey(key),o.keys={privkey:key,pubkey:pubkey,wif:coinjs.privkey2wif(key),address:coinjs.pubkey2address(pubkey)};else if("public"==this.type){q=ecparams.curve.decodePointHex(this.keys.pubkey);var curvePt=ecparams.getG().multiply(il).add(q),x=curvePt.getX().toBigInteger(),y=curvePt.getY().toBigInteger(),publicKeyBytesCompressed=EllipticCurve.integerToBytes(x,32);y.isEven()?publicKeyBytesCompressed.unshift(2):publicKeyBytesCompressed.unshift(3),pubkey=Crypto.util.bytesToHex(publicKeyBytesCompressed),o.keys={pubkey:pubkey,address:coinjs.pubkey2address(pubkey)}}return o.parent_fingerprint=ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(r.keys.pubkey),{asBytes:!0}),{asBytes:!0}).slice(0,4),o.keys_extended=o.extend(),o},master:function(pass){var seed=pass?Crypto.SHA256(pass):coinjs.newPrivkey(),I=new jsSHA(seed,"HEX").getHMAC("Bitcoin seed","TEXT","SHA-512","HEX"),chain=(Crypto.util.hexToBytes(I.slice(0,64)),Crypto.util.hexToBytes(I.slice(64,128)));return coinjs.hd().make({depth:0,parent_fingerprint:[0,0,0,0],child_index:0,chain_code:chain,privkey:I.slice(0,64),pubkey:coinjs.newPubkey(I.slice(0,64))})},make:function(data){var k=[];k.push(1*data.depth),k=(k=(k=k.concat(data.parent_fingerprint)).concat(coinjs.numToBytes(data.child_index,4).reverse())).concat(data.chain_code);var o={};if(data.privkey){var prv=coinjs.numToBytes(coinjs.hdkey.prv,4).reverse();(prv=prv.concat(k)).push(0),prv=prv.concat(Crypto.util.hexToBytes(data.privkey));var checksum=Crypto.SHA256(Crypto.SHA256(prv,{asBytes:!0}),{asBytes:!0}).slice(0,4),ret=prv.concat(checksum);o.privkey=coinjs.base58encode(ret)}if(data.pubkey){var pub=coinjs.numToBytes(coinjs.hdkey.pub,4).reverse();pub=(pub=pub.concat(k)).concat(Crypto.util.hexToBytes(data.pubkey)),checksum=Crypto.SHA256(Crypto.SHA256(pub,{asBytes:!0}),{asBytes:!0}).slice(0,4),ret=pub.concat(checksum),o.pubkey=coinjs.base58encode(ret)}return o}};return r.parse()},coinjs.script=function(data){var r={};return data?"string"==typeof data?r.buffer=Crypto.util.hexToBytes(data):coinjs.isArray(data)?r.buffer=data:data instanceof coinjs.script?r.buffer=data.buffer:r.buffer=data:r.buffer=[],r.parse=function(){var self=this;r.chunks=[];var i=0;function readChunk(n){self.chunks.push(self.buffer.slice(i,i+n)),i+=n}for(;i=240&&(opcode=opcode<<8|this.buffer[i++]),opcode>0&&opcode<76?readChunk(opcode):76==opcode?readChunk(this.buffer[i++]):77==opcode?readChunk(this.buffer[i++]<<8|this.buffer[i++]):78==opcode?readChunk(this.buffer[i++]<<24|this.buffer[i++]<<16|this.buffer[i++]<<8|this.buffer[i++]):this.chunks.push(opcode),i<0)break}return!0},r.decodeRedeemScript=function(script){var r=!1;try{var s=coinjs.script(Crypto.util.hexToBytes(script));if(s.chunks.length>=3&&174==s.chunks[s.chunks.length-1]){(r={}).signaturesRequired=s.chunks[0]-80;for(var pubkeys=[],i=1;i=3&&174==s.chunks[s.chunks.length-1]){(r={}).signaturesRequired=s.chunks[0]-80;for(var pubkeys=[],i=1;i>>8&255)):(this.buffer.push(78),this.buffer.push(255&data.length),this.buffer.push(data.length>>>8&255),this.buffer.push(data.length>>>16&255),this.buffer.push(data.length>>>24&255)),this.buffer=this.buffer.concat(data),this.chunks.push(data),!0},r.parse(),r},coinjs.transaction=function(){var r={version:1,lock_time:0,ins:[],outs:[],witness:!1,timestamp:null,block:null,addinput:function(txid,index,script,sequence){var o={};return o.outpoint={hash:txid,index:index},o.script=coinjs.script(script||[]),o.sequence=sequence||(0==r.lock_time?4294967295:0),this.ins.push(o)},addoutput:function(address,value){var o={};o.value=new BigInteger(""+Math.round(1*value*1e8),10);var s=coinjs.script();return o.script=s.spendToScript(address),this.outs.push(o)},addstealth:function(stealth,value){var ephemeralKeyBigInt=BigInteger.fromByteArrayUnsigned(Crypto.util.hexToBytes(coinjs.newPrivkey())),curve=EllipticCurve.getSECCurveByName("secp256k1"),p=EllipticCurve.fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"),a=BigInteger.ZERO,b=EllipticCurve.fromHex("7"),calccurve=new EllipticCurve.CurveFp(p,a,b),ephemeralPt=curve.getG().multiply(ephemeralKeyBigInt),sharedPt=calccurve.decodePointHex(stealth.scankey).multiply(ephemeralKeyBigInt),stealthindexKeyBigInt=BigInteger.fromByteArrayUnsigned(Crypto.SHA256(sharedPt.getEncoded(!0),{asBytes:!0})),stealthindexPt=curve.getG().multiply(stealthindexKeyBigInt),addressPt=calccurve.decodePointHex(stealth.spendkey).add(stealthindexPt),sendaddress=coinjs.pubkey2address(Crypto.util.bytesToHex(addressPt.getEncoded(!0))),OPRETBytes=[6].concat(Crypto.util.randomBytes(4)).concat(ephemeralPt.getEncoded(!0)),q=coinjs.script();q.writeOp(106),q.writeBytes(OPRETBytes),v={},v.value=0,v.script=q,this.outs.push(v);var o={};o.value=new BigInteger(""+Math.round(1*value*1e8),10);var s=coinjs.script();return o.script=s.spendToScript(sendaddress),this.outs.push(o)},adddata:function(data){if(data.match(/^[a-f0-9]+$/gi)&&data.length<160&&data.length%2==0){var s=coinjs.script();return s.writeOp(106),s.writeBytes(Crypto.util.hexToBytes(data)),o={},o.value=0,o.script=s,this.outs.push(o)}return!1},listUnspent:function(address,callback){coinjs.ajax(coinjs.host+"?uid="+coinjs.uid+"&key="+coinjs.key+"&setmodule=addresses&request=unspent&address="+address+"&r="+Math.random(),callback,"GET")},getTransaction:function(txid,callback){coinjs.ajax(coinjs.host+"?uid="+coinjs.uid+"&key="+coinjs.key+"&setmodule=bitcoin&request=gettransaction&txid="+txid+"&r="+Math.random(),callback,"GET")},addUnspent:function(address,callback,script,segwit,sequence){var self=this;this.listUnspent(address,(function(data){var s=coinjs.script(),value=0,total=0,x={};GLOBAL.DOMParser?(parser=new DOMParser,xmlDoc=parser.parseFromString(data,"text/xml")):(xmlDoc=new ActiveXObject("Microsoft.XMLDOM"),xmlDoc.async=!1,xmlDoc.loadXML(data));var unspent=xmlDoc.getElementsByTagName("unspent")[0];if(unspent)for(i=1;i<=unspent.childElementCount;i++){var u=xmlDoc.getElementsByTagName("unspent_"+i)[0],txhash=u.getElementsByTagName("tx_hash")[0].childNodes[0].nodeValue.match(/.{1,2}/g).reverse().join("")+"",n=u.getElementsByTagName("tx_output_n")[0].childNodes[0].nodeValue,scr=script||u.getElementsByTagName("script")[0].childNodes[0].nodeValue;segwit&&((s=coinjs.script()).writeBytes(Crypto.util.hexToBytes(script)),s.writeOp(0),s.writeBytes(coinjs.numToBytes(1*u.getElementsByTagName("value")[0].childNodes[0].nodeValue,8)),scr=Crypto.util.bytesToHex(s.buffer));var seq=sequence||!1;self.addinput(txhash,n,scr,seq),value+=1*u.getElementsByTagName("value")[0].childNodes[0].nodeValue,total++}return x.result=xmlDoc.getElementsByTagName("result")[0].childNodes[0].nodeValue,x.unspent=unspent,x.value=value,x.total=total,x.response=xmlDoc.getElementsByTagName("response")[0].childNodes[0].nodeValue,callback(x)}))},addUnspentAndSign:function(wif,callback){var self=this,address=coinjs.wif2address(wif);self.addUnspent(address.address,(function(data){return self.sign(wif),callback(data)}))},broadcast:function(callback,txhex){var tx=txhex||this.serialize();coinjs.ajax(coinjs.host+"?uid="+coinjs.uid+"&key="+coinjs.key+"&setmodule=bitcoin&request=sendrawtransaction",callback,"POST",["rawtx="+tx])},transactionHash:function(index,sigHashType){for(var clone=coinjs.clone(this),shType=sigHashType||1,i=0;i=128)if(clone.ins=[clone.ins[index]],129==shType);else if(130==shType)clone.outs=[];else if(131==shType)for(clone.outs.length=index+1,i=0;i80&&scriptcode.unshift(scriptcode.length);var value=coinjs.numToBytes(extract.value,8),zero=coinjs.numToBytes(0,32),version=coinjs.numToBytes(parseInt(this.version),4),bufferTmp=[];if(!(sigHashType>=80))for(var i=0;i=1?Crypto.SHA256(Crypto.SHA256(bufferTmp,{asBytes:!0}),{asBytes:!0}):zero;if(bufferTmp=[],!(sigHashType>=80)&&2!=sigHashType&&3!=sigHashType)for(i=0;i=1?Crypto.SHA256(Crypto.SHA256(bufferTmp,{asBytes:!0}),{asBytes:!0}):zero,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),hashOutputs=zero;if(bufferTmp=[],2!=sigHashType&&3!=sigHashType){for(i=0;i0&&(22==this.ins[index].script.chunks[0].length&&0==this.ins[index].script.chunks[0][0]||20==this.ins[index].script.chunks[0].length&&0==this.ins[index].script.chunks[1])){var sigs="true"==(signed=this.witness[index]&&2==this.witness[index].length?"true":"false")?1:0,value=-1;return this.ins[index].script.chunks[2]&&8==this.ins[index].script.chunks[2].length&&(value=coinjs.bytesToNum(this.ins[index].script.chunks[2])),{type:"segwit",signed:signed,signatures:sigs,script:Crypto.util.bytesToHex(this.ins[index].script.chunks[0]),value:value}}if(0==this.ins[index].script.chunks[0]&&174==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]){var sigcount=0;for(let i=1;i=80&&174==this.ins[index].script.chunks[this.ins[index].script.chunks.length-1])return{type:"multisig",signed:"false",signatures:0,script:Crypto.util.bytesToHex(this.ins[index].script.buffer)};if(3==this.ins[index].script.chunks.length&&this.ins[index].script.chunks[0][0]>=80&&174==this.ins[index].script.chunks[0][this.ins[index].script.chunks[0].length-1]&&0==this.ins[index].script.chunks[1]){let last_index=this.ins[index].script.chunks.length-1;return value=-1,last_index>=2&&8==this.ins[index].script.chunks[last_index].length&&(value=coinjs.bytesToNum(this.ins[index].script.chunks[last_index])),{type:"multisig_bech32",signed:"false",signatures:sigcount=this.witness[index]?this.witness[index].length-2:0,script:Crypto.util.bytesToHex(this.ins[index].script.chunks[0]),value:value}}var signed;return 0==this.ins[index].script.chunks.length?{type:"empty",signed:signed=this.witness[index]&&this.witness[index].length>=2?"true":"false",signatures:sigs="true"==signed?this.witness[index][0]?1:this.witness[index].length-2:0,script:""}:{type:"unknown",signed:"false",signatures:0,script:Crypto.util.bytesToHex(this.ins[index].script.buffer)}}return!1},transactionSig:function(index,wif,sigHashType,txhash){var shType=sigHashType||1,hash=txhash||Crypto.util.hexToBytes(this.transactionHash(index,shType));if(hash){var curve=EllipticCurve.getSECCurveByName("secp256k1"),key=coinjs.wif2privkey(wif),priv=BigInteger.fromByteArrayUnsigned(Crypto.util.hexToBytes(key.privkey)),n=curve.getN(),e=BigInteger.fromByteArrayUnsigned(hash),badrs=0;do{var k=this.deterministicK(wif,hash,badrs),r=curve.getG().multiply(k).getX().toBigInteger().mod(n),s=k.modInverse(n).multiply(e.add(priv.multiply(r))).mod(n);badrs++}while(r.compareTo(BigInteger.ZERO)<=0||s.compareTo(BigInteger.ZERO)<=0);var halfn=n.shiftRight(1);s.compareTo(halfn)>0&&(s=n.subtract(s));var sig=function(r,s){var rBa=r.toByteArraySigned(),sBa=s.toByteArraySigned(),sequence=[];return sequence.push(2),sequence.push(rBa.length),(sequence=sequence.concat(rBa)).push(2),sequence.push(sBa.length),(sequence=sequence.concat(sBa)).unshift(sequence.length),sequence.unshift(48),sequence}(r,s);return sig.push(parseInt(shType,10)),Crypto.util.bytesToHex(sig)}return!1},deterministicK:function(wif,hash,badrs){badrs=badrs||0;var key=coinjs.wif2privkey(wif),x=Crypto.util.hexToBytes(key.privkey),N=EllipticCurve.getSECCurveByName("secp256k1").getN(),v=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],k=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];k=Crypto.HMAC(Crypto.SHA256,v.concat([0]).concat(x).concat(hash),k,{asBytes:!0}),v=Crypto.HMAC(Crypto.SHA256,v,k,{asBytes:!0}),k=Crypto.HMAC(Crypto.SHA256,v.concat([1]).concat(x).concat(hash),k,{asBytes:!0}),v=Crypto.HMAC(Crypto.SHA256,v,k,{asBytes:!0});var T=[];T=v=Crypto.HMAC(Crypto.SHA256,v,k,{asBytes:!0});for(var KBigInt=BigInteger.fromByteArrayUnsigned(T),i=0;KBigInt.compareTo(N)>=0||KBigInt.compareTo(BigInteger.ZERO)<=0||i=decode_rs.signaturesRequired&&(this.ins[index].script=coinjs.script()),w.unshift(0),w.push(redeemScript),this.witness[index]=w}},signmultisig:function(index,wif,sigHashType){var redeemScript=174==this.ins[index].script.chunks[this.ins[index].script.chunks.length-1]?this.ins[index].script.buffer:this.ins[index].script.chunks[this.ins[index].script.chunks.length-1],pubkeyList=function(redeemScript){for(var r={},i=1;i=1)for(i=0;i0&&(s=n.subtract(s));var sig=function(r,s){var rBa=r.toByteArraySigned(),sBa=s.toByteArraySigned(),sequence=[];return sequence.push(2),sequence.push(rBa.length),(sequence=sequence.concat(rBa)).push(2),sequence.push(sBa.length),(sequence=sequence.concat(sBa)).unshift(sequence.length),sequence.unshift(48),sequence}(r,s);return sig.push(parseInt(shType,10)),Crypto.util.bytesToHex(sig)}return!1},deserialize:function(buffer){"string"==typeof buffer&&(buffer=Crypto.util.hexToBytes(buffer));var pos=0,witness=!1,readAsInt=function(bytes){return 0==bytes?0:(pos++,buffer[pos-1]+256*readAsInt(bytes-1))},readVarInt=function(){return pos++,buffer[pos-1]<253?buffer[pos-1]:readAsInt(buffer[pos-1]-251)},readBytes=function(bytes){return pos+=bytes,buffer.slice(pos-bytes,pos)},readVarString=function(){var size=readVarInt();return readBytes(size)},obj=new coinjs.transaction;obj.version=readAsInt(4),0==buffer[pos]&&1==buffer[pos+1]&&(witness=!0,obj.witness=[],pos+=2);for(var ins=readVarInt(),i=0;i=0)return!1;if(s.compareTo(BigInteger.ONE)<0||s.compareTo(n)>=0)return!1;var c=s.modInverse(n),u1=e.multiply(c).mod(n),u2=r.multiply(c).mod(n);return G.multiply(u1).add(Q.multiply(u2)).getX().toBigInteger().mod(n).equals(r)},coinjs.base58encode=function(buffer){for(var alphabet="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",base=BigInteger.valueOf(58),bi=BigInteger.fromByteArrayUnsigned(buffer),chars=[];bi.compareTo(base)>=0;){var mod=bi.mod(base);chars.unshift(alphabet[mod.intValue()]),bi=bi.subtract(mod).divide(base)}chars.unshift(alphabet[bi.intValue()]);for(var i=0;i=0;i--){var alphaIndex="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".indexOf(buffer[i]);if(alphaIndex<0)throw"Invalid character";bi=bi.add(BigInteger.valueOf(alphaIndex).multiply(base.pow(buffer.length-1-i))),"1"==buffer[i]?leadingZerosNum++:leadingZerosNum=0}for(var bytes=bi.toByteArrayUnsigned();leadingZerosNum-- >0;)bytes.unshift(0);return bytes},coinjs.ajax=function(u,f,m,a){var x=!1;try{x=new ActiveXObject("Msxml2.XMLHTTP")}catch(e){try{x=new ActiveXObject("Microsoft.XMLHTTP")}catch(e){x=new XMLHttpRequest}}if(0==x)return!1;x.open(m,u,!0),x.onreadystatechange=function(){4==x.readyState&&f&&f(x.responseText)},"POST"==m&&x.setRequestHeader("Content-type","application/x-www-form-urlencoded"),x.send(a)},coinjs.clone=function(obj){if(null==obj||"object"!=typeof obj)return obj;var temp=new obj.constructor;for(var key in obj)obj.hasOwnProperty(key)&&(temp[key]=coinjs.clone(obj[key]));return temp},coinjs.numToBytes=function(num,bytes){return void 0===bytes&&(bytes=8),0==bytes?[]:-1==num?Crypto.util.hexToBytes("ffffffffffffffff"):[num%256].concat(coinjs.numToBytes(Math.floor(num/256),bytes-1))},coinjs.numToScriptNumBytes=function(_number){for(var value=Math.abs(_number),size=function(i){return i>2147483647?5:i>8388607?4:i>32767?3:i>127?2:i>0?1:0}(value),result=[],i=0;i{const result=[];let len=string.length-2;for(;len>=0;)result.push(string.substr(len,2)),len-=2;return result.join("")},coinjs.getTransactionHash=function(transaction_in_hex,changeOutputEndianess){var x1,x2,x3,x4,x5;return x1=Crypto.util.hexToBytes(transaction_in_hex),x2=Crypto.SHA256(x1),x3=Crypto.util.hexToBytes(x2),x4=Crypto.SHA256(x3),x5=coinjs.changeEndianness(x4),1==changeOutputEndianess||void 0!==changeOutputEndianess&&0!=changeOutputEndianess||(x5=x4),x5},coinjs.compressedToUncompressed=function(compressed){var t1,curve=EllipticCurve.getSECCurveByName("secp256k1");return t1=curve.curve.decodePointHex(compressed),curve.curve.encodePointHex(t1)},coinjs.uncompressedToCompressed=function(uncompressed){var t1;return t1=uncompressed.charAt(uncompressed.length-1),(parseInt(t1,10)%2==1?"03":"02")+uncompressed.substr(2,64)},coinjs.verifySignatureHex=function(hashHex,sigHex,pubHexCompressed){var h1,s1,p1,p2;return h1=Crypto.util.hexToBytes(hashHex),s1=Crypto.util.hexToBytes(sigHex),p1=coinjs.compressedToUncompressed(pubHexCompressed),p2=Crypto.util.hexToBytes(p1),coinjs.verifySignature(h1,s1,p2)},coinjs.generateBitcoinSignature=function(private_key,hash,sighash_type_int=1){var wif;return wif=private_key.length<60?private_key:coinjs.privkey2wif(private_key),coinjs.transaction().transactionSigNoIndex(wif,sighash_type_int,hash)},coinjs.dSHA256=function(data){var t1,t2;return t1=Crypto.SHA256(Crypto.util.hexToBytes(data)),t2=Crypto.util.hexToBytes(t1),Crypto.SHA256(t2)},coinjs.fromBitcoinAmountFormat=function(data){var x1;return x1=coinjs.changeEndianness(data),parseInt(x1,16)/10**8},coinjs.toBitcoinAmountFormat=function(countBitcoin){var t3;return t3=(countBitcoin*10**8).toString(16),coinjs.changeEndianness(t3).padEnd(16,"0")},coinjs.scriptcodeCreatorBasic=function(scriptpubkey){return"0014"==scriptpubkey.substr(0,4)?"1976a9"+scriptpubkey.slice(2)+"88ac":(scriptpubkey.length/2).toString(16)+scriptpubkey},coinjs.ripemd160sha256=function(data){var t1;return t1=ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(data),{asBytes:!0}),{asBytes:!0}),Crypto.util.bytesToHex(t1)},coinjs.random=function(length){var r="",l=length||25;for(let x=0;x<|./;'#][=-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".charAt(Math.floor(62*Math.random()));return r},function(){var SecretShare=GLOBAL.shamirSecretShare={},defaults={bits:8,radix:16,minBits:3,maxBits:20,bytesPerChar:2,maxBytesPerChar:6,primitivePolynomials:[null,null,1,3,3,5,3,3,29,17,9,5,83,27,43,3,45,9,39,39,9,5,3,33,27,9,71,39,9,5,83],warning:"WARNING:\nA secure random number generator was not found.\nUsing securedMathRandom(), which is NOT cryptographically strong!"},config={};function init(bits){if(bits&&("number"!=typeof bits||bits%1!=0||bitsdefaults.maxBits))throw new Error("Number of bits must be an integer between "+defaults.minBits+" and "+defaults.maxBits+", inclusive.");config.radix=defaults.radix,config.bits=bits||defaults.bits,config.size=Math.pow(2,config.bits),config.max=config.size-1;for(var logs=[],exps=[],x=1,primitive=defaults.primitivePolynomials[config.bits],i=0;i=config.size&&(x^=primitive,x&=config.max);config.logs=logs,config.exps=exps}function isInited(){return!!(config.bits&&config.size&&config.max&&config.logs&&config.exps&&config.logs.length===config.size&&config.exps.length===config.size)}function warn(){GLOBAL.console.warn(defaults.warning),"function"==typeof GLOBAL.alert&&config.alert&&GLOBAL.alert(defaults.warning)}function isSetRNG(){return"function"==typeof config.rng}function horner(x,coeffs){for(var logx=config.logs[x],fx=0,i=coeffs.length-1;i>=0;i--)fx=0!==fx?config.exps[(logx+config.logs[fx])%config.max]^coeffs[i]:coeffs[i];return fx}function inArray(arr,val){for(var i=0,len=arr.length;idefaults.maxBits))throw new Error("Number of bits must be an integer between "+defaults.minBits+" and "+defaults.maxBits+", inclusive.");var max=Math.pow(2,bits)-1,idLength=max.toString(config.radix).length,id=parseInt(share.substr(1,idLength),config.radix);if("number"!=typeof id||id%1!=0||id<1||id>max)throw new Error("Share id must be an integer between 1 and "+config.max+", inclusive.");if(!(share=share.substr(idLength+1)).length)throw new Error("Invalid share: zero-length share.");return{bits:bits,id:id,value:share}}function combine(at,shares){for(var setBits,share,x=[],y=[],result="",i=0,len=shares.length;iconfig.bits;i-=config.bits)parts.push(parseInt(str.slice(i-config.bits,i),2));return parts.push(parseInt(str.slice(0,i),2)),parts}function padLeft(str,bits){bits=bits||config.bits;var missing=str.length%bits;return(missing?new Array(bits-missing+1).join("0"):"")+str}function hex2bin(str){for(var num,bin="",i=str.length-1;i>=0;i--){if(num=parseInt(str[i],16),isNaN(num))throw new Error("Invalid hex character.");bin=padLeft(num.toString(2),4)+bin}return bin}function bin2hex(str){for(var num,hex="",i=(str=padLeft(str,4)).length;i>=4;i-=4){if(num=parseInt(str.slice(i-4,i),2),isNaN(num))throw new Error("Invalid binary character.");hex=num.toString(16)+hex}return hex}SecretShare.getConfig=function(){return{bits:config.bits,unsafePRNG:config.unsafePRNG}},SecretShare.init=init,SecretShare.setRNG=function(rng,alert){if(isInited()||this.init(),config.unsafePRNG=!1,"function"!=typeof(rng=rng||function(){var crypto;function construct(bits,arr,radix,size){for(var str="",i=0,len=arr.length-1;iconfig.bits||rng(config.bits).lengthconfig.max){var neededBits=Math.ceil(Math.log(numShares+1)/Math.LN2);throw new Error("Number of shares must be an integer between 2 and 2^bits-1 ("+config.max+"), inclusive. To create "+numShares+" shares, use at least "+neededBits+" bits.")}if("number"!=typeof threshold||threshold%1!=0||threshold<2)throw new Error("Threshold number of shares must be an integer between 2 and 2^bits-1 ("+config.max+"), inclusive.");if(threshold>config.max){neededBits=Math.ceil(Math.log(threshold+1)/Math.LN2);throw new Error("Threshold number of shares must be an integer between 2 and 2^bits-1 ("+config.max+"), inclusive. To use a threshold of "+threshold+", use at least "+neededBits+" bits.")}if("number"!=typeof padLength||padLength%1!=0)throw new Error("Zero-pad length must be an integer greater than 1.");config.unsafePRNG&&warn(),secret=split(secret="1"+hex2bin(secret),padLength);for(var x=new Array(numShares),y=new Array(numShares),i=0,len=secret.length;imax)throw new Error("Share id must be an integer between 1 and "+config.max+", inclusive.");var padding=max.toString(config.radix).length;return config.bits.toString(36).toUpperCase()+padLeft(id.toString(config.radix),padding)+combine(id,shares)},SecretShare._lagrange=lagrange,SecretShare.str2hex=function(str,bytesPerChar){if("string"!=typeof str)throw new Error("Input must be a character string.");if("number"!=typeof(bytesPerChar=bytesPerChar||defaults.bytesPerChar)||bytesPerChar%1!=0||bytesPerChar<1||bytesPerChar>defaults.maxBytesPerChar)throw new Error("Bytes per character must be an integer between 1 and "+defaults.maxBytesPerChar+", inclusive.");for(var num,hexChars=2*bytesPerChar,max=Math.pow(16,hexChars)-1,out="",i=0,len=str.length;imax){var neededBytes=Math.ceil(Math.log(num+1)/Math.log(256));throw new Error("Invalid character code ("+num+"). Maximum allowable is 256^bytes-1 ("+max+"). To convert this character, use at least "+neededBytes+" bytes.")}out=padLeft(num.toString(16),hexChars)+out}return out},SecretShare.hex2str=function(str,bytesPerChar){if("string"!=typeof str)throw new Error("Input must be a hexadecimal string.");if("number"!=typeof(bytesPerChar=bytesPerChar||defaults.bytesPerChar)||bytesPerChar%1!=0||bytesPerChar<1||bytesPerChar>defaults.maxBytesPerChar)throw new Error("Bytes per character must be an integer between 1 and "+defaults.maxBytesPerChar+", inclusive.");for(var hexChars=2*bytesPerChar,out="",i=0,len=(str=padLeft(str,hexChars)).length;icandidate.vectorClock?incumbent:candidate},this.distance=function(firstId,secondId){let distance=0,i=0;const min=Math.min(firstId.length,secondId.length),max=Math.max(firstId.length,secondId.length);for(;i=0?(this._update(node,index,contact),this):node.contacts.length0&&contacts.length[this.distance(a.id,id),a])).sort(((a,b)=>a[0]-b[0])).slice(0,n).map((a=>a[1]))},this.count=function(){let count=0;for(const nodes=[this.root];nodes.length>0;){const node=nodes.pop();null===node.contacts?nodes.push(node.right,node.left):count+=node.contacts.length}return count},this._determineNode=function(node,id,bitIndex){const bytesDescribedByBitIndex=bitIndex>>3,bitIndexWithinByte=bitIndex%8;return id.length<=bytesDescribedByBitIndex&&0!==bitIndexWithinByte?node.left:id[bytesDescribedByBitIndex]&1<<7-bitIndexWithinByte?node.right:node.left},this.get=function(id){this.ensureInt8("id",id);let bitIndex=0,node=this.root;for(;null===node.contacts;)node=this._determineNode(node,id,bitIndex++);const index=this._indexOf(node,id);return index>=0?node.contacts[index]:null},this._indexOf=function(node,id){for(let i=0;i=0&&node.contacts.splice(index,1)[0],this},this._split=function(node,bitIndex){node.left=this.createNode(),node.right=this.createNode();for(const contact of node.contacts)this._determineNode(node,contact.id,bitIndex).contacts.push(contact);node.contacts=null;const detNode=this._determineNode(node,this.localNodeId,bitIndex);(node.left===detNode?node.right:node.left).dontSplit=!0},this.toArray=function(){let result=[];for(const nodes=[this.root];nodes.length>0;){const node=nodes.pop();null===node.contacts?nodes.push(node.right,node.left):result=result.concat(node.contacts)}return result},this._update=function(node,index,contact){if(!this.arrayEquals(node.contacts[index].id,contact.id))throw new Error("wrong index for _update");const incumbent=node.contacts[index],selection=this.arbiter(incumbent,contact);selection===incumbent&&incumbent!==contact||(node.contacts.splice(index,1),node.contacts.push(selection))}}}("undefined"!=typeof global?global:window); \ No newline at end of file