diff --git a/react/change.log b/react/change.log index 65eee02..5ee34f5 100644 --- a/react/change.log +++ b/react/change.log @@ -16,6 +16,10 @@ UI: - qr code generator / scan - basilisk send form reset fix - added native wallet info button +- added coqui assetchain +- jumblr +- zcashparams folder check +- claim interest modal v0.2.0.21a-beta -------------- diff --git a/react/src/actions/actionCreators.js b/react/src/actions/actionCreators.js index 69d451c..5919f83 100644 --- a/react/src/actions/actionCreators.js +++ b/react/src/actions/actionCreators.js @@ -27,6 +27,7 @@ import { DASHBOARD_ACTIVE_COIN_NATIVE_TXHISTORY, DISPLAY_LOGIN_SETTINGS_MODAL, DISPLAY_COIND_DOWN_MODAL, + DISPLAY_CLAIM_INTEREST_MODAL, START_INTERVAL, STOP_INTERVAL } from './storeType'; @@ -68,6 +69,8 @@ export * from './actions/basiliskTxHistory'; export * from './actions/iguanaHelpers'; export * from './actions/cli'; export * from './actions/update'; +export * from './actions/jumblr'; +export * from './actions/interest'; export function changeActiveAddress(address) { return { @@ -366,4 +369,11 @@ export function toggleLoginSettingsModal(display) { type: DISPLAY_LOGIN_SETTINGS_MODAL, displayLoginSettingsModal: display, } +} + +export function toggleClaimInterestModal(display) { + return { + type: DISPLAY_CLAIM_INTEREST_MODAL, + displayClaimInterestModal: display, + } } \ No newline at end of file diff --git a/react/src/actions/actions/copyAddress.js b/react/src/actions/actions/copyAddress.js index 9bf15fe..9accd3b 100644 --- a/react/src/actions/actions/copyAddress.js +++ b/react/src/actions/actions/copyAddress.js @@ -14,4 +14,18 @@ export function copyCoinAddress(address) { ) ); } +} + +export function copyString(string, message) { + const _result = copyToClipboard(string); + + return dispatch => { + dispatch( + triggerToaster( + message, + translate('TOASTR.COIN_NOTIFICATION'), + _result ? 'success' : 'error' + ) + ); + } } \ No newline at end of file diff --git a/react/src/actions/actions/interest.js b/react/src/actions/actions/interest.js new file mode 100644 index 0000000..1dd95c6 --- /dev/null +++ b/react/src/actions/actions/interest.js @@ -0,0 +1,86 @@ +import { + triggerToaster +} from '../actionCreators'; +import { + logGuiHttp, + guiLogState +} from './log'; +import Config from '../../config'; + +export function getListUnspent(coin) { + return new Promise((resolve, reject) => { + const payload = { + mode: null, + chain: coin, + cmd: 'listunspent', + }; + + const _fetchConfig = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ 'payload': payload }), + }; + + fetch( + `http://127.0.0.1:${Config.agamaPort}/shepherd/cli`, + _fetchConfig + ) + .catch(function(error) { + console.log(error); + dispatch( + triggerToaster( + 'getListUnspent', + 'Error', + 'error' + ) + ); + }) + .then(response => response.json()) + .then(json => { + resolve(json.result ? json.result : json); + }) + }); +} + +export function getRawTransaction(coin, txid) { + return new Promise((resolve, reject) => { + const payload = { + mode: null, + chain: coin, + cmd: 'getrawtransaction', + params: [ + txid, + 1 + ], + }; + + const _fetchConfig = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ 'payload': payload }), + }; + + fetch( + `http://127.0.0.1:${Config.agamaPort}/shepherd/cli`, + _fetchConfig + ) + .catch(function(error) { + console.log(error); + dispatch( + triggerToaster( + 'getTransaction', + 'Error', + 'error' + ) + ); + }) + .then(response => response.json()) + .then(json => { + resolve(json.result ? json.result : json); + }) + }); +} \ No newline at end of file diff --git a/react/src/actions/actions/jumblr.js b/react/src/actions/actions/jumblr.js new file mode 100644 index 0000000..c734c07 --- /dev/null +++ b/react/src/actions/actions/jumblr.js @@ -0,0 +1,164 @@ +import { + triggerToaster, + getNewKMDAddresses +} from '../actionCreators'; +import { + logGuiHttp, + guiLogState +} from './log'; +import Config from '../../config'; + +function getNewAddress(coin) { // TODO: remove(?) + return new Promise((resolve, reject) => { + const payload = { + mode: null, + chain: coin, + cmd: 'getnewaddress' + }; + + const _fetchConfig = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ 'payload': payload }), + }; + + fetch( + `http://127.0.0.1:${Config.agamaPort}/shepherd/cli`, + _fetchConfig + ) + .catch(function(error) { + console.log(error); + dispatch( + triggerToaster( + 'genJumblrAddress + getKMDAddressesNative', + 'Error', + 'error' + ) + ); + }) + .then(response => response.json()) + .then(json => { + resolve(json.result ? json.result : json); + }) + }); +} + +export function setJumblrAddress(coin, type, address) { + return new Promise((resolve, reject) => { + const payload = { + mode: null, + chain: coin, + cmd: type === 'deposit' ? 'jumblr_deposit' : 'jumblr_secret', + params: [address], + }; + + const _fetchConfig = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ 'payload': payload }), + }; + + fetch( + `http://127.0.0.1:${Config.agamaPort}/shepherd/cli`, + _fetchConfig + ) + .catch(function(error) { + console.log(error); + dispatch( + triggerToaster( + 'setJumblrAddress', + 'Error', + 'error' + ) + ); + }) + .then(response => response.json()) + .then(json => { + resolve(json); + }); + }); +} + +function dumpPrivkey(coin, key) { + return new Promise((resolve, reject) => { + const payload = { + mode: null, + chain: coin, + cmd: 'dumpprivkey', + params: [key], + }; + + const _fetchConfig = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ 'payload': payload }), + }; + + fetch( + `http://127.0.0.1:${Config.agamaPort}/shepherd/cli`, + _fetchConfig + ) + .catch(function(error) { + console.log(error); + dispatch( + triggerToaster( + 'dumpPrivkey ', + 'Error', + 'error' + ) + ); + }) + .then(response => response.json()) + .then(json => { + resolve(json.result ? json.result : json); + }) + }); +} + +export function importPrivkey(coin, key) { + return new Promise((resolve, reject) => { + const payload = { + mode: null, + chain: coin, + cmd: 'importprivkey', + params: [ + key, + '', + false + ], + }; + + const _fetchConfig = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ 'payload': payload }), + }; + + fetch( + `http://127.0.0.1:${Config.agamaPort}/shepherd/cli`, + _fetchConfig + ) + .catch(function(error) { + console.log(error); + dispatch( + triggerToaster( + 'importPrivkey ', + 'Error', + 'error' + ) + ); + }) + .then(response => response.json()) + .then(json => { + resolve(json.result ? json.result : json); + }) + }); +} \ No newline at end of file diff --git a/react/src/actions/actions/log.js b/react/src/actions/actions/log.js index ca42d5b..c53f402 100644 --- a/react/src/actions/actions/log.js +++ b/react/src/actions/actions/log.js @@ -41,7 +41,6 @@ export function getAgamaLog(type) { ); }) .then(response => response.json()) - .then() } } diff --git a/react/src/actions/actions/nativeNewAddress.js b/react/src/actions/actions/nativeNewAddress.js index 4bd4088..e3f9821 100644 --- a/react/src/actions/actions/nativeNewAddress.js +++ b/react/src/actions/actions/nativeNewAddress.js @@ -10,21 +10,7 @@ import { guiLogState } from './log'; -function handleGetNewKMDAddresses(pubpriv, coin, dispatch, json) { - dispatch( - triggerToaster( - json.result ? json.result : json, - translate('KMD_NATIVE.NEW_ADDR_GENERATED'), - 'info', - false - ) - ); - dispatch(getKMDAddressesNative(coin)); - - return {}; -} - -export function getNewKMDAddresses(coin, pubpriv) { +export function getNewKMDAddresses(coin, pubpriv, mode) { let payload; let ajaxFunctionInput = pubpriv === 'public' ? 'getnewaddress' : 'z_getnewaddress'; @@ -115,22 +101,25 @@ export function getNewKMDAddresses(coin, pubpriv) { })); } dispatch( - handleGetNewKMDAddresses( - pubpriv, - coin, - dispatch, - json + triggerToaster( + json.result ? json.result : json, + translate('KMD_NATIVE.NEW_ADDR_GENERATED'), + 'info', + false ) ); + dispatch(getKMDAddressesNative(coin, mode)); }) .catch(function(ex) { dispatch( - handleGetNewKMDAddresses( - pubpriv, - coin, - dispatch + triggerToaster( + json.result ? json.result : json, + translate('KMD_NATIVE.NEW_ADDR_GENERATED'), + 'info', + false ) ); + dispatch(getKMDAddressesNative(coin, mode)); }); } } \ No newline at end of file diff --git a/react/src/actions/actions/nativeSend.js b/react/src/actions/actions/nativeSend.js index 0f788c8..fc3e3e2 100644 --- a/react/src/actions/actions/nativeSend.js +++ b/react/src/actions/actions/nativeSend.js @@ -195,7 +195,7 @@ export function getKMDOPID(opid, coin) { passthruAgent = getPassthruAgent(coin), tmpIguanaRPCAuth = `tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}`; - if (passthruAgent == 'iguana') { + if (passthruAgent === 'iguana') { payload = { 'userpass': tmpIguanaRPCAuth, 'agent': passthruAgent, @@ -284,4 +284,48 @@ export function getKMDOPID(opid, coin) { }) }) } +} + +export function sendToAddressPromise(coin, address, amount) { + return new Promise((resolve, reject) => { + const payload = { + mode: null, + chain: coin, + cmd: 'sendtoaddress', + params: [ + address, + amount, + 'KMD interest claim request', + 'KMD interest claim request', + true + ] + }; + + const _fetchConfig = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ 'payload': payload }), + }; + + fetch( + `http://127.0.0.1:${Config.agamaPort}/shepherd/cli`, + _fetchConfig + ) + .catch(function(error) { + console.log(error); + dispatch( + triggerToaster( + 'sendToAddress', + 'Error', + 'error' + ) + ); + }) + .then(response => response.json()) + .then(json => { + resolve(json); + }) + }); } \ No newline at end of file diff --git a/react/src/actions/actions/nativeSyncInfo.js b/react/src/actions/actions/nativeSyncInfo.js index 8260128..009c190 100644 --- a/react/src/actions/actions/nativeSyncInfo.js +++ b/react/src/actions/actions/nativeSyncInfo.js @@ -11,9 +11,9 @@ import { } from './log'; import Config from '../../config'; -export function getSyncInfoNativeKMD(skipDebug) { +export function getSyncInfoNativeKMD(skipDebug, json) { const coin = 'KMD'; - + // https://www.kmd.host/ return dispatch => { const _timestamp = Date.now(); if (Config.debug) { @@ -40,13 +40,15 @@ export function getSyncInfoNativeKMD(skipDebug) { 'response': error, })); } - dispatch( + /*dispatch( triggerToaster( 'getSyncInfoNativeKMD', 'Error', 'error' ) - ); + );*/ + console.warn('remote kmd node fetch failed', true); + dispatch(getSyncInfoNativeState({ 'remoteKMDNode': null })); }) .then(response => response.json()) .then(json => { @@ -72,7 +74,7 @@ function getSyncInfoNativeState(json, coin, skipDebug) { json && json.error && json.error.message.indexOf('Activating best') === -1) { - return getSyncInfoNativeKMD(skipDebug); + return getSyncInfoNativeKMD(skipDebug, json); } else { if (json && json.error && @@ -161,41 +163,60 @@ export function getSyncInfoNative(coin, skipDebug) { return _response; }) .then(json => { - if (!json && - Config.cli.default) { + if (json === 'Work queue depth exceeded') { dispatch( - triggerToaster( - 'Komodod is down', - 'Critical Error', - 'error', - true + getSyncInfoNativeState( + { result: 'daemon is busy', error: null, id: null }, + coin, + skipDebug ) ); - dispatch(getDebugLog('komodo', 50)); - dispatch(toggleCoindDownModal(true)); } else { - json = JSON.parse(json); - } + if (!json && + Config.cli.default) { + dispatch( + triggerToaster( + 'Komodod is down', + 'Critical Error', + 'error', + true + ) + ); - if (json.error && - json.error.message.indexOf('Activating best') === -1) { - dispatch(getDebugLog('komodo', 1)); - } + if (coin === 'KMD') { + dispatch(getDebugLog('komodo', 50)); + } else { + dispatch(getDebugLog('komodo', 50, coin)); + } + dispatch(toggleCoindDownModal(true)); + } else { + json = JSON.parse(json); + } - if (Config.debug) { - dispatch(logGuiHttp({ - 'timestamp': _timestamp, - 'status': 'success', - 'response': json, - })); + if (json.error && + json.error.message.indexOf('Activating best') === -1) { + if (coin === 'KMD') { + dispatch(getDebugLog('komodo', 1)); + } else { + dispatch(getDebugLog('komodo', 1, coin)); + } + } + + if (Config.debug) { + dispatch(logGuiHttp({ + 'timestamp': _timestamp, + 'status': 'success', + 'response': json, + })); + } + dispatch( + getSyncInfoNativeState( + json, + coin, + skipDebug + ) + ); } - dispatch( - getSyncInfoNativeState( - json, - coin, - skipDebug - ) - ); }) } } \ No newline at end of file diff --git a/react/src/actions/actions/settings.js b/react/src/actions/actions/settings.js index f38adfa..2b53637 100644 --- a/react/src/actions/actions/settings.js +++ b/react/src/actions/actions/settings.js @@ -167,12 +167,16 @@ function getDebugLogState(json) { } } -export function getDebugLog(target, linesCount) { +export function getDebugLog(target, linesCount, acName) { const payload = { 'herdname': target, 'lastLines': linesCount }; + if (acName) { + payload['ac'] = acName; + } + return dispatch => { return fetch(`http://127.0.0.1:${Config.agamaPort}/shepherd/debuglog`, { method: 'POST', diff --git a/react/src/actions/storeType.js b/react/src/actions/storeType.js index 23deb33..1e4c8af 100644 --- a/react/src/actions/storeType.js +++ b/react/src/actions/storeType.js @@ -45,4 +45,5 @@ export const LOG_GUI_HTTP = 'LOG_GUI_HTTP'; export const CLI = 'CLI'; export const LOGOUT = 'LOGOUT'; export const DISPLAY_COIND_DOWN_MODAL = 'DISPLAY_COIND_DOWN_MODAL'; -export const DISPLAY_LOGIN_SETTINGS_MODAL = 'DISPLAY_LOGIN_SETTINGS_MODAL'; \ No newline at end of file +export const DISPLAY_LOGIN_SETTINGS_MODAL = 'DISPLAY_LOGIN_SETTINGS_MODAL'; +export const DISPLAY_CLAIM_INTEREST_MODAL = 'DISPLAY_CLAIM_INTEREST_MODAL'; \ No newline at end of file diff --git a/react/src/assets/images/cryptologo/AUD.png b/react/src/assets/images/cryptologo/aud.png similarity index 100% rename from react/src/assets/images/cryptologo/AUD.png rename to react/src/assets/images/cryptologo/aud.png diff --git a/react/src/assets/images/cryptologo/BET.png b/react/src/assets/images/cryptologo/bet.png similarity index 100% rename from react/src/assets/images/cryptologo/BET.png rename to react/src/assets/images/cryptologo/bet.png diff --git a/react/src/assets/images/cryptologo/BGN.png b/react/src/assets/images/cryptologo/bgn.png similarity index 100% rename from react/src/assets/images/cryptologo/BGN.png rename to react/src/assets/images/cryptologo/bgn.png diff --git a/react/src/assets/images/cryptologo/BOTS.png b/react/src/assets/images/cryptologo/bots.png similarity index 100% rename from react/src/assets/images/cryptologo/BOTS.png rename to react/src/assets/images/cryptologo/bots.png diff --git a/react/src/assets/images/cryptologo/BRL.png b/react/src/assets/images/cryptologo/brl.png similarity index 100% rename from react/src/assets/images/cryptologo/BRL.png rename to react/src/assets/images/cryptologo/brl.png diff --git a/react/src/assets/images/cryptologo/CAD.png b/react/src/assets/images/cryptologo/cad.png similarity index 100% rename from react/src/assets/images/cryptologo/CAD.png rename to react/src/assets/images/cryptologo/cad.png diff --git a/react/src/assets/images/cryptologo/CEAL.png b/react/src/assets/images/cryptologo/ceal.png similarity index 100% rename from react/src/assets/images/cryptologo/CEAL.png rename to react/src/assets/images/cryptologo/ceal.png diff --git a/react/src/assets/images/cryptologo/CHF.png b/react/src/assets/images/cryptologo/chf.png similarity index 100% rename from react/src/assets/images/cryptologo/CHF.png rename to react/src/assets/images/cryptologo/chf.png diff --git a/react/src/assets/images/cryptologo/CNY.png b/react/src/assets/images/cryptologo/cny.png similarity index 100% rename from react/src/assets/images/cryptologo/CNY.png rename to react/src/assets/images/cryptologo/cny.png diff --git a/react/src/assets/images/cryptologo/coqui.png b/react/src/assets/images/cryptologo/coqui.png new file mode 100644 index 0000000..59f61a8 Binary files /dev/null and b/react/src/assets/images/cryptologo/coqui.png differ diff --git a/react/src/assets/images/cryptologo/CRYPTO.png b/react/src/assets/images/cryptologo/crypto.png similarity index 100% rename from react/src/assets/images/cryptologo/CRYPTO.png rename to react/src/assets/images/cryptologo/crypto.png diff --git a/react/src/assets/images/cryptologo/CZK.png b/react/src/assets/images/cryptologo/czk.png similarity index 100% rename from react/src/assets/images/cryptologo/CZK.png rename to react/src/assets/images/cryptologo/czk.png diff --git a/react/src/assets/images/cryptologo/DKK.png b/react/src/assets/images/cryptologo/dkk.png similarity index 100% rename from react/src/assets/images/cryptologo/DKK.png rename to react/src/assets/images/cryptologo/dkk.png diff --git a/react/src/assets/images/cryptologo/EUR.png b/react/src/assets/images/cryptologo/eur.png similarity index 100% rename from react/src/assets/images/cryptologo/EUR.png rename to react/src/assets/images/cryptologo/eur.png diff --git a/react/src/assets/images/cryptologo/GAME.png b/react/src/assets/images/cryptologo/game.png similarity index 100% rename from react/src/assets/images/cryptologo/GAME.png rename to react/src/assets/images/cryptologo/game.png diff --git a/react/src/assets/images/cryptologo/GBP.png b/react/src/assets/images/cryptologo/gbp.png similarity index 100% rename from react/src/assets/images/cryptologo/GBP.png rename to react/src/assets/images/cryptologo/gbp.png diff --git a/react/src/assets/images/cryptologo/HKD.png b/react/src/assets/images/cryptologo/hkd.png similarity index 100% rename from react/src/assets/images/cryptologo/HKD.png rename to react/src/assets/images/cryptologo/hkd.png diff --git a/react/src/assets/images/cryptologo/HODL.png b/react/src/assets/images/cryptologo/hodl.png similarity index 100% rename from react/src/assets/images/cryptologo/HODL.png rename to react/src/assets/images/cryptologo/hodl.png diff --git a/react/src/assets/images/cryptologo/HRK.png b/react/src/assets/images/cryptologo/hrk.png similarity index 100% rename from react/src/assets/images/cryptologo/HRK.png rename to react/src/assets/images/cryptologo/hrk.png diff --git a/react/src/assets/images/cryptologo/HUF.png b/react/src/assets/images/cryptologo/huf.png similarity index 100% rename from react/src/assets/images/cryptologo/HUF.png rename to react/src/assets/images/cryptologo/huf.png diff --git a/react/src/assets/images/cryptologo/IDR.png b/react/src/assets/images/cryptologo/idr.png similarity index 100% rename from react/src/assets/images/cryptologo/IDR.png rename to react/src/assets/images/cryptologo/idr.png diff --git a/react/src/assets/images/cryptologo/ILS.png b/react/src/assets/images/cryptologo/ils.png similarity index 100% rename from react/src/assets/images/cryptologo/ILS.png rename to react/src/assets/images/cryptologo/ils.png diff --git a/react/src/assets/images/cryptologo/INR.png b/react/src/assets/images/cryptologo/inr.png similarity index 100% rename from react/src/assets/images/cryptologo/INR.png rename to react/src/assets/images/cryptologo/inr.png diff --git a/react/src/assets/images/cryptologo/JPY.png b/react/src/assets/images/cryptologo/jpy.png similarity index 100% rename from react/src/assets/images/cryptologo/JPY.png rename to react/src/assets/images/cryptologo/jpy.png diff --git a/react/src/assets/images/cryptologo/JUMBLR.png b/react/src/assets/images/cryptologo/jumblr.png similarity index 100% rename from react/src/assets/images/cryptologo/JUMBLR.png rename to react/src/assets/images/cryptologo/jumblr.png diff --git a/react/src/assets/images/cryptologo/komodo.png b/react/src/assets/images/cryptologo/kmd.png similarity index 100% rename from react/src/assets/images/cryptologo/komodo.png rename to react/src/assets/images/cryptologo/kmd.png diff --git a/react/src/assets/images/cryptologo/KRW.png b/react/src/assets/images/cryptologo/krw.png similarity index 100% rename from react/src/assets/images/cryptologo/KRW.png rename to react/src/assets/images/cryptologo/krw.png diff --git a/react/src/assets/images/cryptologo/KV.png b/react/src/assets/images/cryptologo/kv.png similarity index 100% rename from react/src/assets/images/cryptologo/KV.png rename to react/src/assets/images/cryptologo/kv.png diff --git a/react/src/assets/images/cryptologo/MESH.png b/react/src/assets/images/cryptologo/mesh.png similarity index 100% rename from react/src/assets/images/cryptologo/MESH.png rename to react/src/assets/images/cryptologo/mesh.png diff --git a/react/src/assets/images/cryptologo/MGW.png b/react/src/assets/images/cryptologo/mgw.png similarity index 100% rename from react/src/assets/images/cryptologo/MGW.png rename to react/src/assets/images/cryptologo/mgw.png diff --git a/react/src/assets/images/cryptologo/MVP.png b/react/src/assets/images/cryptologo/mvp.png similarity index 100% rename from react/src/assets/images/cryptologo/MVP.png rename to react/src/assets/images/cryptologo/mvp.png diff --git a/react/src/assets/images/cryptologo/MXN.png b/react/src/assets/images/cryptologo/mxn.png similarity index 100% rename from react/src/assets/images/cryptologo/MXN.png rename to react/src/assets/images/cryptologo/mxn.png diff --git a/react/src/assets/images/cryptologo/MYR.png b/react/src/assets/images/cryptologo/myr.png similarity index 100% rename from react/src/assets/images/cryptologo/MYR.png rename to react/src/assets/images/cryptologo/myr.png diff --git a/react/src/assets/images/cryptologo/NOK.png b/react/src/assets/images/cryptologo/nok.png similarity index 100% rename from react/src/assets/images/cryptologo/NOK.png rename to react/src/assets/images/cryptologo/nok.png diff --git a/react/src/assets/images/cryptologo/NZD.png b/react/src/assets/images/cryptologo/nzd.png similarity index 100% rename from react/src/assets/images/cryptologo/NZD.png rename to react/src/assets/images/cryptologo/nzd.png diff --git a/react/src/assets/images/cryptologo/PANGEA.png b/react/src/assets/images/cryptologo/pangea.png similarity index 100% rename from react/src/assets/images/cryptologo/PANGEA.png rename to react/src/assets/images/cryptologo/pangea.png diff --git a/react/src/assets/images/cryptologo/PHP.png b/react/src/assets/images/cryptologo/php.png similarity index 100% rename from react/src/assets/images/cryptologo/PHP.png rename to react/src/assets/images/cryptologo/php.png diff --git a/react/src/assets/images/cryptologo/PLN.png b/react/src/assets/images/cryptologo/pln.png similarity index 100% rename from react/src/assets/images/cryptologo/PLN.png rename to react/src/assets/images/cryptologo/pln.png diff --git a/react/src/assets/images/cryptologo/REVS.png b/react/src/assets/images/cryptologo/revs.png similarity index 100% rename from react/src/assets/images/cryptologo/REVS.png rename to react/src/assets/images/cryptologo/revs.png diff --git a/react/src/assets/images/cryptologo/RON.png b/react/src/assets/images/cryptologo/ron.png similarity index 100% rename from react/src/assets/images/cryptologo/RON.png rename to react/src/assets/images/cryptologo/ron.png diff --git a/react/src/assets/images/cryptologo/RUB.png b/react/src/assets/images/cryptologo/rub.png similarity index 100% rename from react/src/assets/images/cryptologo/RUB.png rename to react/src/assets/images/cryptologo/rub.png diff --git a/react/src/assets/images/cryptologo/SEK.png b/react/src/assets/images/cryptologo/sek.png similarity index 100% rename from react/src/assets/images/cryptologo/SEK.png rename to react/src/assets/images/cryptologo/sek.png diff --git a/react/src/assets/images/cryptologo/SGD.png b/react/src/assets/images/cryptologo/sgd.png similarity index 100% rename from react/src/assets/images/cryptologo/SGD.png rename to react/src/assets/images/cryptologo/sgd.png diff --git a/react/src/assets/images/cryptologo/SHARK.png b/react/src/assets/images/cryptologo/shark.png similarity index 100% rename from react/src/assets/images/cryptologo/SHARK.png rename to react/src/assets/images/cryptologo/shark.png diff --git a/react/src/assets/images/cryptologo/SUPERNET.png b/react/src/assets/images/cryptologo/supernet.png similarity index 100% rename from react/src/assets/images/cryptologo/SUPERNET.png rename to react/src/assets/images/cryptologo/supernet.png diff --git a/react/src/assets/images/cryptologo/THB.png b/react/src/assets/images/cryptologo/thb.png similarity index 100% rename from react/src/assets/images/cryptologo/THB.png rename to react/src/assets/images/cryptologo/thb.png diff --git a/react/src/assets/images/cryptologo/TRY.png b/react/src/assets/images/cryptologo/try.png similarity index 100% rename from react/src/assets/images/cryptologo/TRY.png rename to react/src/assets/images/cryptologo/try.png diff --git a/react/src/assets/images/cryptologo/WLC.png b/react/src/assets/images/cryptologo/wlc.png similarity index 100% rename from react/src/assets/images/cryptologo/WLC.png rename to react/src/assets/images/cryptologo/wlc.png diff --git a/react/src/assets/images/cryptologo/ZAR.png b/react/src/assets/images/cryptologo/zar.png similarity index 100% rename from react/src/assets/images/cryptologo/ZAR.png rename to react/src/assets/images/cryptologo/zar.png diff --git a/react/src/components/addcoin/addcoinOptionsAC.js b/react/src/components/addcoin/addcoinOptionsAC.js index f47202c..020a097 100644 --- a/react/src/components/addcoin/addcoinOptionsAC.js +++ b/react/src/components/addcoin/addcoinOptionsAC.js @@ -8,6 +8,7 @@ class AddCoinOptionsAC extends React.Component { <option value="BET|basilisk|native">BET (BET)</option> <option value="BOTS|basilisk|native">BOTS (BOTS)</option> <option value="CEAL|basilisk|native">CEAL NET (CEAL)</option> + <option value="COQUI|basilisk|native">COQUI (COQUI)</option> <option value="CRYPTO|basilisk|native">CRYPTO (CRYPTO)</option> <option value="HOD|basilisk|native">HODL (HODL)</option> <option value="DEX|basilisk|native">InstantDEX (DEX)</option> diff --git a/react/src/components/addcoin/payload.js b/react/src/components/addcoin/payload.js index 7ea2ef3..7e727f6 100644 --- a/react/src/components/addcoin/payload.js +++ b/react/src/components/addcoin/payload.js @@ -1,4 +1,5 @@ // TODO: merge check functions +// move to nodejs export function checkAC(coinVal) { if (coinVal === 'SUPERNET' || @@ -9,6 +10,7 @@ export function checkAC(coinVal) { coinVal === 'JUMBLR' || coinVal === 'BET' || coinVal === 'CRYPTO' || + coinVal === 'COQUI' || coinVal === 'HODL' || coinVal === 'SHARK' || coinVal === 'BOTS' || @@ -98,6 +100,7 @@ export function checkCoinType(coin) { coin === 'JUMBLR' || coin === 'BET' || coin === 'CRYPTO' || + coin === 'COQUI' || coin === 'HODL' || coin === 'SHARK' || coin === 'BOTS' || @@ -131,10 +134,10 @@ export function checkCoinType(coin) { } export function startCrypto(confpath, coin, mode) { - let tmpinternval = 0, - AddCoinData = {}, - tmpPendValue = 1, // TODO: hook up to shepherd sysinfo - tmpIguanaRPCAuth = `tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}`; + let tmpinternval = 0; + let AddCoinData = {}; + let tmpPendValue = 1; // TODO: hook up to shepherd sysinfo + let tmpIguanaRPCAuth = `tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}`; if (coin !== 'BTC' && coin !== 'LTC' && @@ -176,9 +179,9 @@ export function startCrypto(confpath, coin, mode) { } export function startCurrencyAssetChain(confpath, coin, mode) { - let AddCoinDataPayload = {}, - tmpPendValue = 1, - tmpIguanaRPCAuth = `tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}`; + let AddCoinDataPayload = {}; + let tmpPendValue = 1; + let tmpIguanaRPCAuth = `tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}`; if (coin !== 'BTC' && coin !== 'LTC' && @@ -702,7 +705,7 @@ export function startAssetChain(confpath, coin, mode, getSuppyOnly) { }, 'DEX': { 'name': 'DEX', - 'supply': 1300000, + 'supply': 999999, 'AddCoinData': confpath ? Object.assign({}, _acPayloadOrigin, {"coin":"DEX","conf":"DEX.conf","path":confpath,"RELAY":-1,"VALIDATE":1,"startpend":4,"endpend":4,"maxpeers":8,"newcoin":"DEX","name":"DEX","netmagic":"f2ae0516","p2p":9502,"rpc":9503}) : {}, 'AddCoinDataVar': Object.assign({}, _acPayloadOrigin, {'userpass':tmpIguanaRPCAuth,"RELAY":mode,"VALIDATE":mode,"startpend":tmpPendValue,"endpend":tmpPendValue,"maxpeers":8,"newcoin":"DEX","name":"DEX","netmagic":"f2ae0516","p2p":9502,"rpc":9503}) }, @@ -726,7 +729,7 @@ export function startAssetChain(confpath, coin, mode, getSuppyOnly) { }, 'HODL': { 'name': 'HODL', - 'supply': 999999, + 'supply': 9999999, 'AddCoinData': confpath ? Object.assign({}, _acPayloadOrigin, {"coin":"HODL","conf":"HODL.conf","path":confpath,"RELAY":-1,"VALIDATE":1,"startpend":4,"endpend":4,"maxpeers":8,"newcoin":"HODL","name":"HODL","netmagic":"9b13fb5f","p2p":8009,"rpc":8010}) : {}, 'AddCoinDataVar': Object.assign({}, _acPayloadOrigin, {'userpass':tmpIguanaRPCAuth,"RELAY":mode,"VALIDATE":mode,"startpend":tmpPendValue,"endpend":tmpPendValue,"maxpeers":8,"newcoin":"HODL","name":"HODL","netmagic":"9b13fb5f","p2p":8009,"rpc":8010}) }, @@ -756,7 +759,7 @@ export function startAssetChain(confpath, coin, mode, getSuppyOnly) { }, 'KV': { 'name': 'KV', - 'supply': 999999, + 'supply': 1000000, 'AddCoinData': confpath ? Object.assign({}, _acPayloadOrigin, {"coin":"KV","conf":"KV.conf","path":confpath,"RELAY":-1,"VALIDATE":1,"startpend":4,"endpend":4,"maxpeers":8,"newcoin":"KV","name":"KV","netmagic":"b09a2d65","p2p":9746,"rpc":9747}) : {}, 'AddCoinDataVar': Object.assign(_acPayloadOrigin, {'userpass':tmpIguanaRPCAuth,"RELAY":mode,"VALIDATE":mode,"startpend":tmpPendValue,"endpend":tmpPendValue,"maxpeers":8,"newcoin":"KV","name":"KV","netmagic":"b09a2d65","p2p":9746,"rpc":9747}) }, @@ -768,9 +771,15 @@ export function startAssetChain(confpath, coin, mode, getSuppyOnly) { }, 'MESH': { 'name': 'MESH', - 'supply': 1000000, + 'supply': 1000007, 'AddCoinData': confpath ? Object.assign({}, _acPayloadOrigin, {"coin":"MESH","conf":"MESH.conf","path":confpath,"RELAY":-1,"VALIDATE":1,"startpend":4,"endpend":4,"maxpeers":8,"newcoin":"MESH","name":"MESH","netmagic":"f0265c67","p2p":8399,"rpc":8400}) : {}, 'AddCoinDataVar': Object.assign({}, _acPayloadOrigin, {'userpass':tmpIguanaRPCAuth,"RELAY":mode,"VALIDATE":mode,"startpend":tmpPendValue,"endpend":tmpPendValue,"maxpeers":8,"newcoin":"MESH","name":"MESH","netmagic":"f0265c67","p2p":8399,"rpc":8400}) + }, + 'COQUI': { + 'name': 'COQUI', + 'supply': 72000000, + 'AddCoinData': confpath ? Object.assign({}, _acPayloadOrigin, {"coin":"COQUI","conf":"COQUI.conf","path":confpath,"RELAY":-1,"VALIDATE":1,"startpend":4,"endpend":4,"maxpeers":8,"newcoin":"COQUI","name":"COQUI","netmagic":"4cbd5ef4","p2p":14275,"rpc":14276}) : {}, + 'AddCoinDataVar': Object.assign({}, _acPayloadOrigin, {'userpass':tmpIguanaRPCAuth,"RELAY":mode,"VALIDATE":mode,"startpend":tmpPendValue,"endpend":tmpPendValue,"maxpeers":8,"newcoin":"COQUI","name":"COQUI","netmagic":"4cbd5ef4","p2p":14275,"rpc":14276}) } }; diff --git a/react/src/components/dashboard/claimInterestModal/claimInterestModal.js b/react/src/components/dashboard/claimInterestModal/claimInterestModal.js new file mode 100755 index 0000000..94e05f5 --- /dev/null +++ b/react/src/components/dashboard/claimInterestModal/claimInterestModal.js @@ -0,0 +1,136 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import Store from '../../../store'; +import { + toggleClaimInterestModal, + getListUnspent, + getRawTransaction, + copyString, + sendToAddressPromise, + triggerToaster +} from '../../../actions/actionCreators'; +import { translate } from '../../../translate/translate'; +import { + ClaimInterestModalRender, + _ClaimInterestTableRender +} from './claimInterestModal.render'; + +class ClaimInterestModal extends React.Component { + constructor(props) { + super(props); + this.state = { + open: false, + isLoading: true, + transactionsList: [], + showZeroInterest: true, + }; + this.claimInterestTableRender = this.claimInterestTableRender.bind(this); + this.toggleZeroInterest = this.toggleZeroInterest.bind(this); + this.loadListUnspent = this.loadListUnspent.bind(this); + this.checkTransactionsListLength = this.checkTransactionsListLength.bind(this); + } + + componentWillMount() { + this.loadListUnspent(); + } + + loadListUnspent() { + let _transactionsList = []; + + getListUnspent(this.props.ActiveCoin.coin) + .then((json) => { + if (json && + json.length) { + for (let i = 0; i < json.length; i++) { + getRawTransaction(this.props.ActiveCoin.coin, json[i].txid) + .then((_json) => { + _transactionsList.push({ + address: json[i].address, + locktime: _json.locktime, + amount: json[i].amount, + interest: json[i].interest, + txid: json[i].txid, + }); + + if (i === json.length - 1) { + this.setState({ + transactionsList: _transactionsList, + isLoading: false, + }); + } + }); + } + } + }); + } + + claimInterest(address, amount) { + sendToAddressPromise(this.props.ActiveCoin.coin, this.state.transactionsList[0].address, this.props.ActiveCoin.balance.transparent) + .then((json) => { + if (json.error && + json.error.code) { + Store.dispatch( + triggerToaster( + json.error.message, + 'Error', + 'error' + ) + ); + } else if (json.result && json.result.length && json.result.length === 64) { + Store.dispatch( + triggerToaster( + `Your full balance is sent to address ${this.state.transactionsList[0].address}. Check back your new balance in a few minutes.`, + translate('TOASTR.WALLET_NOTIFICATION'), + 'success', + false + ) + ); + } + }); + } + + checkTransactionsListLength() { + if (this.state.transactionsList && this.state.transactionsList.length) { + return true; + } else if (!this.state.transactionsList || !this.state.transactionsList.length) { + return false; + } + } + + toggleZeroInterest() { + this.setState({ + showZeroInterest: !this.state.showZeroInterest, + }); + } + + copyTxId(txid) { + Store.dispatch(copyString(txid, 'Transaction ID copied')); + } + + claimInterestTableRender() { + return _ClaimInterestTableRender.call(this); + } + + componentWillReceiveProps(props) { + if (props.Dashboard.displayClaimInterestModal !== this.state.open) { + this.setState({ + open: props.Dashboard.displayClaimInterestModal, + }); + } + + if (!this.state.open && + props.Dashboard.displayClaimInterestModal) { + this.loadListUnspent(); + } + } + + closeModal() { + Store.dispatch(toggleClaimInterestModal(false)); + } + + render() { + return ClaimInterestModalRender.call(this); + } +} + +export default ClaimInterestModal; \ No newline at end of file diff --git a/react/src/components/dashboard/claimInterestModal/claimInterestModal.render.js b/react/src/components/dashboard/claimInterestModal/claimInterestModal.render.js new file mode 100644 index 0000000..8754965 --- /dev/null +++ b/react/src/components/dashboard/claimInterestModal/claimInterestModal.render.js @@ -0,0 +1,132 @@ +import React from 'react'; +import { translate } from '../../../translate/translate'; + +const MIN_INTEREST_THRESHOLD = 0.001; + +export const _ClaimInterestTableRender = function() { + const _transactionsList = this.state.transactionsList; + let _items = []; + + for (let i = 0; i < _transactionsList.length; i++) { + if ((_transactionsList[i].interest === 0 && this.state.showZeroInterest) || (_transactionsList[i].amount > 0 && _transactionsList[i].interest > 0)) { + _items.push( + <tr key={ `${_transactionsList[i].txid}${_transactionsList[i].address}` }> + <td> + <button + className="btn btn-default btn-xs clipboard-edexaddr copy-string-btn" + title={ translate('INDEX.COPY_TO_CLIPBOARD') } + onClick={ () => this.copyTxId(_transactionsList[i].txid) }> + <i className="icon wb-copy"></i> { translate('INDEX.COPY') } + </button> + </td> + <td>{ _transactionsList[i].address }</td> + <td className={ _transactionsList[i].amount > 10 ? 'green bold' : '' }>{ _transactionsList[i].amount }</td> + <td>{ _transactionsList[i].interest }</td> + <td className="locktime center"> + { _transactionsList[i].locktime && + <i className="fa-check-circle green"></i> + } + { !_transactionsList[i].locktime && + <i className="fa-exclamation-circle red"></i> + } + </td> + </tr> + ); + } + } + + return ( + <span> + <div className="padding-bottom-20"> + <strong>Requirements to accrue interest:</strong> locktime field is set and amount is greater than <strong>10 KMD</strong> + </div> + <div className="text-left padding-top-10 padding-bottom-10"> + <label className="switch"> + <input + type="checkbox" + checked={ this.state.showZeroInterest } /> + <div + className="slider" + onClick={ this.toggleZeroInterest }></div> + </label> + <div + className="toggle-label margin-right-15 pointer" + onClick={ this.toggleZeroInterest }> + Show zero interest + </div> + </div> + <button + type="button" + className="btn btn-success waves-effect waves-light claim-btn" + onClick={ () => this.claimInterest() }> + <i className="icon fa-dollar"></i> Claim interest + </button> + <div className="table-scroll"> + <table className="table table-hover dataTable table-striped"> + <thead> + <tr> + <th></th> + <th>Address</th> + <th>Amount</th> + <th>Interest</th> + <th>Locktime</th> + </tr> + </thead> + <tbody> + { _items } + </tbody> + <tfoot> + <tr> + <th></th> + <th>Address</th> + <th>Amount</th> + <th>Interest</th> + <th>Locktime</th> + </tr> + </tfoot> + </table> + </div> + </span> + ); +}; + +export const ClaimInterestModalRender = function() { + return ( + <span> + <div className={ 'modal modal-claim-interest modal-3d-sign ' + (this.state.open ? 'show in' : 'fade hide') }> + <div className="modal-dialog modal-center modal-sm"> + <div className="modal-content"> + <div className="modal-header bg-orange-a400 wallet-send-header"> + <button + type="button" + className="close white" + onClick={ this.closeModal }> + <span>×</span> + </button> + <h4 className="modal-title white text-left">Claim interest</h4> + </div> + <div className="modal-body"> + <i + className="icon fa-refresh pointer refresh-icon" + onClick={ this.loadListUnspent }></i> + <div className="animsition vertical-align fade-in"> + <div className="page-content vertical-align-middle full-width"> + { this.state.isLoading && + <span>Loading interest data...</span> + } + { !this.state.isLoading && this.checkTransactionsListLength() && + <div>{ this.claimInterestTableRender() }</div> + } + { !this.state.isLoading && !this.checkTransactionsListLength() && + <div>No data</div> + } + </div> + </div> + </div> + </div> + </div> + </div> + <div className={ 'modal-backdrop ' + (this.state.open ? 'show in' : 'fade hide') }></div> + </span> + ); +}; \ No newline at end of file diff --git a/react/src/components/dashboard/coinTile/coinTileItem.js b/react/src/components/dashboard/coinTile/coinTileItem.js index e270774..b43c1d1 100644 --- a/react/src/components/dashboard/coinTile/coinTileItem.js +++ b/react/src/components/dashboard/coinTile/coinTileItem.js @@ -111,6 +111,11 @@ class CoinTileItem extends React.Component { setTimeout(() => { this.dispatchCoinActions(coin, mode); }, 100); + if (mode === 'native') { // faster coin data load if fully synced + setTimeout(() => { + this.dispatchCoinActions(coin, mode); + }, 1000); + } Store.dispatch( stopInterval( @@ -141,7 +146,7 @@ class CoinTileItem extends React.Component { if (mode === 'native') { const _iguanaActiveHandle = setInterval(() => { this.dispatchCoinActions(coin, mode); - }, coin === 'KMD' ? IGUNA_ACTIVE_HANDLE_TIMEOUT_KMD_NATIVE : IGUNA_ACTIVE_HANDLE_TIMEOUT); + }, IGUNA_ACTIVE_HANDLE_TIMEOUT_KMD_NATIVE); Store.dispatch(startInterval('sync', _iguanaActiveHandle)); } diff --git a/react/src/components/dashboard/coinTile/coinTileItem.render.js b/react/src/components/dashboard/coinTile/coinTileItem.render.js index 832dd4a..b669c6c 100644 --- a/react/src/components/dashboard/coinTile/coinTileItem.render.js +++ b/react/src/components/dashboard/coinTile/coinTileItem.render.js @@ -12,7 +12,7 @@ const CoinTileItemRender = function() { <a className="avatar margin-bottom-5"> <img className="img-responsive" - src={ `assets/images/cryptologo/${item.coinlogo}.png` } + src={ `assets/images/cryptologo/${item.coinlogo.toLowerCase()}.png` } alt={ item.coinname }/> <span className={ `badge up badge-${item.modecolor}` }> { item.modecode } diff --git a/react/src/components/dashboard/coindDownModal/coindDownModal.render.js b/react/src/components/dashboard/coindDownModal/coindDownModal.render.js index 548e661..3787039 100644 --- a/react/src/components/dashboard/coindDownModal/coindDownModal.render.js +++ b/react/src/components/dashboard/coindDownModal/coindDownModal.render.js @@ -16,7 +16,7 @@ const CoindDownModalRender = function () { onClick={ this.dismiss }> <span>×</span> </button> - <h4 className="modal-title white">Komodod is down!</h4> + <h4 className="modal-title white">{ this.props.ActiveCoin.coin === 'KMD' ? 'Komodod' : `Komodod / ${this.props.ActiveCoin.coin}` } is down!</h4> </div> <div className="modal-body"> <div className="vertical-align text-center"> diff --git a/react/src/components/dashboard/jumblr/jumblr.js b/react/src/components/dashboard/jumblr/jumblr.js index 4ae03a0..a69dbd1 100755 --- a/react/src/components/dashboard/jumblr/jumblr.js +++ b/react/src/components/dashboard/jumblr/jumblr.js @@ -1,14 +1,391 @@ import React from 'react'; import { translate } from '../../../translate/translate'; +import { + dashboardChangeActiveCoin, + getKMDAddressesNative, + startInterval, + stopInterval, + triggerToaster, + setJumblrAddress, + importPrivkey, + copyCoinAddress, + copyString +} from '../../../actions/actionCreators'; +import Store from '../../../store'; +import Config from '../../../config'; +import { + JumblrRender, + JumblrRenderSecretAddressList +} from './jumblr.render'; +import { PassPhraseGenerator } from '../../../util/crypto/passphrasegenerator'; -import JumblrRender from './jumblr.render'; +// import gen komodo keys utils +import '../../../util/crypto/gen/array.map.js'; +import '../../../util/crypto/gen/cryptojs.js'; +import '../../../util/crypto/gen/cryptojs.sha256.js'; +import '../../../util/crypto/gen/cryptojs.pbkdf2.js'; +import '../../../util/crypto/gen/cryptojs.hmac.js'; +import '../../../util/crypto/gen/cryptojs.aes.js'; +import '../../../util/crypto/gen/cryptojs.blockmodes.js'; +import '../../../util/crypto/gen/cryptojs.ripemd160.js'; +import '../../../util/crypto/gen/securerandom.js'; +import '../../../util/crypto/gen/ellipticcurve.js'; +import '../../../util/crypto/gen/biginteger.js'; +import '../../../util/crypto/gen/crypto-scrypt.js'; +import { Bitcoin } from '../../../util/crypto/gen/bitcoin.js'; + +if (!window.jumblrPasshrase) { // gen jumblr passphrase + window.jumblrPasshrase = 'jumblr ' + PassPhraseGenerator.generatePassPhrase(256); +} class Jumblr extends React.Component { constructor(props) { super(props); this.state = { activeTab: 0, + randomSeed: window.jumblrPasshrase, + jumblrDepositAddress: null, + jumblrDepositAddressPBased: true, + jumblrSecretAddressShow: true, + jumblrSecretAddress: [], + jumblrSecretAddressImport: [], + jumblrSecretAddressCountImport: 0, + jumblrSecretAddressShowImport: true, + jumblrSecretAddressCount: 0, + jumblrMode: 'public', + secretAddressCount: 1, + secretAddressCountImport: 1, + jumblrPassphraseImport: '', + }; + this.generateJumblrDepositAddress = this.generateJumblrDepositAddress.bind(this); + this.generateJumblrSecretAddress = this.generateJumblrSecretAddress.bind(this); + this.checkJumblrSecretAddressListLength = this.checkJumblrSecretAddressListLength.bind(this); + this.returnPassphrase = this.returnPassphrase.bind(this); + this.generateKeys = this.generateKeys.bind(this); + this._copyCoinAddress = this._copyCoinAddress.bind(this); + this.copyPassphrase = this.copyPassphrase.bind(this); + this.checkPassphraseValid = this.checkPassphraseValid.bind(this); + this.importJumblrSecretAddress = this.importJumblrSecretAddress.bind(this); + this.onChange = this.onChange.bind(this); + } + + generateKeys(passphrase) { + if (!passphrase) { + const key = new Bitcoin.ECKey(false).setCompressed(true); + const kmdAddress = key.getBitcoinAddress(); + const wifAddress = key.getBitcoinWalletImportFormat(); + + return { + address: kmdAddress, + wif: wifAddress, + }; + } else { + const bytes = Crypto.SHA256(passphrase, { asBytes: true }); + const btcKey = new Bitcoin.ECKey(bytes).setCompressed(true); + const kmdAddress = btcKey.getBitcoinAddress(); + const wifAddress = btcKey.getBitcoinWalletImportFormat(); + + return { + address: kmdAddress, + wif: wifAddress, + }; + } + } + + _JumblrRenderSecretAddressList(type) { + return JumblrRenderSecretAddressList.call(this, type); + } + + onChange(e) { + const regex = /^[0-9\b]+$/; + + if (e.target.value === '' || + regex.test(e.target.value)) { + this.setState({ + [e.target.name]: e.target.value, + }); + } + } + + passphraseOnChange(e) { + this.setState({ + [e.target.name]: e.target.value, + }); + } + + returnPassphrase() { + this.setState({ + randomSeed: window.jumblrPasshrase, + }); + } + + toggle(prop) { + const _prop = this.state[prop]; + + this.setState({ + [prop]: !_prop, + }); + } + + /*toggleAddressGenMod() { + this.setState({ + jumblrDepositAddressPBased: !this.state.jumblrDepositAddressPBased, + }); + }*/ + + generateJumblrSecretAddress() { + let _jumblrSecretAddress = []; + let _apiSuccessCount = 0; + + if (this.state.secretAddressCount === '') { + Store.dispatch( + triggerToaster( + 'Enter a correct address count value', + 'Jumblr', + 'error' + ) + ); + } else { + for (let i = 0; i < this.state.secretAddressCount; i++) { + let _genKeys; + + if (this.state.jumblrDepositAddressPBased) { + let _postfix; + + if (i < 9) { + _postfix = `00${i + 1}`; + } else if (i > 10 && i < 100) { + _postfix = `0${i + 1}`; + } + _genKeys = this.generateKeys(`${this.state.randomSeed} ${_postfix}`); + // console.warn(`${this.state.randomSeed} ${_postfix}`); + } else { + _genKeys = this.generateKeys(); + } + + setJumblrAddress(this.props.ActiveCoin.coin, 'secret', _genKeys.address) + .then((json) => { + if (json.error && + json.error.code) { + Store.dispatch( + triggerToaster( + json.error.message, + 'Error', + 'error' + ) + ); + } else if (json.result && json.result.result && json.result.result === 'success') { + _jumblrSecretAddress.push(_genKeys); + this.setState(Object.assign({}, this.state, { + jumblrSecretAddress: _jumblrSecretAddress, + })); + + if (_apiSuccessCount === this.state.secretAddressCount - 1) { + Store.dispatch( + triggerToaster( + this.state.secretAddressCount > 1 ? 'Jumblr secret addresses are set' : 'Jumblr secret address is set', + 'Jumblr', + 'success' + ) + ); + } + _apiSuccessCount++; + } + }); + } + } + } + + checkPassphraseValid() { // test passphrase validity + const _passphrase = this.state.jumblrPassphraseImport; + const _jumblrPrefix = _passphrase.substring(0, 6); + const _passphraseWords = _passphrase.substring(6, _passphrase.length); + let _errors = { + prefix: false, // jumblr + length: false, // 24 }; + + if (_jumblrPrefix !== 'jumblr') { + _errors.prefix = true; + } + + try { + const _passphraseWordsSplit = _passphraseWords.split(' '); + let _correctWords = 0; + + if (_passphraseWordsSplit && + _passphraseWordsSplit.length) { + for (let i = 0; i < _passphraseWordsSplit.length; i++) { + if (_passphraseWordsSplit[i].length > 2) { + _correctWords++; + } + } + + if (_correctWords !== _passphraseWordsSplit.length - 1 || _correctWords !== 24) { + _errors.length = true; + } + } else { + _errors.length = true; + } + } catch(e) { + _errors.length = true; + } + + + if (_errors.length || + _errors.prefix) { + Store.dispatch( + triggerToaster( + 'Provided passphrase has wrong format', + 'Jumblr', + 'error', + false + ) + ); + + return false; + } + + return true; + } + + importJumblrSecretAddress() { + let _jumblrSecretAddress = []; + let _apiSuccessCount = 0; + + if (this.state.secretAddressCountImport === '') { + Store.dispatch( + triggerToaster( + 'Enter a correct address count value', + 'Jumblr', + 'error' + ) + ); + } else { + if (this.checkPassphraseValid()) { + for (let i = 0; i < this.state.secretAddressCountImport; i++) { + let _genKeys; + + if (this.state.jumblrDepositAddressPBased) { + let _postfix; + + if (i < 9) { + _postfix = `00${i + 1}`; + } else if (i > 10 && i < 100) { + _postfix = `0${i + 1}`; + } + _genKeys = this.generateKeys(`${this.state.jumblrPassphraseImport} ${_postfix}`); + } else { + _genKeys = this.generateKeys(); + } + + importPrivkey(this.props.ActiveCoin.coin, _genKeys.wif) + .then((json) => { + if (!json.id && !json.result && !json.error) { + _jumblrSecretAddress.push(_genKeys); + this.setState(Object.assign({}, this.state, { + jumblrSecretAddressImport: _jumblrSecretAddress, + })); + if (_apiSuccessCount === this.state.secretAddressCountImport - 1) { + Store.dispatch( + triggerToaster( + this.state.secretAddressCountImport > 1 ? 'Jumblr secret addresses imported' : 'Jumblr secret address imported', + 'Jumblr', + 'success' + ) + ); + } + _apiSuccessCount++; + } else { + Store.dispatch( + triggerToaster( + json.error.message, + 'Error', + 'error' + ) + ); + } + }); + } + } + } + } + + checkJumblrSecretAddressListLength(type) { + if (type === 'gen') { + if (this.state.jumblrSecretAddress && + this.state.jumblrSecretAddress.length) { + return true; + } else { + return false; + } + } else { + if (this.state.jumblrSecretAddressImport && + this.state.jumblrSecretAddressImport.length) { + return true; + } else { + return false; + } + } + } + + generateJumblrDepositAddress() { + let _genKeys; + + if (this.state.jumblrDepositAddressPBased) { + _genKeys = this.generateKeys(this.state.randomSeed); + } else { + _genKeys = this.generateKeys(); + } + + importPrivkey(this.props.ActiveCoin.coin, _genKeys.wif) + .then((json) => { + if (!json.id && !json.result && !json.error) { + // console.warn('importPrivkey', json); + setJumblrAddress(this.props.ActiveCoin.coin, 'deposit', _genKeys.address) + .then((json) => { + if (json.error && + json.error.code) { + Store.dispatch( + triggerToaster( + json.error.message, + 'Error', + 'error' + ) + ); + } else if (json.result && json.result.result === 0) { + this.setState(Object.assign({}, this.state, { + jumblrDepositAddress: { + address: _genKeys.address, + wif: _genKeys.wif, + }, + })); + Store.dispatch( + triggerToaster( + 'Jumblr deposit address is set', + 'Jumblr', + 'success' + ) + ); + } + }); + } else { + Store.dispatch( + triggerToaster( + json.error.message, + 'Error', + 'error' + ) + ); + } + }); + } + + switchJumblrMode(mode) { + this.setState(Object.assign({}, this.state, { + jumblrMode: mode, + activeTab: 0, + })); } openTab(tab) { @@ -17,6 +394,14 @@ class Jumblr extends React.Component { })); } + _copyCoinAddress(address) { + Store.dispatch(copyCoinAddress(address)); + } + + copyPassphrase() { + Store.dispatch(copyString(this.state.randomSeed, 'Passphrase copied')); + } + renderLB(_translationID) { const _translationComponents = translate(_translationID).split('<br>'); diff --git a/react/src/components/dashboard/jumblr/jumblr.render.js b/react/src/components/dashboard/jumblr/jumblr.render.js index 846400d..fe060f7 100644 --- a/react/src/components/dashboard/jumblr/jumblr.render.js +++ b/react/src/components/dashboard/jumblr/jumblr.render.js @@ -2,10 +2,52 @@ import React from 'react'; import { translate } from '../../../translate/translate'; import WalletsHeader from '../walletsHeader/walletsHeader'; +import WalletsNativeSend from '../walletsNativeSend/walletsNativeSend'; +import ReceiveCoin from '../receiveCoin/receiveCoin'; -const JumblrRender = function() { +export const JumblrRenderSecretAddressList = function(type) { + const _jumblrAddressList = type === 'gen' ? this.state.jumblrSecretAddress : this.state.jumblrSecretAddressImport; + let _items = []; + + if (_jumblrAddressList && + _jumblrAddressList.length) { + for (let i = 0; i < _jumblrAddressList.length; i++) { + _items.push( + <tr key={ `jumblr-secret-address-${i}` }> + <td>{ _jumblrAddressList[i].address }</td> + <td>{ _jumblrAddressList[i].wif }</td> + </tr> + ); + } + return _items; + } else { + return null; + } +}; + +/* passphrase toggle + <div className={ 'toggle-box padding-top-20 padding-bottom-' + (this.state.jumblrDepositAddressPBased ? '10' : '30') }> + <span className="pointer"> + <label className="switch"> + <input + type="checkbox" + checked={ this.state.jumblrDepositAddressPBased } /> + <div + className="slider" + onClick={ () => this.toggleAddressGenMod() }></div> + </label> + <div + className="toggle-label" + onClick={ () => this.toggleAddressGenMod() }> + Passphrase based address + </div> + </span> + </div> +*/ + +export const JumblrRender = function() { return ( - <div className="page margin-left-0"> + <div className="page margin-left-0 jumblr"> <WalletsHeader activeSection="jumblr" /> <div className="page-content margin-top-30"> <div className="row"> @@ -32,87 +74,135 @@ const JumblrRender = function() { <span>×</span> </button> <span className="jumblr-header"> - <i className="icon fa-paw"></i> { translate('JUMBLR.NEED_NATIVE') } + <i className="icon fa-paw"></i> About Jumblr </span> <br /> - { translate('JUMBLR.TO_USE_JUMBLR') } - <br /> - { translate('JUMBLR.IF_YOU_ALREADY_RUNNING') } + <p> + Jumblr functions all locally which means no middle man is required to jumble your funds. You take control over the whole process. + </p> + <p> + <strong>Tip:</strong> to achive maximum anonimity setup Jumblr node on a dedicated piece of hardware (laptop or VPS), use a separate IP address for main Jumblr node. + </p> </div> </div> - <div className="col-xlg-12 col-md-12"> - <p>{ translate('JUMBLR.THIS_SCREEN_DOESNT_REFRESH') }</p> + <div className="col-xlg-12 col-md-12 padding-top-20 padding-bottom-30"> + <div + className="form-group col-lg-2 col-md-2 col-sm-2 col-xs-2" + style={{ padding: 0 }}> + <input + type="radio" + className="to-labelauty labelauty" + name={ `mode-public` } + id={ `mode-public` } + checked={ this.state.jumblrMode === 'public' ? true : false } /> + <label + htmlFor={ `mode-public` } + style={{ margin: 0 }} + onClick={ () => this.switchJumblrMode('public') }> + <span + className="labelauty-unchecked-image" + style={{ display: this.state.jumblrMode === 'public' ? 'none' : 'inline-block' }}></span> + <span + className="labelauty-unchecked" + style={{ display: this.state.jumblrMode === 'public' ? 'none' : 'inline-block' }}> + Public node + </span> + <span + className="labelauty-checked-image" + style={{ display: this.state.jumblrMode === 'public' ? 'inline-block' : 'none' }}></span> + <span + className="labelauty-checked" + style={{ display: this.state.jumblrMode === 'public' ? 'inline-block' : 'none' }}> + Public node + </span> + </label> + </div> + + <div + className="form-group col-lg-2 col-md-2 col-sm-2 col-xs-2" + style={{ padding: 0 }}> + <input + type="radio" + className="to-labelauty labelauty" + name={ `mode-private` } + id={ `mode-private` } + checked={ this.state.jumblrMode === 'private' ? true : false } /> + <label + htmlFor={ `mode-private` } + style={{ margin: 0 }} + onClick={ () => this.switchJumblrMode('private') }> + <span + className="labelauty-unchecked-image" + style={{ display: this.state.jumblrMode === 'private' ? 'none' : 'inline-block' }}></span> + <span + className="labelauty-unchecked" + style={{ display: this.state.jumblrMode === 'private' ? 'none' : 'inline-block' }}> + Private node + </span> + <span + className="labelauty-checked-image" + style={{ display: this.state.jumblrMode === 'private' ? 'inline-block' : 'none' }}></span> + <span + className="labelauty-checked" + style={{ display: this.state.jumblrMode === 'private' ? 'inline-block' : 'none' }}> + Private node + </span> + </label> + </div> </div> - <div className="col-xs-12"> - <div className="panel-group"> - <div className="panel"> - <div - className="panel-heading" - onClick={ () => this.openTab(0) }> - <a className={ this.state.activeTab === 0 ? 'panel-title' : 'panel-title collapsed' }>{ translate('JUMBLR.FEW_SECURITY_NOTES') }</a> - </div> - <div className={ this.state.activeTab === 0 ? 'panel-collapse collapse in' : 'panel-collapse collapse' }> - <div className="panel-body"> - <ul> - <li>{ translate('JUMBLR.FEW_SECURITY_NOTES_DESC1') }</li> - <li>{ translate('JUMBLR.FEW_SECURITY_NOTES_DESC2') }</li> - <li>{ translate('JUMBLR.FEW_SECURITY_NOTES_DESC3') }</li> - <li>{ translate('JUMBLR.FEW_SECURITY_NOTES_DESC4') }</li> - <li>{ translate('JUMBLR.FEW_SECURITY_NOTES_DESC5') }</li> - </ul> - </div> - </div> - </div> - <div className="panel"> - <div - className="panel-heading" - onClick={ () => this.openTab(1) }> - <a className={ this.state.activeTab === 1 ? 'panel-title' : 'panel-title collapsed' }>{ translate('JUMBLR.ACCESS_JUMBLR_FUNDS') }</a> - </div> - <div className={ this.state.activeTab === 1 ? 'panel-collapse collapse in' : 'panel-collapse collapse' }> - <div className="panel-body"> - <p>{ translate('JUMBLR.ADDRESS_ACCESSIBLE_EASILY') }</p> - <ul> - <code>duck dog cat donkey</code> - </ul> - <ol> - <li>{ translate('JUMBLR.TO_ACCESS') }</li> - <li>{ translate('JUMBLR.CLOSE_IAPP') }</li> - <li>{ translate('JUMBLR.START_IAPP') }</li> - <li>{ translate('JUMBLR.START_KMD') }</li> - <li>{ translate('JUMBLR.ACCESS_JUMBLR_FUNDS') } - <ul> - <li>{ translate('JUMBLR.SMALL_LETTERS') }</li> - <li>{ translate('JUMBLR.WHITE_SPACE') }</li> - </ul> - </li> - <li> - { translate('JUMBLR.PER_EXAMPLE') } - <br /> - <code>jumblr duck dog cat donkey</code> - </li> - <li>{ translate('JUMBLR.LOGIN_WITH_JUMBLR') }</li> - </ol> - <h4>{ translate('JUMBLR.AGAIN_DONT_SHARE') }</h4> - </div> - </div> - </div> - <div className="panel"> - <div - className="panel-heading" - onClick={ () => this.openTab(2) }> - <a className={ this.state.activeTab === 2 ? 'panel-title' : 'panel-title collapsed' }>{ translate('JUMBLR.USING_JUMBLR') }</a> + <div className="col-xlg-12 col-md-12"> + { this.state.jumblrMode === 'public' && + <div className="jumblr-mode-selector nav-tabs-horizontal nav-tabs-inverse"> + <div className="img-responsive"> + <span className="coin">{ this.props.ActiveCoin.coin }</span> + <img + className="image" + src={ `assets/images/cryptologo/${this.props.ActiveCoin.coin.toLowerCase()}.png` } + alt={ this.props.ActiveCoin.coin }/> </div> - <div className={ this.state.activeTab === 2 ? 'panel-collapse collapse in' : 'panel-collapse collapse' }> - <div className="panel-body"> + <ul className="nav nav-tabs"> + <li + className={ this.state.activeTab === 0 ? 'active' : '' } + onClick={ () => this.openTab(0) }> + <a> + { translate('JUMBLR.USING_JUMBLR') } + </a> + </li> + <li + className={ this.state.activeTab === 1 ? 'active' : '' } + onClick={ () => this.openTab(1) }> + <a> + Deposit address + </a> + </li> + <li + className={ this.state.activeTab === 2 ? 'active' : '' } + onClick={ () => this.openTab(2) }> + <a> + Secret address + </a> + </li> + <li + className={ this.state.activeTab === 3 ? 'active' : '' } + onClick={ () => this.openTab(3) }> + <a> + Deposit funds + </a> + </li> + </ul> + <div className="tab-content padding-20"> + <div className={ 'tab-pane' + (this.state.activeTab === 0 ? ' active' : '') }> + <button + type="button" + className="btn btn-success waves-effect waves-light margin-top-20 btn-next" + onClick={ () => this.openTab(1) }>Next</button> + <h5>How to use Jumblr</h5> <ul> - <li>{ translate('JUMBLR.RUN_KMD') }</li> - <li>{ translate('JUMBLR.LOGIN_KMD') }</li> - <li>{ translate('JUMBLR.GO_TO') }</li> - <li>{ translate('JUMBLR.FIND_DEPOSIT_ADDR') }</li> - <li>{ translate('JUMBLR.YOU_SEND_FUNDS') }</li> + <li>Create deposit address</li> + <li>Create secret address</li> + <li>Send funds to deposit address</li> <li>{ translate('JUMBLR.KEEP_WALLET_OPEN') }</li> <li>{ translate('JUMBLR.IMPORTANT_FUNDS') }</li> <li>{ translate('JUMBLR.LARGE_LOT') }</li> @@ -122,105 +212,276 @@ const JumblrRender = function() { <p>{ translate('JUMBLR.TO_CLEAR_THEM') }</p> <p>{ translate('JUMBLR.WHEN_IT_TOTALS') }</p> </div> - </div> - </div> - </div> - </div> - - <div className="col-xlg-12 col-md-12"> - <h4 className="font-size-14 text-uppercase">{ translate('JUMBLR.JADDR') }</h4> - <div className="panel"> - <div className="table-responsive"> - <table className="table table-striped"> - <tbody> - <tr> - <td width="20%">{ translate('JUMBLR.BTC_DEPOSIT') }</td> - <td> - <span></span> - </td> - </tr> - <tr> - <td>BTC Jumblr</td> - <td> + <div className={ 'tab-pane' + (this.state.activeTab === 1 ? ' active' : '') }> + <button + type="button" + className="btn btn-success waves-effect waves-light btn-next" + onClick={ () => this.openTab(2) }>Next</button> + <h5>{ translate('JUMBLR.FEW_SECURITY_NOTES') }</h5> + <div className="col-xs-12 nofloat"> + <ul className="padding-bottom-20"> + <li>{ translate('JUMBLR.FEW_SECURITY_NOTES_DESC1') }</li> + <li>{ translate('JUMBLR.FEW_SECURITY_NOTES_DESC2') }</li> + <li>{ translate('JUMBLR.FEW_SECURITY_NOTES_DESC3') }</li> + <li>{ translate('JUMBLR.FEW_SECURITY_NOTES_DESC4') }</li> + <li>{ translate('JUMBLR.FEW_SECURITY_NOTES_DESC5') }</li> + </ul> + </div> + { this.state.jumblrDepositAddressPBased && + <div className="padding-bottom-30"> + <div className="padding-bottom-20"> + <p> + <strong>Please write down your Jumblr passphrase and keept it safe.</strong> + </p> + <p>This is your main recovery passphrase.</p> + <p>All Jumblr addresses can be regenrated based on it.</p> + <p> + <strong>Tip:</strong> do not use smart editors to store your passphrase as they tend to add extra characters.<br />This may result in passphrase mismatch with the original passphrase. + </p> + </div> + <label>Passphrase</label> + <input + type="text" + className="form-control" + name="loginPassphrase" + onChange={ this.returnPassphrase } + value={ this.state.randomSeed } /> <button - type="button" - className="btn btn-animate btn-animate-side btn-default btn-sm waves-effect waves-light"> - <span> - <i className="icon fa-eye"></i> { translate('JUMBLR.SHOW_HIDE') } - </span> + className="btn btn-default btn-xs clipboard-edexaddr copy-string-btn" + title={ translate('INDEX.COPY_TO_CLIPBOARD') } + onClick={ () => this.copyPassphrase() }> + <i className="icon wb-copy"></i> { translate('INDEX.COPY') } </button> - <span className="label label-lg label-outline label-success hide"></span> - <span className="label label-lg label-outline label-default">{ translate('JUMBLR.HIDDEN') }</span> - </td> - </tr> - <tr> - <td>{ translate('JUMBLR.KMD_DEPOSIT') }</td> - <td></td> - </tr> - <tr> - <td>KMD Jumblr</td> - <td> + </div> + } + <button + type="button" + className="btn btn-info waves-effect waves-light" + onClick={ this.generateJumblrDepositAddress }>Create Jumblr deposit address</button> + { this.state.jumblrDepositAddress && this.state.jumblrDepositAddress.address && + <div className="padding-top-40"> + <strong>Your Jumblr deposit address:</strong> + <p> + { this.state.jumblrDepositAddress.address } + <button + className="btn btn-default btn-xs clipboard-edexaddr margin-left-10" + title={ translate('INDEX.COPY_TO_CLIPBOARD') } + onClick={ () => this._copyCoinAddress(this.state.jumblrDepositAddress.address) }> + <i className="icon wb-copy"></i> { translate('INDEX.COPY') } + </button> + </p> + <p> + { this.state.jumblrDepositAddress.wif } + <button + className="btn btn-default btn-xs clipboard-edexaddr margin-left-10" + title={ translate('INDEX.COPY_TO_CLIPBOARD') } + onClick={ () => this._copyCoinAddress(this.state.jumblrDepositAddress.wif) }> + <i className="icon wb-copy"></i> { translate('INDEX.COPY') } + </button> + </p> + </div> + } + </div> + <div className={ 'tab-pane' + (this.state.activeTab === 2 ? ' active' : '') }> + <button + type="button" + className="btn btn-success waves-effect waves-light margin-top-20 btn-next" + onClick={ () => this.openTab(3) }>Next</button> + <p>Jumblr secret addresses are used for the final z -> t transactions.</p> + <p>In order to allow larger accounts to obtain privacy, up to 777 secret addresses are supported.</p> + <p>Whenever a z -> t stage is activated, a random secret address from the list of the then active secret addresses is selected.</p> + <p>To add a new set of secret addresses enter address count below. The passphrase below is exactly the same you saw on the previous step.</p> + <p>Your Jumblr secret address recovery passphrase will have the following pattern <code>jumblr muffin smart educate tomato boss foil open dirt opinion pizza goddess skate action card garden cotton life write life note shine myself gloom summer XXX</code>. Where XXX any number from 001 to 777.</p> + + { this.state.jumblrDepositAddressPBased && + <div className="padding-bottom-20 padding-top-20"> + <label>Passphrase</label> + <input + type="text" + className="form-control" + name="jumblrPassphrase" + onChange={ this.returnPassphrase } + value={ this.state.randomSeed } /> <button - type="button" - className="btn btn-animate btn-animate-side btn-default btn-sm waves-effect waves-light"> - <span> - <i className="icon fa-eye"></i> { translate('JUMBLR.SHOW_HIDE') } - </span> + className="btn btn-default btn-xs clipboard-edexaddr copy-string-btn" + title={ translate('INDEX.COPY_TO_CLIPBOARD') } + onClick={ () => this.copyPassphrase() }> + <i className="icon wb-copy"></i> { translate('INDEX.COPY') } </button> - <span className="label label-lg label-outline label-success hide"></span> - <span className="label label-lg label-outline label-default"> - { translate('JUMBLR.HIDDEN') } - </span> - </td> - </tr> - </tbody> - </table> + </div> + } + <div className="col-xs-2 nofloat padding-top-30">Number of secret addresses</div> + <div className="col-xs-2 nofloat padding-left-10"> + <input + type="text" + pattern="[0-9]*" + className="form-control" + name="secretAddressCount" + min="1" + max="777" + onChange={ this.onChange } + value={ this.state.secretAddressCount } /> + </div> + <div className="col-xs-2 nofloat"> + <button + type="button" + className="btn btn-info waves-effect waves-light" + onClick={ this.generateJumblrSecretAddress }>Create Jumblr secret address(es)</button> + </div> + <div className="toggle-box padding-top-20"> + <span className="pointer"> + <label className="switch"> + <input + type="checkbox" + checked={ this.state.jumblrSecretAddressShow } /> + <div + className="slider" + onClick={ () => this.toggle('jumblrSecretAddressShow') }></div> + </label> + <div + className="toggle-label" + onClick={ () => this.toggle('jumblrSecretAddressShow') }> + Show address list + </div> + </span> + </div> + <div className="col-xlg-12 col-md-12 padding-top-20 nofloat"> + { this.state.jumblrSecretAddressShow && this.checkJumblrSecretAddressListLength('gen') && + <table className="table table-hover dataTable table-striped"> + <thead> + <tr> + <td> + <strong>Address</strong> + </td> + <td> + <strong>Wif</strong> + </td> + </tr> + </thead> + <tbody> + { this._JumblrRenderSecretAddressList('gen') } + </tbody> + </table> + } + </div> + </div> + <div className={ 'tab-pane' + (this.state.activeTab === 3 ? ' active' : '') }> + <p>Use the form below to send funds to your jumblr deposit address.</p> + <p className="padding-bottom-20">You can also send funds to deposit address from an external service or another wallet.</p> + <WalletsNativeSend + {...this.props} + renderFormOnly="true" + activeSection="send" /> + </div> + </div> </div> - </div> - </div> + } + { this.state.jumblrMode === 'private' && + <div className="jumblr-mode-selector nav-tabs-horizontal nav-tabs-inverse"> + <ul className="nav nav-tabs"> + <li + className={ this.state.activeTab === 0 ? 'active' : '' } + onClick={ () => this.openTab(0) }> + <a> + Import secret address + </a> + </li> + <li + className={ this.state.activeTab === 1 ? 'active' : '' } + onClick={ () => this.openTab(1) }> + <a> + Check funds + </a> + </li> + </ul> + <div className="tab-content padding-20"> + <div className={ 'tab-pane' + (this.state.activeTab === 0 ? ' active' : '') }> + <button + type="button" + className="btn btn-success waves-effect waves-light margin-top-20 btn-next" + onClick={ () => this.openTab(1) }>Next</button> + <div className="col-xlg-12 col-md-12 nofloat"> + <p>Enter your Jumblr passphrase you got previously during Public node configuration to import secret address.</p> + <p>Passphrase example: <code>jumblr muffin smart educate tomato boss foil open dirt opinion pizza goddess skate action card garden cotton life write life note shine myself gloom summer</code>.</p> + <p>The form below will "regenerate" Jumblr secret address based on passphrase provided.</p> + <p>After this final step expect to see funds processed and credited to your address after 2 days period.</p> - <div className="col-xlg-12 col-md-12"> - <h4 className="font-size-14 text-uppercase"> - { translate('JUMBLR.JSTATUS') } - </h4> - <div className="panel"> - <div className="table-responsive"> - <table className="table table-striped"> - <tbody> - <tr> - <td width="20%">{ translate('JUMBLR.RESULT') }</td> - <td> - <span className="label label-success"></span> - </td> - </tr> - <tr> - <td>{ translate('JUMBLR.DEPOSITED') }</td> - <td></td> - </tr> - <tr> - <td>{ translate('JUMBLR.PUB_TO_PRIV') }</td> - <td></td> - </tr> - <tr> - <td>{ translate('JUMBLR.PRIV_TO_PRIV') }</td> - <td></td> - </tr> - <tr> - <td>{ translate('JUMBLR.PRIV_TO_PUB') }</td> - <td></td> - </tr> - <tr> - <td>{ translate('JUMBLR.FINISHED') }</td> - <td></td> - </tr> - <tr> - <td>{ translate('JUMBLR.PENDING') }</td> - <td></td> - </tr> - </tbody> - </table> + { this.state.jumblrDepositAddressPBased && + <div className="padding-bottom-20 padding-top-20"> + <label>Passphrase</label> + <input + type="text" + className="form-control" + name="jumblrPassphraseImport" + onChange={ (event) => this.passphraseOnChange(event) } + value={ this.state.jumblrPassphraseImport } /> + </div> + } + <div className="col-xs-2 nofloat padding-top-30">Number of secret addresses</div> + <div className="col-xs-2 nofloat padding-left-10"> + <input + type="text" + pattern="[0-9]*" + className="form-control" + name="secretAddressCountImport" + min="1" + max="777" + onChange={ this.onChange } + value={ this.state.secretAddressCountImport } /> + </div> + <div className="col-xs-2 nofloat"> + <button + type="button" + className="btn btn-info waves-effect waves-light" + onClick={ this.importJumblrSecretAddress }>Import Jumblr secret address(es)</button> + </div> + <div className="toggle-box padding-top-20"> + <span className="pointer"> + <label className="switch"> + <input + type="checkbox" + checked={ this.state.jumblrSecretAddressShowImport } /> + <div + className="slider" + onClick={ () => this.toggle('jumblrSecretAddressShowImport') }></div> + </label> + <div + className="toggle-label" + onClick={ () => this.toggle('jumblrSecretAddressShowImport') }> + Show address list + </div> + </span> + </div> + <div className="col-xlg-12 col-md-12 padding-top-20 nofloat"> + { this.state.jumblrSecretAddressShowImport && this.checkJumblrSecretAddressListLength('import') && + <table className="table table-hover dataTable table-striped"> + <thead> + <tr> + <td> + <strong>Address</strong> + </td> + <td> + <strong>Wif</strong> + </td> + </tr> + </thead> + <tbody> + { this._JumblrRenderSecretAddressList('import') } + </tbody> + </table> + } + </div> + </div> + </div> + <div className={ 'tab-pane' + (this.state.activeTab === 1 ? ' active' : '') }> + <ReceiveCoin + {...this.props.ActiveCoin} + activeSection="receive" + renderTableOnly="true" /> + </div> + </div> </div> - </div> + } </div> </div> </div> diff --git a/react/src/components/dashboard/navbar/navbar.js b/react/src/components/dashboard/navbar/navbar.js index 6480b97..dfacb44 100755 --- a/react/src/components/dashboard/navbar/navbar.js +++ b/react/src/components/dashboard/navbar/navbar.js @@ -10,6 +10,7 @@ import { } from '../../../actions/actionCreators'; import Store from '../../../store'; import Config from '../../../config'; +import { checkAC } from '../../addcoin/payload'; import NavbarRender from './navbar.render'; @@ -23,6 +24,7 @@ class Navbar extends React.Component { this.openDropMenu = this.openDropMenu.bind(this); this.logout = this.logout.bind(this); this.handleClickOutside = this.handleClickOutside.bind(this); + this._checkAC = this._checkAC.bind(this); } componentWillMount() { @@ -67,6 +69,10 @@ class Navbar extends React.Component { Store.dispatch(dashboardChangeSection(sectionName)); } + _checkAC() { + return checkAC(this.props.ActiveCoin.coin); + } + logout() { Store.dispatch( stopInterval( diff --git a/react/src/components/dashboard/navbar/navbar.render.js b/react/src/components/dashboard/navbar/navbar.render.js index a3d80ff..4449f5f 100644 --- a/react/src/components/dashboard/navbar/navbar.render.js +++ b/react/src/components/dashboard/navbar/navbar.render.js @@ -57,11 +57,13 @@ const NavbarRender = function() { <i className="site-menu-icon"></i> BarterDEX </a> </li> - <li className={ 'hide ' + (this.isSectionActive('jumblr') ? 'active nav-top-menu' : 'nav-top-menu') }> - <a onClick={ () => this.dashboardChangeSection('jumblr') }> - <i className="site-menu-icon"></i> Jumblr - </a> - </li> + { this.props.ActiveCoin && this.props.ActiveCoin.mode === 'native' && (this._checkAC() || this.props.ActiveCoin.coin === 'KMD') && + <li className={ this.isSectionActive('jumblr') ? 'active nav-top-menu' : 'nav-top-menu' }> + <a onClick={ () => this.dashboardChangeSection('jumblr') }> + <i className="site-menu-icon"></i> Jumblr + </a> + </li> + } <li className={ this.state.nativeOnly ? 'hide' : (this.isSectionActive('atomic') ? 'active nav-top-menu' : 'nav-top-menu') }> <a onClick={ () => this.dashboardChangeSection('atomic') }> <i className="site-menu-icon"></i> Atomic Explorer diff --git a/react/src/components/dashboard/receiveCoin/receiveCoin.js b/react/src/components/dashboard/receiveCoin/receiveCoin.js index 1c13748..2038f55 100644 --- a/react/src/components/dashboard/receiveCoin/receiveCoin.js +++ b/react/src/components/dashboard/receiveCoin/receiveCoin.js @@ -10,7 +10,8 @@ import { AddressActionsBasiliskModeRender, AddressActionsNonBasiliskModeRender, AddressItemRender, - ReceiveCoinRender + ReceiveCoinRender, + _ReceiveCoinTableRender } from './receiveCoin.render'; // TODO: implement balance/interest sorting @@ -28,6 +29,11 @@ class ReceiveCoin extends React.Component { this.handleClickOutside = this.handleClickOutside.bind(this); this.toggleVisibleAddress = this.toggleVisibleAddress.bind(this); this.checkTotalBalance = this.checkTotalBalance.bind(this); + this.ReceiveCoinTableRender = _ReceiveCoinTableRender.bind(this); + } + + ReceiveCoinTableRender() { + return this._ReceiveCoinTableRender(); } componentWillMount() { @@ -108,7 +114,7 @@ class ReceiveCoin extends React.Component { } getNewAddress(type) { - Store.dispatch(getNewKMDAddresses(this.props.coin, type)); + Store.dispatch(getNewKMDAddresses(this.props.coin, type, this.props.mode)); } toggleVisibleAddress() { @@ -181,7 +187,7 @@ class ReceiveCoin extends React.Component { } if (this.state.hideZeroAddresses) { - if (!this.hasNoAmount) { + if (!this.hasNoAmount(address)) { items.push( AddressItemRender.call(this, address, type) ); @@ -200,10 +206,10 @@ class ReceiveCoin extends React.Component { } render() { - // TODO nativeActiveSection === 'receive' should be removed when native mode is fully merged + // TODO activeSection === 'receive' should be removed when native mode is fully merged // into the rest of the components if (this.props && - (this.props.receive || (this.isNativeMode() && this.props.nativeActiveSection === 'receive'))) { + (this.props.receive || (this.isNativeMode() && this.props.activeSection === 'receive'))) { return ReceiveCoinRender.call(this); } diff --git a/react/src/components/dashboard/receiveCoin/receiveCoin.render.js b/react/src/components/dashboard/receiveCoin/receiveCoin.render.js index 788988c..038ea1c 100644 --- a/react/src/components/dashboard/receiveCoin/receiveCoin.render.js +++ b/react/src/components/dashboard/receiveCoin/receiveCoin.render.js @@ -61,105 +61,119 @@ export const AddressItemRender = function(address, type) { ); }; -export const ReceiveCoinRender = function() { +export const _ReceiveCoinTableRender = function() { return ( - <div> - <div className="col-xs-12 margin-top-20"> - <div className="panel nav-tabs-horizontal"> - <div> - <div className="col-xlg-12 col-lg-12 col-sm-12 col-xs-12"> - <div className="panel"> - <header className="panel-heading"> - {this.isNativeMode() && - <div className="panel-actions"> - <div - className={ 'dropdown' + (this.state.openDropMenu ? ' open' : '') } - onClick={ this.openDropMenu }> - <a className="dropdown-toggle white btn btn-warning"> - <i className="icon md-arrows margin-right-10"></i> { translate('INDEX.GET_NEW_ADDRESS') } - <span className="caret"></span> - </a> - <ul - className="dropdown-menu dropdown-menu-right"> - <li> - <a onClick={ () => this.getNewAddress('public') }> - <i className="icon fa-eye"></i> { translate('INDEX.TRANSPARENT_ADDRESS') } - </a> - </li> - <li> - <a onClick={ () => this.getNewAddress('private') }> - <i className="icon fa-eye-slash"></i> { translate('INDEX.PRIVATE_Z_ADDRESS') } - </a> - </li> - </ul> - </div> - </div> - } - <h4 className="panel-title">{ translate('INDEX.RECEIVING_ADDRESS') }</h4> - </header> - <div className="panel-body"> - { this.checkTotalBalance() === 0 && - <div className="text-left padding-top-10 padding-bottom-10"> - <div - className="toggle-label margin-right-15 pointer" - onClick={ this.toggleVisibleAddress }> - { translate('INDEX.TOGGLE_ZERO_ADDRESSES') } - </div> - <label className="switch"> - <input - type="checkbox" - checked={ this.state.hideZeroAddresses } /> + <span> + { this.checkTotalBalance() !== 0 && + <div className="text-left padding-top-10 padding-bottom-10"> + <label className="switch"> + <input + type="checkbox" + checked={ this.state.hideZeroAddresses } /> + <div + className="slider" + onClick={ this.toggleVisibleAddress }></div> + </label> + <div + className="toggle-label margin-right-15 pointer" + onClick={ this.toggleVisibleAddress }> + { translate('INDEX.TOGGLE_ZERO_ADDRESSES') } + </div> + </div> + } + <table className="table table-hover dataTable table-striped"> + <thead> + { this.isNativeMode() ? + <tr> + <th>{ translate('INDEX.TYPE') }</th> + <th>{ translate('INDEX.ADDRESS') }</th> + <th>{ translate('INDEX.AMOUNT') }</th> + </tr> + : + <tr> + <th>{ translate('INDEX.TYPE') }</th> + <th>{ translate('INDEX.ADDRESS') }</th> + <th>{ translate('INDEX.BALANCE') }</th> + <th> {translate('INDEX.INTEREST') }</th> + </tr> + } + </thead> + <tbody> + { this.renderAddressList('public') } + { this.isNativeMode() && this.renderAddressList('private') } + </tbody> + <tfoot> + { this.isNativeMode() ? + <tr> + <th>{ translate('INDEX.TYPE') }</th> + <th>{ translate('INDEX.ADDRESS') }</th> + <th>{ translate('INDEX.AMOUNT') }</th> + </tr> + : + <tr> + <th>{ translate('INDEX.TYPE') }</th> + <th>{ translate('INDEX.ADDRESS') }</th> + <th>{ translate('INDEX.BALANCE') }</th> + <th>{ translate('INDEX.INTEREST') }</th> + </tr> + } + </tfoot> + </table> + </span> + ); +}; + +export const ReceiveCoinRender = function() { + if (this.props.renderTableOnly) { + return ( + <div>{ this.ReceiveCoinTableRender() }</div> + ); + } else { + return ( + <div> + <div className="col-xs-12 margin-top-20"> + <div className="panel nav-tabs-horizontal"> + <div> + <div className="col-xlg-12 col-lg-12 col-sm-12 col-xs-12"> + <div className="panel"> + <header className="panel-heading"> + { this.isNativeMode() && + <div className="panel-actions"> <div - className="slider" - onClick={ this.toggleVisibleAddress }></div> - </label> - </div> - } - <table className="table table-hover dataTable table-striped"> - <thead> - { this.isNativeMode() ? - <tr> - <th>{ translate('INDEX.TYPE') }</th> - <th>{ translate('INDEX.ADDRESS') }</th> - <th>{ translate('INDEX.AMOUNT') }</th> - </tr> - : - <tr> - <th>{ translate('INDEX.TYPE') }</th> - <th>{ translate('INDEX.ADDRESS') }</th> - <th>{ translate('INDEX.BALANCE') }</th> - <th> {translate('INDEX.INTEREST') }</th> - </tr> - } - </thead> - <tbody> - { this.renderAddressList('public') } - { this.isNativeMode() && this.renderAddressList('private') } - </tbody> - <tfoot> - { this.isNativeMode() ? - <tr> - <th>{ translate('INDEX.TYPE') }</th> - <th>{ translate('INDEX.ADDRESS') }</th> - <th>{ translate('INDEX.AMOUNT') }</th> - </tr> - : - <tr> - <th>{ translate('INDEX.TYPE') }</th> - <th>{ translate('INDEX.ADDRESS') }</th> - <th>{ translate('INDEX.BALANCE') }</th> - <th>{ translate('INDEX.INTEREST') }</th> - </tr> + className={ 'dropdown' + (this.state.openDropMenu ? ' open' : '') } + onClick={ this.openDropMenu }> + <a className="dropdown-toggle white btn btn-warning"> + <i className="icon md-arrows margin-right-10"></i> { translate('INDEX.GET_NEW_ADDRESS') } + <span className="caret"></span> + </a> + <ul + className="dropdown-menu dropdown-menu-right"> + <li> + <a onClick={ () => this.getNewAddress('public') }> + <i className="icon fa-eye"></i> { translate('INDEX.TRANSPARENT_ADDRESS') } + </a> + </li> + <li> + <a onClick={ () => this.getNewAddress('private') }> + <i className="icon fa-eye-slash"></i> { translate('INDEX.PRIVATE_Z_ADDRESS') } + </a> + </li> + </ul> + </div> + </div> } - </tfoot> - </table> + <h4 className="panel-title">{ translate('INDEX.RECEIVING_ADDRESS') }</h4> + </header> + <div className="panel-body"> + { this.ReceiveCoinTableRender() } + </div> </div> </div> </div> </div> </div> </div> - </div> - ); + ); + } }; diff --git a/react/src/components/dashboard/walletsBalance/walletsBalance.js b/react/src/components/dashboard/walletsBalance/walletsBalance.js index 72a4e43..b492df0 100755 --- a/react/src/components/dashboard/walletsBalance/walletsBalance.js +++ b/react/src/components/dashboard/walletsBalance/walletsBalance.js @@ -167,7 +167,7 @@ class WalletsBalance extends React.Component { } isNativeBalanceActive() { - return this.isNativeMode() && this.props.ActiveCoin.nativeActiveSection === 'default'; + return this.isNativeMode() && this.props.ActiveCoin.activeSection === 'default'; } isNonNativeBalanceActive() { diff --git a/react/src/components/dashboard/walletsData/pagination.js b/react/src/components/dashboard/walletsData/pagination.js index a3ff832..dba569d 100644 --- a/react/src/components/dashboard/walletsData/pagination.js +++ b/react/src/components/dashboard/walletsData/pagination.js @@ -4,42 +4,43 @@ import PaginationRender from './pagination.render'; export default class TablePaginationRenderer extends Component { constructor (props) { super(); - - this.getSafePage = this.getSafePage.bind(this); - this.changePage = this.changePage.bind(this); - this.applyPage = this.applyPage.bind(this); - this.state = { page: props.page } + this.getSafePage = this.getSafePage.bind(this); + this.changePage = this.changePage.bind(this); + this.applyPage = this.applyPage.bind(this); } - componentWillReceiveProps (nextProps) { + componentWillReceiveProps(nextProps) { this.setState({ page: nextProps.page }); } - getSafePage (page) { + getSafePage(page) { if (isNaN(page)) { page = this.props.page; } + return Math.min(Math.max(page, 0), this.props.pages - 1); } - changePage (page) { + changePage(page) { page = this.getSafePage(page); this.setState({ page }); + if (this.props.page !== page) { this.props.onPageChange(page); } } - applyPage (e) { - e && e.preventDefault(); + applyPage(e) { const page = this.state.page; + + e && e.preventDefault(); this.changePage(page === '' ? this.props.page : page); } - render () { + render() { return PaginationRender.call(this); } } \ No newline at end of file diff --git a/react/src/components/dashboard/walletsData/pagination.render.js b/react/src/components/dashboard/walletsData/pagination.render.js index f90af8a..e7535de 100644 --- a/react/src/components/dashboard/walletsData/pagination.render.js +++ b/react/src/components/dashboard/walletsData/pagination.render.js @@ -27,71 +27,67 @@ const PaginationRender = function() { return ( <div className={classnames(className, '-pagination')} - style={this.props.paginationStyle} - > - <div className='-previous'> + style={this.props.paginationStyle}> + <div className="-previous"> <PreviousComponent onClick={e => { if (!canPrevious) return; this.changePage(page - 1) }} - disabled={!canPrevious} - > + disabled={!canPrevious}> {this.props.previousText} </PreviousComponent> </div> - <div className='-center'> - <span className='-pageInfo'> - {this.props.pageText}{' '} - {showPageJump - ? - <div className='-pageJump'> - <input - type={this.state.page === '' ? 'text' : 'number'} - onChange={e => { - const val = e.target.value; - this.changePage(val - 1); - }} - value={this.state.page === '' ? '' : this.state.page + 1} - onBlur={this.applyPage} - onKeyPress={e => { - if (e.which === 13 || e.keyCode === 13) { - this.applyPage(); - } - }} - /> - </div> - : - <span className='-currentPage'> - {page + 1} - </span>}{' '} - {this.props.ofText}{' '} - <span className='-totalPages'>{pages || 1}</span> + <div className="-center"> + <span className="-pageInfo"> + {this.props.pageText}{' '} + {showPageJump + ? + <div className="-pageJump"> + <input + type={this.state.page === '' ? 'text' : 'number'} + onChange={e => { + const val = e.target.value; + this.changePage(val - 1); + }} + value={this.state.page === '' ? '' : this.state.page + 1} + onBlur={this.applyPage} + onKeyPress={e => { + if (e.which === 13 || e.keyCode === 13) { + this.applyPage(); + } + }} /> + </div> + : + <span className="-currentPage"> + {page + 1} + </span>}{' '} + {this.props.ofText}{' '} + <span className="-totalPages">{pages || 1}</span> + </span> + { showPageSizeOptions && + <span className="select-wrap -pageSizeOptions"> + <select + onChange={e => onPageSizeChange(Number(e.target.value))} + value={pageSize}> + { pageSizeOptions.map((option, i) => { + return ( + <option key={i} value={option}> + {option} {this.props.rowsText} + </option> + ); + })} + </select> </span> - {showPageSizeOptions && - <span className='select-wrap -pageSizeOptions'> - <select - onChange={e => onPageSizeChange(Number(e.target.value))} - value={pageSize} - > - {pageSizeOptions.map((option, i) => { - return ( - <option key={i} value={option}> - {option} {this.props.rowsText} - </option> - ) - })} - </select> - </span>} + } </div> - <div className='-next'> + <div className="-next"> <NextComponent onClick={e => { if (!canNext) return; this.changePage(page + 1) }} - disabled={!canNext} - > + disabled={!canNext}> {this.props.nextText} </NextComponent> </div> diff --git a/react/src/components/dashboard/walletsData/walletsData.js b/react/src/components/dashboard/walletsData/walletsData.js index b5fcd8b..2480162 100644 --- a/react/src/components/dashboard/walletsData/walletsData.js +++ b/react/src/components/dashboard/walletsData/walletsData.js @@ -53,7 +53,7 @@ class WalletsData extends React.Component { totalStackLength: 0, useCache: true, itemsListColumns: this.generateItemsListColumns(), - pageSize: 20, + pageSize: 10, showPagination: false, searchTerm: null, coin: null, @@ -117,6 +117,9 @@ class WalletsData extends React.Component { id: 'direction', Header: translate('INDEX.DIRECTION'), Footer: translate('INDEX.DIRECTION'), + className: 'colum--direction', + headerClassName: 'colum--direction', + footerClassName: 'colum--direction', accessor: (tx) => TxTypeRender.call(this, tx.category || tx.type) }, { @@ -158,15 +161,15 @@ class WalletsData extends React.Component { }); } - const txDetailColumnCssClasses = this.isBasiliskMode() ? 'hidden-xs hidden-sm text-center' : 'hidden-xs hidden-sm'; + // const txDetailColumnCssClasses = this.isBasiliskMode() ? 'hidden-xs hidden-sm' : 'hidden-xs hidden-sm'; columns.push({ id: 'tx-detail', Header: translate('INDEX.TX_DETAIL'), Footer: translate('INDEX.TX_DETAIL'), - headerClassName: txDetailColumnCssClasses, - footerClassName: txDetailColumnCssClasses, - className: txDetailColumnCssClasses, + className: 'colum--txinfo', + headerClassName: 'colum--txinfo', + footerClassName: 'colum--txinfo', Cell: props => TransactionDetailRender.call(this, props.index) }); @@ -389,15 +392,21 @@ class WalletsData extends React.Component { // TODO: add basilisk first run check, display no data if second run renderTxHistoryList() { - if (this.state.itemsList === 'loading') { - if (!this.isNativeMode() || this.isFullySynced()) { + if (this.state.itemsList === 'loading' || this.state.itemsList.length == 0) { + if (this.isFullySynced()) { return ( <tr className="hover--none"> <td colSpan="7">{ translate('INDEX.LOADING_HISTORY') }...</td> </tr> ); + } else { + return ( + <tr className="hover--none"> + <td colSpan="7">Synchronization is in progress...</td> + </tr> + ); } - } else if (this.state.itemsList === 'no data' || this.state.itemsList.length == 0) { + } else if (this.state.itemsList === 'no data') { return ( <tr className="hover--none"> <td colSpan="7">{ translate('INDEX.NO_DATA') }</td> @@ -413,7 +422,7 @@ class WalletsData extends React.Component { onPageSizeChange(pageSize, pageIndex) { this.setState(Object.assign({}, this.state, { pageSize: pageSize, - showPagination: this.state.itemsList && this.state.itemsList.length >= pageSize + showPagination: this.state.itemsList && this.state.itemsList.length >= pageSize, })) } @@ -547,6 +556,7 @@ class WalletsData extends React.Component { } shouldDisplayAddressList() { + //return true; return this.props.Dashboard && this.props.Dashboard.activeHandle && this.props.Dashboard.activeHandle[this.props.ActiveCoin.coin]; @@ -613,7 +623,7 @@ class WalletsData extends React.Component { !this.props.ActiveCoin.receive ) || ( this.props.ActiveCoin.mode === 'native' && - this.props.ActiveCoin.nativeActiveSection === 'default' + this.props.ActiveCoin.activeSection === 'default' )) { return WalletsDataRender.call(this); } else { diff --git a/react/src/components/dashboard/walletsData/walletsData.render.js b/react/src/components/dashboard/walletsData/walletsData.render.js index 121c21b..9c19aa6 100644 --- a/react/src/components/dashboard/walletsData/walletsData.render.js +++ b/react/src/components/dashboard/walletsData/walletsData.render.js @@ -13,11 +13,11 @@ import Config from '../../../config'; export const AddressTypeRender = function() { return ( - <td> + <span> <span className="label label-default"> <i className="icon fa-eye"></i> { translate('IAPI.PUBLIC_SM') } </span> - </td> + </span> ); }; @@ -49,8 +49,9 @@ export const AddressRender = function(tx) { export const AddressItemRender = function(address, type, amount, coin) { return ( - <li key={address} - className={ address === this.state.currentAddress ? 'selected' : '' }> + <li + key={address} + className={ address === this.state.currentAddress ? 'selected' : '' }> <a onClick={ () => this.updateAddressSelection(address) }> <i className={ 'icon fa-eye' + (type === 'public' ? '' : '-slash') }></i> <span className="text">[ { amount } { coin } ] { address }</span> @@ -98,37 +99,37 @@ export const TxTypeRender = function(category) { category === 'sent') { return ( <span className="label label-danger"> - <i className="icon fa-arrow-circle-left"></i> <span>{ translate('DASHBOARD.OUT') }</span> - </span> + <i className="icon fa-arrow-circle-left"></i> <span>{ translate('DASHBOARD.OUT') }</span> + </span> ); } if (category === 'receive' || category === 'received') { return ( <span className="label label-success"> - <i className="icon fa-arrow-circle-right"></i> <span>{ translate('DASHBOARD.IN') }</span> - </span> + <i className="icon fa-arrow-circle-right"></i> <span>{ translate('DASHBOARD.IN') }</span> + </span> ); } if (category === 'generate') { return ( <span> - <i className="icon fa-cogs"></i> <span>{ translate('DASHBOARD.MINED') }</span> - </span> + <i className="icon fa-cogs"></i> <span>{ translate('DASHBOARD.MINED') }</span> + </span> ); } if (category === 'immature') { return ( <span> - <i className="icon fa-clock-o"></i> <span>{ translate('DASHBOARD.IMMATURE') }</span> - </span> + <i className="icon fa-clock-o"></i> <span>{ translate('DASHBOARD.IMMATURE') }</span> + </span> ); } if (category === 'unknown') { return ( <span> - <i className="icon fa-meh-o"></i> <span>{ translate('DASHBOARD.UNKNOWN') }</span> - </span> + <i className="icon fa-meh-o"></i> <span>{ translate('DASHBOARD.UNKNOWN') }</span> + </span> ); } }; @@ -136,12 +137,12 @@ export const TxTypeRender = function(category) { export const TxAmountRender = function (tx) { if (Config.roundValues) { return ( - <td title={ tx.amount }>{ formatValue('round', tx.amount, -6) || translate('DASHBOARD.UNKNOWN') }</td> + <span title={ tx.amount }>{ formatValue('round', tx.amount, -6) || translate('DASHBOARD.UNKNOWN') }</span> ); } return ( - <td>{ tx.amount || translate('DASHBOARD.UNKNOWN') }</td> + <span>{ tx.amount || translate('DASHBOARD.UNKNOWN') }</span> ); }; @@ -151,15 +152,14 @@ export const TxHistoryListRender = function() { data={this.state.filteredItemsList} columns={this.state.itemsListColumns} sortable={true} - className='-striped -highlight' + className="-striped -highlight" PaginationComponent={TablePaginationRenderer} nextText={translate('INDEX.NEXT_PAGE')} previousText={translate('INDEX.PREVIOUS_PAGE')} showPaginationBottom={this.state.showPagination} showPaginationTop={this.state.showPagination} pageSize={this.pageSize} - onPageSizeChange={(pageSize, pageIndex) => this.onPageSizeChange(pageSize, pageIndex)} - /> + onPageSizeChange={(pageSize, pageIndex) => this.onPageSizeChange(pageSize, pageIndex)} /> ); }; @@ -240,22 +240,23 @@ export const WalletsDataRender = function() { null } </div> - <h4 className='panel-title'>{ translate('INDEX.TRANSACTION_HISTORY') }</h4> + <h4 className="panel-title">{ translate('INDEX.TRANSACTION_HISTORY') }</h4> </header> - <div className='panel-body'> - <div className='row padding-bottom-20'> - {this.shouldDisplayAddressList() && - <div className='col-sm-8'> + <div className="panel-body"> + <div className="row padding-bottom-20"> + { this.shouldDisplayAddressList() && + <div className="col-sm-8"> {this.renderAddressList()} </div> } - <div className='col-sm-4'> - <input className="form-control" - onChange={e => this.onSearchTermChange(e.target.value)} - placeholder='Search' /> + <div className="col-sm-4"> + <input + className="form-control" + onChange={e => this.onSearchTermChange(e.target.value)} + placeholder="Search" /> </div> </div> - <div className='row'> + <div className="row"> { this.renderTxHistoryList() } </div> </div> diff --git a/react/src/components/dashboard/walletsInfo/walletsInfo.js b/react/src/components/dashboard/walletsInfo/walletsInfo.js new file mode 100644 index 0000000..c3e1e81 --- /dev/null +++ b/react/src/components/dashboard/walletsInfo/walletsInfo.js @@ -0,0 +1,28 @@ +import React from 'react'; +import WalletsNativeInfoRender from './walletsInfo.render'; +import { toggleClaimInterestModal } from '../../../actions/actionCreators'; +import Store from '../../../store'; + +class WalletsNativeInfo extends React.Component { + constructor(props) { + super(props); + this.openClaimInterestModal = this.openClaimInterestModal.bind(this); + } + + openClaimInterestModal() { + Store.dispatch(toggleClaimInterestModal(true)); + } + + render() { + if (this.props && + this.props.Dashboard && + this.props.Dashboard.progress && + this.props.ActiveCoin.activeSection === 'settings') { + return WalletsNativeInfoRender.call(this); + } + + return null; + } +} + +export default WalletsNativeInfo; diff --git a/react/src/components/dashboard/walletsNativeInfo/walletsNativeInfo.render.js b/react/src/components/dashboard/walletsInfo/walletsInfo.render.js similarity index 90% rename from react/src/components/dashboard/walletsNativeInfo/walletsNativeInfo.render.js rename to react/src/components/dashboard/walletsInfo/walletsInfo.render.js index 07bd784..5b8dbd6 100644 --- a/react/src/components/dashboard/walletsNativeInfo/walletsNativeInfo.render.js +++ b/react/src/components/dashboard/walletsInfo/walletsInfo.render.js @@ -1,7 +1,8 @@ import React from 'react'; import { translate } from '../../../translate/translate'; +import ClaimInterestModal from '../claimInterestModal/claimInterestModal'; -const WalletsNativeInfoRender = function() { +const WalletsInfoRender = function() { return ( <div> <div className="col-xlg-6 col-md-4"> @@ -40,6 +41,15 @@ const WalletsNativeInfoRender = function() { </table> </div> </div> + { this.props.ActiveCoin.coin === 'KMD' && + <div> + <button + type="button" + className="btn btn-success waves-effect waves-light margin-top-20 btn-next" + onClick={ () => this.openClaimInterestModal() }>Claim interest</button> + <ClaimInterestModal {...this.props} /> + </div> + } </div> <div className="col-xlg-6 col-md-8"> @@ -146,4 +156,4 @@ const WalletsNativeInfoRender = function() { ); }; -export default WalletsNativeInfoRender; \ No newline at end of file +export default WalletsInfoRender; \ No newline at end of file diff --git a/react/src/components/dashboard/walletsNative/walletsNative.js b/react/src/components/dashboard/walletsNative/walletsNative.js index 764a55e..793ff9d 100644 --- a/react/src/components/dashboard/walletsNative/walletsNative.js +++ b/react/src/components/dashboard/walletsNative/walletsNative.js @@ -2,6 +2,7 @@ import React from 'react'; import WalletsNativeRender from './walletsNative.render'; import { translate } from '../../../translate/translate'; import { triggerToaster } from '../../../actions/actionCreators'; +import { getCoinTitle } from '../../../util/coinHelper'; import Config from '../../../config'; import Store from '../../../store'; @@ -13,6 +14,10 @@ const socket = io.connect(`http://127.0.0.1:${Config.agamaPort}`); class WalletsNative extends React.Component { constructor(props) { super(props); + this.state = { + nativeOnly: Config.iguanaLessMode, + }; + this.getCoinStyle = this.getCoinStyle.bind(this); socket.on('service', msg => this.updateSocketsData(msg)); } @@ -35,11 +40,21 @@ class WalletsNative extends React.Component { } } - defaultBG() { - if (this.props.ActiveCoin.coin === 'REVS') { - return 'supernet'; - } else { - return this.props.ActiveCoin.coin.toLowerCase(); + getCoinStyle(type) { + if (type === 'transparent') { + if (getCoinTitle(this.props.ActiveCoin.coin).transparentBG && getCoinTitle().logo) { + return { 'backgroundImage': `url("assets/images/bg/${getCoinTitle().logo.toLowerCase()}_transparent_header_bg.png")` }; + } + } else if (type === 'title') { + let _iconPath; + + if (getCoinTitle(this.props.ActiveCoin.coin).titleBG) { + _iconPath = `assets/images/native/${getCoinTitle(this.props.ActiveCoin.coin).logo.toLowerCase()}_header_title_logo.png`; + } else if (!getCoinTitle(this.props.ActiveCoin.coin).titleBG && getCoinTitle(this.props.ActiveCoin.coin).logo) { + _iconPath = `assets/images/cryptologo/${getCoinTitle(this.props.ActiveCoin.coin).logo.toLowerCase()}.png`; + } + + return _iconPath; } } diff --git a/react/src/components/dashboard/walletsNative/walletsNative.render.js b/react/src/components/dashboard/walletsNative/walletsNative.render.js index 15d5be5..e9202c2 100644 --- a/react/src/components/dashboard/walletsNative/walletsNative.render.js +++ b/react/src/components/dashboard/walletsNative/walletsNative.render.js @@ -1,6 +1,6 @@ import React from 'react'; import WalletsBalance from '../walletsBalance/walletsBalance'; -import WalletsNativeInfo from '../walletsNativeInfo/walletsNativeInfo'; +import WalletsInfo from '../walletsInfo/walletsInfo'; import WalletsNativeSend from '../walletsNativeSend/walletsNativeSend'; import WalletsProgress from '../walletsProgress/walletsProgress'; import WalletsData from '../walletsData/walletsData'; @@ -13,12 +13,14 @@ const WalletsNativeRender = function() { <div id="easydex-header-div" className="background-color-white" - style={{ 'backgroundImage': `url("assets/images/bg/${this.defaultBG()}_transparent_header_bg.png")` }}> - <ol className="breadcrumb"> + style={ this.getCoinStyle('transparent') }> + <ol className={ (!this.state.nativeOnly ? 'breadcrumb breadcrumb--normal' : 'breadcrumb') + (this.props.ActiveCoin.coin === 'KMD' || this.props.ActiveCoin.coin === 'JUMBLR' || this.props.ActiveCoin.coin === 'MESH' || this.props.ActiveCoin.coin === 'MVP' ? ' coin-logo-wide' : '') + (this.state.nativeOnly ? ' native-coin-logo' : '') }> <li className="header-easydex-section"> - <img src={ `assets/images/native/${this.defaultBG()}_header_title_logo.png` } /> + { this.getCoinStyle('title') && + <img src={ this.getCoinStyle('title') } /> + } <span - className={ `easydex-section-image ${(this.props.ActiveCoin.coin === 'KMD' ? 'hide' : '')}` } + className={ `easydex-section-image ${(this.props.ActiveCoin.coin === 'KMD' || this.props.ActiveCoin.coin === 'JUMBLR' || this.props.ActiveCoin.coin === 'MESH' || this.props.ActiveCoin.coin === 'MVP' ? 'hide' : '')}` } style={{ marginLeft: '20px' }}> { this.props.ActiveCoin.coin } </span> @@ -32,7 +34,7 @@ const WalletsNativeRender = function() { <ReceiveCoin {...this.props.ActiveCoin} /> <WalletsData {...this.props} /> <WalletsNativeSend {...this.props} /> - <WalletsNativeInfo {...this.props} /> + <WalletsInfo {...this.props} /> </div> </div> </div> diff --git a/react/src/components/dashboard/walletsNativeInfo/walletsNativeInfo.js b/react/src/components/dashboard/walletsNativeInfo/walletsNativeInfo.js deleted file mode 100644 index 6e025e1..0000000 --- a/react/src/components/dashboard/walletsNativeInfo/walletsNativeInfo.js +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; -import WalletsNativeInfoRender from './walletsNativeInfo.render'; - -class WalletsNativeInfo extends React.Component { - constructor(props) { - super(props); - } - - render() { - if (this.props && - this.props.Dashboard && - this.props.Dashboard.progress && - this.props.ActiveCoin.nativeActiveSection === 'settings') { - return WalletsNativeInfoRender.call(this); - } - - return null; - } -} - -export default WalletsNativeInfo; diff --git a/react/src/components/dashboard/walletsNativeSend/walletsNativeSend.js b/react/src/components/dashboard/walletsNativeSend/walletsNativeSend.js index d9a601e..0c89e11 100644 --- a/react/src/components/dashboard/walletsNativeSend/walletsNativeSend.js +++ b/react/src/components/dashboard/walletsNativeSend/walletsNativeSend.js @@ -12,7 +12,9 @@ import Store from '../../../store'; import { AddressListRender, OASendUIRender, - WalletsNativeSendRender + WalletsNativeSendRender, + WalletsNativeSendFormRender, + _WalletsNativeSendFormRender } from './walletsNativeSend.render'; class WalletsNativeSend extends React.Component { @@ -37,6 +39,11 @@ class WalletsNativeSend extends React.Component { this.checkZAddressCount = this.checkZAddressCount.bind(this); this.setRecieverFromScan = this.setRecieverFromScan.bind(this); this.renderOPIDListCheck = this.renderOPIDListCheck.bind(this); + this.WalletsNativeSendFormRender = _WalletsNativeSendFormRender.bind(this); + } + + WalletsNativeSendFormRender() { + return this._WalletsNativeSendFormRender(); } componentWillMount() { @@ -344,7 +351,7 @@ class WalletsNativeSend extends React.Component { render() { if (this.props && this.props.ActiveCoin && - this.props.ActiveCoin.nativeActiveSection === 'send') { + (this.props.ActiveCoin.activeSection === 'send' || this.props.activeSection === 'send')) { return WalletsNativeSendRender.call(this); } diff --git a/react/src/components/dashboard/walletsNativeSend/walletsNativeSend.render.js b/react/src/components/dashboard/walletsNativeSend/walletsNativeSend.render.js index fb9203f..d11ce18 100644 --- a/react/src/components/dashboard/walletsNativeSend/walletsNativeSend.render.js +++ b/react/src/components/dashboard/walletsNativeSend/walletsNativeSend.render.js @@ -65,151 +65,163 @@ export const OASendUIRender = function() { ); }; -export const WalletsNativeSendRender = function() { +export const _WalletsNativeSendFormRender = function() { return ( - <div id="kmd_wallet_send"> - <div className="col-xlg-12 col-md-12 col-sm-12 col-xs-12"> - <div - className="panel" - id="projects"> - <div className="panel-heading"> - <h3 className="panel-title"> - { translate('INDEX.SEND') } { this.props.ActiveCoin.coin } - </h3> - </div> - <div className="qr-modal-send-block"> - <QRModal - mode="scan" - setRecieverFromScan={ this.setRecieverFromScan } /> - </div> - <div className="panel-body container-fluid"> - <form - className="extcoin-send-form" - method="post" - autoComplete="off"> - { this.state.renderAddressDropdown && - <div className="row"> - <div className="col-xlg-12 form-group form-material"> - <label className="control-label">{ translate('INDEX.SEND_FROM') }</label> - { this.renderAddressList() } - </div> - </div> - } - { this.renderOASendUI() } - <div className="row"> - <div className="col-xlg-12 form-group form-material"> - <label - className="control-label" - htmlFor="kmdWalletSendTo">{ translate('INDEX.SEND_TO') }</label> - <input - type="text" - className="form-control" - name="sendTo" - onChange={ this.updateInput } - value={ this.state.sendTo } - id="kmdWalletSendTo" - placeholder={ translate('SEND.ENTER_T_OR_Z_ADDR') } - autoComplete="off" - required /> - </div> - <div className="col-lg-12 form-group form-material"> - <label - className="control-label" - htmlFor="kmdWalletAmount"> - { translate('INDEX.AMOUNT') } - </label> - <input - type="text" - className="form-control" - name="amount" - value={ this.state.amount !== 0 ? this.state.amount : '' } - onChange={ this.updateInput } - id="kmdWalletAmount" - placeholder="0.000" - autoComplete="off" /> - </div> - <div className="col-lg-6 form-group form-material hide"> - <label - className="control-label" - htmlFor="kmdWalletFee"> - { translate('INDEX.FEE') } - </label> - <input - type="text" - className="form-control" - name="fee" - onChange={ this.updateInput } - id="kmdWalletFee" - placeholder="0.000" - value={ this.state.fee !== 0 ? this.state.fee : '' } - autoComplete="off" /> - </div> - <div className="col-lg-12 hide"> - <span> - <strong>{ translate('INDEX.TOTAL') }:</strong> - { this.state.amount } - { this.state.fee }/kb = { Number(this.state.amount) - Number(this.state.fee) } - { this.props.ActiveCoin.coin } - </span> - </div> - <div className="col-lg-12"> - <button - type="button" - className="btn btn-primary waves-effect waves-light pull-right" - onClick={ this.handleSubmit } - disabled={ !this.state.sendTo || !this.state.amount }> - { translate('INDEX.SEND') } { this.state.amount } { this.props.ActiveCoin.coin } - </button> - </div> - </div> - </form> + <form + className="extcoin-send-form" + method="post" + autoComplete="off"> + { this.state.renderAddressDropdown && + <div className="row"> + <div className="col-xlg-12 form-group form-material"> + <label className="control-label">{ translate('INDEX.SEND_FROM') }</label> + { this.renderAddressList() } </div> </div> + } + { this.renderOASendUI() } + <div className="row"> + <div className="col-xlg-12 form-group form-material"> + <label + className="control-label" + htmlFor="kmdWalletSendTo">{ translate('INDEX.SEND_TO') }</label> + <input + type="text" + className="form-control" + name="sendTo" + onChange={ this.updateInput } + value={ this.state.sendTo } + id="kmdWalletSendTo" + placeholder={ translate('SEND.ENTER_T_OR_Z_ADDR') } + autoComplete="off" + required /> + </div> + <div className="col-lg-12 form-group form-material"> + <label + className="control-label" + htmlFor="kmdWalletAmount"> + { translate('INDEX.AMOUNT') } + </label> + <input + type="text" + className="form-control" + name="amount" + value={ this.state.amount !== 0 ? this.state.amount : '' } + onChange={ this.updateInput } + id="kmdWalletAmount" + placeholder="0.000" + autoComplete="off" /> + </div> + <div className="col-lg-6 form-group form-material hide"> + <label + className="control-label" + htmlFor="kmdWalletFee"> + { translate('INDEX.FEE') } + </label> + <input + type="text" + className="form-control" + name="fee" + onChange={ this.updateInput } + id="kmdWalletFee" + placeholder="0.000" + value={ this.state.fee !== 0 ? this.state.fee : '' } + autoComplete="off" /> + </div> + <div className="col-lg-12 hide"> + <span> + <strong>{ translate('INDEX.TOTAL') }:</strong> + { this.state.amount } - { this.state.fee }/kb = { Number(this.state.amount) - Number(this.state.fee) } + { this.props.ActiveCoin.coin } + </span> + </div> + <div className="col-lg-12"> + <button + type="button" + className="btn btn-primary waves-effect waves-light pull-right" + onClick={ this.handleSubmit } + disabled={ !this.state.sendTo || !this.state.amount }> + { translate('INDEX.SEND') } { this.state.amount } { this.props.ActiveCoin.coin } + </button> + </div> </div> + </form> + ); +} - { this.renderOPIDListCheck() && - <div className="col-xs-12"> - <div className="row"> - <div className="panel nav-tabs-horizontal"> - <div> - <div className="col-xlg-12 col-lg-12 col-sm-12 col-xs-12"> - <div className="panel"> - <header className="panel-heading"> - <h3 className="panel-title"> - { translate('INDEX.OPERATIONS_STATUSES') } - </h3> - </header> - <div className="panel-body"> - <table - className="table table-hover dataTable table-striped" - width="100%"> - <thead> - <tr> - <th>{ translate('INDEX.STATUS') }</th> - <th>ID</th> - <th>{ translate('INDEX.TIME') }</th> - <th>{ translate('INDEX.RESULT') }</th> - </tr> - </thead> - <tbody> - { this.renderOPIDList() } - </tbody> - <tfoot> - <tr> - <th>{ translate('INDEX.STATUS') }</th> - <th>ID</th> - <th>{ translate('INDEX.TIME') }</th> - <th>{ translate('INDEX.RESULT') }</th> - </tr> - </tfoot> - </table> +export const WalletsNativeSendRender = function() { + if (this.props.renderFormOnly) { + return ( + <div>{ this.WalletsNativeSendFormRender() }</div> + ); + } else { + return ( + <div id="kmd_wallet_send"> + <div className="col-xlg-12 col-md-12 col-sm-12 col-xs-12"> + <div + className="panel" + id="projects"> + <div className="panel-heading"> + <h3 className="panel-title"> + { translate('INDEX.SEND') } { this.props.ActiveCoin.coin } + </h3> + </div> + <div className="qr-modal-send-block"> + <QRModal + mode="scan" + setRecieverFromScan={ this.setRecieverFromScan } /> + </div> + <div className="panel-body container-fluid"> + { this.WalletsNativeSendFormRender() } + </div> + </div> + </div> + + { this.renderOPIDListCheck() && + <div className="col-xs-12"> + <div className="row"> + <div className="panel nav-tabs-horizontal"> + <div> + <div className="col-xlg-12 col-lg-12 col-sm-12 col-xs-12"> + <div className="panel"> + <header className="panel-heading"> + <h3 className="panel-title"> + { translate('INDEX.OPERATIONS_STATUSES') } + </h3> + </header> + <div className="panel-body"> + <table + className="table table-hover dataTable table-striped" + width="100%"> + <thead> + <tr> + <th>{ translate('INDEX.STATUS') }</th> + <th>ID</th> + <th>{ translate('INDEX.TIME') }</th> + <th>{ translate('INDEX.RESULT') }</th> + </tr> + </thead> + <tbody> + { this.renderOPIDList() } + </tbody> + <tfoot> + <tr> + <th>{ translate('INDEX.STATUS') }</th> + <th>ID</th> + <th>{ translate('INDEX.TIME') }</th> + <th>{ translate('INDEX.RESULT') }</th> + </tr> + </tfoot> + </table> + </div> </div> </div> </div> </div> </div> </div> - </div> - } - </div> - ); + } + </div> + ); + } }; \ No newline at end of file diff --git a/react/src/components/dashboard/walletsNav/walletsNav.js b/react/src/components/dashboard/walletsNav/walletsNav.js index 4b17767..702e236 100644 --- a/react/src/components/dashboard/walletsNav/walletsNav.js +++ b/react/src/components/dashboard/walletsNav/walletsNav.js @@ -73,7 +73,7 @@ class WalletsNav extends React.Component { if (this.props.ActiveCoin.mode === 'native') { Store.dispatch( toggleDashboardActiveSection( - this.props.ActiveCoin.nativeActiveSection === 'settings' ? 'default' : 'settings' + this.props.ActiveCoin.activeSection === 'settings' ? 'default' : 'settings' ) ); } else { @@ -93,7 +93,7 @@ class WalletsNav extends React.Component { if (this.props.ActiveCoin.mode === 'native') { Store.dispatch( toggleDashboardActiveSection( - this.props.ActiveCoin.nativeActiveSection === 'send' ? 'default' : 'send' + this.props.ActiveCoin.activeSection === 'send' ? 'default' : 'send' ) ); } else { @@ -105,7 +105,7 @@ class WalletsNav extends React.Component { if (this.props.ActiveCoin.mode === 'native') { Store.dispatch( toggleDashboardActiveSection( - this.props.ActiveCoin.nativeActiveSection === 'receive' ? 'default' : 'receive' + this.props.ActiveCoin.activeSection === 'receive' ? 'default' : 'receive' ) ); } else { diff --git a/react/src/components/dashboard/walletsNav/walletsNav.render.js b/react/src/components/dashboard/walletsNav/walletsNav.render.js index 67d43a7..b17f82d 100644 --- a/react/src/components/dashboard/walletsNav/walletsNav.render.js +++ b/react/src/components/dashboard/walletsNav/walletsNav.render.js @@ -24,9 +24,9 @@ export const WalletsNavWithWalletRender = function() { return ( <div> <div - className={ 'page-header page-header-bordered header-easydex padding-bottom-' + (this.state.nativeOnly ? '40' : '20') } + className={ 'page-header page-header-bordered header-easydex padding-bottom-' + (this.state.nativeOnly ? '40 page-header--native' : '20') } id="header-dashboard" - style={{ marginBottom: this.props.ActiveCoin.mode === 'basilisk' ? '30px' : '0' }}> + style={{ marginBottom: this.props.ActiveCoin.mode === 'basilisk' ? '30px' : (this.state.nativeOnly ? '30px' : '0') }}> <ol className={ this.state.nativeOnly ? 'hide' : 'breadcrumb' }> <strong>{ translate('INDEX.MY') } { this.props && this.props.ActiveCoin ? this.props.ActiveCoin.coin : '-' } { translate('INDEX.ADDRESS') }: </strong> { this.props && this.props.Dashboard && this.props.Dashboard.activeHandle ? this.props.Dashboard.activeHandle[this.props.ActiveCoin.coin] : '-' } diff --git a/react/src/components/dashboard/walletsTxInfo/walletsTxInfo.js b/react/src/components/dashboard/walletsTxInfo/walletsTxInfo.js index 2ee27b8..0a5b07d 100644 --- a/react/src/components/dashboard/walletsTxInfo/walletsTxInfo.js +++ b/react/src/components/dashboard/walletsTxInfo/walletsTxInfo.js @@ -43,7 +43,7 @@ class WalletsTxInfo extends React.Component { // TODO the conditions below should be merged once the native mode components are fully merged // into the rest of the components (!this.isNativeMode() || - (this.isNativeMode() && this.props.ActiveCoin.nativeActiveSection === 'default'))) { + (this.isNativeMode() && this.props.ActiveCoin.activeSection === 'default'))) { const txInfo = sortByDate(this.props.ActiveCoin.txhistory)[this.props.ActiveCoin.showTransactionInfoTxIndex]; return WalletsTxInfoRender.call(this, txInfo); } diff --git a/react/src/components/main/main.js b/react/src/components/main/main.js index 88f66c3..6394888 100644 --- a/react/src/components/main/main.js +++ b/react/src/components/main/main.js @@ -5,7 +5,8 @@ import Store from '../../store'; import { Config, getDexCoins, - iguanaActiveHandle + iguanaActiveHandle, + triggerToaster } from '../../actions/actionCreators'; const IGUANA_ACTIVE_HANDLE_TIMEOUT = 30000; @@ -24,15 +25,28 @@ class Main extends React.Component { componentDidMount() { let appVersion; + let zcashParamsExist; try { appVersion = window.require('electron').remote.getCurrentWindow().appBasicInfo; + zcashParamsExist = window.require('electron').remote.getCurrentWindow().zcashParamsExist; } catch (e) {} if (appVersion) { document.title = `${appVersion.name} (v${appVersion.version.replace('version=', '')}-beta)`; } + if (!zcashParamsExist) { + Store.dispatch( + triggerToaster( + 'Zcash params are missing', + 'Komodo', + 'error', + false + ) + ); + } + Store.dispatch(iguanaActiveHandle()); const _iguanaActiveHandle = setInterval(function() { Store.dispatch(iguanaActiveHandle()); diff --git a/react/src/components/overrides.scss b/react/src/components/overrides.scss index a3cb152..3b9c82a 100644 --- a/react/src/components/overrides.scss +++ b/react/src/components/overrides.scss @@ -94,7 +94,8 @@ body { display: block; } -.collapse-active { +.collapse-active, +.panel>:not(.panel-loading):not(.collapsing) { transition: height 0.3s ease-out; } @@ -628,12 +629,19 @@ select{ > div { height: 100%; } + .form-group { + &.form-material { + &.floating { + height: 80%; + } + } + } .page-content { width: 90%; height: 100%; textarea { - min-height: 200px; + height: 100%; } } } @@ -684,4 +692,237 @@ select{ } } } +} + +.breadcrumb { + padding: 8px 30px 0; + position: relative; + top: -10px; +} + +.header-easydex-section { + img { + max-width: 60px; + } +} + +.coin-logo-wide { + padding: 8px 30px 0; + position: relative; + top: 0; + + .header-easydex-section { + img { + width: inherit; + max-width: inherit; + position: relative; + top: -5px; + } + } +} + +.native-coin-logo { + float: left; + position: absolute; + top: -105px; + z-index: 100; + + .header-easydex-section { + img { + width: 60px; + } + } +} + +.coin-logo-wide { + &.native-coin-logo { + top: -93px; + + .header-easydex-section img { + width: inherit; + } + } +} + +.page-header--native { + height: 75px; +} + +#toast-container { + > div { + opacity: 1; + } +} + +/* jumblr */ +.jumblr { + p { + width: calc(100% - 100px); + } + .breadcrumb { + padding: 8px 30px; + position: relative; + top: 0; + } + .img-responsive { + position: absolute; + top: -28px; + right: 18px; + + .coin { + font-size: 30px; + position: relative; + left: -18px; + top: 4px; + } + .image { + width: 60px; + } + } + .header-easydex-section { + img { + max-width: inherit; + } + } + .copy-string-btn { + position: absolute; + right: 36px; + margin-top: -68px; + } + .btn-next { + position: absolute; + top: 60px; + right: 32px; + } + input.labelauty+label, + input.labelauty+label { + background: #d6d5d5; + color: #504e4e; + } + input.labelauty:checked+label { + color: #fff; + background-color: #3949ab; + } + input.labelauty + label:hover .labelauty-unchecked, + input.labelauty + label .labelauty-unchecked { + color: #504e4e; + } + .nofloat { + float: none; + display: inline-block; + padding-left: 0; + } +} + +.jumblr-mode-selector { + .nav-tabs { + li { + cursor: pointer; + + &.active { + > a { + cursor: pointer; + color: #fff; + background-color: #62a8ea; + border-color: transparent; + border-bottom-color: #62a8ea; + } + } + } + } + + .panel-heading { + background: #f3f3f3; + cursor: pointer; + } + .panel-title { + color: #676767; + } + .jumblr-addresses-list { + .col-xs-3 { + padding: 0; + } + } +} + +.modal-claim-interest { + .modal-dialog { + width: 70%; + + .table > tbody > tr > td, + .table > tbody > tr > th, + .table > tfoot > tr > td, + .table > tfoot > tr > th, + .table > thead > tr > td, + .table > thead > tr > th { + padding: 8px 30px 8px 0; + } + + .claim-btn { + position: absolute; + right: 29px; + top: 66px; + } + .table-scroll { + height: 366px; + overflow-y: auto; + overflow-x: hidden; + width: 100%; + } + .bold { + font-weight: bold; + } + .green { + color: #66bb6a; + } + .red { + color: #f96868; + } + .locktime { + i { + font-size: 20px; + line-height: 1.1; + } + } + + .refresh-icon { + position: absolute; + right: 20px; + font-size: 20px; + z-index: 100; + } + } +} + +.ReactTable { + border: none; + + .pagination-top { + display: none; + } + .rt-td { + text-align: center; + } + .ReactTable .rt-thead .rt-th, + .ReactTable .rt-thead .rt-td { + padding: 10px 5px; + } + .rt-table { + border: 1px solid rgba(0, 0, 0, 0.1); + } + .rt-tfoot { + border-top: 1px solid rgba(0, 0, 0, 0.1); + } + .rt-thead { + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + } + .rt-thead .rt-th, + .rt-thead .rt-td { + padding: 10px 5px; + } + .colum--direction { + width: 40px !important; + flex: 40 0 auto !important; + padding-right: 10px; + } } \ No newline at end of file diff --git a/react/src/reducers/activeCoin.js b/react/src/reducers/activeCoin.js index ec0dee3..0a976a6 100644 --- a/react/src/reducers/activeCoin.js +++ b/react/src/reducers/activeCoin.js @@ -27,7 +27,7 @@ export function ActiveCoin(state = { send: false, receive: false, balance: 0, - nativeActiveSection: 'default', + activeSection: 'default', showTransactionInfo: false, showTransactionInfoTxIndex: null, txhistory: [], @@ -53,7 +53,7 @@ export function ActiveCoin(state = { receive: state.receive, showTransactionInfo: state.showTransactionInfo, showTransactionInfoTxIndex: state.showTransactionInfoTxIndex, - nativeActiveSection: state.nativeActiveSection, + activeSection: state.activeSection, lastSendToResponse: state.lastSendToResponse, mainBasiliskAddress: state.mainBasiliskAddress, opids: state.opids, @@ -73,7 +73,7 @@ export function ActiveCoin(state = { receive: _coinData.receive, showTransactionInfo: _coinData.showTransactionInfo, showTransactionInfoTxIndex: _coinData.showTransactionInfoTxIndex, - nativeActiveSection: _coinData.nativeActiveSection, + activeSection: _coinData.activeSection, lastSendToResponse: _coinData.lastSendToResponse, mainBasiliskAddress: _coinData.mainBasiliskAddress, opids: _coinData.opids, @@ -91,7 +91,7 @@ export function ActiveCoin(state = { receive: state.receive, showTransactionInfo: state.showTransactionInfo, showTransactionInfoTxIndex: state.showTransactionInfoTxIndex, - nativeActiveSection: state.nativeActiveSection, + activeSection: state.activeSection, lastSendToResponse: state.lastSendToResponse, mainBasiliskAddress: state.mainBasiliskAddress, opids: state.opids, @@ -110,7 +110,7 @@ export function ActiveCoin(state = { receive: false, showTransactionInfo: false, showTransactionInfoTxIndex: null, - nativeActiveSection: 'default', + activeSection: 'default', }); } else { return Object.assign({}, state, { @@ -122,7 +122,7 @@ export function ActiveCoin(state = { receive: false, showTransactionInfo: false, showTransactionInfoTxIndex: null, - nativeActiveSection: 'default', + activeSection: 'default', }); } } @@ -151,7 +151,7 @@ export function ActiveCoin(state = { }); case DASHBOARD_ACTIVE_SECTION: return Object.assign({}, state, { - nativeActiveSection: action.section, + activeSection: action.section, }); case DASHBOARD_ACTIVE_TXINFO_MODAL: return Object.assign({}, state, { diff --git a/react/src/reducers/dashboard.js b/react/src/reducers/dashboard.js index 98df82e..54e2e63 100644 --- a/react/src/reducers/dashboard.js +++ b/react/src/reducers/dashboard.js @@ -9,14 +9,15 @@ import { VIEW_CACHE_DATA, LOG_GUI_HTTP, TOGGLE_NOTIFICATIONS_MODAL, - DISPLAY_COIND_DOWN_MODAL + DISPLAY_COIND_DOWN_MODAL, + DISPLAY_CLAIM_INTEREST_MODAL } from '../actions/storeType'; const HTTP_STACK_MAX_ENTRIES = 150; // limit stack mem length to N records per type const trimHTTPLogs = (logObject) => { const logObjectArray = Object.keys(logObject); - + if (logObjectArray.length - HTTP_STACK_MAX_ENTRIES === 1) { delete logObject[logObjectArray.shift()]; } @@ -38,6 +39,7 @@ export function Dashboard(state = { }, guiLog: {}, displayCoindDownModal: false, + displayClaimInterestModal: false, }, action) { switch (action.type) { case DASHBOARD_SECTION_CHANGE: @@ -95,7 +97,7 @@ export function Dashboard(state = { const logItem = { [actionTS]: action.log }; newLogState = trimHTTPLogs(Object.assign({}, logState, logItem)); } - + return Object.assign({}, state, { guiLog: newLogState, }); @@ -104,6 +106,11 @@ export function Dashboard(state = { displayCoindDownModal: action.displayCoindDownModal, }); break; + case DISPLAY_CLAIM_INTEREST_MODAL: + return Object.assign({}, state, { + displayClaimInterestModal: action.displayClaimInterestModal, + }); + break; default: return state; } diff --git a/react/src/translate/en.js b/react/src/translate/en.js index 9779a73..c3032d6 100644 --- a/react/src/translate/en.js +++ b/react/src/translate/en.js @@ -281,15 +281,15 @@ export const _lang = { }, 'JUMBLR': { 'NOTICE': 'EXPERIMENTAL TEST VERSION ONLY', - 'DESCRIPTION': 'Jumblr feature is very experimental and for now, is Only enabled for testing and debugging.' + + 'DESCRIPTION': 'Jumblr feature is very experimental and for now, is Only enabled for testing and debugging. ' + 'Please use the current version of Jumblr only with small amounts if you are participating in testing this feature.', 'NEED_NATIVE': 'Need Native Mode Komodo', 'TO_USE_JUMBLR': 'To use Jumblr feature, you need to activate Komodo in Native Mode.', 'IF_YOU_ALREADY_RUNNING': 'If you are already running Komodo in either Basilisk Mode or Full Mode, close the wallet and restart again to start Komodo In Native Mode.', 'THIS_SCREEN_DOESNT_REFRESH': 'This screen does not auto refresh. ' + - 'You will need to hit the Refresh button on the top right corner of the screen to get latest Jumblr data.', + 'You will need to hit the Refresh button on the top right corner of the screen to get latest Jumblr data.', 'FEW_SECURITY_NOTES': 'Few Security Notes for your Privacy and Anonymity of funds', - 'FEW_SECURITY_NOTES_DESC1': 'Jumblr addresses (BTC Jumbler and KMD Jumbler) addresses are your Private Addresses.', + 'FEW_SECURITY_NOTES_DESC1': 'Jumblr addresses addresses are your Private Addresses.', 'FEW_SECURITY_NOTES_DESC2': 'DO NOT SHARE your Jumblr addresses with anyone.', 'FEW_SECURITY_NOTES_DESC3': 'Jumblr addresses are like YOUR PASSWORD. Keep them safe, secure and hidden.', 'FEW_SECURITY_NOTES_DESC4': 'Only YOU should know your Jumblr Address. Nobody else.', diff --git a/react/src/util/coinHelper.js b/react/src/util/coinHelper.js index 216795f..9ee30c1 100644 --- a/react/src/util/coinHelper.js +++ b/react/src/util/coinHelper.js @@ -1,6 +1,9 @@ export function getCoinTitle(coin) { - let coinlogo, - coinname; + let coinlogo; + let coinname; + let transparentBG = false; + let titleBG = false; + let hideTitle = false; switch (coin) { case 'BTC': @@ -56,7 +59,10 @@ export function getCoinTitle(coin) { coinname = 'Zetacoin'; break; case 'KMD': - coinlogo = 'komodo'; + hideTitle = true; + titleBG = true; + transparentBG = true; + coinlogo = 'kmd'; coinname = 'Komodo'; break; case 'BTM': @@ -80,6 +86,7 @@ export function getCoinTitle(coin) { coinname = 'GameCredits'; break; case 'SUPERNET': + titleBG = true; coinlogo = 'SUPERNET'; coinname = 'SUPERNET'; break; @@ -88,14 +95,20 @@ export function getCoinTitle(coin) { coinname = 'REVS'; break; case 'WLC': + titleBG = true; + transparentBG = true; coinlogo = 'WLC'; coinname = 'WIRELESS'; break; case 'PANGEA': + titleBG = true; coinlogo = 'PANGEA'; coinname = 'PANGEA'; break; case 'JUMBLR': + titleBG = true; + transparentBG = true; + hideTitle = true; coinlogo = 'JUMBLR'; coinname = 'JUMBLR'; break; @@ -124,6 +137,9 @@ export function getCoinTitle(coin) { coinname = 'MultiGateway'; break; case 'MVP': + hideTitle = true; + titleBG = true; + transparentBG = true; coinlogo = 'MVP'; coinname = 'MVP Lineup'; break; @@ -132,138 +148,197 @@ export function getCoinTitle(coin) { coinname = 'KV'; break; case 'CEAL': + titleBG = true; + transparentBG = true; coinlogo = 'CEAL'; coinname = 'CEAL NET'; break; + case 'COQUI': + coinlogo = 'COQUI'; + coinname = 'COQUI'; + break; case 'MESH': + hideTitle = true; + titleBG = true; + transparentBG = true; coinlogo = 'MESH'; coinname = 'SpaceMesh'; break; case 'USD': + titleBG = true; + transparentBG = true; coinlogo = 'usd'; coinname = 'US Dollar'; break; case 'RON': + titleBG = true; + transparentBG = true; coinlogo = 'RON'; coinname = 'Romanian Leu'; break; case 'EUR': + titleBG = true; + transparentBG = true; coinlogo = 'EUR'; coinname = 'Euro'; break; case 'JPY': + titleBG = true; + transparentBG = true; coinlogo = 'JPY'; coinname = 'Japanese Yen'; break; case 'GBP': + titleBG = true; + transparentBG = true; coinlogo = 'GBP'; coinname = 'British Pound'; break; case 'AUD': + titleBG = true; + transparentBG = true; coinlogo = 'AUD'; coinname = 'Australian Dollar'; break; case 'CAD': + titleBG = true; + transparentBG = true; coinlogo = 'CAD'; coinname = 'Canadian Dollar'; break; case 'CHF': + titleBG = true; + transparentBG = true; coinlogo = 'CHF'; coinname = 'Swiss Franc'; break; case 'NZD': + titleBG = true; + transparentBG = true; coinlogo = 'NZD'; coinname = 'New Zealand Dollar'; break; case 'CNY': + titleBG = true; + transparentBG = true; coinlogo = 'CNY'; coinname = 'Chinese Yuan'; break; case 'RUB': + titleBG = true; + transparentBG = true; coinlogo = 'RUB'; coinname = 'Russian Ruble'; break; case 'MXN': + titleBG = true; + transparentBG = true; coinlogo = 'MXN'; coinname = 'Mexican peso'; break; case 'BRL': + titleBG = true; + transparentBG = true; coinlogo = 'BRL'; coinname = 'Brazilian Real'; break; case 'INR': + titleBG = true; + transparentBG = true; coinlogo = 'INR'; coinname = 'Indian Rupee'; break; case 'HKD': + titleBG = true; + transparentBG = true; coinlogo = 'HKD'; coinname = 'Hong Kong Dollar'; break; case 'TRY': + titleBG = true; + transparentBG = true; coinlogo = 'TRY'; coinname = 'Turkish Lira'; break; case 'ZAR': + titleBG = true; + transparentBG = true; coinlogo = 'ZAR'; coinname = 'South African Rand'; break; case 'PLN': + titleBG = true; + transparentBG = true; coinlogo = 'PLN'; coinname = 'Polish Zloty'; break; case 'NOK': + titleBG = true; coinlogo = 'NOK'; coinname = 'Norwegian Krone'; break; case 'SEK': + titleBG = true; coinlogo = 'SEK'; coinname = 'Swedish Krona'; break; case 'DKK': + titleBG = true; coinlogo = 'DKK'; coinname = 'Danish Krone'; break; case 'CZK': + titleBG = true; coinlogo = 'CZK'; coinname = 'Czech Koruna'; break; case 'HUF': + titleBG = true; coinlogo = 'HUF'; coinname = 'Hungarian Forint'; break; case 'ILS': + titleBG = true; coinlogo = 'ILS'; coinname = 'Israeli Shekel'; break; case 'KRW': + titleBG = true; coinlogo = 'KRW'; coinname = 'Korean Won'; break; case 'MYR': + titleBG = true; coinlogo = 'MYR'; coinname = 'Malaysian Ringgit'; break; case 'PHP': + titleBG = true; coinlogo = 'PHP'; coinname = 'Philippine Peso'; break; case 'SGD': + titleBG = true; coinlogo = 'SGD'; coinname = 'Singapore Dollar'; break; case 'THB': + titleBG = true; coinlogo = 'THB'; coinname = 'Thai Baht'; break; case 'BGN': + titleBG = true; coinlogo = 'BGN'; coinname = 'Bulgarian Lev'; break; case 'IDR': + titleBG = true; coinlogo = 'IDR'; coinname = 'Indonesian Rupiah'; break; case 'HRK': + titleBG = true; coinlogo = 'HRK'; coinname = 'Croatian Kuna'; break; @@ -271,14 +346,16 @@ export function getCoinTitle(coin) { return { 'logo': coinlogo, - 'name': coinname + 'name': coinname, + titleBG, + transparentBG, }; } export function getModeInfo(mode) { - let modecode, - modetip, - modecolor; + let modecode; + let modetip; + let modecolor; switch (mode) { case 'native': diff --git a/react/src/util/crypto/gen/array.map.js b/react/src/util/crypto/gen/array.map.js new file mode 100755 index 0000000..d1b362f --- /dev/null +++ b/react/src/util/crypto/gen/array.map.js @@ -0,0 +1,57 @@ +// Array.prototype.map function is in the public domain. +// Production steps of ECMA-262, Edition 5, 15.4.4.19 +// Reference: http://es5.github.com/#x15.4.4.19 +if (!Array.prototype.map) { + Array.prototype.map = function (callback, thisArg) { + var T, A, k; + if (this == null) { + throw new TypeError(" this is null or not defined"); + } + // 1. Let O be the result of calling ToObject passing the |this| value as the argument. + var O = Object(this); + // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". + // 3. Let len be ToUint32(lenValue). + var len = O.length >>> 0; + // 4. If IsCallable(callback) is false, throw a TypeError exception. + // See: http://es5.github.com/#x9.11 + if ({}.toString.call(callback) != "[object Function]") { + throw new TypeError(callback + " is not a function"); + } + // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. + if (thisArg) { + T = thisArg; + } + // 6. Let A be a new array created as if by the expression new Array(len) where Array is + // the standard built-in constructor with that name and len is the value of len. + A = new Array(len); + // 7. Let k be 0 + k = 0; + // 8. Repeat, while k < len + while (k < len) { + var kValue, mappedValue; + // a. Let Pk be ToString(k). + // This is implicit for LHS operands of the in operator + // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. + // This step can be combined with c + // c. If kPresent is true, then + if (k in O) { + // i. Let kValue be the result of calling the Get internal method of O with argument Pk. + kValue = O[k]; + // ii. Let mappedValue be the result of calling the Call internal method of callback + // with T as the this value and argument list containing kValue, k, and O. + mappedValue = callback.call(T, kValue, k, O); + // iii. Call the DefineOwnProperty internal method of A with arguments + // Pk, Property Descriptor {Value: mappedValue, Writable: true, Enumerable: true, Configurable: true}, + // and false. + // In browsers that support Object.defineProperty, use the following: + // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true }); + // For best browser support, use the following: + A[k] = mappedValue; + } + // d. Increase k by 1. + k++; + } + // 9. return A + return A; + }; +} \ No newline at end of file diff --git a/react/src/util/crypto/gen/biginteger.js b/react/src/util/crypto/gen/biginteger.js new file mode 100755 index 0000000..4d9c4ef --- /dev/null +++ b/react/src/util/crypto/gen/biginteger.js @@ -0,0 +1,1271 @@ +/*! +* Basic JavaScript BN library - subset useful for RSA encryption. v1.3 +* +* Copyright (c) 2005 Tom Wu +* All Rights Reserved. +* BSD License +* http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE +* +* Copyright Stephan Thomas +* Copyright bitaddress.org +*/ + +(function () { + + // (public) Constructor function of Global BigInteger object + var BigInteger = window.BigInteger = function BigInteger(a, b, c) { + if (a != null) + if ("number" == typeof a) this.fromNumber(a, b, c); + else if (b == null && "string" != typeof a) this.fromString(a, 256); + else this.fromString(a, b); + }; + + // Bits per digit + var dbits; + + // JavaScript engine analysis + var canary = 0xdeadbeefcafe; + var j_lm = ((canary & 0xffffff) == 0xefcafe); + + // return new, unset BigInteger + function nbi() { return new BigInteger(null); } + + // am: Compute w_j += (x*this_i), propagate carries, + // c is initial carry, returns final carry. + // c < 3*dvalue, x < 2*dvalue, this_i < dvalue + // We need to select the fastest one that works in this environment. + + // am1: use a single mult and divide to get the high bits, + // max digit bits should be 26 because + // max internal value = 2*dvalue^2-2*dvalue (< 2^53) + function am1(i, x, w, j, c, n) { + while (--n >= 0) { + var v = x * this[i++] + w[j] + c; + c = Math.floor(v / 0x4000000); + w[j++] = v & 0x3ffffff; + } + return c; + } + // am2 avoids a big mult-and-extract completely. + // Max digit bits should be <= 30 because we do bitwise ops + // on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) + function am2(i, x, w, j, c, n) { + var xl = x & 0x7fff, xh = x >> 15; + while (--n >= 0) { + var l = this[i] & 0x7fff; + var h = this[i++] >> 15; + var m = xh * l + h * xl; + l = xl * l + ((m & 0x7fff) << 15) + w[j] + (c & 0x3fffffff); + c = (l >>> 30) + (m >>> 15) + xh * h + (c >>> 30); + w[j++] = l & 0x3fffffff; + } + return c; + } + // Alternately, set max digit bits to 28 since some + // browsers slow down when dealing with 32-bit numbers. + function am3(i, x, w, j, c, n) { + var xl = x & 0x3fff, xh = x >> 14; + while (--n >= 0) { + var l = this[i] & 0x3fff; + var h = this[i++] >> 14; + var m = xh * l + h * xl; + l = xl * l + ((m & 0x3fff) << 14) + w[j] + c; + c = (l >> 28) + (m >> 14) + xh * h; + w[j++] = l & 0xfffffff; + } + return c; + } + if (j_lm && (navigator.appName == "Microsoft Internet Explorer")) { + BigInteger.prototype.am = am2; + dbits = 30; + } + else if (j_lm && (navigator.appName != "Netscape")) { + BigInteger.prototype.am = am1; + dbits = 26; + } + else { // Mozilla/Netscape seems to prefer am3 + BigInteger.prototype.am = am3; + dbits = 28; + } + + BigInteger.prototype.DB = dbits; + BigInteger.prototype.DM = ((1 << dbits) - 1); + BigInteger.prototype.DV = (1 << dbits); + + var BI_FP = 52; + BigInteger.prototype.FV = Math.pow(2, BI_FP); + BigInteger.prototype.F1 = BI_FP - dbits; + BigInteger.prototype.F2 = 2 * dbits - BI_FP; + + // Digit conversions + var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz"; + var BI_RC = new Array(); + var rr, vv; + rr = "0".charCodeAt(0); + for (vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv; + rr = "a".charCodeAt(0); + for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv; + rr = "A".charCodeAt(0); + for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv; + + function int2char(n) { return BI_RM.charAt(n); } + function intAt(s, i) { + var c = BI_RC[s.charCodeAt(i)]; + return (c == null) ? -1 : c; + } + + + + // return bigint initialized to value + function nbv(i) { var r = nbi(); r.fromInt(i); return r; } + + + // returns bit length of the integer x + function nbits(x) { + var r = 1, t; + if ((t = x >>> 16) != 0) { x = t; r += 16; } + if ((t = x >> 8) != 0) { x = t; r += 8; } + if ((t = x >> 4) != 0) { x = t; r += 4; } + if ((t = x >> 2) != 0) { x = t; r += 2; } + if ((t = x >> 1) != 0) { x = t; r += 1; } + return r; + } + + + + + + + + // (protected) copy this to 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; + }; + + + // (protected) set from integer value x, -DV <= x < DV + BigInteger.prototype.fromInt = function (x) { + this.t = 1; + this.s = (x < 0) ? -1 : 0; + if (x > 0) this[0] = x; + else if (x < -1) this[0] = x + this.DV; + else this.t = 0; + }; + + // (protected) set from string and radix + BigInteger.prototype.fromString = function (s, b) { + var k; + if (b == 16) k = 4; + else if (b == 8) k = 3; + else if (b == 256) k = 8; // byte array + else if (b == 2) k = 1; + else if (b == 32) k = 5; + else if (b == 4) k = 2; + else { this.fromRadix(s, b); return; } + this.t = 0; + this.s = 0; + var i = s.length, mi = false, sh = 0; + while (--i >= 0) { + var x = (k == 8) ? s[i] & 0xff : intAt(s, i); + if (x < 0) { + if (s.charAt(i) == "-") mi = true; + continue; + } + mi = false; + if (sh == 0) + this[this.t++] = x; + else if (sh + k > this.DB) { + this[this.t - 1] |= (x & ((1 << (this.DB - sh)) - 1)) << sh; + this[this.t++] = (x >> (this.DB - sh)); + } + else + this[this.t - 1] |= x << sh; + sh += k; + if (sh >= this.DB) sh -= this.DB; + } + if (k == 8 && (s[0] & 0x80) != 0) { + this.s = -1; + if (sh > 0) this[this.t - 1] |= ((1 << (this.DB - sh)) - 1) << sh; + } + this.clamp(); + if (mi) BigInteger.ZERO.subTo(this, this); + }; + + + // (protected) clamp off excess high words + BigInteger.prototype.clamp = function () { + var c = this.s & this.DM; + while (this.t > 0 && this[this.t - 1] == c) --this.t; + }; + + // (protected) r = this << n*DB + 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; + }; + + // (protected) r = this >> n*DB + BigInteger.prototype.drShiftTo = function (n, r) { + for (var i = n; i < this.t; ++i) r[i - n] = this[i]; + r.t = Math.max(this.t - n, 0); + r.s = this.s; + }; + + + // (protected) r = this << n + BigInteger.prototype.lShiftTo = function (n, r) { + var bs = n % this.DB; + var cbs = this.DB - bs; + var bm = (1 << cbs) - 1; + var ds = Math.floor(n / this.DB), c = (this.s << bs) & this.DM, i; + for (i = this.t - 1; i >= 0; --i) { + r[i + ds + 1] = (this[i] >> cbs) | c; + c = (this[i] & bm) << bs; + } + for (i = ds - 1; i >= 0; --i) r[i] = 0; + r[ds] = c; + r.t = this.t + ds + 1; + r.s = this.s; + r.clamp(); + }; + + + // (protected) r = this >> n + BigInteger.prototype.rShiftTo = function (n, r) { + r.s = this.s; + var ds = Math.floor(n / this.DB); + if (ds >= this.t) { r.t = 0; return; } + var bs = n % this.DB; + var cbs = this.DB - bs; + var bm = (1 << bs) - 1; + r[0] = this[ds] >> bs; + for (var i = ds + 1; i < this.t; ++i) { + r[i - ds - 1] |= (this[i] & bm) << cbs; + r[i - ds] = this[i] >> bs; + } + if (bs > 0) r[this.t - ds - 1] |= (this.s & bm) << cbs; + r.t = this.t - ds; + r.clamp(); + }; + + + // (protected) r = this - a + BigInteger.prototype.subTo = function (a, r) { + var i = 0, c = 0, m = Math.min(a.t, this.t); + while (i < m) { + c += this[i] - a[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + if (a.t < this.t) { + c -= a.s; + while (i < this.t) { + c += this[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c += this.s; + } + else { + c += this.s; + while (i < a.t) { + c -= a[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c -= a.s; + } + r.s = (c < 0) ? -1 : 0; + if (c < -1) r[i++] = this.DV + c; + else if (c > 0) r[i++] = c; + r.t = i; + r.clamp(); + }; + + + // (protected) r = this * a, r != this,a (HAC 14.12) + // "this" should be the larger one if appropriate. + BigInteger.prototype.multiplyTo = function (a, r) { + var x = this.abs(), y = a.abs(); + var i = x.t; + r.t = i + y.t; + while (--i >= 0) r[i] = 0; + for (i = 0; i < y.t; ++i) r[i + x.t] = x.am(0, y[i], r, i, 0, x.t); + r.s = 0; + r.clamp(); + if (this.s != a.s) BigInteger.ZERO.subTo(r, r); + }; + + + // (protected) r = this^2, r != this (HAC 14.16) + BigInteger.prototype.squareTo = function (r) { + var x = this.abs(); + var i = r.t = 2 * x.t; + while (--i >= 0) r[i] = 0; + for (i = 0; i < x.t - 1; ++i) { + var c = x.am(i, x[i], r, 2 * i, 0, 1); + if ((r[i + x.t] += x.am(i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= x.DV) { + r[i + x.t] -= x.DV; + r[i + x.t + 1] = 1; + } + } + if (r.t > 0) r[r.t - 1] += x.am(i, x[i], r, 2 * i, 0, 1); + r.s = 0; + r.clamp(); + }; + + + + // (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) + // r != q, this != m. q or r may be null. + BigInteger.prototype.divRemTo = function (m, q, r) { + var pm = m.abs(); + if (pm.t <= 0) return; + var pt = this.abs(); + if (pt.t < pm.t) { + if (q != null) q.fromInt(0); + if (r != null) this.copyTo(r); + return; + } + if (r == null) r = nbi(); + var y = nbi(), ts = this.s, ms = m.s; + var nsh = this.DB - nbits(pm[pm.t - 1]); // normalize modulus + if (nsh > 0) { pm.lShiftTo(nsh, y); pt.lShiftTo(nsh, r); } + else { pm.copyTo(y); pt.copyTo(r); } + var ys = y.t; + var y0 = y[ys - 1]; + if (y0 == 0) return; + var yt = y0 * (1 << this.F1) + ((ys > 1) ? y[ys - 2] >> this.F2 : 0); + var d1 = this.FV / yt, d2 = (1 << this.F1) / yt, e = 1 << this.F2; + var i = r.t, j = i - ys, t = (q == null) ? nbi() : q; + y.dlShiftTo(j, t); + if (r.compareTo(t) >= 0) { + r[r.t++] = 1; + r.subTo(t, r); + } + BigInteger.ONE.dlShiftTo(ys, t); + t.subTo(y, y); // "negative" y so we can replace sub with am later + while (y.t < ys) y[y.t++] = 0; + while (--j >= 0) { + // Estimate quotient digit + 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)) < qd) { // Try it out + y.dlShiftTo(j, t); + r.subTo(t, r); + while (r[i] < --qd) r.subTo(t, r); + } + } + if (q != null) { + r.drShiftTo(ys, q); + if (ts != ms) BigInteger.ZERO.subTo(q, q); + } + r.t = ys; + r.clamp(); + if (nsh > 0) r.rShiftTo(nsh, r); // Denormalize remainder + if (ts < 0) BigInteger.ZERO.subTo(r, r); + }; + + + // (protected) return "-1/this % 2^DB"; useful for Mont. reduction + // justification: + // xy == 1 (mod m) + // xy = 1+km + // xy(2-xy) = (1+km)(1-km) + // x[y(2-xy)] = 1-k^2m^2 + // x[y(2-xy)] == 1 (mod m^2) + // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 + // should reduce x and y(2-xy) by m^2 at each step to keep size bounded. + // JS multiply "overflows" differently from C/C++, so care is needed here. + BigInteger.prototype.invDigit = function () { + if (this.t < 1) return 0; + var x = this[0]; + if ((x & 1) == 0) return 0; + var y = x & 3; // y == 1/x mod 2^2 + y = (y * (2 - (x & 0xf) * y)) & 0xf; // y == 1/x mod 2^4 + y = (y * (2 - (x & 0xff) * y)) & 0xff; // y == 1/x mod 2^8 + y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16 + // last step - calculate inverse mod DV directly; + // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints + y = (y * (2 - x * y % this.DV)) % this.DV; // y == 1/x mod 2^dbits + // we really want the negative inverse, and -DV < y < DV + return (y > 0) ? this.DV - y : -y; + }; + + + // (protected) true iff this is even + BigInteger.prototype.isEven = function () { return ((this.t > 0) ? (this[0] & 1) : this.s) == 0; }; + + + // (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) + BigInteger.prototype.exp = function (e, z) { + if (e > 0xffffffff || e < 1) return BigInteger.ONE; + var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e) - 1; + g.copyTo(r); + while (--i >= 0) { + z.sqrTo(r, r2); + if ((e & (1 << i)) > 0) z.mulTo(r2, g, r); + else { var t = r; r = r2; r2 = t; } + } + return z.revert(r); + }; + + + // (public) return string representation in given radix + BigInteger.prototype.toString = function (b) { + if (this.s < 0) return "-" + this.negate().toString(b); + var k; + if (b == 16) k = 4; + else if (b == 8) k = 3; + else if (b == 2) k = 1; + else if (b == 32) k = 5; + else if (b == 4) k = 2; + else return this.toRadix(b); + var km = (1 << k) - 1, d, m = false, r = "", i = this.t; + var p = this.DB - (i * this.DB) % k; + if (i-- > 0) { + if (p < this.DB && (d = this[i] >> p) > 0) { m = true; r = int2char(d); } + while (i >= 0) { + if (p < k) { + d = (this[i] & ((1 << p) - 1)) << (k - p); + d |= this[--i] >> (p += this.DB - k); + } + else { + d = (this[i] >> (p -= k)) & km; + if (p <= 0) { p += this.DB; --i; } + } + if (d > 0) m = true; + if (m) r += int2char(d); + } + } + return m ? r : "0"; + }; + + + // (public) -this + BigInteger.prototype.negate = function () { var r = nbi(); BigInteger.ZERO.subTo(this, r); return r; }; + + // (public) |this| + BigInteger.prototype.abs = function () { return (this.s < 0) ? this.negate() : this; }; + + // (public) return + if this > a, - if this < a, 0 if equal + BigInteger.prototype.compareTo = function (a) { + var r = this.s - a.s; + if (r != 0) return r; + var i = this.t; + r = i - a.t; + if (r != 0) return (this.s < 0) ? -r : r; + while (--i >= 0) if ((r = this[i] - a[i]) != 0) return r; + return 0; + } + + // (public) return the number of bits in "this" + BigInteger.prototype.bitLength = function () { + if (this.t <= 0) return 0; + return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM)); + }; + + // (public) this mod a + BigInteger.prototype.mod = function (a) { + var r = nbi(); + this.abs().divRemTo(a, null, r); + if (this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r, r); + return r; + } + + // (public) this^e % m, 0 <= e < 2^32 + BigInteger.prototype.modPowInt = function (e, m) { + var z; + if (e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m); + return this.exp(e, z); + }; + + // "constants" + BigInteger.ZERO = nbv(0); + BigInteger.ONE = nbv(1); + + + + + + + + // Copyright (c) 2005-2009 Tom Wu + // All Rights Reserved. + // See "LICENSE" for details. + // Extended JavaScript BN functions, required for RSA private ops. + // Version 1.1: new BigInteger("0", 10) returns "proper" zero + // Version 1.2: square() API, isProbablePrime fix + + + // return index of lowest 1-bit in x, x < 2^31 + function lbit(x) { + if (x == 0) return -1; + var r = 0; + if ((x & 0xffff) == 0) { x >>= 16; r += 16; } + if ((x & 0xff) == 0) { x >>= 8; r += 8; } + if ((x & 0xf) == 0) { x >>= 4; r += 4; } + if ((x & 3) == 0) { x >>= 2; r += 2; } + if ((x & 1) == 0) ++r; + return r; + } + + // return number of 1 bits in x + function cbit(x) { + var r = 0; + while (x != 0) { x &= x - 1; ++r; } + return r; + } + + 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]; + var lplim = (1 << 26) / lowprimes[lowprimes.length - 1]; + + + + // (protected) return x s.t. r^x < DV + BigInteger.prototype.chunkSize = function (r) { return Math.floor(Math.LN2 * this.DB / Math.log(r)); }; + + // (protected) convert to radix string + BigInteger.prototype.toRadix = function (b) { + if (b == null) b = 10; + if (this.signum() == 0 || b < 2 || b > 36) return "0"; + var cs = this.chunkSize(b); + var a = Math.pow(b, cs); + var d = nbv(a), y = nbi(), z = nbi(), r = ""; + this.divRemTo(d, y, z); + while (y.signum() > 0) { + r = (a + z.intValue()).toString(b).substr(1) + r; + y.divRemTo(d, y, z); + } + return z.intValue().toString(b) + r; + }; + + // (protected) convert from radix string + BigInteger.prototype.fromRadix = function (s, b) { + this.fromInt(0); + if (b == null) b = 10; + var cs = this.chunkSize(b); + var d = Math.pow(b, cs), mi = false, j = 0, w = 0; + for (var i = 0; i < s.length; ++i) { + var x = intAt(s, i); + if (x < 0) { + if (s.charAt(i) == "-" && this.signum() == 0) mi = true; + continue; + } + w = b * w + x; + if (++j >= cs) { + this.dMultiply(d); + this.dAddOffset(w, 0); + j = 0; + w = 0; + } + } + if (j > 0) { + this.dMultiply(Math.pow(b, j)); + this.dAddOffset(w, 0); + } + if (mi) BigInteger.ZERO.subTo(this, this); + }; + + // (protected) alternate constructor + BigInteger.prototype.fromNumber = function (a, b, c) { + if ("number" == typeof b) { + // new BigInteger(int,int,RNG) + if (a < 2) this.fromInt(1); + else { + this.fromNumber(a, c); + if (!this.testBit(a - 1)) // force MSB set + this.bitwiseTo(BigInteger.ONE.shiftLeft(a - 1), op_or, this); + if (this.isEven()) this.dAddOffset(1, 0); // force odd + while (!this.isProbablePrime(b)) { + this.dAddOffset(2, 0); + if (this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a - 1), this); + } + } + } + else { + // new BigInteger(int,RNG) + var x = new Array(), t = a & 7; + x.length = (a >> 3) + 1; + b.nextBytes(x); + if (t > 0) x[0] &= ((1 << t) - 1); else x[0] = 0; + this.fromString(x, 256); + } + }; + + // (protected) r = this op a (bitwise) + BigInteger.prototype.bitwiseTo = function (a, op, r) { + var i, f, m = Math.min(a.t, this.t); + for (i = 0; i < m; ++i) r[i] = op(this[i], a[i]); + if (a.t < this.t) { + f = a.s & this.DM; + for (i = m; i < this.t; ++i) r[i] = op(this[i], f); + r.t = this.t; + } + else { + f = this.s & this.DM; + for (i = m; i < a.t; ++i) r[i] = op(f, a[i]); + r.t = a.t; + } + r.s = op(this.s, a.s); + r.clamp(); + }; + + // (protected) this op (1<<n) + BigInteger.prototype.changeBit = function (n, op) { + var r = BigInteger.ONE.shiftLeft(n); + this.bitwiseTo(r, op, r); + return r; + }; + + // (protected) r = this + a + BigInteger.prototype.addTo = function (a, r) { + var i = 0, c = 0, m = Math.min(a.t, this.t); + while (i < m) { + c += this[i] + a[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + if (a.t < this.t) { + c += a.s; + while (i < this.t) { + c += this[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c += this.s; + } + else { + c += this.s; + while (i < a.t) { + c += a[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c += a.s; + } + r.s = (c < 0) ? -1 : 0; + if (c > 0) r[i++] = c; + else if (c < -1) r[i++] = this.DV + c; + r.t = i; + r.clamp(); + }; + + // (protected) this *= n, this >= 0, 1 < n < DV + BigInteger.prototype.dMultiply = function (n) { + this[this.t] = this.am(0, n - 1, this, 0, 0, this.t); + ++this.t; + this.clamp(); + }; + + // (protected) this += n << w words, this >= 0 + BigInteger.prototype.dAddOffset = function (n, w) { + if (n == 0) return; + while (this.t <= w) this[this.t++] = 0; + this[w] += n; + while (this[w] >= this.DV) { + this[w] -= this.DV; + if (++w >= this.t) this[this.t++] = 0; + ++this[w]; + } + }; + + // (protected) r = lower n words of "this * a", a.t <= n + // "this" should be the larger one if appropriate. + BigInteger.prototype.multiplyLowerTo = function (a, n, r) { + var i = Math.min(this.t + a.t, n); + r.s = 0; // assumes a,this >= 0 + r.t = i; + while (i > 0) r[--i] = 0; + var j; + for (j = r.t - this.t; i < j; ++i) r[i + this.t] = this.am(0, a[i], r, i, 0, this.t); + for (j = Math.min(a.t, n); i < j; ++i) this.am(0, a[i], r, i, 0, n - i); + r.clamp(); + }; + + + // (protected) r = "this * a" without lower n words, n > 0 + // "this" should be the larger one if appropriate. + BigInteger.prototype.multiplyUpperTo = function (a, n, r) { + --n; + var i = r.t = this.t + a.t - n; + r.s = 0; // assumes a,this >= 0 + while (--i >= 0) r[i] = 0; + for (i = Math.max(n - this.t, 0); i < a.t; ++i) + r[this.t + i - n] = this.am(n - i, a[i], r, 0, 0, this.t + i - n); + r.clamp(); + r.drShiftTo(1, r); + }; + + // (protected) this % n, n < 2^26 + BigInteger.prototype.modInt = function (n) { + if (n <= 0) return 0; + var d = this.DV % n, r = (this.s < 0) ? n - 1 : 0; + if (this.t > 0) + if (d == 0) r = this[0] % n; + else for (var i = this.t - 1; i >= 0; --i) r = (d * r + this[i]) % n; + return r; + }; + + + // (protected) true if probably prime (HAC 4.24, Miller-Rabin) + BigInteger.prototype.millerRabin = function (t) { + var n1 = this.subtract(BigInteger.ONE); + var k = n1.getLowestSetBit(); + if (k <= 0) return false; + var r = n1.shiftRight(k); + t = (t + 1) >> 1; + if (t > lowprimes.length) t = lowprimes.length; + var a = nbi(); + for (var i = 0; i < t; ++i) { + //Pick bases at random, instead of starting at 2 + a.fromInt(lowprimes[Math.floor(Math.random() * lowprimes.length)]); + var y = a.modPow(r, this); + if (y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) { + var j = 1; + while (j++ < k && y.compareTo(n1) != 0) { + y = y.modPowInt(2, this); + if (y.compareTo(BigInteger.ONE) == 0) return false; + } + if (y.compareTo(n1) != 0) return false; + } + } + return true; + }; + + + + // (public) + BigInteger.prototype.clone = function () { var r = nbi(); this.copyTo(r); return r; }; + + // (public) return value as integer + BigInteger.prototype.intValue = function () { + if (this.s < 0) { + if (this.t == 1) return this[0] - this.DV; + else if (this.t == 0) return -1; + } + else if (this.t == 1) return this[0]; + else if (this.t == 0) return 0; + // assumes 16 < DB < 32 + return ((this[1] & ((1 << (32 - this.DB)) - 1)) << this.DB) | this[0]; + }; + + + // (public) return value as byte + BigInteger.prototype.byteValue = function () { return (this.t == 0) ? this.s : (this[0] << 24) >> 24; }; + + // (public) return value as short (assumes DB>=16) + BigInteger.prototype.shortValue = function () { return (this.t == 0) ? this.s : (this[0] << 16) >> 16; }; + + // (public) 0 if this == 0, 1 if this > 0 + BigInteger.prototype.signum = function () { + if (this.s < 0) return -1; + else if (this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0; + else return 1; + }; + + + // (public) convert to bigendian byte array + BigInteger.prototype.toByteArray = function () { + var i = this.t, r = new Array(); + r[0] = this.s; + var p = this.DB - (i * this.DB) % 8, d, k = 0; + if (i-- > 0) { + if (p < this.DB && (d = this[i] >> p) != (this.s & this.DM) >> p) + r[k++] = d | (this.s << (this.DB - p)); + while (i >= 0) { + if (p < 8) { + d = (this[i] & ((1 << p) - 1)) << (8 - p); + d |= this[--i] >> (p += this.DB - 8); + } + else { + d = (this[i] >> (p -= 8)) & 0xff; + if (p <= 0) { p += this.DB; --i; } + } + if ((d & 0x80) != 0) d |= -256; + if (k == 0 && (this.s & 0x80) != (d & 0x80)) ++k; + if (k > 0 || d != this.s) r[k++] = d; + } + } + return r; + }; + + BigInteger.prototype.equals = function (a) { return (this.compareTo(a) == 0); }; + BigInteger.prototype.min = function (a) { return (this.compareTo(a) < 0) ? this : a; }; + BigInteger.prototype.max = function (a) { return (this.compareTo(a) > 0) ? this : a; }; + + // (public) this & a + function op_and(x, y) { return x & y; } + BigInteger.prototype.and = function (a) { var r = nbi(); this.bitwiseTo(a, op_and, r); return r; }; + + // (public) this | a + function op_or(x, y) { return x | y; } + BigInteger.prototype.or = function (a) { var r = nbi(); this.bitwiseTo(a, op_or, r); return r; }; + + // (public) this ^ a + function op_xor(x, y) { return x ^ y; } + BigInteger.prototype.xor = function (a) { var r = nbi(); this.bitwiseTo(a, op_xor, r); return r; }; + + // (public) this & ~a + function op_andnot(x, y) { return x & ~y; } + BigInteger.prototype.andNot = function (a) { var r = nbi(); this.bitwiseTo(a, op_andnot, r); return r; }; + + // (public) ~this + BigInteger.prototype.not = function () { + var r = nbi(); + for (var i = 0; i < this.t; ++i) r[i] = this.DM & ~this[i]; + r.t = this.t; + r.s = ~this.s; + return r; + }; + + // (public) this << n + BigInteger.prototype.shiftLeft = function (n) { + var r = nbi(); + if (n < 0) this.rShiftTo(-n, r); else this.lShiftTo(n, r); + return r; + }; + + // (public) this >> n + BigInteger.prototype.shiftRight = function (n) { + var r = nbi(); + if (n < 0) this.lShiftTo(-n, r); else this.rShiftTo(n, r); + return r; + }; + + // (public) returns index of lowest 1-bit (or -1 if none) + BigInteger.prototype.getLowestSetBit = function () { + for (var i = 0; i < this.t; ++i) + if (this[i] != 0) return i * this.DB + lbit(this[i]); + if (this.s < 0) return this.t * this.DB; + return -1; + }; + + // (public) return number of set bits + BigInteger.prototype.bitCount = function () { + var r = 0, x = this.s & this.DM; + for (var i = 0; i < this.t; ++i) r += cbit(this[i] ^ x); + return r; + }; + + // (public) true iff nth bit is set + BigInteger.prototype.testBit = function (n) { + var j = Math.floor(n / this.DB); + if (j >= this.t) return (this.s != 0); + return ((this[j] & (1 << (n % this.DB))) != 0); + }; + + // (public) this | (1<<n) + BigInteger.prototype.setBit = function (n) { return this.changeBit(n, op_or); }; + // (public) this & ~(1<<n) + BigInteger.prototype.clearBit = function (n) { return this.changeBit(n, op_andnot); }; + // (public) this ^ (1<<n) + BigInteger.prototype.flipBit = function (n) { return this.changeBit(n, op_xor); }; + // (public) this + a + BigInteger.prototype.add = function (a) { var r = nbi(); this.addTo(a, r); return r; }; + // (public) this - a + BigInteger.prototype.subtract = function (a) { var r = nbi(); this.subTo(a, r); return r; }; + // (public) this * a + BigInteger.prototype.multiply = function (a) { var r = nbi(); this.multiplyTo(a, r); return r; }; + // (public) this / a + BigInteger.prototype.divide = function (a) { var r = nbi(); this.divRemTo(a, r, null); return r; }; + // (public) this % a + BigInteger.prototype.remainder = function (a) { var r = nbi(); this.divRemTo(a, null, r); return r; }; + // (public) [this/a,this%a] + BigInteger.prototype.divideAndRemainder = function (a) { + var q = nbi(), r = nbi(); + this.divRemTo(a, q, r); + return new Array(q, r); + }; + + // (public) this^e % m (HAC 14.85) + BigInteger.prototype.modPow = function (e, m) { + var i = e.bitLength(), k, r = nbv(1), z; + if (i <= 0) return r; + else if (i < 18) k = 1; + else if (i < 48) k = 3; + else if (i < 144) k = 4; + else if (i < 768) k = 5; + else k = 6; + if (i < 8) + z = new Classic(m); + else if (m.isEven()) + z = new Barrett(m); + else + z = new Montgomery(m); + + // precomputation + var g = new Array(), n = 3, k1 = k - 1, km = (1 << k) - 1; + g[1] = z.convert(this); + if (k > 1) { + var g2 = nbi(); + z.sqrTo(g[1], g2); + while (n <= km) { + g[n] = nbi(); + z.mulTo(g2, g[n - 2], g[n]); + n += 2; + } + } + + var j = e.t - 1, w, is1 = true, r2 = nbi(), t; + i = nbits(e[j]) - 1; + while (j >= 0) { + if (i >= k1) w = (e[j] >> (i - k1)) & km; + else { + w = (e[j] & ((1 << (i + 1)) - 1)) << (k1 - i); + if (j > 0) w |= e[j - 1] >> (this.DB + i - k1); + } + + n = k; + while ((w & 1) == 0) { w >>= 1; --n; } + if ((i -= n) < 0) { i += this.DB; --j; } + if (is1) { // ret == 1, don't bother squaring or multiplying it + g[w].copyTo(r); + is1 = false; + } + else { + while (n > 1) { z.sqrTo(r, r2); z.sqrTo(r2, r); n -= 2; } + if (n > 0) z.sqrTo(r, r2); else { t = r; r = r2; r2 = t; } + z.mulTo(r2, g[w], r); + } + + while (j >= 0 && (e[j] & (1 << i)) == 0) { + z.sqrTo(r, r2); t = r; r = r2; r2 = t; + if (--i < 0) { i = this.DB - 1; --j; } + } + } + return z.revert(r); + }; + + // (public) 1/this % m (HAC 14.61) + BigInteger.prototype.modInverse = function (m) { + var ac = m.isEven(); + if ((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO; + var u = m.clone(), v = this.clone(); + var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1); + while (u.signum() != 0) { + while (u.isEven()) { + u.rShiftTo(1, u); + if (ac) { + if (!a.isEven() || !b.isEven()) { a.addTo(this, a); b.subTo(m, b); } + a.rShiftTo(1, a); + } + else if (!b.isEven()) b.subTo(m, b); + b.rShiftTo(1, b); + } + while (v.isEven()) { + v.rShiftTo(1, v); + if (ac) { + if (!c.isEven() || !d.isEven()) { c.addTo(this, c); d.subTo(m, d); } + c.rShiftTo(1, c); + } + else if (!d.isEven()) d.subTo(m, d); + d.rShiftTo(1, d); + } + if (u.compareTo(v) >= 0) { + u.subTo(v, u); + if (ac) a.subTo(c, a); + b.subTo(d, b); + } + else { + v.subTo(u, v); + if (ac) c.subTo(a, c); + d.subTo(b, d); + } + } + if (v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO; + if (d.compareTo(m) >= 0) return d.subtract(m); + if (d.signum() < 0) d.addTo(m, d); else return d; + if (d.signum() < 0) return d.add(m); else return d; + }; + + + // (public) this^e + BigInteger.prototype.pow = function (e) { return this.exp(e, new NullExp()); }; + + // (public) gcd(this,a) (HAC 14.54) + BigInteger.prototype.gcd = function (a) { + var x = (this.s < 0) ? this.negate() : this.clone(); + var 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; + if (i < g) g = i; + if (g > 0) { + x.rShiftTo(g, x); + y.rShiftTo(g, y); + } + while (x.signum() > 0) { + if ((i = x.getLowestSetBit()) > 0) x.rShiftTo(i, x); + if ((i = y.getLowestSetBit()) > 0) y.rShiftTo(i, y); + if (x.compareTo(y) >= 0) { + x.subTo(y, x); + x.rShiftTo(1, x); + } + else { + y.subTo(x, y); + y.rShiftTo(1, y); + } + } + if (g > 0) y.lShiftTo(g, y); + return y; + }; + + // (public) test primality with certainty >= 1-.5^t + BigInteger.prototype.isProbablePrime = function (t) { + var i, x = this.abs(); + if (x.t == 1 && x[0] <= lowprimes[lowprimes.length - 1]) { + for (i = 0; i < lowprimes.length; ++i) + if (x[0] == lowprimes[i]) return true; + return false; + } + if (x.isEven()) return false; + i = 1; + while (i < lowprimes.length) { + var m = lowprimes[i], j = i + 1; + while (j < lowprimes.length && m < lplim) m *= lowprimes[j++]; + m = x.modInt(m); + while (i < j) if (m % lowprimes[i++] == 0) return false; + } + return x.millerRabin(t); + }; + + + // JSBN-specific extension + + // (public) this^2 + BigInteger.prototype.square = function () { var r = nbi(); this.squareTo(r); return r; }; + + + // NOTE: BigInteger interfaces not implemented in jsbn: + // BigInteger(int signum, byte[] magnitude) + // double doubleValue() + // float floatValue() + // int hashCode() + // long longValue() + // static BigInteger valueOf(long val) + + + + // Copyright Stephan Thomas (start) --- // + // https://raw.github.com/bitcoinjs/bitcoinjs-lib/07f9d55ccb6abd962efb6befdd37671f85ea4ff9/src/util.js + // BigInteger monkey patching + BigInteger.valueOf = nbv; + + /** + * Returns a byte array representation of the big integer. + * + * This returns the absolute of the contained value in big endian + * form. A value of zero results in an empty array. + */ + BigInteger.prototype.toByteArrayUnsigned = function () { + var ba = this.abs().toByteArray(); + if (ba.length) { + if (ba[0] == 0) { + ba = ba.slice(1); + } + return ba.map(function (v) { + return (v < 0) ? v + 256 : v; + }); + } else { + // Empty array, nothing to do + return ba; + } + }; + + /** + * Turns a byte array into a big integer. + * + * This function will interpret a byte array as a big integer in big + * endian notation and ignore leading zeros. + */ + BigInteger.fromByteArrayUnsigned = function (ba) { + if (!ba.length) { + return ba.valueOf(0); + } else if (ba[0] & 0x80) { + // Prepend a zero so the BigInteger class doesn't mistake this + // for a negative integer. + return new BigInteger([0].concat(ba)); + } else { + return new BigInteger(ba); + } + }; + + /** + * Converts big integer to signed byte representation. + * + * The format for this value uses a the most significant bit as a sign + * bit. If the most significant bit is already occupied by the + * absolute value, an extra byte is prepended and the sign bit is set + * there. + * + * Examples: + * + * 0 => 0x00 + * 1 => 0x01 + * -1 => 0x81 + * 127 => 0x7f + * -127 => 0xff + * 128 => 0x0080 + * -128 => 0x8080 + * 255 => 0x00ff + * -255 => 0x80ff + * 16300 => 0x3fac + * -16300 => 0xbfac + * 62300 => 0x00f35c + * -62300 => 0x80f35c + */ + BigInteger.prototype.toByteArraySigned = function () { + var val = this.abs().toByteArrayUnsigned(); + var neg = this.compareTo(BigInteger.ZERO) < 0; + + if (neg) { + if (val[0] & 0x80) { + val.unshift(0x80); + } else { + val[0] |= 0x80; + } + } else { + if (val[0] & 0x80) { + val.unshift(0x00); + } + } + + return val; + }; + + /** + * Parse a signed big integer byte representation. + * + * For details on the format please see BigInteger.toByteArraySigned. + */ + BigInteger.fromByteArraySigned = function (ba) { + // Check for negative value + if (ba[0] & 0x80) { + // Remove sign bit + ba[0] &= 0x7f; + + return BigInteger.fromByteArrayUnsigned(ba).negate(); + } else { + return BigInteger.fromByteArrayUnsigned(ba); + } + }; + // Copyright Stephan Thomas (end) --- // + + + + + // ****** REDUCTION ******* // + + // Modular reduction using "classic" algorithm + var Classic = window.Classic = function Classic(m) { this.m = m; } + Classic.prototype.convert = function (x) { + if (x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m); + else return 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); }; + + + + + + // Montgomery reduction + var Montgomery = window.Montgomery = function Montgomery(m) { + this.m = m; + this.mp = m.invDigit(); + this.mpl = this.mp & 0x7fff; + this.mph = this.mp >> 15; + this.um = (1 << (m.DB - 15)) - 1; + this.mt2 = 2 * m.t; + } + // xR mod m + Montgomery.prototype.convert = function (x) { + var r = nbi(); + x.abs().dlShiftTo(this.m.t, r); + r.divRemTo(this.m, null, r); + if (x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r, r); + return r; + } + // x/R mod m + Montgomery.prototype.revert = function (x) { + var r = nbi(); + x.copyTo(r); + this.reduce(r); + return r; + }; + // x = x/R mod m (HAC 14.32) + Montgomery.prototype.reduce = function (x) { + while (x.t <= this.mt2) // pad x so am has enough room later + x[x.t++] = 0; + for (var i = 0; i < this.m.t; ++i) { + // faster way of calculating u0 = x[i]*mp mod DV + var j = x[i] & 0x7fff; + var u0 = (j * this.mpl + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & x.DM; + // use am to combine the multiply-shift-add into one call + j = i + this.m.t; + x[j] += this.m.am(0, u0, x, i, 0, this.m.t); + // propagate carry + while (x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; } + } + x.clamp(); + x.drShiftTo(this.m.t, x); + if (x.compareTo(this.m) >= 0) x.subTo(this.m, x); + }; + // r = "xy/R mod m"; x,y != r + Montgomery.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); this.reduce(r); }; + // r = "x^2/R mod m"; x != r + Montgomery.prototype.sqrTo = function (x, r) { x.squareTo(r); this.reduce(r); }; + + + + + + // A "null" reducer + var NullExp = window.NullExp = function NullExp() { } + 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); }; + + + + + + // Barrett modular reduction + var Barrett = window.Barrett = function Barrett(m) { + // setup Barrett + 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); + else if (x.compareTo(this.m) < 0) return x; + else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; } + }; + Barrett.prototype.revert = function (x) { return x; }; + // x = x mod m (HAC 14.42) + Barrett.prototype.reduce = function (x) { + x.drShiftTo(this.m.t - 1, this.r2); + if (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); + while (x.compareTo(this.r2) < 0) x.dAddOffset(1, this.m.t + 1); + x.subTo(this.r2, x); + while (x.compareTo(this.m) >= 0) x.subTo(this.m, x); + }; + // r = x*y mod m; x,y != r + Barrett.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); this.reduce(r); }; + // r = x^2 mod m; x != r + Barrett.prototype.sqrTo = function (x, r) { x.squareTo(r); this.reduce(r); }; + +})(); \ No newline at end of file diff --git a/react/src/util/crypto/gen/bitcoin.js b/react/src/util/crypto/gen/bitcoin.js new file mode 100644 index 0000000..47dfdd5 --- /dev/null +++ b/react/src/util/crypto/gen/bitcoin.js @@ -0,0 +1,1974 @@ +// ----- Big Integer -----// +// (public) Constructor function of Global BigInteger object +var BigInteger = window.BigInteger = function BigInteger(a, b, c) { + if (a != null) + if ("number" == typeof a) this.fromNumber(a, b, c); + else if (b == null && "string" != typeof a) this.fromString(a, 256); + else this.fromString(a, b); +}; + +// Bits per digit +var dbits; + +// JavaScript engine analysis +var canary = 0xdeadbeefcafe; +var j_lm = ((canary & 0xffffff) == 0xefcafe); + +// return new, unset BigInteger +function nbi() { return new BigInteger(null); } + +// am: Compute w_j += (x*this_i), propagate carries, +// c is initial carry, returns final carry. +// c < 3*dvalue, x < 2*dvalue, this_i < dvalue +// We need to select the fastest one that works in this environment. + +// am1: use a single mult and divide to get the high bits, +// max digit bits should be 26 because +// max internal value = 2*dvalue^2-2*dvalue (< 2^53) +function am1(i, x, w, j, c, n) { + while (--n >= 0) { + var v = x * this[i++] + w[j] + c; + c = Math.floor(v / 0x4000000); + w[j++] = v & 0x3ffffff; + } + return c; +} +// am2 avoids a big mult-and-extract completely. +// Max digit bits should be <= 30 because we do bitwise ops +// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) +function am2(i, x, w, j, c, n) { + var xl = x & 0x7fff, xh = x >> 15; + while (--n >= 0) { + var l = this[i] & 0x7fff; + var h = this[i++] >> 15; + var m = xh * l + h * xl; + l = xl * l + ((m & 0x7fff) << 15) + w[j] + (c & 0x3fffffff); + c = (l >>> 30) + (m >>> 15) + xh * h + (c >>> 30); + w[j++] = l & 0x3fffffff; + } + return c; +} +// Alternately, set max digit bits to 28 since some +// browsers slow down when dealing with 32-bit numbers. +function am3(i, x, w, j, c, n) { + var xl = x & 0x3fff, xh = x >> 14; + while (--n >= 0) { + var l = this[i] & 0x3fff; + var h = this[i++] >> 14; + var m = xh * l + h * xl; + l = xl * l + ((m & 0x3fff) << 14) + w[j] + c; + c = (l >> 28) + (m >> 14) + xh * h; + w[j++] = l & 0xfffffff; + } + return c; +} +if (j_lm && (navigator.appName == "Microsoft Internet Explorer")) { + BigInteger.prototype.am = am2; + dbits = 30; +} +else if (j_lm && (navigator.appName != "Netscape")) { + BigInteger.prototype.am = am1; + dbits = 26; +} +else { // Mozilla/Netscape seems to prefer am3 + BigInteger.prototype.am = am3; + dbits = 28; +} + +BigInteger.prototype.DB = dbits; +BigInteger.prototype.DM = ((1 << dbits) - 1); +BigInteger.prototype.DV = (1 << dbits); + +var BI_FP = 52; +BigInteger.prototype.FV = Math.pow(2, BI_FP); +BigInteger.prototype.F1 = BI_FP - dbits; +BigInteger.prototype.F2 = 2 * dbits - BI_FP; + +// Digit conversions +var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz"; +var BI_RC = new Array(); +var rr, vv; +rr = "0".charCodeAt(0); +for (vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv; +rr = "a".charCodeAt(0); +for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv; +rr = "A".charCodeAt(0); +for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv; + +function int2char(n) { return BI_RM.charAt(n); } +function intAt(s, i) { + var c = BI_RC[s.charCodeAt(i)]; + return (c == null) ? -1 : c; +} + + + +// return bigint initialized to value +function nbv(i) { var r = nbi(); r.fromInt(i); return r; } + + +// returns bit length of the integer x +function nbits(x) { + var r = 1, t; + if ((t = x >>> 16) != 0) { x = t; r += 16; } + if ((t = x >> 8) != 0) { x = t; r += 8; } + if ((t = x >> 4) != 0) { x = t; r += 4; } + if ((t = x >> 2) != 0) { x = t; r += 2; } + if ((t = x >> 1) != 0) { x = t; r += 1; } + return r; +} + +// (protected) copy this to 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; +}; + +// (protected) set from integer value x, -DV <= x < DV +BigInteger.prototype.fromInt = function (x) { + this.t = 1; + this.s = (x < 0) ? -1 : 0; + if (x > 0) this[0] = x; + else if (x < -1) this[0] = x + this.DV; + else this.t = 0; +}; + +// (protected) set from string and radix +BigInteger.prototype.fromString = function (s, b) { + var k; + if (b == 16) k = 4; + else if (b == 8) k = 3; + else if (b == 256) k = 8; // byte array + else if (b == 2) k = 1; + else if (b == 32) k = 5; + else if (b == 4) k = 2; + else { this.fromRadix(s, b); return; } + this.t = 0; + this.s = 0; + var i = s.length, mi = false, sh = 0; + while (--i >= 0) { + var x = (k == 8) ? s[i] & 0xff : intAt(s, i); + if (x < 0) { + if (s.charAt(i) == "-") mi = true; + continue; + } + mi = false; + if (sh == 0) + this[this.t++] = x; + else if (sh + k > this.DB) { + this[this.t - 1] |= (x & ((1 << (this.DB - sh)) - 1)) << sh; + this[this.t++] = (x >> (this.DB - sh)); + } + else + this[this.t - 1] |= x << sh; + sh += k; + if (sh >= this.DB) sh -= this.DB; + } + if (k == 8 && (s[0] & 0x80) != 0) { + this.s = -1; + if (sh > 0) this[this.t - 1] |= ((1 << (this.DB - sh)) - 1) << sh; + } + this.clamp(); + if (mi) BigInteger.ZERO.subTo(this, this); +}; + + +// (protected) clamp off excess high words +BigInteger.prototype.clamp = function () { + var c = this.s & this.DM; + while (this.t > 0 && this[this.t - 1] == c) --this.t; +}; + +// (protected) r = this << n*DB +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; +}; + +// (protected) r = this >> n*DB +BigInteger.prototype.drShiftTo = function (n, r) { + for (var i = n; i < this.t; ++i) r[i - n] = this[i]; + r.t = Math.max(this.t - n, 0); + r.s = this.s; +}; + +// (protected) r = this << n +BigInteger.prototype.lShiftTo = function (n, r) { + var bs = n % this.DB; + var cbs = this.DB - bs; + var bm = (1 << cbs) - 1; + var ds = Math.floor(n / this.DB), c = (this.s << bs) & this.DM, i; + for (i = this.t - 1; i >= 0; --i) { + r[i + ds + 1] = (this[i] >> cbs) | c; + c = (this[i] & bm) << bs; + } + for (i = ds - 1; i >= 0; --i) r[i] = 0; + r[ds] = c; + r.t = this.t + ds + 1; + r.s = this.s; + r.clamp(); +}; + +// (protected) r = this >> n +BigInteger.prototype.rShiftTo = function (n, r) { + r.s = this.s; + var ds = Math.floor(n / this.DB); + if (ds >= this.t) { r.t = 0; return; } + var bs = n % this.DB; + var cbs = this.DB - bs; + var bm = (1 << bs) - 1; + r[0] = this[ds] >> bs; + for (var i = ds + 1; i < this.t; ++i) { + r[i - ds - 1] |= (this[i] & bm) << cbs; + r[i - ds] = this[i] >> bs; + } + if (bs > 0) r[this.t - ds - 1] |= (this.s & bm) << cbs; + r.t = this.t - ds; + r.clamp(); +}; + +// (protected) r = this - a +BigInteger.prototype.subTo = function (a, r) { + var i = 0, c = 0, m = Math.min(a.t, this.t); + while (i < m) { + c += this[i] - a[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + if (a.t < this.t) { + c -= a.s; + while (i < this.t) { + c += this[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c += this.s; + } + else { + c += this.s; + while (i < a.t) { + c -= a[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c -= a.s; + } + r.s = (c < 0) ? -1 : 0; + if (c < -1) r[i++] = this.DV + c; + else if (c > 0) r[i++] = c; + r.t = i; + r.clamp(); +}; + +// (protected) r = this * a, r != this,a (HAC 14.12) +// "this" should be the larger one if appropriate. +BigInteger.prototype.multiplyTo = function (a, r) { + var x = this.abs(), y = a.abs(); + var i = x.t; + r.t = i + y.t; + while (--i >= 0) r[i] = 0; + for (i = 0; i < y.t; ++i) r[i + x.t] = x.am(0, y[i], r, i, 0, x.t); + r.s = 0; + r.clamp(); + if (this.s != a.s) BigInteger.ZERO.subTo(r, r); +}; + +// (protected) r = this^2, r != this (HAC 14.16) +BigInteger.prototype.squareTo = function (r) { + var x = this.abs(); + var i = r.t = 2 * x.t; + while (--i >= 0) r[i] = 0; + for (i = 0; i < x.t - 1; ++i) { + var c = x.am(i, x[i], r, 2 * i, 0, 1); + if ((r[i + x.t] += x.am(i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= x.DV) { + r[i + x.t] -= x.DV; + r[i + x.t + 1] = 1; + } + } + if (r.t > 0) r[r.t - 1] += x.am(i, x[i], r, 2 * i, 0, 1); + r.s = 0; + r.clamp(); +}; + +// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) +// r != q, this != m. q or r may be null. +BigInteger.prototype.divRemTo = function (m, q, r) { + var pm = m.abs(); + if (pm.t <= 0) return; + var pt = this.abs(); + if (pt.t < pm.t) { + if (q != null) q.fromInt(0); + if (r != null) this.copyTo(r); + return; + } + if (r == null) r = nbi(); + var y = nbi(), ts = this.s, ms = m.s; + var nsh = this.DB - nbits(pm[pm.t - 1]); // normalize modulus + if (nsh > 0) { pm.lShiftTo(nsh, y); pt.lShiftTo(nsh, r); } + else { pm.copyTo(y); pt.copyTo(r); } + var ys = y.t; + var y0 = y[ys - 1]; + if (y0 == 0) return; + var yt = y0 * (1 << this.F1) + ((ys > 1) ? y[ys - 2] >> this.F2 : 0); + var d1 = this.FV / yt, d2 = (1 << this.F1) / yt, e = 1 << this.F2; + var i = r.t, j = i - ys, t = (q == null) ? nbi() : q; + y.dlShiftTo(j, t); + if (r.compareTo(t) >= 0) { + r[r.t++] = 1; + r.subTo(t, r); + } + BigInteger.ONE.dlShiftTo(ys, t); + t.subTo(y, y); // "negative" y so we can replace sub with am later + while (y.t < ys) y[y.t++] = 0; + while (--j >= 0) { + // Estimate quotient digit + 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)) < qd) { // Try it out + y.dlShiftTo(j, t); + r.subTo(t, r); + while (r[i] < --qd) r.subTo(t, r); + } + } + if (q != null) { + r.drShiftTo(ys, q); + if (ts != ms) BigInteger.ZERO.subTo(q, q); + } + r.t = ys; + r.clamp(); + if (nsh > 0) r.rShiftTo(nsh, r); // Denormalize remainder + if (ts < 0) BigInteger.ZERO.subTo(r, r); +}; + +// (protected) return "-1/this % 2^DB"; useful for Mont. reduction +// justification: +// xy == 1 (mod m) +// xy = 1+km +// xy(2-xy) = (1+km)(1-km) +// x[y(2-xy)] = 1-k^2m^2 +// x[y(2-xy)] == 1 (mod m^2) +// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 +// should reduce x and y(2-xy) by m^2 at each step to keep size bounded. +// JS multiply "overflows" differently from C/C++, so care is needed here. +BigInteger.prototype.invDigit = function () { + if (this.t < 1) return 0; + var x = this[0]; + if ((x & 1) == 0) return 0; + var y = x & 3; // y == 1/x mod 2^2 + y = (y * (2 - (x & 0xf) * y)) & 0xf; // y == 1/x mod 2^4 + y = (y * (2 - (x & 0xff) * y)) & 0xff; // y == 1/x mod 2^8 + y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16 + // last step - calculate inverse mod DV directly; + // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints + y = (y * (2 - x * y % this.DV)) % this.DV; // y == 1/x mod 2^dbits + // we really want the negative inverse, and -DV < y < DV + return (y > 0) ? this.DV - y : -y; +}; + +// (protected) true iff this is even +BigInteger.prototype.isEven = function () { return ((this.t > 0) ? (this[0] & 1) : this.s) == 0; }; + +// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) +BigInteger.prototype.exp = function (e, z) { + if (e > 0xffffffff || e < 1) return BigInteger.ONE; + var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e) - 1; + g.copyTo(r); + while (--i >= 0) { + z.sqrTo(r, r2); + if ((e & (1 << i)) > 0) z.mulTo(r2, g, r); + else { var t = r; r = r2; r2 = t; } + } + return z.revert(r); +}; + +// (public) return string representation in given radix +BigInteger.prototype.toString = function (b) { + if (this.s < 0) return "-" + this.negate().toString(b); + var k; + if (b == 16) k = 4; + else if (b == 8) k = 3; + else if (b == 2) k = 1; + else if (b == 32) k = 5; + else if (b == 4) k = 2; + else return this.toRadix(b); + var km = (1 << k) - 1, d, m = false, r = "", i = this.t; + var p = this.DB - (i * this.DB) % k; + if (i-- > 0) { + if (p < this.DB && (d = this[i] >> p) > 0) { m = true; r = int2char(d); } + while (i >= 0) { + if (p < k) { + d = (this[i] & ((1 << p) - 1)) << (k - p); + d |= this[--i] >> (p += this.DB - k); + } + else { + d = (this[i] >> (p -= k)) & km; + if (p <= 0) { p += this.DB; --i; } + } + if (d > 0) m = true; + if (m) r += int2char(d); + } + } + return m ? r : "0"; +}; + +// (public) -this +BigInteger.prototype.negate = function () { var r = nbi(); BigInteger.ZERO.subTo(this, r); return r; }; + +// (public) |this| +BigInteger.prototype.abs = function () { return (this.s < 0) ? this.negate() : this; }; + +// (public) return + if this > a, - if this < a, 0 if equal +BigInteger.prototype.compareTo = function (a) { + var r = this.s - a.s; + if (r != 0) return r; + var i = this.t; + r = i - a.t; + if (r != 0) return (this.s < 0) ? -r : r; + while (--i >= 0) if ((r = this[i] - a[i]) != 0) return r; + return 0; +} + +// (public) return the number of bits in "this" +BigInteger.prototype.bitLength = function () { + if (this.t <= 0) return 0; + return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM)); +}; + +// (public) this mod a +BigInteger.prototype.mod = function (a) { + var r = nbi(); + this.abs().divRemTo(a, null, r); + if (this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r, r); + return r; +} + +// (public) this^e % m, 0 <= e < 2^32 +BigInteger.prototype.modPowInt = function (e, m) { + var z; + if (e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m); + return this.exp(e, z); +}; + +// "constants" +BigInteger.ZERO = nbv(0); +BigInteger.ONE = nbv(1); + +// Copyright (c) 2005-2009 Tom Wu +// All Rights Reserved. +// See "LICENSE" for details. +// Extended JavaScript BN functions, required for RSA private ops. +// Version 1.1: new BigInteger("0", 10) returns "proper" zero +// Version 1.2: square() API, isProbablePrime fix + +// return index of lowest 1-bit in x, x < 2^31 +function lbit(x) { + if (x == 0) return -1; + var r = 0; + if ((x & 0xffff) == 0) { x >>= 16; r += 16; } + if ((x & 0xff) == 0) { x >>= 8; r += 8; } + if ((x & 0xf) == 0) { x >>= 4; r += 4; } + if ((x & 3) == 0) { x >>= 2; r += 2; } + if ((x & 1) == 0) ++r; + return r; +} + +// return number of 1 bits in x +function cbit(x) { + var r = 0; + while (x != 0) { x &= x - 1; ++r; } + return r; +} + +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]; +var lplim = (1 << 26) / lowprimes[lowprimes.length - 1]; + +// (protected) return x s.t. r^x < DV +BigInteger.prototype.chunkSize = function (r) { return Math.floor(Math.LN2 * this.DB / Math.log(r)); }; + +// (protected) convert to radix string +BigInteger.prototype.toRadix = function (b) { + if (b == null) b = 10; + if (this.signum() == 0 || b < 2 || b > 36) return "0"; + var cs = this.chunkSize(b); + var a = Math.pow(b, cs); + var d = nbv(a), y = nbi(), z = nbi(), r = ""; + this.divRemTo(d, y, z); + while (y.signum() > 0) { + r = (a + z.intValue()).toString(b).substr(1) + r; + y.divRemTo(d, y, z); + } + return z.intValue().toString(b) + r; +}; + +// (protected) convert from radix string +BigInteger.prototype.fromRadix = function (s, b) { + this.fromInt(0); + if (b == null) b = 10; + var cs = this.chunkSize(b); + var d = Math.pow(b, cs), mi = false, j = 0, w = 0; + for (var i = 0; i < s.length; ++i) { + var x = intAt(s, i); + if (x < 0) { + if (s.charAt(i) == "-" && this.signum() == 0) mi = true; + continue; + } + w = b * w + x; + if (++j >= cs) { + this.dMultiply(d); + this.dAddOffset(w, 0); + j = 0; + w = 0; + } + } + if (j > 0) { + this.dMultiply(Math.pow(b, j)); + this.dAddOffset(w, 0); + } + if (mi) BigInteger.ZERO.subTo(this, this); +}; + +// (protected) alternate constructor +BigInteger.prototype.fromNumber = function (a, b, c) { + if ("number" == typeof b) { + // new BigInteger(int,int,RNG) + if (a < 2) this.fromInt(1); + else { + this.fromNumber(a, c); + if (!this.testBit(a - 1)) // force MSB set + this.bitwiseTo(BigInteger.ONE.shiftLeft(a - 1), op_or, this); + if (this.isEven()) this.dAddOffset(1, 0); // force odd + while (!this.isProbablePrime(b)) { + this.dAddOffset(2, 0); + if (this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a - 1), this); + } + } + } + else { + // new BigInteger(int,RNG) + var x = new Array(), t = a & 7; + x.length = (a >> 3) + 1; + b.nextBytes(x); + if (t > 0) x[0] &= ((1 << t) - 1); else x[0] = 0; + this.fromString(x, 256); + } +}; + +// (protected) r = this op a (bitwise) +BigInteger.prototype.bitwiseTo = function (a, op, r) { + var i, f, m = Math.min(a.t, this.t); + for (i = 0; i < m; ++i) r[i] = op(this[i], a[i]); + if (a.t < this.t) { + f = a.s & this.DM; + for (i = m; i < this.t; ++i) r[i] = op(this[i], f); + r.t = this.t; + } + else { + f = this.s & this.DM; + for (i = m; i < a.t; ++i) r[i] = op(f, a[i]); + r.t = a.t; + } + r.s = op(this.s, a.s); + r.clamp(); +}; + +// (protected) this op (1<<n) +BigInteger.prototype.changeBit = function (n, op) { + var r = BigInteger.ONE.shiftLeft(n); + this.bitwiseTo(r, op, r); + return r; +}; + +// (protected) r = this + a +BigInteger.prototype.addTo = function (a, r) { + var i = 0, c = 0, m = Math.min(a.t, this.t); + while (i < m) { + c += this[i] + a[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + if (a.t < this.t) { + c += a.s; + while (i < this.t) { + c += this[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c += this.s; + } + else { + c += this.s; + while (i < a.t) { + c += a[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c += a.s; + } + r.s = (c < 0) ? -1 : 0; + if (c > 0) r[i++] = c; + else if (c < -1) r[i++] = this.DV + c; + r.t = i; + r.clamp(); +}; + +// (protected) this *= n, this >= 0, 1 < n < DV +BigInteger.prototype.dMultiply = function (n) { + this[this.t] = this.am(0, n - 1, this, 0, 0, this.t); + ++this.t; + this.clamp(); +}; + +// (protected) this += n << w words, this >= 0 +BigInteger.prototype.dAddOffset = function (n, w) { + if (n == 0) return; + while (this.t <= w) this[this.t++] = 0; + this[w] += n; + while (this[w] >= this.DV) { + this[w] -= this.DV; + if (++w >= this.t) this[this.t++] = 0; + ++this[w]; + } +}; + +// (protected) r = lower n words of "this * a", a.t <= n +// "this" should be the larger one if appropriate. +BigInteger.prototype.multiplyLowerTo = function (a, n, r) { + var i = Math.min(this.t + a.t, n); + r.s = 0; // assumes a,this >= 0 + r.t = i; + while (i > 0) r[--i] = 0; + var j; + for (j = r.t - this.t; i < j; ++i) r[i + this.t] = this.am(0, a[i], r, i, 0, this.t); + for (j = Math.min(a.t, n); i < j; ++i) this.am(0, a[i], r, i, 0, n - i); + r.clamp(); +}; + + +// (protected) r = "this * a" without lower n words, n > 0 +// "this" should be the larger one if appropriate. +BigInteger.prototype.multiplyUpperTo = function (a, n, r) { + --n; + var i = r.t = this.t + a.t - n; + r.s = 0; // assumes a,this >= 0 + while (--i >= 0) r[i] = 0; + for (i = Math.max(n - this.t, 0); i < a.t; ++i) + r[this.t + i - n] = this.am(n - i, a[i], r, 0, 0, this.t + i - n); + r.clamp(); + r.drShiftTo(1, r); +}; + +// (protected) this % n, n < 2^26 +BigInteger.prototype.modInt = function (n) { + if (n <= 0) return 0; + var d = this.DV % n, r = (this.s < 0) ? n - 1 : 0; + if (this.t > 0) + if (d == 0) r = this[0] % n; + else for (var i = this.t - 1; i >= 0; --i) r = (d * r + this[i]) % n; + return r; +}; + +// (protected) true if probably prime (HAC 4.24, Miller-Rabin) +BigInteger.prototype.millerRabin = function (t) { + var n1 = this.subtract(BigInteger.ONE); + var k = n1.getLowestSetBit(); + if (k <= 0) return false; + var r = n1.shiftRight(k); + t = (t + 1) >> 1; + if (t > lowprimes.length) t = lowprimes.length; + var a = nbi(); + for (var i = 0; i < t; ++i) { + //Pick bases at random, instead of starting at 2 + a.fromInt(lowprimes[Math.floor(Math.random() * lowprimes.length)]); + var y = a.modPow(r, this); + if (y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) { + var j = 1; + while (j++ < k && y.compareTo(n1) != 0) { + y = y.modPowInt(2, this); + if (y.compareTo(BigInteger.ONE) == 0) return false; + } + if (y.compareTo(n1) != 0) return false; + } + } + return true; +}; + +// (public) +BigInteger.prototype.clone = function () { var r = nbi(); this.copyTo(r); return r; }; + +// (public) return value as integer +BigInteger.prototype.intValue = function () { + if (this.s < 0) { + if (this.t == 1) return this[0] - this.DV; + else if (this.t == 0) return -1; + } + else if (this.t == 1) return this[0]; + else if (this.t == 0) return 0; + // assumes 16 < DB < 32 + return ((this[1] & ((1 << (32 - this.DB)) - 1)) << this.DB) | this[0]; +}; + +// (public) return value as byte +BigInteger.prototype.byteValue = function () { return (this.t == 0) ? this.s : (this[0] << 24) >> 24; }; + +// (public) return value as short (assumes DB>=16) +BigInteger.prototype.shortValue = function () { return (this.t == 0) ? this.s : (this[0] << 16) >> 16; }; + +// (public) 0 if this == 0, 1 if this > 0 +BigInteger.prototype.signum = function () { + if (this.s < 0) return -1; + else if (this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0; + else return 1; +}; + +// (public) convert to bigendian byte array +BigInteger.prototype.toByteArray = function () { + var i = this.t, r = new Array(); + r[0] = this.s; + var p = this.DB - (i * this.DB) % 8, d, k = 0; + if (i-- > 0) { + if (p < this.DB && (d = this[i] >> p) != (this.s & this.DM) >> p) + r[k++] = d | (this.s << (this.DB - p)); + while (i >= 0) { + if (p < 8) { + d = (this[i] & ((1 << p) - 1)) << (8 - p); + d |= this[--i] >> (p += this.DB - 8); + } + else { + d = (this[i] >> (p -= 8)) & 0xff; + if (p <= 0) { p += this.DB; --i; } + } + if ((d & 0x80) != 0) d |= -256; + if (k == 0 && (this.s & 0x80) != (d & 0x80)) ++k; + if (k > 0 || d != this.s) r[k++] = d; + } + } + return r; +}; + +BigInteger.prototype.equals = function (a) { return (this.compareTo(a) == 0); }; +BigInteger.prototype.min = function (a) { return (this.compareTo(a) < 0) ? this : a; }; +BigInteger.prototype.max = function (a) { return (this.compareTo(a) > 0) ? this : a; }; + +// (public) this & a +function op_and(x, y) { return x & y; } +BigInteger.prototype.and = function (a) { var r = nbi(); this.bitwiseTo(a, op_and, r); return r; }; + +// (public) this | a +function op_or(x, y) { return x | y; } +BigInteger.prototype.or = function (a) { var r = nbi(); this.bitwiseTo(a, op_or, r); return r; }; + +// (public) this ^ a +function op_xor(x, y) { return x ^ y; } +BigInteger.prototype.xor = function (a) { var r = nbi(); this.bitwiseTo(a, op_xor, r); return r; }; + +// (public) this & ~a +function op_andnot(x, y) { return x & ~y; } +BigInteger.prototype.andNot = function (a) { var r = nbi(); this.bitwiseTo(a, op_andnot, r); return r; }; + +// (public) ~this +BigInteger.prototype.not = function () { + var r = nbi(); + for (var i = 0; i < this.t; ++i) r[i] = this.DM & ~this[i]; + r.t = this.t; + r.s = ~this.s; + return r; +}; + +// (public) this << n +BigInteger.prototype.shiftLeft = function (n) { + var r = nbi(); + if (n < 0) this.rShiftTo(-n, r); else this.lShiftTo(n, r); + return r; +}; + +// (public) this >> n +BigInteger.prototype.shiftRight = function (n) { + var r = nbi(); + if (n < 0) this.lShiftTo(-n, r); else this.rShiftTo(n, r); + return r; +}; + +// (public) returns index of lowest 1-bit (or -1 if none) +BigInteger.prototype.getLowestSetBit = function () { + for (var i = 0; i < this.t; ++i) + if (this[i] != 0) return i * this.DB + lbit(this[i]); + if (this.s < 0) return this.t * this.DB; + return -1; +}; + +// (public) return number of set bits +BigInteger.prototype.bitCount = function () { + var r = 0, x = this.s & this.DM; + for (var i = 0; i < this.t; ++i) r += cbit(this[i] ^ x); + return r; +}; + +// (public) true iff nth bit is set +BigInteger.prototype.testBit = function (n) { + var j = Math.floor(n / this.DB); + if (j >= this.t) return (this.s != 0); + return ((this[j] & (1 << (n % this.DB))) != 0); +}; + +// (public) this | (1<<n) +BigInteger.prototype.setBit = function (n) { return this.changeBit(n, op_or); }; +// (public) this & ~(1<<n) +BigInteger.prototype.clearBit = function (n) { return this.changeBit(n, op_andnot); }; +// (public) this ^ (1<<n) +BigInteger.prototype.flipBit = function (n) { return this.changeBit(n, op_xor); }; +// (public) this + a +BigInteger.prototype.add = function (a) { var r = nbi(); this.addTo(a, r); return r; }; +// (public) this - a +BigInteger.prototype.subtract = function (a) { var r = nbi(); this.subTo(a, r); return r; }; +// (public) this * a +BigInteger.prototype.multiply = function (a) { var r = nbi(); this.multiplyTo(a, r); return r; }; +// (public) this / a +BigInteger.prototype.divide = function (a) { var r = nbi(); this.divRemTo(a, r, null); return r; }; +// (public) this % a +BigInteger.prototype.remainder = function (a) { var r = nbi(); this.divRemTo(a, null, r); return r; }; +// (public) [this/a,this%a] +BigInteger.prototype.divideAndRemainder = function (a) { + var q = nbi(), r = nbi(); + this.divRemTo(a, q, r); + return new Array(q, r); +}; + +// (public) this^e % m (HAC 14.85) +BigInteger.prototype.modPow = function (e, m) { + var i = e.bitLength(), k, r = nbv(1), z; + if (i <= 0) return r; + else if (i < 18) k = 1; + else if (i < 48) k = 3; + else if (i < 144) k = 4; + else if (i < 768) k = 5; + else k = 6; + if (i < 8) + z = new Classic(m); + else if (m.isEven()) + z = new Barrett(m); + else + z = new Montgomery(m); + + // precomputation + var g = new Array(), n = 3, k1 = k - 1, km = (1 << k) - 1; + g[1] = z.convert(this); + if (k > 1) { + var g2 = nbi(); + z.sqrTo(g[1], g2); + while (n <= km) { + g[n] = nbi(); + z.mulTo(g2, g[n - 2], g[n]); + n += 2; + } + } + + var j = e.t - 1, w, is1 = true, r2 = nbi(), t; + i = nbits(e[j]) - 1; + while (j >= 0) { + if (i >= k1) w = (e[j] >> (i - k1)) & km; + else { + w = (e[j] & ((1 << (i + 1)) - 1)) << (k1 - i); + if (j > 0) w |= e[j - 1] >> (this.DB + i - k1); + } + + n = k; + while ((w & 1) == 0) { w >>= 1; --n; } + if ((i -= n) < 0) { i += this.DB; --j; } + if (is1) { // ret == 1, don't bother squaring or multiplying it + g[w].copyTo(r); + is1 = false; + } + else { + while (n > 1) { z.sqrTo(r, r2); z.sqrTo(r2, r); n -= 2; } + if (n > 0) z.sqrTo(r, r2); else { t = r; r = r2; r2 = t; } + z.mulTo(r2, g[w], r); + } + + while (j >= 0 && (e[j] & (1 << i)) == 0) { + z.sqrTo(r, r2); t = r; r = r2; r2 = t; + if (--i < 0) { i = this.DB - 1; --j; } + } + } + return z.revert(r); +}; + +// (public) 1/this % m (HAC 14.61) +BigInteger.prototype.modInverse = function (m) { + var ac = m.isEven(); + if ((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO; + var u = m.clone(), v = this.clone(); + var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1); + while (u.signum() != 0) { + while (u.isEven()) { + u.rShiftTo(1, u); + if (ac) { + if (!a.isEven() || !b.isEven()) { a.addTo(this, a); b.subTo(m, b); } + a.rShiftTo(1, a); + } + else if (!b.isEven()) b.subTo(m, b); + b.rShiftTo(1, b); + } + while (v.isEven()) { + v.rShiftTo(1, v); + if (ac) { + if (!c.isEven() || !d.isEven()) { c.addTo(this, c); d.subTo(m, d); } + c.rShiftTo(1, c); + } + else if (!d.isEven()) d.subTo(m, d); + d.rShiftTo(1, d); + } + if (u.compareTo(v) >= 0) { + u.subTo(v, u); + if (ac) a.subTo(c, a); + b.subTo(d, b); + } + else { + v.subTo(u, v); + if (ac) c.subTo(a, c); + d.subTo(b, d); + } + } + if (v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO; + if (d.compareTo(m) >= 0) return d.subtract(m); + if (d.signum() < 0) d.addTo(m, d); else return d; + if (d.signum() < 0) return d.add(m); else return d; +}; + +// (public) this^e +BigInteger.prototype.pow = function (e) { return this.exp(e, new NullExp()); }; + +// (public) gcd(this,a) (HAC 14.54) +BigInteger.prototype.gcd = function (a) { + var x = (this.s < 0) ? this.negate() : this.clone(); + var 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; + if (i < g) g = i; + if (g > 0) { + x.rShiftTo(g, x); + y.rShiftTo(g, y); + } + while (x.signum() > 0) { + if ((i = x.getLowestSetBit()) > 0) x.rShiftTo(i, x); + if ((i = y.getLowestSetBit()) > 0) y.rShiftTo(i, y); + if (x.compareTo(y) >= 0) { + x.subTo(y, x); + x.rShiftTo(1, x); + } + else { + y.subTo(x, y); + y.rShiftTo(1, y); + } + } + if (g > 0) y.lShiftTo(g, y); + return y; +}; + +// (public) test primality with certainty >= 1-.5^t +BigInteger.prototype.isProbablePrime = function (t) { + var i, x = this.abs(); + if (x.t == 1 && x[0] <= lowprimes[lowprimes.length - 1]) { + for (i = 0; i < lowprimes.length; ++i) + if (x[0] == lowprimes[i]) return true; + return false; + } + if (x.isEven()) return false; + i = 1; + while (i < lowprimes.length) { + var m = lowprimes[i], j = i + 1; + while (j < lowprimes.length && m < lplim) m *= lowprimes[j++]; + m = x.modInt(m); + while (i < j) if (m % lowprimes[i++] == 0) return false; + } + return x.millerRabin(t); +}; + +// JSBN-specific extension + +// (public) this^2 +BigInteger.prototype.square = function () { var r = nbi(); this.squareTo(r); return r; }; +// NOTE: BigInteger interfaces not implemented in jsbn: +// BigInteger(int signum, byte[] magnitude) +// double doubleValue() +// float floatValue() +// int hashCode() +// long longValue() +// static BigInteger valueOf(long val) + +// Copyright Stephan Thomas (start) --- // +// https://raw.github.com/bitcoinjs/bitcoinjs-lib/07f9d55ccb6abd962efb6befdd37671f85ea4ff9/src/util.js +// BigInteger monkey patching +BigInteger.valueOf = nbv; + +/** +* Returns a byte array representation of the big integer. +* +* This returns the absolute of the contained value in big endian +* form. A value of zero results in an empty array. +*/ +BigInteger.prototype.toByteArrayUnsigned = function () { + var ba = this.abs().toByteArray(); + if (ba.length) { + if (ba[0] == 0) { + ba = ba.slice(1); + } + return ba.map(function (v) { + return (v < 0) ? v + 256 : v; + }); + } else { + // Empty array, nothing to do + return ba; + } +}; + +/** +* Turns a byte array into a big integer. +* +* This function will interpret a byte array as a big integer in big +* endian notation and ignore leading zeros. +*/ +BigInteger.fromByteArrayUnsigned = function (ba) { + if (!ba.length) { + return ba.valueOf(0); + } else if (ba[0] & 0x80) { + // Prepend a zero so the BigInteger class doesn't mistake this + // for a negative integer. + return new BigInteger([0].concat(ba)); + } else { + return new BigInteger(ba); + } +}; + +/** +* Converts big integer to signed byte representation. +* +* The format for this value uses a the most significant bit as a sign +* bit. If the most significant bit is already occupied by the +* absolute value, an extra byte is prepended and the sign bit is set +* there. +* +* Examples: +* +* 0 => 0x00 +* 1 => 0x01 +* -1 => 0x81 +* 127 => 0x7f +* -127 => 0xff +* 128 => 0x0080 +* -128 => 0x8080 +* 255 => 0x00ff +* -255 => 0x80ff +* 16300 => 0x3fac +* -16300 => 0xbfac +* 62300 => 0x00f35c +* -62300 => 0x80f35c +*/ +BigInteger.prototype.toByteArraySigned = function () { + var val = this.abs().toByteArrayUnsigned(); + var neg = this.compareTo(BigInteger.ZERO) < 0; + + if (neg) { + if (val[0] & 0x80) { + val.unshift(0x80); + } else { + val[0] |= 0x80; + } + } else { + if (val[0] & 0x80) { + val.unshift(0x00); + } + } + + return val; +}; + +/** +* Parse a signed big integer byte representation. +* +* For details on the format please see BigInteger.toByteArraySigned. +*/ +BigInteger.fromByteArraySigned = function (ba) { + // Check for negative value + if (ba[0] & 0x80) { + // Remove sign bit + ba[0] &= 0x7f; + + return BigInteger.fromByteArrayUnsigned(ba).negate(); + } else { + return BigInteger.fromByteArrayUnsigned(ba); + } +}; +// Copyright Stephan Thomas (end) --- // + +// ****** REDUCTION ******* // + +// Modular reduction using "classic" algorithm +var Classic = window.Classic = function Classic(m) { this.m = m; } +Classic.prototype.convert = function (x) { + if (x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m); + else return 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); }; + +// Montgomery reduction +var Montgomery = window.Montgomery = function Montgomery(m) { + this.m = m; + this.mp = m.invDigit(); + this.mpl = this.mp & 0x7fff; + this.mph = this.mp >> 15; + this.um = (1 << (m.DB - 15)) - 1; + this.mt2 = 2 * m.t; +} +// xR mod m +Montgomery.prototype.convert = function (x) { + var r = nbi(); + x.abs().dlShiftTo(this.m.t, r); + r.divRemTo(this.m, null, r); + if (x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r, r); + return r; +} +// x/R mod m +Montgomery.prototype.revert = function (x) { + var r = nbi(); + x.copyTo(r); + this.reduce(r); + return r; +}; +// x = x/R mod m (HAC 14.32) +Montgomery.prototype.reduce = function (x) { + while (x.t <= this.mt2) // pad x so am has enough room later + x[x.t++] = 0; + for (var i = 0; i < this.m.t; ++i) { + // faster way of calculating u0 = x[i]*mp mod DV + var j = x[i] & 0x7fff; + var u0 = (j * this.mpl + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & x.DM; + // use am to combine the multiply-shift-add into one call + j = i + this.m.t; + x[j] += this.m.am(0, u0, x, i, 0, this.m.t); + // propagate carry + while (x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; } + } + x.clamp(); + x.drShiftTo(this.m.t, x); + if (x.compareTo(this.m) >= 0) x.subTo(this.m, x); +}; +// r = "xy/R mod m"; x,y != r +Montgomery.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); this.reduce(r); }; +// r = "x^2/R mod m"; x != r +Montgomery.prototype.sqrTo = function (x, r) { x.squareTo(r); this.reduce(r); }; + +// A "null" reducer +var NullExp = window.NullExp = function NullExp() { } +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); }; + +// Barrett modular reduction +var Barrett = window.Barrett = function Barrett(m) { + // setup Barrett + 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); + else if (x.compareTo(this.m) < 0) return x; + else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; } +}; +Barrett.prototype.revert = function (x) { return x; }; +// x = x mod m (HAC 14.42) +Barrett.prototype.reduce = function (x) { + x.drShiftTo(this.m.t - 1, this.r2); + if (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); + while (x.compareTo(this.r2) < 0) x.dAddOffset(1, this.m.t + 1); + x.subTo(this.r2, x); + while (x.compareTo(this.m) >= 0) x.subTo(this.m, x); +}; +// r = x*y mod m; x,y != r +Barrett.prototype.mulTo = function (x, y, r) { x.multiplyTo(y, r); this.reduce(r); }; +// r = x^2 mod m; x != r +Barrett.prototype.sqrTo = function (x, r) { x.squareTo(r); this.reduce(r); }; + +// ----- Bitcoin -----// +export let Bitcoin = {}; + +//https://raw.github.com/bitcoinjs/bitcoinjs-lib/09e8c6e184d6501a0c2c59d73ca64db5c0d3eb95/src/address.js +Bitcoin.Address = function (bytes) { +if ("string" == typeof bytes) { + bytes = Bitcoin.Address.decodeString(bytes); +} +this.hash = bytes; +}; + +/** +* Serialize this object as a standard currency address. +* +* Returns the address as a base58-encoded string in the standardized format. +*/ +Bitcoin.Address.prototype.toString = function () { +// Get a copy of the hash +var hash = this.hash.slice(0); + +// Version +hash.unshift('0x3c'); // KMD +var checksum = Crypto.SHA256(Crypto.SHA256(hash, { asBytes: true }), { asBytes: true }); +var bytes = hash.concat(checksum.slice(0, 4)); +return Bitcoin.Base58.encode(bytes); +}; + +Bitcoin.Address.prototype.getHashBase64 = function () { +return Crypto.util.bytesToBase64(this.hash); +}; + +/** +* Parse a Bitcoin address contained in a string. +*/ +Bitcoin.Address.decodeString = function (string) { +var bytes = Bitcoin.Base58.decode(string); +var hash = bytes.slice(0, 21); +var checksum = Crypto.SHA256(Crypto.SHA256(hash, { asBytes: true }), { asBytes: true }); + +if (checksum[0] != bytes[21] || + checksum[1] != bytes[22] || + checksum[2] != bytes[23] || + checksum[3] != bytes[24]) { + throw "Checksum validation failed!"; +} + +return hash; +}; + +Bitcoin.Base58 = { + alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", + validRegex: /^[1-9A-HJ-NP-Za-km-z]+$/, + base: BigInteger.valueOf(58), + + /** + * Convert a byte array to a base58-encoded string. + * + * Written by Mike Hearn for BitcoinJ. + * Copyright (c) 2011 Google Inc. + * + * Ported to JavaScript by Stefan Thomas. + */ + encode: function (input) { + var bi = BigInteger.fromByteArrayUnsigned(input); + var chars = []; + + while (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()]); + + // Convert leading zeros too. + for (var i = 0; i < input.length; i++) { + if (input[i] == 0x00) { + chars.unshift(B58.alphabet[0]); + } else break; + } + + return chars.join(''); + }, + + /** + * Convert a base58-encoded string to a byte array. + * + * Written by Mike Hearn for BitcoinJ. + * Copyright (c) 2011 Google Inc. + * + * Ported to JavaScript by Stefan Thomas. + */ + decode: function (input) { + var bi = BigInteger.valueOf(0); + var leadingZerosNum = 0; + for (var i = input.length - 1; 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))); + + // This counts leading zero bytes + if (input[i] == "1") leadingZerosNum++; + else leadingZerosNum = 0; + } + var bytes = bi.toByteArrayUnsigned(); + + // Add leading zeros + while (leadingZerosNum-- > 0) bytes.unshift(0); + + return bytes; + } +}; + +const B58 = Bitcoin.Base58; + +Bitcoin.ECDSA = (function () { + var ecparams = EllipticCurve.getSECCurveByName("secp256k1"); + var rng = new SecureRandom(); + + var P_OVER_FOUR = null; + + function implShamirsTrick(P, k, Q, l) { + var m = Math.max(k.bitLength(), l.bitLength()); + var Z = P.add2D(Q); + var R = P.curve.getInfinity(); + + for (var i = m - 1; i >= 0; --i) { + R = R.twice2D(); + + R.z = BigInteger.ONE; + + if (k.testBit(i)) { + if (l.testBit(i)) { + R = R.add2D(Z); + } else { + R = R.add2D(P); + } + } else { + if (l.testBit(i)) { + R = R.add2D(Q); + } + } + } + + return R; + }; + + var 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; + var n = ecparams.getN(); + var e = BigInteger.fromByteArrayUnsigned(hash); + + do { + var k = ECDSA.getBigRandom(n); + var G = ecparams.getG(); + var Q = G.multiply(k); + var r = Q.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; + 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) { + r = sig.r; + s = sig.s; + } else { + throw "Invalid value for signature"; + } + + var Q; + if (pubkey instanceof ec.PointFp) { + Q = pubkey; + } else if (Bitcoin.Util.isArray(pubkey)) { + Q = EllipticCurve.PointFp.decodeFrom(ecparams.getCurve(), pubkey); + } else { + throw "Invalid format for pubkey value, must be byte array or ec.PointFp"; + } + var e = BigInteger.fromByteArrayUnsigned(hash); + + return ECDSA.verifyRaw(e, r, s, Q); + }, + + verifyRaw: function (e, r, s, Q) { + var n = ecparams.getN(); + var G = ecparams.getG(); + + if (r.compareTo(BigInteger.ONE) < 0 || + r.compareTo(n) >= 0) + return false; + + if (s.compareTo(BigInteger.ONE) < 0 || + s.compareTo(n) >= 0) + return false; + + var c = s.modInverse(n); + + var u1 = e.multiply(c).mod(n); + var u2 = r.multiply(c).mod(n); + + // TODO(!!!): For some reason Shamir's trick isn't working with + // signed message verification!? Probably an implementation + // error! + //var point = implShamirsTrick(G, u1, Q, u2); + var point = G.multiply(u1).add(Q.multiply(u2)); + + var v = point.getX().toBigInteger().mod(n); + + return v.equals(r); + }, + + /** + * Serialize a signature into DER format. + * + * Takes two BigIntegers representing r and s and returns a byte array. + */ + serializeSig: function (r, s) { + var rBa = r.toByteArraySigned(); + var sBa = s.toByteArraySigned(); + + var sequence = []; + sequence.push(0x02); // INTEGER + sequence.push(rBa.length); + sequence = sequence.concat(rBa); + + sequence.push(0x02); // INTEGER + sequence.push(sBa.length); + sequence = sequence.concat(sBa); + + sequence.unshift(sequence.length); + sequence.unshift(0x30); // SEQUENCE + + return sequence; + }, + + /** + * Parses a byte array containing a DER-encoded signature. + * + * This function will return an object of the form: + * + * { + * r: BigInteger, + * s: BigInteger + * } + */ + parseSig: function (sig) { + var cursor; + if (sig[0] != 0x30) + throw new Error("Signature not a valid DERSequence"); + + cursor = 2; + if (sig[cursor] != 0x02) + throw new Error("First element in signature must be a DERInteger"); ; + var rBa = sig.slice(cursor + 2, cursor + 2 + sig[cursor + 1]); + + cursor += 2 + sig[cursor + 1]; + if (sig[cursor] != 0x02) + throw new Error("Second element in signature must be a DERInteger"); + var sBa = sig.slice(cursor + 2, cursor + 2 + sig[cursor + 1]); + + cursor += 2 + sig[cursor + 1]; + + //if (cursor != sig.length) + // throw new Error("Extra bytes in signature"); + + var r = BigInteger.fromByteArrayUnsigned(rBa); + var s = BigInteger.fromByteArrayUnsigned(sBa); + + return { r: r, s: s }; + }, + + parseSigCompact: function (sig) { + if (sig.length !== 65) { + throw "Signature has the wrong length"; + } + + // Signature is prefixed with a type byte storing three bits of + // information. + var i = sig[0] - 27; + if (i < 0 || i > 7) { + throw "Invalid signature type"; + } + + var n = ecparams.getN(); + var r = BigInteger.fromByteArrayUnsigned(sig.slice(1, 33)).mod(n); + var s = BigInteger.fromByteArrayUnsigned(sig.slice(33, 65)).mod(n); + + return { r: r, s: s, i: i }; + }, + + /** + * Recover a public key from a signature. + * + * See SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public + * Key Recovery Operation". + * + * http://www.secg.org/download/aid-780/sec1-v2.pdf + */ + recoverPubKey: function (r, s, hash, i) { + // The recovery parameter i has two bits. + i = i & 3; + + // The less significant bit specifies whether the y coordinate + // of the compressed point is even or not. + var isYEven = i & 1; + + // The more significant bit specifies whether we should use the + // first or second candidate key. + var isSecondKey = i >> 1; + + var n = ecparams.getN(); + var G = ecparams.getG(); + var curve = ecparams.getCurve(); + var p = curve.getQ(); + var a = curve.getA().toBigInteger(); + var b = curve.getB().toBigInteger(); + + // We precalculate (p + 1) / 4 where p is if the field order + if (!P_OVER_FOUR) { + P_OVER_FOUR = p.add(BigInteger.ONE).divide(BigInteger.valueOf(4)); + } + + // 1.1 Compute x + var x = isSecondKey ? r.add(n) : r; + + // 1.3 Convert x to point + var alpha = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p); + var beta = alpha.modPow(P_OVER_FOUR, p); + + var xorOdd = beta.isEven() ? (i % 2) : ((i + 1) % 2); + // If beta is even, but y isn't or vice versa, then convert it, + // otherwise we're done and y == beta. + var y = (beta.isEven() ? !isYEven : isYEven) ? beta : p.subtract(beta); + + // 1.4 Check that nR is at infinity + var R = new EllipticCurve.PointFp(curve, + curve.fromBigInteger(x), + curve.fromBigInteger(y)); + R.validate(); + + // 1.5 Compute e from M + var e = BigInteger.fromByteArrayUnsigned(hash); + var eNeg = BigInteger.ZERO.subtract(e).mod(n); + + // 1.6 Compute Q = r^-1 (sR - eG) + var rInv = r.modInverse(n); + var Q = implShamirsTrick(R, s, G, eNeg).multiply(rInv); + + Q.validate(); + if (!ECDSA.verifyRaw(e, r, s, Q)) { + throw "Pubkey recovery unsuccessful"; + } + + var pubKey = new Bitcoin.ECKey(); + pubKey.pub = Q; + return pubKey; + }, + + /** + * Calculate pubkey extraction parameter. + * + * When extracting a pubkey from a signature, we have to + * distinguish four different cases. Rather than putting this + * burden on the verifier, Bitcoin includes a 2-bit value with the + * signature. + * + * This function simply tries all four cases and returns the value + * that resulted in a successful pubkey recovery. + */ + calcPubkeyRecoveryParam: function (address, r, s, hash) { + for (var i = 0; i < 4; i++) { + try { + var pubkey = Bitcoin.ECDSA.recoverPubKey(r, s, hash, i); + if (pubkey.getBitcoinAddress().toString() == address) { + return i; + } + } catch (e) { } + } + throw "Unable to find valid recovery factor"; + } + }; + + return ECDSA; +})(); + +Bitcoin.ECKey = (function () { + var ECDSA = Bitcoin.ECDSA; + var ecparams = EllipticCurve.getSECCurveByName("secp256k1"); + var rng = new SecureRandom(); + + var ECKey = function (input) { + if (!input) { + // Generate new key + var n = ecparams.getN(); + this.priv = ECDSA.getBigRandom(n); + } else if (input instanceof BigInteger) { + // Input is a private key value + this.priv = input; + } else if (Bitcoin.Util.isArray(input)) { + // Prepend zero byte to prevent interpretation as negative integer + this.priv = BigInteger.fromByteArrayUnsigned(input); + } else if ("string" == typeof input) { + var bytes = null; + if (ECKey.isWalletImportFormat(input)) { + bytes = ECKey.decodeWalletImportFormat(input); + } else if (ECKey.isCompressedWalletImportFormat(input)) { + bytes = ECKey.decodeCompressedWalletImportFormat(input); + this.compressed = true; + } else if (ECKey.isMiniFormat(input)) { + bytes = Crypto.SHA256(input, { asBytes: true }); + } else if (ECKey.isHexFormat(input)) { + bytes = Crypto.util.hexToBytes(input); + } else if (ECKey.isBase64Format(input)) { + bytes = Crypto.util.base64ToBytes(input); + } + + if (ECKey.isBase6Format(input)) { + this.priv = new BigInteger(input, 6); + } else if (bytes == null || bytes.length != 32) { + this.priv = null; + } else { + // Prepend zero byte to prevent interpretation as negative integer + this.priv = BigInteger.fromByteArrayUnsigned(bytes); + } + } + + this.compressed = (this.compressed == undefined) ? !!ECKey.compressByDefault : this.compressed; + }; + + /** + * Whether public keys should be returned compressed by default. + */ + ECKey.compressByDefault = false; + + /** + * Set whether the public key should be returned compressed or not. + */ + ECKey.prototype.setCompressed = function (v) { + this.compressed = !!v; + if (this.pubPoint) this.pubPoint.compressed = this.compressed; + return this; + }; + + /* + * Return public key as a byte array in DER encoding + */ + ECKey.prototype.getPub = function () { + if (this.compressed) { + if (this.pubComp) return this.pubComp; + return this.pubComp = this.getPubPoint().getEncoded(1); + } else { + if (this.pubUncomp) return this.pubUncomp; + return this.pubUncomp = this.getPubPoint().getEncoded(0); + } + }; + + /** + * Return public point as ECPoint object. + */ + ECKey.prototype.getPubPoint = function () { + if (!this.pubPoint) { + this.pubPoint = ecparams.getG().multiply(this.priv); + this.pubPoint.compressed = this.compressed; + } + return this.pubPoint; + }; + + ECKey.prototype.getPubKeyHex = function () { + if (this.compressed) { + if (this.pubKeyHexComp) return this.pubKeyHexComp; + return this.pubKeyHexComp = Crypto.util.bytesToHex(this.getPub()).toString().toUpperCase(); + } else { + if (this.pubKeyHexUncomp) return this.pubKeyHexUncomp; + return this.pubKeyHexUncomp = Crypto.util.bytesToHex(this.getPub()).toString().toUpperCase(); + } + }; + + /** + * Get the pubKeyHash for this key. + * + * This is calculated as RIPE160(SHA256([encoded pubkey])) and returned as + * a byte array. + */ + ECKey.prototype.getPubKeyHash = function () { + if (this.compressed) { + if (this.pubKeyHashComp) return this.pubKeyHashComp; + return this.pubKeyHashComp = Bitcoin.Util.sha256ripe160(this.getPub()); + } else { + if (this.pubKeyHashUncomp) return this.pubKeyHashUncomp; + return this.pubKeyHashUncomp = Bitcoin.Util.sha256ripe160(this.getPub()); + } + }; + + ECKey.prototype.getBitcoinAddress = function () { + var hash = this.getPubKeyHash(); + var addr = new Bitcoin.Address(hash); + return addr.toString(); + }; + + /* + * Takes a public point as a hex string or byte array + */ + ECKey.prototype.setPub = function (pub) { + // byte array + if (Bitcoin.Util.isArray(pub)) { + pub = Crypto.util.bytesToHex(pub).toString().toUpperCase(); + } + var ecPoint = ecparams.getCurve().decodePointHex(pub); + this.setCompressed(ecPoint.compressed); + this.pubPoint = ecPoint; + return this; + }; + + // Sipa Private Key Wallet Import Format + ECKey.prototype.getBitcoinWalletImportFormat = function () { + var bytes = this.getBitcoinPrivateKeyByteArray(); + bytes.unshift('0xbc'); // prepend private key prefix // KMD + if (this.compressed) bytes.push(0x01); // append 0x01 byte for compressed format + var checksum = Crypto.SHA256(Crypto.SHA256(bytes, { asBytes: true }), { asBytes: true }); + bytes = bytes.concat(checksum.slice(0, 4)); + var privWif = Bitcoin.Base58.encode(bytes); + return privWif; + }; + + // Private Key Hex Format + ECKey.prototype.getBitcoinHexFormat = function () { + return Crypto.util.bytesToHex(this.getBitcoinPrivateKeyByteArray()).toString().toUpperCase(); + }; + + // Private Key Base64 Format + ECKey.prototype.getBitcoinBase64Format = function () { + return Crypto.util.bytesToBase64(this.getBitcoinPrivateKeyByteArray()); + }; + + ECKey.prototype.getBitcoinPrivateKeyByteArray = function () { + // Get a copy of private key as a byte array + var bytes = this.priv.toByteArrayUnsigned(); + // zero pad if private key is less than 32 bytes + while (bytes.length < 32) bytes.unshift(0x00); + return bytes; + }; + + ECKey.prototype.toString = function (format) { + format = format || ""; + if (format.toString().toLowerCase() == "base64" || format.toString().toLowerCase() == "b64") { + return this.getBitcoinBase64Format(); + } + // Wallet Import Format + else if (format.toString().toLowerCase() == "wif") { + return this.getBitcoinWalletImportFormat(); + } + else { + return 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()); + }; + + /** + * Parse a wallet import format private key contained in a string. + */ + ECKey.decodeWalletImportFormat = function (privStr) { + var bytes = Bitcoin.Base58.decode(privStr); + var hash = bytes.slice(0, 33); + var checksum = Crypto.SHA256(Crypto.SHA256(hash, { asBytes: true }), { asBytes: true }); + if (checksum[0] != bytes[33] || + checksum[1] != bytes[34] || + checksum[2] != bytes[35] || + checksum[3] != bytes[36]) { + throw "Checksum validation failed!"; + } + var version = hash.shift(); + // TODO: detect currency + if (version != janin.currency.privateKeyPrefix()) { + throw "Version " + version + " not supported!"; + } + return hash; + }; + + /** + * Parse a compressed wallet import format private key contained in a string. + */ + ECKey.decodeCompressedWalletImportFormat = function (privStr) { + var bytes = Bitcoin.Base58.decode(privStr); + var hash = bytes.slice(0, 34); + var checksum = Crypto.SHA256(Crypto.SHA256(hash, { asBytes: true }), { asBytes: true }); + if (checksum[0] != bytes[34] || + checksum[1] != bytes[35] || + checksum[2] != bytes[36] || + checksum[3] != bytes[37]) { + throw "Checksum validation failed!"; + } + var version = hash.shift(); + // TODO: detect currency + if (version != janin.currency.privateKeyPrefix()) { + throw "Version " + version + " not supported!"; + } + hash.pop(); + return hash; + }; + + // 64 characters [0-9A-F] + ECKey.isHexFormat = function (key) { + key = key.toString(); + return /^[A-Fa-f0-9]{64}$/.test(key); + }; + + // 51 characters base58, always starts with a '5' + ECKey.isWalletImportFormat = function (key) { + key = key.toString(); + return janin.currency.WIF_RegEx().test(key); + }; + + // 52 characters base58 + ECKey.isCompressedWalletImportFormat = function (key) { + key = key.toString(); + return janin.currency.CWIF_RegEx().test(key); + }; + + // 44 characters + ECKey.isBase64Format = function (key) { + key = key.toString(); + return (/^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789=+\/]{44}$/.test(key)); + }; + + // 99 characters, 1=1, if using dice convert 6 to 0 + ECKey.isBase6Format = function (key) { + key = key.toString(); + return (/^[012345]{99}$/.test(key)); + }; + + // 22, 26 or 30 characters, always starts with an 'S' + ECKey.isMiniFormat = function (key) { + key = key.toString(); + var validChars22 = /^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21}$/.test(key); + var validChars26 = /^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{25}$/.test(key); + var validChars30 = /^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{29}$/.test(key); + var testBytes = Crypto.SHA256(key + "?", { asBytes: true }); + + return ((testBytes[0] === 0x00 || testBytes[0] === 0x01) && (validChars22 || validChars26 || validChars30)); + }; + + return ECKey; +})(); + +//https://raw.github.com/bitcoinjs/bitcoinjs-lib/09e8c6e184d6501a0c2c59d73ca64db5c0d3eb95/src/util.js +// Bitcoin utility functions +Bitcoin.Util = { + /** + * Cross-browser compatibility version of Array.isArray. + */ + isArray: Array.isArray || function (o) { + return Object.prototype.toString.call(o) === '[object Array]'; + }, + /** + * Create an array of a certain length filled with a specific value. + */ + makeFilledArray: function (len, val) { + var array = []; + var i = 0; + while (i < len) { + array[i++] = val; + } + return array; + }, + /** + * Turn an integer into a "var_int". + * + * "var_int" is a variable length integer used by Bitcoin's binary format. + * + * Returns a byte array. + */ + numToVarInt: function (i) { + if (i < 0xfd) { + // unsigned char + return [i]; + } else if (i <= 1 << 16) { + // unsigned short (LE) + return [0xfd, i >>> 8, i & 255]; + } else if (i <= 1 << 32) { + // unsigned int (LE) + return [0xfe].concat(Crypto.util.wordsToBytes([i])); + } else { + // unsigned long long (LE) + return [0xff].concat(Crypto.util.wordsToBytes([i >>> 32, i])); + } + }, + /** + * Parse a Bitcoin value byte array, returning a BigInteger. + */ + valueToBigInt: function (valueBuffer) { + if (valueBuffer instanceof BigInteger) return valueBuffer; + + // Prepend zero byte to prevent interpretation as negative integer + return BigInteger.fromByteArrayUnsigned(valueBuffer); + }, + /** + * Format a Bitcoin value as a string. + * + * Takes a BigInteger or byte-array and returns that amount of Bitcoins in a + * nice standard formatting. + * + * Examples: + * 12.3555 + * 0.1234 + * 900.99998888 + * 34.00 + */ + formatValue: function (valueBuffer) { + var value = this.valueToBigInt(valueBuffer).toString(); + var integerPart = value.length > 8 ? value.substr(0, value.length - 8) : '0'; + var decimalPart = value.length > 8 ? value.substr(value.length - 8) : value; + while (decimalPart.length < 8) decimalPart = "0" + decimalPart; + decimalPart = decimalPart.replace(/0*$/, ''); + while (decimalPart.length < 2) decimalPart += "0"; + return integerPart + "." + decimalPart; + }, + /** + * Parse a floating point string as a Bitcoin value. + * + * Keep in mind that parsing user input is messy. You should always display + * the parsed value back to the user to make sure we understood his input + * correctly. + */ + parseValue: function (valueString) { + // TODO: Detect other number formats (e.g. comma as decimal separator) + var valueComp = valueString.split('.'); + var integralPart = valueComp[0]; + var fractionalPart = valueComp[1] || "0"; + while (fractionalPart.length < 8) fractionalPart += "0"; + fractionalPart = fractionalPart.replace(/^0+/g, ''); + var value = BigInteger.valueOf(parseInt(integralPart)); + value = value.multiply(BigInteger.valueOf(100000000)); + value = value.add(BigInteger.valueOf(parseInt(fractionalPart))); + return value; + }, + /** + * Calculate RIPEMD160(SHA256(data)). + * + * Takes an arbitrary byte array as inputs and returns the hash as a byte + * array. + */ + sha256ripe160: function (data) { + return Crypto.RIPEMD160(Crypto.SHA256(data, { asBytes: true }), { asBytes: true }); + }, + // double sha256 + dsha256: function (data) { + return Crypto.SHA256(Crypto.SHA256(data, { asBytes: true }), { asBytes: true }); + } +}; \ No newline at end of file diff --git a/react/src/util/crypto/gen/crypto-scrypt.js b/react/src/util/crypto/gen/crypto-scrypt.js new file mode 100755 index 0000000..01600f4 --- /dev/null +++ b/react/src/util/crypto/gen/crypto-scrypt.js @@ -0,0 +1,295 @@ +/* +* Copyright (c) 2010-2011 Intalio Pte, All Rights Reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ +// https://github.com/cheongwy/node-scrypt-js +(function () { + + var MAX_VALUE = 2147483647; + var workerUrl = null; + + //function scrypt(byte[] passwd, byte[] salt, int N, int r, int p, int dkLen) + /* + * N = Cpu cost + * r = Memory cost + * p = parallelization cost + * + */ + window.Crypto_scrypt = function (passwd, salt, N, r, p, dkLen, callback) { + if (N == 0 || (N & (N - 1)) != 0) throw Error("N must be > 0 and a power of 2"); + + if (N > MAX_VALUE / 128 / r) throw Error("Parameter N is too large"); + if (r > MAX_VALUE / 128 / p) throw Error("Parameter r is too large"); + + var PBKDF2_opts = { iterations: 1, hasher: Crypto.SHA256, asBytes: true }; + + var B = Crypto.PBKDF2(passwd, salt, p * 128 * r, PBKDF2_opts); + + try { + var i = 0; + var worksDone = 0; + var makeWorker = function () { + if (!workerUrl) { + var code = '(' + scryptCore.toString() + ')()'; + var blob; + try { + blob = new Blob([code], { type: "text/javascript" }); + } catch (e) { + window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; + blob = new BlobBuilder(); + blob.append(code); + blob = blob.getBlob("text/javascript"); + } + workerUrl = URL.createObjectURL(blob); + } + var worker = new Worker(workerUrl); + worker.onmessage = function (event) { + var Bi = event.data[0], Bslice = event.data[1]; + worksDone++; + + if (i < p) { + worker.postMessage([N, r, p, B, i++]); + } + + var length = Bslice.length, destPos = Bi * 128 * r, srcPos = 0; + while (length--) { + B[destPos++] = Bslice[srcPos++]; + } + + if (worksDone == p) { + callback(Crypto.PBKDF2(passwd, B, dkLen, PBKDF2_opts)); + } + }; + return worker; + }; + var workers = [makeWorker(), makeWorker()]; + workers[0].postMessage([N, r, p, B, i++]); + if (p > 1) { + workers[1].postMessage([N, r, p, B, i++]); + } + } catch (e) { + window.setTimeout(function () { + scryptCore(); + callback(Crypto.PBKDF2(passwd, B, dkLen, PBKDF2_opts)); + }, 0); + } + + // using this function to enclose everything needed to create a worker (but also invokable directly for synchronous use) + function scryptCore() { + var XY = [], V = []; + + if (typeof B === 'undefined') { + onmessage = function (event) { + var data = event.data; + var N = data[0], r = data[1], p = data[2], B = data[3], i = data[4]; + + var Bslice = []; + arraycopy32(B, i * 128 * r, Bslice, 0, 128 * r); + smix(Bslice, 0, r, N, V, XY); + + postMessage([i, Bslice]); + }; + } else { + for (var i = 0; i < p; i++) { + smix(B, i * 128 * r, r, N, V, XY); + } + } + + function smix(B, Bi, r, N, V, XY) { + var Xi = 0; + var Yi = 128 * r; + var i; + + arraycopy32(B, Bi, XY, Xi, Yi); + + for (i = 0; i < N; i++) { + arraycopy32(XY, Xi, V, i * Yi, Yi); + blockmix_salsa8(XY, Xi, Yi, r); + } + + for (i = 0; i < N; i++) { + var j = integerify(XY, Xi, r) & (N - 1); + blockxor(V, j * Yi, XY, Xi, Yi); + blockmix_salsa8(XY, Xi, Yi, r); + } + + arraycopy32(XY, Xi, B, Bi, Yi); + } + + function blockmix_salsa8(BY, Bi, Yi, r) { + var X = []; + var i; + + arraycopy32(BY, Bi + (2 * r - 1) * 64, X, 0, 64); + + for (i = 0; i < 2 * r; i++) { + blockxor(BY, i * 64, X, 0, 64); + salsa20_8(X); + arraycopy32(X, 0, BY, Yi + (i * 64), 64); + } + + for (i = 0; i < r; i++) { + arraycopy32(BY, Yi + (i * 2) * 64, BY, Bi + (i * 64), 64); + } + + for (i = 0; i < r; i++) { + arraycopy32(BY, Yi + (i * 2 + 1) * 64, BY, Bi + (i + r) * 64, 64); + } + } + + function R(a, b) { + return (a << b) | (a >>> (32 - b)); + } + + function salsa20_8(B) { + var B32 = new Array(32); + var x = new Array(32); + var i; + + for (i = 0; i < 16; i++) { + B32[i] = (B[i * 4 + 0] & 0xff) << 0; + B32[i] |= (B[i * 4 + 1] & 0xff) << 8; + B32[i] |= (B[i * 4 + 2] & 0xff) << 16; + B32[i] |= (B[i * 4 + 3] & 0xff) << 24; + } + + arraycopy(B32, 0, x, 0, 16); + + for (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 = i * 4; + B[bi + 0] = (B32[i] >> 0 & 0xff); + B[bi + 1] = (B32[i] >> 8 & 0xff); + B[bi + 2] = (B32[i] >> 16 & 0xff); + B[bi + 3] = (B32[i] >> 24 & 0xff); + } + } + + function blockxor(S, Si, D, Di, len) { + var i = len >> 6; + while (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; + + bi += (2 * r - 1) * 64; + + n = (B[bi + 0] & 0xff) << 0; + n |= (B[bi + 1] & 0xff) << 8; + n |= (B[bi + 2] & 0xff) << 16; + n |= (B[bi + 3] & 0xff) << 24; + + return n; + } + + function arraycopy(src, srcPos, dest, destPos, length) { + while (length--) { + dest[destPos++] = src[srcPos++]; + } + } + + function arraycopy32(src, srcPos, dest, destPos, length) { + var i = length >> 5; + while (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++]; + } + } + } // scryptCore + }; // window.Crypto_scrypt +})(); \ No newline at end of file diff --git a/react/src/util/crypto/gen/cryptojs.aes.js b/react/src/util/crypto/gen/cryptojs.aes.js new file mode 100755 index 0000000..dfcba32 --- /dev/null +++ b/react/src/util/crypto/gen/cryptojs.aes.js @@ -0,0 +1,407 @@ +/*! +* 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 () { + + // Shortcuts + var C = Crypto, + util = C.util, + charenc = C.charenc, + UTF8 = charenc.UTF8; + + // Precomputed SBOX + var SBOX = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, + 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, + 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, + 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, + 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, + 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, + 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, + 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, + 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, + 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, + 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16]; + + // Compute inverse SBOX lookup table + for (var INVSBOX = [], i = 0; i < 256; i++) INVSBOX[SBOX[i]] = i; + + // Compute multiplication in GF(2^8) lookup tables + var MULT2 = [], + MULT3 = [], + MULT9 = [], + MULTB = [], + MULTD = [], + MULTE = []; + + function xtime(a, b) { + for (var result = 0, i = 0; i < 8; i++) { + if (b & 1) result ^= a; + var hiBitSet = a & 0x80; + a = (a << 1) & 0xFF; + if (hiBitSet) a ^= 0x1b; + b >>>= 1; + } + return result; + } + + for (var i = 0; i < 256; i++) { + MULT2[i] = xtime(i, 2); + MULT3[i] = xtime(i, 3); + MULT9[i] = xtime(i, 9); + MULTB[i] = xtime(i, 0xB); + MULTD[i] = xtime(i, 0xD); + MULTE[i] = xtime(i, 0xE); + } + + // Precomputed RCon lookup + var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36]; + + // Inner state + var state = [[], [], [], []], + keylength, + nrounds, + keyschedule; + + var AES = C.AES = { + + /** + * Public API + */ + + encrypt: function (message, password, options) { + + options = options || {}; + + // Determine mode + var mode = options.mode || new C.mode.OFB; + + // Allow mode to override options + if (mode.fixOptions) mode.fixOptions(options); + + var + + // Convert to bytes if message is a string + m = ( + message.constructor == String ? + UTF8.stringToBytes(message) : + message + ), + + // Generate random IV + iv = options.iv || util.randomBytes(AES._blocksize * 4), + + // Generate key + k = ( + password.constructor == String ? + // Derive key from pass-phrase + C.PBKDF2(password, iv, 32, { asBytes: true }) : + // else, assume byte array representing cryptographic key + password + ); + + // Encrypt + AES._init(k); + mode.encrypt(AES, m, iv); + + // Return ciphertext + m = options.iv ? m : iv.concat(m); + return (options && options.asBytes) ? m : util.bytesToBase64(m); + + }, + + decrypt: function (ciphertext, password, options) { + + options = options || {}; + + // Determine mode + var mode = options.mode || new C.mode.OFB; + + // Allow mode to override options + if (mode.fixOptions) mode.fixOptions(options); + + var + + // Convert to bytes if ciphertext is a string + c = ( + ciphertext.constructor == String ? + util.base64ToBytes(ciphertext) : + ciphertext + ), + + // Separate IV and message + iv = options.iv || c.splice(0, AES._blocksize * 4), + + // Generate key + k = ( + password.constructor == String ? + // Derive key from pass-phrase + C.PBKDF2(password, iv, 32, { asBytes: true }) : + // else, assume byte array representing cryptographic key + password + ); + + // Decrypt + AES._init(k); + mode.decrypt(AES, c, iv); + + // Return plaintext + return (options && options.asBytes) ? c : UTF8.bytesToString(c); + + }, + + + /** + * Package private methods and properties + */ + + _blocksize: 4, + + _encryptblock: function (m, offset) { + + // Set input + for (var row = 0; row < AES._blocksize; row++) { + for (var col = 0; col < 4; col++) + state[row][col] = m[offset + col * 4 + row]; + } + + // Add round key + for (var row = 0; row < 4; row++) { + for (var col = 0; col < 4; col++) + state[row][col] ^= keyschedule[col][row]; + } + + for (var round = 1; round < nrounds; round++) { + + // Sub bytes + for (var row = 0; row < 4; row++) { + for (var col = 0; col < 4; col++) + state[row][col] = SBOX[state[row][col]]; + } + + // Shift rows + state[1].push(state[1].shift()); + state[2].push(state[2].shift()); + state[2].push(state[2].shift()); + state[3].unshift(state[3].pop()); + + // Mix columns + for (var col = 0; col < 4; col++) { + + var s0 = state[0][col], + s1 = state[1][col], + s2 = state[2][col], + s3 = state[3][col]; + + state[0][col] = MULT2[s0] ^ MULT3[s1] ^ s2 ^ s3; + state[1][col] = s0 ^ MULT2[s1] ^ MULT3[s2] ^ s3; + state[2][col] = s0 ^ s1 ^ MULT2[s2] ^ MULT3[s3]; + state[3][col] = MULT3[s0] ^ s1 ^ s2 ^ MULT2[s3]; + + } + + // Add round key + for (var row = 0; row < 4; row++) { + for (var col = 0; col < 4; col++) + state[row][col] ^= keyschedule[round * 4 + col][row]; + } + + } + + // Sub bytes + for (var row = 0; row < 4; row++) { + for (var col = 0; col < 4; col++) + state[row][col] = SBOX[state[row][col]]; + } + + // Shift rows + state[1].push(state[1].shift()); + state[2].push(state[2].shift()); + state[2].push(state[2].shift()); + state[3].unshift(state[3].pop()); + + // Add round key + for (var row = 0; row < 4; row++) { + for (var col = 0; col < 4; col++) + state[row][col] ^= keyschedule[nrounds * 4 + col][row]; + } + + // Set output + for (var row = 0; row < AES._blocksize; row++) { + for (var col = 0; col < 4; col++) + m[offset + col * 4 + row] = state[row][col]; + } + + }, + + _decryptblock: function (c, offset) { + + // Set input + for (var row = 0; row < AES._blocksize; row++) { + for (var col = 0; col < 4; col++) + state[row][col] = c[offset + col * 4 + row]; + } + + // Add round key + for (var row = 0; row < 4; row++) { + for (var col = 0; col < 4; col++) + state[row][col] ^= keyschedule[nrounds * 4 + col][row]; + } + + for (var round = 1; round < nrounds; round++) { + + // Inv shift rows + state[1].unshift(state[1].pop()); + state[2].push(state[2].shift()); + state[2].push(state[2].shift()); + state[3].push(state[3].shift()); + + // Inv sub bytes + for (var row = 0; row < 4; row++) { + for (var col = 0; col < 4; col++) + state[row][col] = INVSBOX[state[row][col]]; + } + + // Add round key + for (var row = 0; row < 4; row++) { + for (var col = 0; col < 4; col++) + state[row][col] ^= keyschedule[(nrounds - round) * 4 + col][row]; + } + + // Inv mix columns + for (var col = 0; col < 4; col++) { + + var s0 = state[0][col], + s1 = state[1][col], + s2 = state[2][col], + s3 = state[3][col]; + + state[0][col] = MULTE[s0] ^ MULTB[s1] ^ MULTD[s2] ^ MULT9[s3]; + state[1][col] = MULT9[s0] ^ MULTE[s1] ^ MULTB[s2] ^ MULTD[s3]; + state[2][col] = MULTD[s0] ^ MULT9[s1] ^ MULTE[s2] ^ MULTB[s3]; + state[3][col] = MULTB[s0] ^ MULTD[s1] ^ MULT9[s2] ^ MULTE[s3]; + + } + + } + + // Inv shift rows + state[1].unshift(state[1].pop()); + state[2].push(state[2].shift()); + state[2].push(state[2].shift()); + state[3].push(state[3].shift()); + + // Inv sub bytes + for (var row = 0; row < 4; row++) { + for (var col = 0; col < 4; col++) + state[row][col] = INVSBOX[state[row][col]]; + } + + // Add round key + for (var row = 0; row < 4; row++) { + for (var col = 0; col < 4; col++) + state[row][col] ^= keyschedule[col][row]; + } + + // Set output + for (var row = 0; row < AES._blocksize; row++) { + for (var col = 0; col < 4; col++) + c[offset + col * 4 + row] = state[row][col]; + } + + }, + + + /** + * Private methods + */ + + _init: function (k) { + keylength = k.length / 4; + nrounds = keylength + 6; + AES._keyexpansion(k); + }, + + // Generate a key schedule + _keyexpansion: function (k) { + + keyschedule = []; + + for (var row = 0; row < keylength; row++) { + keyschedule[row] = [ + k[row * 4], + k[row * 4 + 1], + k[row * 4 + 2], + k[row * 4 + 3] + ]; + } + + for (var row = keylength; row < AES._blocksize * (nrounds + 1); row++) { + + var temp = [ + keyschedule[row - 1][0], + keyschedule[row - 1][1], + keyschedule[row - 1][2], + keyschedule[row - 1][3] + ]; + + if (row % keylength == 0) { + + // Rot word + temp.push(temp.shift()); + + // Sub word + temp[0] = SBOX[temp[0]]; + temp[1] = SBOX[temp[1]]; + temp[2] = SBOX[temp[2]]; + temp[3] = SBOX[temp[3]]; + + temp[0] ^= RCON[row / keylength]; + + } else if (keylength > 6 && row % keylength == 4) { + + // Sub word + 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] + ]; + + } + + } + + }; + +})(); \ No newline at end of file diff --git a/react/src/util/crypto/gen/cryptojs.blockmodes.js b/react/src/util/crypto/gen/cryptojs.blockmodes.js new file mode 100755 index 0000000..e0de9e6 --- /dev/null +++ b/react/src/util/crypto/gen/cryptojs.blockmodes.js @@ -0,0 +1,410 @@ +/*! +* Crypto-JS 2.5.4 BlockModes.js +* contribution from Simon Greatrix +*/ + +(function (C) { + + // Create pad namespace + var C_pad = C.pad = {}; + + // Calculate the number of padding bytes required. + function _requiredPadding(cipher, message) { + var blockSizeInBytes = cipher._blocksize * 4; + var reqd = blockSizeInBytes - message.length % blockSizeInBytes; + return reqd; + } + + // Remove padding when the final byte gives the number of padding bytes. + var _unpadLength = function (cipher, message, alg, padding) { + var pad = message.pop(); + if (pad == 0) { + throw new Error("Invalid zero-length padding specified for " + alg + + ". Wrong cipher specification or key used?"); + } + var maxPad = cipher._blocksize * 4; + if (pad > maxPad) { + throw new Error("Invalid padding length of " + pad + + " specified for " + alg + + ". Wrong cipher specification or key used?"); + } + for (var i = 1; i < pad; i++) { + var b = message.pop(); + if (padding != undefined && padding != b) { + throw new Error("Invalid padding byte of 0x" + b.toString(16) + + " specified for " + alg + + ". Wrong cipher specification or key used?"); + } + } + }; + + // No-operation padding, used for stream ciphers + C_pad.NoPadding = { + pad: function (cipher, message) { }, + unpad: function (cipher, message) { } + }; + + // Zero Padding. + // + // If the message is not an exact number of blocks, the final block is + // completed with 0x00 bytes. There is no unpadding. + C_pad.ZeroPadding = { + pad: function (cipher, message) { + var blockSizeInBytes = cipher._blocksize * 4; + var reqd = message.length % blockSizeInBytes; + if (reqd != 0) { + for (reqd = blockSizeInBytes - reqd; reqd > 0; reqd--) { + message.push(0x00); + } + } + }, + + unpad: function (cipher, message) { + while (message[message.length - 1] == 0) { + message.pop(); + } + } + }; + + // ISO/IEC 7816-4 padding. + // + // Pads the plain text with an 0x80 byte followed by as many 0x00 + // bytes are required to complete the block. + C_pad.iso7816 = { + pad: function (cipher, message) { + var reqd = _requiredPadding(cipher, message); + message.push(0x80); + for (; reqd > 1; reqd--) { + message.push(0x00); + } + }, + + unpad: function (cipher, message) { + var padLength; + for (padLength = cipher._blocksize * 4; padLength > 0; padLength--) { + var b = message.pop(); + if (b == 0x80) return; + if (b != 0x00) { + 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?"); + } + }; + + // ANSI X.923 padding + // + // The final block is padded with zeros except for the last byte of the + // last block which contains the number of padding bytes. + C_pad.ansix923 = { + pad: function (cipher, message) { + var reqd = _requiredPadding(cipher, message); + for (var i = 1; i < reqd; i++) { + message.push(0x00); + } + message.push(reqd); + }, + + unpad: function (cipher, message) { + _unpadLength(cipher, message, "ANSI X.923", 0); + } + }; + + // ISO 10126 + // + // The final block is padded with random bytes except for the last + // byte of the last block which contains the number of padding bytes. + C_pad.iso10126 = { + pad: function (cipher, message) { + var reqd = _requiredPadding(cipher, message); + for (var i = 1; i < reqd; i++) { + message.push(Math.floor(Math.random() * 256)); + } + message.push(reqd); + }, + + unpad: function (cipher, message) { + _unpadLength(cipher, message, "ISO 10126", undefined); + } + }; + + // PKCS7 padding + // + // PKCS7 is described in RFC 5652. Padding is in whole bytes. The + // value of each added byte is the number of bytes that are added, + // i.e. N bytes, each of value N are added. + C_pad.pkcs7 = { + pad: function (cipher, message) { + var reqd = _requiredPadding(cipher, message); + for (var i = 0; i < reqd; i++) { + message.push(reqd); + } + }, + + unpad: function (cipher, message) { + _unpadLength(cipher, message, "PKCS 7", message[message.length - 1]); + } + }; + + // Create mode namespace + var C_mode = C.mode = {}; + + /** + * Mode base "class". + */ + var Mode = C_mode.Mode = function (padding) { + if (padding) { + this._padding = padding; + } + }; + + Mode.prototype = { + encrypt: function (cipher, m, iv) { + this._padding.pad(cipher, m); + this._doEncrypt(cipher, m, iv); + }, + + decrypt: function (cipher, m, iv) { + this._doDecrypt(cipher, m, iv); + this._padding.unpad(cipher, m); + }, + + // Default padding + _padding: C_pad.iso7816 + }; + + + /** + * Electronic Code Book mode. + * + * ECB applies the cipher directly against each block of the input. + * + * ECB does not require an initialization vector. + */ + var ECB = C_mode.ECB = function () { + // Call parent constructor + Mode.apply(this, arguments); + }; + + // Inherit from Mode + var ECB_prototype = ECB.prototype = new Mode; + + // Concrete steps for Mode template + ECB_prototype._doEncrypt = function (cipher, m, iv) { + var blockSizeInBytes = cipher._blocksize * 4; + // Encrypt each block + for (var offset = 0; offset < m.length; offset += blockSizeInBytes) { + cipher._encryptblock(m, offset); + } + }; + ECB_prototype._doDecrypt = function (cipher, c, iv) { + var blockSizeInBytes = cipher._blocksize * 4; + // Decrypt each block + for (var offset = 0; offset < c.length; offset += blockSizeInBytes) { + cipher._decryptblock(c, offset); + } + }; + + // ECB never uses an IV + ECB_prototype.fixOptions = function (options) { + options.iv = []; + }; + + + /** + * Cipher block chaining + * + * The first block is XORed with the IV. Subsequent blocks are XOR with the + * previous cipher output. + */ + var CBC = C_mode.CBC = function () { + // Call parent constructor + Mode.apply(this, arguments); + }; + + // Inherit from Mode + var CBC_prototype = CBC.prototype = new Mode; + + // Concrete steps for Mode template + CBC_prototype._doEncrypt = function (cipher, m, iv) { + var blockSizeInBytes = cipher._blocksize * 4; + + // Encrypt each block + for (var offset = 0; offset < m.length; offset += blockSizeInBytes) { + if (offset == 0) { + // XOR first block using IV + for (var i = 0; i < blockSizeInBytes; i++) + m[i] ^= iv[i]; + } else { + // XOR this block using previous crypted block + for (var i = 0; i < blockSizeInBytes; i++) + m[offset + i] ^= m[offset + i - blockSizeInBytes]; + } + // Encrypt block + cipher._encryptblock(m, offset); + } + }; + CBC_prototype._doDecrypt = function (cipher, c, iv) { + var blockSizeInBytes = cipher._blocksize * 4; + + // At the start, the previously crypted block is the IV + var prevCryptedBlock = iv; + + // Decrypt each block + for (var offset = 0; offset < c.length; offset += blockSizeInBytes) { + // Save this crypted block + var thisCryptedBlock = c.slice(offset, offset + blockSizeInBytes); + // Decrypt block + cipher._decryptblock(c, offset); + // XOR decrypted block using previous crypted block + for (var i = 0; i < blockSizeInBytes; i++) { + c[offset + i] ^= prevCryptedBlock[i]; + } + prevCryptedBlock = thisCryptedBlock; + } + }; + + + /** + * Cipher feed back + * + * The cipher output is XORed with the plain text to produce the cipher output, + * which is then fed back into the cipher to produce a bit pattern to XOR the + * next block with. + * + * This is a stream cipher mode and does not require padding. + */ + var CFB = C_mode.CFB = function () { + // Call parent constructor + Mode.apply(this, arguments); + }; + + // Inherit from Mode + var CFB_prototype = CFB.prototype = new Mode; + + // Override padding + CFB_prototype._padding = C_pad.NoPadding; + + // Concrete steps for Mode template + CFB_prototype._doEncrypt = function (cipher, m, iv) { + var blockSizeInBytes = cipher._blocksize * 4, + keystream = iv.slice(0); + + // Encrypt each byte + for (var i = 0; i < m.length; i++) { + + var j = i % blockSizeInBytes; + if (j == 0) cipher._encryptblock(keystream, 0); + + m[i] ^= keystream[j]; + keystream[j] = m[i]; + } + }; + CFB_prototype._doDecrypt = function (cipher, c, iv) { + var blockSizeInBytes = cipher._blocksize * 4, + keystream = iv.slice(0); + + // Encrypt each byte + for (var i = 0; i < c.length; i++) { + + var j = i % blockSizeInBytes; + if (j == 0) cipher._encryptblock(keystream, 0); + + var b = c[i]; + c[i] ^= keystream[j]; + keystream[j] = b; + } + }; + + + /** + * Output feed back + * + * The cipher repeatedly encrypts its own output. The output is XORed with the + * plain text to produce the cipher text. + * + * This is a stream cipher mode and does not require padding. + */ + var OFB = C_mode.OFB = function () { + // Call parent constructor + Mode.apply(this, arguments); + }; + + // Inherit from Mode + var OFB_prototype = OFB.prototype = new Mode; + + // Override padding + OFB_prototype._padding = C_pad.NoPadding; + + // Concrete steps for Mode template + OFB_prototype._doEncrypt = function (cipher, m, iv) { + + var blockSizeInBytes = cipher._blocksize * 4, + keystream = iv.slice(0); + + // Encrypt each byte + for (var i = 0; i < m.length; i++) { + + // Generate keystream + if (i % blockSizeInBytes == 0) + cipher._encryptblock(keystream, 0); + + // Encrypt byte + m[i] ^= keystream[i % blockSizeInBytes]; + + } + }; + OFB_prototype._doDecrypt = OFB_prototype._doEncrypt; + + /** + * Counter + * @author Gergely Risko + * + * After every block the last 4 bytes of the IV is increased by one + * with carry and that IV is used for the next block. + * + * This is a stream cipher mode and does not require padding. + */ + var CTR = C_mode.CTR = function () { + // Call parent constructor + Mode.apply(this, arguments); + }; + + // Inherit from Mode + var CTR_prototype = CTR.prototype = new Mode; + + // Override padding + CTR_prototype._padding = C_pad.NoPadding; + + CTR_prototype._doEncrypt = function (cipher, m, iv) { + var blockSizeInBytes = cipher._blocksize * 4; + var counter = iv.slice(0); + + for (var i = 0; i < m.length; ) { + // do not lose iv + var keystream = counter.slice(0); + + // Generate keystream for next block + cipher._encryptblock(keystream, 0); + + // XOR keystream with block + for (var j = 0; i < m.length && j < blockSizeInBytes; j++, i++) { + m[i] ^= keystream[j]; + } + + // Increase counter + if (++(counter[blockSizeInBytes - 1]) == 256) { + counter[blockSizeInBytes - 1] = 0; + if (++(counter[blockSizeInBytes - 2]) == 256) { + counter[blockSizeInBytes - 2] = 0; + if (++(counter[blockSizeInBytes - 3]) == 256) { + counter[blockSizeInBytes - 3] = 0; + ++(counter[blockSizeInBytes - 4]); + } + } + } + } + }; + CTR_prototype._doDecrypt = CTR_prototype._doEncrypt; + +})(Crypto); \ No newline at end of file diff --git a/react/src/util/crypto/gen/cryptojs.hmac.js b/react/src/util/crypto/gen/cryptojs.hmac.js new file mode 100755 index 0000000..f33ac76 --- /dev/null +++ b/react/src/util/crypto/gen/cryptojs.hmac.js @@ -0,0 +1,43 @@ +/*! +* Crypto-JS v2.5.4 HMAC.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 () { + + // Shortcuts + var C = Crypto, + util = C.util, + charenc = C.charenc, + UTF8 = charenc.UTF8, + Binary = charenc.Binary; + + C.HMAC = function (hasher, message, key, options) { + + // Convert to byte arrays + if (message.constructor == String) message = UTF8.stringToBytes(message); + if (key.constructor == String) key = UTF8.stringToBytes(key); + /* else, assume byte arrays already */ + + // Allow arbitrary length keys + if (key.length > hasher._blocksize * 4) + key = hasher(key, { asBytes: true }); + + // XOR keys with pad constants + var okey = key.slice(0), + ikey = key.slice(0); + for (var i = 0; i < hasher._blocksize * 4; i++) { + okey[i] ^= 0x5C; + ikey[i] ^= 0x36; + } + + var hmacbytes = hasher(okey.concat(hasher(ikey.concat(message), { asBytes: true })), { asBytes: true }); + + return options && options.asBytes ? hmacbytes : + options && options.asString ? Binary.bytesToString(hmacbytes) : + util.bytesToHex(hmacbytes); + + }; + +})(); \ No newline at end of file diff --git a/react/src/util/crypto/gen/cryptojs.js b/react/src/util/crypto/gen/cryptojs.js new file mode 100755 index 0000000..b8d2b15 --- /dev/null +++ b/react/src/util/crypto/gen/cryptojs.js @@ -0,0 +1,149 @@ +/*! +* 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 +*/ +if (typeof Crypto == "undefined" || !Crypto.util) { + (function () { + + var base64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + // Global Crypto object + var Crypto = window.Crypto = {}; + + // Crypto utilities + var util = Crypto.util = { + + // Bit-wise rotate left + rotl: function (n, b) { + return (n << b) | (n >>> (32 - b)); + }, + + // Bit-wise rotate right + rotr: function (n, b) { + return (n << (32 - b)) | (n >>> b); + }, + + // Swap big-endian to little-endian and vice versa + endian: function (n) { + + // If number given, swap endian + if (n.constructor == Number) { + return util.rotl(n, 8) & 0x00FF00FF | + util.rotl(n, 24) & 0xFF00FF00; + } + + // Else, assume array and swap all items + for (var i = 0; i < n.length; i++) + n[i] = util.endian(n[i]); + return n; + + }, + + // Generate an array of any length of random bytes + randomBytes: function (n) { + for (var bytes = []; n > 0; n--) + bytes.push(Math.floor(Math.random() * 256)); + return bytes; + }, + + // Convert a byte array to big-endian 32-bit words + bytesToWords: function (bytes) { + for (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8) + words[b >>> 5] |= (bytes[i] & 0xFF) << (24 - b % 32); + return words; + }, + + // Convert big-endian 32-bit words to a byte array + wordsToBytes: function (words) { + for (var bytes = [], b = 0; b < words.length * 32; b += 8) + bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF); + return bytes; + }, + + // Convert a byte array to a hex string + bytesToHex: function (bytes) { + for (var hex = [], i = 0; i < bytes.length; i++) { + hex.push((bytes[i] >>> 4).toString(16)); + hex.push((bytes[i] & 0xF).toString(16)); + } + return hex.join(""); + }, + + // Convert a hex string to a byte array + hexToBytes: function (hex) { + for (var bytes = [], c = 0; c < hex.length; c += 2) + bytes.push(parseInt(hex.substr(c, 2), 16)); + return bytes; + }, + + // Convert a byte array to a base-64 string + bytesToBase64: function (bytes) { + for (var base64 = [], i = 0; i < bytes.length; i += 3) { + var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]; + for (var j = 0; j < 4; j++) { + if (i * 8 + j * 6 <= bytes.length * 8) + base64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F)); + else base64.push("="); + } + } + + return base64.join(""); + }, + + // Convert a base-64 string to a byte array + base64ToBytes: function (base64) { + // Remove non-base-64 characters + base64 = base64.replace(/[^A-Z0-9+\/]/ig, ""); + + for (var bytes = [], i = 0, imod4 = 0; i < base64.length; imod4 = ++i % 4) { + if (imod4 == 0) continue; + bytes.push(((base64map.indexOf(base64.charAt(i - 1)) & (Math.pow(2, -2 * imod4 + 8) - 1)) << (imod4 * 2)) | + (base64map.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2))); + } + + return bytes; + } + + }; + + // Crypto character encodings + var charenc = Crypto.charenc = {}; + + // UTF-8 encoding + var UTF8 = charenc.UTF8 = { + + // Convert a string to a byte array + stringToBytes: function (str) { + return Binary.stringToBytes(unescape(encodeURIComponent(str))); + }, + + // Convert a byte array to a string + bytesToString: function (bytes) { + return decodeURIComponent(escape(Binary.bytesToString(bytes))); + } + + }; + + // Binary encoding + var Binary = charenc.Binary = { + + // Convert a string to a byte array + stringToBytes: function (str) { + for (var bytes = [], i = 0; i < str.length; i++) + bytes.push(str.charCodeAt(i) & 0xFF); + return bytes; + }, + + // Convert a byte array to a string + bytesToString: function (bytes) { + for (var str = [], i = 0; i < bytes.length; i++) + str.push(String.fromCharCode(bytes[i])); + return str.join(""); + } + + }; + + })(); +} \ No newline at end of file diff --git a/react/src/util/crypto/gen/cryptojs.pbkdf2.js b/react/src/util/crypto/gen/cryptojs.pbkdf2.js new file mode 100755 index 0000000..e5be087 --- /dev/null +++ b/react/src/util/crypto/gen/cryptojs.pbkdf2.js @@ -0,0 +1,54 @@ +/*! +* Crypto-JS v2.5.4 PBKDF2.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 () { + + // Shortcuts + var C = Crypto, + util = C.util, + charenc = C.charenc, + UTF8 = charenc.UTF8, + Binary = charenc.Binary; + + C.PBKDF2 = function (password, salt, keylen, options) { + + // Convert to byte arrays + if (password.constructor == String) password = UTF8.stringToBytes(password); + if (salt.constructor == String) salt = UTF8.stringToBytes(salt); + /* else, assume byte arrays already */ + + // Defaults + var hasher = options && options.hasher || C.SHA1, + iterations = options && options.iterations || 1; + + // Pseudo-random function + function PRF(password, salt) { + return C.HMAC(hasher, salt, password, { asBytes: true }); + } + + // Generate key + var derivedKeyBytes = [], + blockindex = 1; + while (derivedKeyBytes.length < keylen) { + var block = PRF(password, salt.concat(util.wordsToBytes([blockindex]))); + for (var u = block, i = 1; i < iterations; i++) { + u = PRF(password, u); + for (var j = 0; j < block.length; j++) block[j] ^= u[j]; + } + derivedKeyBytes = derivedKeyBytes.concat(block); + blockindex++; + } + + // Truncate excess bytes + derivedKeyBytes.length = keylen; + + return options && options.asBytes ? derivedKeyBytes : + options && options.asString ? Binary.bytesToString(derivedKeyBytes) : + util.bytesToHex(derivedKeyBytes); + + }; + +})(); \ No newline at end of file diff --git a/react/src/util/crypto/gen/cryptojs.ripemd160.js b/react/src/util/crypto/gen/cryptojs.ripemd160.js new file mode 100755 index 0000000..6917536 --- /dev/null +++ b/react/src/util/crypto/gen/cryptojs.ripemd160.js @@ -0,0 +1,164 @@ +/*! +* Crypto-JS v2.0.0 RIPEMD-160 +* http://code.google.com/p/crypto-js/ +* Copyright (c) 2009, Jeff Mott. All rights reserved. +* http://code.google.com/p/crypto-js/wiki/License +* +* A JavaScript implementation of the RIPEMD-160 Algorithm +* Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009. +* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet +* Distributed under the BSD License +* See http://pajhome.org.uk/crypt/md5 for details. +* Also http://www.ocf.berkeley.edu/~jjlin/jsotp/ +* Ported to Crypto-JS by Stefan Thomas. +*/ + +(function () { + // Shortcuts + var C = Crypto, + util = C.util, + charenc = C.charenc, + UTF8 = charenc.UTF8, + Binary = charenc.Binary; + + // Convert a byte array to little-endian 32-bit words + util.bytesToLWords = function (bytes) { + + var output = Array(bytes.length >> 2); + for (var i = 0; i < output.length; i++) + output[i] = 0; + for (var i = 0; i < bytes.length * 8; i += 8) + output[i >> 5] |= (bytes[i / 8] & 0xFF) << (i % 32); + return output; + }; + + // Convert little-endian 32-bit words to a byte array + util.lWordsToBytes = function (words) { + var output = []; + for (var i = 0; i < words.length * 32; i += 8) + output.push((words[i >> 5] >>> (i % 32)) & 0xff); + return output; + }; + + // Public API + var RIPEMD160 = C.RIPEMD160 = function (message, options) { + var digestbytes = util.lWordsToBytes(RIPEMD160._rmd160(message)); + return options && options.asBytes ? digestbytes : + options && options.asString ? Binary.bytesToString(digestbytes) : + util.bytesToHex(digestbytes); + }; + + // The core + RIPEMD160._rmd160 = function (message) { + // Convert to byte array + if (message.constructor == String) message = UTF8.stringToBytes(message); + + var x = util.bytesToLWords(message), + len = message.length * 8; + + /* append padding */ + x[len >> 5] |= 0x80 << (len % 32); + x[(((len + 64) >>> 9) << 4) + 14] = len; + + var h0 = 0x67452301; + var h1 = 0xefcdab89; + var h2 = 0x98badcfe; + var h3 = 0x10325476; + var h4 = 0xc3d2e1f0; + + for (var i = 0; i < x.length; i += 16) { + var T; + var A1 = h0, B1 = h1, C1 = h2, D1 = h3, E1 = h4; + var A2 = h0, B2 = h1, C2 = h2, D2 = h3, E2 = h4; + for (var j = 0; j <= 79; ++j) { + T = safe_add(A1, rmd160_f(j, B1, C1, D1)); + T = safe_add(T, x[i + rmd160_r1[j]]); + T = safe_add(T, rmd160_K1(j)); + T = safe_add(bit_rol(T, rmd160_s1[j]), E1); + A1 = E1; E1 = D1; D1 = bit_rol(C1, 10); C1 = B1; B1 = T; + T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2)); + T = safe_add(T, x[i + rmd160_r2[j]]); + T = safe_add(T, rmd160_K2(j)); + T = safe_add(bit_rol(T, rmd160_s2[j]), E2); + A2 = E2; E2 = D2; D2 = bit_rol(C2, 10); C2 = B2; B2 = T; + } + T = safe_add(h1, safe_add(C1, D2)); + h1 = safe_add(h2, safe_add(D1, E2)); + h2 = safe_add(h3, safe_add(E1, A2)); + h3 = safe_add(h4, safe_add(A1, B2)); + h4 = safe_add(h0, safe_add(B1, C2)); + h0 = T; + } + return [h0, h1, h2, h3, h4]; + } + + function rmd160_f(j, x, y, z) { + return (0 <= j && j <= 15) ? (x ^ y ^ z) : + (16 <= j && j <= 31) ? (x & y) | (~x & z) : + (32 <= j && j <= 47) ? (x | ~y) ^ z : + (48 <= j && j <= 63) ? (x & z) | (y & ~z) : + (64 <= j && j <= 79) ? x ^ (y | ~z) : + "rmd160_f: j out of range"; + } + function rmd160_K1(j) { + return (0 <= j && j <= 15) ? 0x00000000 : + (16 <= j && j <= 31) ? 0x5a827999 : + (32 <= j && j <= 47) ? 0x6ed9eba1 : + (48 <= j && j <= 63) ? 0x8f1bbcdc : + (64 <= j && j <= 79) ? 0xa953fd4e : + "rmd160_K1: j out of range"; + } + function rmd160_K2(j) { + return (0 <= j && j <= 15) ? 0x50a28be6 : + (16 <= j && j <= 31) ? 0x5c4dd124 : + (32 <= j && j <= 47) ? 0x6d703ef3 : + (48 <= j && j <= 63) ? 0x7a6d76e9 : + (64 <= j && j <= 79) ? 0x00000000 : + "rmd160_K2: j out of range"; + } + var rmd160_r1 = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, + 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 + ]; + var rmd160_r2 = [ + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, + 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 + ]; + var rmd160_s1 = [ + 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, + 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 + ]; + var rmd160_s2 = [ + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, + 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 + ]; + + /* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ + function safe_add(x, y) { + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); + } + + /* + * Bitwise rotate a 32-bit number to the left. + */ + function bit_rol(num, cnt) { + return (num << cnt) | (num >>> (32 - cnt)); + } +})(); \ No newline at end of file diff --git a/react/src/util/crypto/gen/cryptojs.sha256.js b/react/src/util/crypto/gen/cryptojs.sha256.js new file mode 100755 index 0000000..8209973 --- /dev/null +++ b/react/src/util/crypto/gen/cryptojs.sha256.js @@ -0,0 +1,135 @@ +/*! +* Crypto-JS v2.5.4 SHA256.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 () { + + // Shortcuts + var C = Crypto, + util = C.util, + charenc = C.charenc, + UTF8 = charenc.UTF8, + Binary = charenc.Binary; + + // Constants + var K = [0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2]; + + // Public API + var SHA256 = C.SHA256 = function (message, options) { + var digestbytes = util.wordsToBytes(SHA256._sha256(message)); + return options && options.asBytes ? digestbytes : + options && options.asString ? Binary.bytesToString(digestbytes) : + util.bytesToHex(digestbytes); + }; + + // The core + SHA256._sha256 = function (message) { + + // Convert to byte array + if (message.constructor == String) message = UTF8.stringToBytes(message); + /* else, assume byte array already */ + + var m = util.bytesToWords(message), + l = message.length * 8, + H = [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19], + w = [], + a, b, c, d, e, f, g, h, i, j, + t1, t2; + + // Padding + m[l >> 5] |= 0x80 << (24 - l % 32); + m[((l + 64 >> 9) << 4) + 15] = l; + + for (var i = 0; i < m.length; i += 16) { + + a = H[0]; + b = H[1]; + c = H[2]; + d = H[3]; + e = H[4]; + f = H[5]; + g = H[6]; + h = H[7]; + + for (var j = 0; j < 64; j++) { + + if (j < 16) w[j] = m[j + i]; + else { + + var gamma0x = w[j - 15], + gamma1x = w[j - 2], + gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^ + ((gamma0x << 14) | (gamma0x >>> 18)) ^ + (gamma0x >>> 3), + gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^ + ((gamma1x << 13) | (gamma1x >>> 19)) ^ + (gamma1x >>> 10); + + w[j] = gamma0 + (w[j - 7] >>> 0) + + gamma1 + (w[j - 16] >>> 0); + + } + + var ch = e & f ^ ~e & g, + maj = a & b ^ a & c ^ b & c, + sigma0 = ((a << 30) | (a >>> 2)) ^ + ((a << 19) | (a >>> 13)) ^ + ((a << 10) | (a >>> 22)), + sigma1 = ((e << 26) | (e >>> 6)) ^ + ((e << 21) | (e >>> 11)) ^ + ((e << 7) | (e >>> 25)); + + + t1 = (h >>> 0) + sigma1 + ch + (K[j]) + (w[j] >>> 0); + t2 = sigma0 + maj; + + h = g; + g = f; + f = e; + e = (d + t1) >>> 0; + d = c; + c = b; + b = a; + a = (t1 + t2) >>> 0; + + } + + H[0] += a; + H[1] += b; + H[2] += c; + H[3] += d; + H[4] += e; + H[5] += f; + H[6] += g; + H[7] += h; + + } + + return H; + + }; + + // Package private blocksize + SHA256._blocksize = 16; + + SHA256._digestsize = 32; + +})(); \ No newline at end of file diff --git a/react/src/util/crypto/gen/ellipticcurve.js b/react/src/util/crypto/gen/ellipticcurve.js new file mode 100755 index 0000000..d41fee6 --- /dev/null +++ b/react/src/util/crypto/gen/ellipticcurve.js @@ -0,0 +1,669 @@ +//https://raw.github.com/bitcoinjs/bitcoinjs-lib/faa10f0f6a1fff0b9a99fffb9bc30cee33b17212/src/ecdsa.js +/*! +* Basic Javascript Elliptic Curve implementation +* Ported loosely from BouncyCastle's Java EC code +* Only Fp curves implemented for now +* +* Copyright Tom Wu, bitaddress.org BSD License. +* http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE +*/ +(function () { + + // Constructor function of Global EllipticCurve object + var ec = window.EllipticCurve = function () { }; + + + // ---------------- + // ECFieldElementFp constructor + // q instanceof BigInteger + // x instanceof BigInteger + ec.FieldElementFp = function (q, x) { + this.x = x; + // TODO if(x.compareTo(q) >= 0) error + this.q = q; + }; + + ec.FieldElementFp.prototype.equals = function (other) { + if (other == this) return true; + return (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); + }; + + // D.1.4 91 + /** + * return a sqrt root - the routine verifies that the calculation + * returns the right value - if none exists it returns null. + * + * Copyright (c) 2000 - 2011 The Legion Of The Bouncy Castle (http://www.bouncycastle.org) + * Ported to JavaScript by bitaddress.org + */ + ec.FieldElementFp.prototype.sqrt = function () { + if (!this.q.testBit(0)) throw new Error("even value of q"); + + // p mod 4 == 3 + if (this.q.testBit(1)) { + // z = g^(u+1) + p, p = 4u + 3 + 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; + } + + // p mod 4 == 1 + var qMinusOne = this.q.subtract(BigInteger.ONE); + var legendreExponent = qMinusOne.shiftRight(1); + if (!(this.x.modPow(legendreExponent, this.q).equals(BigInteger.ONE))) return null; + var u = qMinusOne.shiftRight(2); + var k = u.shiftLeft(1).add(BigInteger.ONE); + var Q = this.x; + var fourQ = Q.shiftLeft(2).mod(this.q); + var U, V; + + do { + var rand = new SecureRandom(); + var P; + 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); + + U = result[0]; + V = result[1]; + if (V.multiply(V).mod(this.q).equals(fourQ)) { + // Integer division by 2, mod q + if (V.testBit(0)) { + V = V.add(this.q); + } + V = V.shiftRight(1); + return new ec.FieldElementFp(this.q, V); + } + } + while (U.equals(BigInteger.ONE) || U.equals(qMinusOne)); + + return null; + }; + + /* + * Copyright (c) 2000 - 2011 The Legion Of The Bouncy Castle (http://www.bouncycastle.org) + * Ported to JavaScript by bitaddress.org + */ + ec.FieldElementFp.fastLucasSequence = function (p, P, Q, k) { + // TODO Research and apply "common-multiplicand multiplication here" + + var n = k.bitLength(); + var s = k.getLowestSetBit(); + var Uh = BigInteger.ONE; + var Vl = BigInteger.TWO; + var Vh = P; + var Ql = BigInteger.ONE; + var Qh = BigInteger.ONE; + + for (var j = n - 1; j >= s + 1; --j) { + Ql = Ql.multiply(Qh).mod(p); + if (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); + } + else { + 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); + } + } + + Ql = Ql.multiply(Qh).mod(p); + Qh = Ql.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); + + for (var 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]; + }; + + // ---------------- + // ECPointFp constructor + ec.PointFp = function (curve, x, y, z, compressed) { + this.curve = curve; + this.x = x; + this.y = y; + // Projective coordinates: either zinv == null or z * zinv == 1 + // z and zinv are just BigIntegers, not fieldElements + if (z == null) { + this.z = BigInteger.ONE; + } + else { + this.z = z; + } + this.zinv = null; + // compression flag + this.compressed = !!compressed; + }; + + ec.PointFp.prototype.getX = function () { + if (this.zinv == null) { + this.zinv = this.z.modInverse(this.curve.q); + } + var r = this.x.toBigInteger().multiply(this.zinv); + this.curve.reduce(r); + return this.curve.fromBigInteger(r); + }; + + ec.PointFp.prototype.getY = function () { + if (this.zinv == null) { + this.zinv = this.z.modInverse(this.curve.q); + } + var r = this.y.toBigInteger().multiply(this.zinv); + this.curve.reduce(r); + return this.curve.fromBigInteger(r); + }; + + ec.PointFp.prototype.equals = function (other) { + if (other == this) return true; + if (this.isInfinity()) return other.isInfinity(); + if (other.isInfinity()) return this.isInfinity(); + var u, v; + // u = Y2 * Z1 - Y1 * Z2 + u = other.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(other.z)).mod(this.curve.q); + if (!u.equals(BigInteger.ZERO)) return false; + // v = X2 * Z1 - X1 * Z2 + v = other.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(other.z)).mod(this.curve.q); + return v.equals(BigInteger.ZERO); + }; + + ec.PointFp.prototype.isInfinity = function () { + if ((this.x == null) && (this.y == null)) return true; + return 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; + + // u = Y2 * Z1 - Y1 * Z2 + var u = b.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(b.z)).mod(this.curve.q); + // v = X2 * Z1 - X1 * Z2 + var v = b.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(b.z)).mod(this.curve.q); + + + if (BigInteger.ZERO.equals(v)) { + if (BigInteger.ZERO.equals(u)) { + return this.twice(); // this == b, so double + } + return this.curve.getInfinity(); // this = -b, so infinity + } + + var THREE = new BigInteger("3"); + var x1 = this.x.toBigInteger(); + var y1 = this.y.toBigInteger(); + var x2 = b.x.toBigInteger(); + var y2 = b.y.toBigInteger(); + + var v2 = v.square(); + var v3 = v2.multiply(v); + var x1v2 = x1.multiply(v2); + var zu2 = u.square().multiply(this.z); + + // x3 = v * (z2 * (z1 * u^2 - 2 * x1 * v^2) - v^3) + var x3 = zu2.subtract(x1v2.shiftLeft(1)).multiply(b.z).subtract(v3).multiply(v).mod(this.curve.q); + // y3 = z2 * (3 * x1 * u * v^2 - y1 * v^3 - z1 * u^3) + u * v^3 + var 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 = v^3 * z1 * z2 + var 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 (this.y.toBigInteger().signum() == 0) return this.curve.getInfinity(); + + // TODO: optimized handling of constants + var THREE = new BigInteger("3"); + var x1 = this.x.toBigInteger(); + var y1 = this.y.toBigInteger(); + + var y1z1 = y1.multiply(this.z); + var y1sqz1 = y1z1.multiply(y1).mod(this.curve.q); + var a = this.curve.a.toBigInteger(); + + // w = 3 * x1^2 + a * z1^2 + var w = x1.square().multiply(THREE); + if (!BigInteger.ZERO.equals(a)) { + w = w.add(this.z.square().multiply(a)); + } + w = w.mod(this.curve.q); + //this.curve.reduce(w); + // x3 = 2 * y1 * z1 * (w^2 - 8 * x1 * y1^2 * z1) + var x3 = w.square().subtract(x1.shiftLeft(3).multiply(y1sqz1)).shiftLeft(1).multiply(y1z1).mod(this.curve.q); + // y3 = 4 * y1^2 * z1 * (3 * w * x1 - 2 * y1^2 * z1) - w^3 + var y3 = w.multiply(THREE).multiply(x1).subtract(y1sqz1.shiftLeft(1)).shiftLeft(2).multiply(y1sqz1).subtract(w.square().multiply(w)).mod(this.curve.q); + // z3 = 8 * (y1 * z1)^3 + var 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); + }; + + // Simple NAF (Non-Adjacent Form) multiplication algorithm + // TODO: modularize the multiplication algorithm + ec.PointFp.prototype.multiply = function (k) { + if (this.isInfinity()) return this; + if (k.signum() == 0) return this.curve.getInfinity(); + + var e = k; + var h = e.multiply(new BigInteger("3")); + + var neg = this.negate(); + var R = this; + + var i; + for (i = h.bitLength() - 2; i > 0; --i) { + R = R.twice(); + + var hBit = h.testBit(i); + var eBit = e.testBit(i); + + if (hBit != eBit) { + R = R.add(hBit ? this : neg); + } + } + + return R; + }; + + // Compute this*j + x*k (simultaneous multiplication) + ec.PointFp.prototype.multiplyTwo = function (j, x, k) { + var i; + if (j.bitLength() > k.bitLength()) + i = j.bitLength() - 1; + else + i = k.bitLength() - 1; + + var R = this.curve.getInfinity(); + var both = this.add(x); + while (i >= 0) { + R = R.twice(); + if (j.testBit(i)) { + if (k.testBit(i)) { + R = R.add(both); + } + else { + R = R.add(this); + } + } + else { + if (k.testBit(i)) { + R = R.add(x); + } + } + --i; + } + + return R; + }; + + // patched by bitaddress.org and Casascius for use with Bitcoin.ECKey + // patched by coretechs to support compressed public keys + ec.PointFp.prototype.getEncoded = function (compressed) { + var x = this.getX().toBigInteger(); + var y = this.getY().toBigInteger(); + var len = 32; // integerToBytes will zero pad if integer is less than 32 bytes. 32 bytes length is required by the Bitcoin protocol. + var enc = ec.integerToBytes(x, len); + + // when compressed prepend byte depending if y point is even or odd + if (compressed) { + if (y.isEven()) { + enc.unshift(0x02); + } + else { + enc.unshift(0x03); + } + } + else { + enc.unshift(0x04); + enc = enc.concat(ec.integerToBytes(y, len)); // uncompressed public key appends the bytes of the y point + } + return enc; + }; + + ec.PointFp.decodeFrom = function (curve, enc) { + var type = enc[0]; + var dataLen = enc.length - 1; + + // Extract x and y as byte arrays + var xBa = enc.slice(1, 1 + dataLen / 2); + var yBa = enc.slice(1 + dataLen / 2, 1 + dataLen); + + // Prepend zero byte to prevent interpretation as negative integer + xBa.unshift(0); + yBa.unshift(0); + + // Convert to BigIntegers + var x = new BigInteger(xBa); + var y = new BigInteger(yBa); + + // Return point + 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)) { + if (this.y.equals(b.y)) { + // this = b, i.e. this must be doubled + return this.twice(); + } + // this = -b, i.e. the result is the point at infinity + return this.curve.getInfinity(); + } + + var x_x = b.x.subtract(this.x); + var y_y = b.y.subtract(this.y); + var gamma = y_y.divide(x_x); + + var x3 = gamma.square().subtract(this.x).subtract(b.x); + var 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 (this.y.toBigInteger().signum() == 0) { + // if y1 == 0, then (x1, y1) == (x1, -y1) + // and hence this = -this and thus 2(x1, y1) == infinity + return this.curve.getInfinity(); + } + + var TWO = this.curve.fromBigInteger(BigInteger.valueOf(2)); + var THREE = this.curve.fromBigInteger(BigInteger.valueOf(3)); + var gamma = this.x.square().multiply(THREE).add(this.curve.a).divide(this.y.multiply(TWO)); + + var x3 = gamma.square().subtract(this.x.multiply(TWO)); + var 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 (k.signum() == 0) return this.curve.getInfinity(); + + var e = k; + var h = e.multiply(new BigInteger("3")); + + var neg = this.negate(); + var R = this; + + var i; + for (i = h.bitLength() - 2; i > 0; --i) { + R = R.twice(); + + var hBit = h.testBit(i); + var eBit = e.testBit(i); + + if (hBit != eBit) { + R = R.add2D(hBit ? this : neg); + } + } + + return R; + }; + + ec.PointFp.prototype.isOnCurve = function () { + var x = this.getX().toBigInteger(); + var y = this.getY().toBigInteger(); + var a = this.curve.getA().toBigInteger(); + var b = this.curve.getB().toBigInteger(); + var n = this.curve.getQ(); + var lhs = y.multiply(y).mod(n); + var 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() + ')'; + }; + + /** + * Validate an elliptic curve point. + * + * See SEC 1, section 3.2.2.1: Elliptic Curve Public Key Validation Primitive + */ + ec.PointFp.prototype.validate = function () { + var n = this.curve.getQ(); + + // Check Q != O + if (this.isInfinity()) { + throw new Error("Point is at infinity."); + } + + // Check coordinate bounds + var x = this.getX().toBigInteger(); + var 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'); + } + + // Check y^2 = x^3 + ax + b (mod n) + if (!this.isOnCurve()) { + throw new Error("Point is not on the curve."); + } + + // Check nQ = 0 (Q is a scalar multiple of G) + if (this.multiply(n).isInfinity()) { + // TODO: This check doesn't work - fix. + throw new Error("Point is not a scalar multiple of G."); + } + + return true; + }; + + + + + // ---------------- + // ECCurveFp constructor + 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) { + if (other == this) return true; + return (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); + }; + + // for now, work with hex strings because they're easier in JS + // compressed support added by bitaddress.org + ec.CurveFp.prototype.decodePointHex = function (s) { + var firstByte = parseInt(s.substr(0, 2), 16); + switch (firstByte) { // first byte + case 0: + return this.infinity; + case 2: // compressed + case 3: // compressed + var yTilde = firstByte & 1; + var xHex = s.substr(2, s.length - 2); + var X1 = new BigInteger(xHex, 16); + return this.decompressPoint(yTilde, X1); + case 4: // uncompressed + case 6: // hybrid + case 7: // hybrid + var len = (s.length - 2) / 2; + var xHex = s.substr(2, len); + var yHex = s.substr(len + 2, len); + + return new ec.PointFp(this, + this.fromBigInteger(new BigInteger(xHex, 16)), + this.fromBigInteger(new BigInteger(yHex, 16))); + + default: // unsupported + return null; + } + }; + + ec.CurveFp.prototype.encodePointHex = function (p) { + if (p.isInfinity()) return "00"; + var xHex = p.getX().toBigInteger().toString(16); + var yHex = p.getY().toBigInteger().toString(16); + var oLen = this.getQ().toString(16).length; + if ((oLen % 2) != 0) oLen++; + while (xHex.length < oLen) { + xHex = "0" + xHex; + } + while (yHex.length < oLen) { + yHex = "0" + yHex; + } + return "04" + xHex + yHex; + }; + + /* + * Copyright (c) 2000 - 2011 The Legion Of The Bouncy Castle (http://www.bouncycastle.org) + * Ported to JavaScript by bitaddress.org + * + * Number yTilde + * BigInteger X1 + */ + ec.CurveFp.prototype.decompressPoint = function (yTilde, X1) { + var x = this.fromBigInteger(X1); + var alpha = x.multiply(x.square().add(this.getA())).add(this.getB()); + var beta = alpha.sqrt(); + // if we can't find a sqrt we haven't got a point on the curve - run! + if (beta == null) throw new Error("Invalid point compression"); + var betaValue = beta.toBigInteger(); + var bit0 = betaValue.testBit(0) ? 1 : 0; + if (bit0 != yTilde) { + // Use the other root + beta = this.fromBigInteger(this.getQ().subtract(betaValue)); + } + return new ec.PointFp(this, x, beta, null, true); + }; + + + ec.fromHex = function (s) { return new BigInteger(s, 16); }; + + ec.integerToBytes = function (i, len) { + var bytes = i.toByteArrayUnsigned(); + if (len < bytes.length) { + bytes = bytes.slice(bytes.length - len); + } else while (len > bytes.length) { + bytes.unshift(0); + } + return bytes; + }; + + + // Named EC curves + // ---------------- + // X9ECParameters constructor + 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; }; + + // secp256k1 is the Curve used by Bitcoin + ec.secNamedCurves = { + // used by Bitcoin + "secp256k1": function () { + // p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1 + var p = ec.fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"); + var a = BigInteger.ZERO; + var b = ec.fromHex("7"); + var n = ec.fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"); + var h = BigInteger.ONE; + var curve = new ec.CurveFp(p, a, b); + var G = curve.decodePointHex("04" + + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" + + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"); + return new ec.X9Parameters(curve, G, n, h); + } + }; + + // secp256k1 called by Bitcoin's ECKEY + ec.getSECCurveByName = function (name) { + if (ec.secNamedCurves[name] == undefined) return null; + return ec.secNamedCurves[name](); + } +})(); \ No newline at end of file diff --git a/react/src/util/crypto/gen/securerandom.js b/react/src/util/crypto/gen/securerandom.js new file mode 100755 index 0000000..51b8349 --- /dev/null +++ b/react/src/util/crypto/gen/securerandom.js @@ -0,0 +1,187 @@ +/*! +* Random number generator with ArcFour PRNG +* +* NOTE: For best results, put code like +* <body onclick='SecureRandom.seedTime();' onkeypress='SecureRandom.seedTime();'> +* in your main HTML document. +* +* Copyright Tom Wu, bitaddress.org BSD License. +* http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE +*/ +(function () { + + // Constructor function of Global SecureRandom object + var sr = window.SecureRandom = function () { }; + + // Properties + sr.state; + sr.pool; + sr.pptr; + + // Pool size must be a multiple of 4 and greater than 32. + // An array of bytes the size of the pool will be passed to init() + sr.poolSize = 256; + + // --- object methods --- + + // public method + // ba: byte array + sr.prototype.nextBytes = function (ba) { + var i; + if (window.crypto && window.crypto.getRandomValues && window.Uint8Array) { + try { + var rvBytes = new Uint8Array(ba.length); + window.crypto.getRandomValues(rvBytes); + for (i = 0; i < ba.length; ++i) + ba[i] = sr.getByte() ^ rvBytes[i]; + return; + } catch (e) { + alert(e); + } + } + for (i = 0; i < ba.length; ++i) ba[i] = sr.getByte(); + }; + + + // --- static methods --- + + // Mix in the current time (w/milliseconds) into the pool + // NOTE: this method should be called from body click/keypress event handlers to increase entropy + sr.seedTime = function () { + sr.seedInt(new Date().getTime()); + } + + sr.getByte = function () { + /*if(!ninja.seeder.isDone()) { + alert("Premature initialisation of the random generator. Something is really wrong, do not generate wallets."); + return NaN; + }*/ + + if (sr.state == null) { + sr.seedTime(); + sr.state = sr.ArcFour(); // Plug in your RNG constructor here + sr.state.init(sr.pool); + sr.pptr = 0; + } + // TODO: allow reseeding after first request + return sr.state.next(); + } + + // Mix in a 32-bit integer into the pool + sr.seedInt = function (x) { + sr.seedInt8(x); + sr.seedInt8((x >> 8)); + sr.seedInt8((x >> 16)); + sr.seedInt8((x >> 24)); + } + + // Mix in a 16-bit integer into the pool + sr.seedInt16 = function (x) { + sr.seedInt8(x); + sr.seedInt8((x >> 8)); + } + + // Mix in a 8-bit integer into the pool + sr.seedInt8 = function (x) { + sr.pool[sr.pptr++] ^= x & 255; + if (sr.pptr >= sr.poolSize) sr.pptr -= sr.poolSize; + } + + // Arcfour is a PRNG + sr.ArcFour = function () { + function Arcfour() { + this.i = 0; + this.j = 0; + this.S = new Array(); + } + + // Initialize arcfour context from key, an array of ints, each from [0..255] + function ARC4init(key) { + var i, j, t; + for (i = 0; i < 256; ++i) + this.S[i] = i; + j = 0; + for (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; + } + + function ARC4next() { + var t; + 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; + return this.S[(t + this.S[this.i]) & 255]; + } + + Arcfour.prototype.init = ARC4init; + Arcfour.prototype.next = ARC4next; + + return new Arcfour(); + }; + + + // Initialize the pool with junk if needed. + if (sr.pool == null) { + sr.pool = new Array(); + sr.pptr = 0; + var t; + if (window.crypto && window.crypto.getRandomValues && window.Uint8Array) { + try { + // Use webcrypto if available + var ua = new Uint8Array(sr.poolSize); + window.crypto.getRandomValues(ua); + for (t = 0; t < sr.poolSize; ++t) + sr.pool[sr.pptr++] = ua[t]; + } catch (e) { alert(e); } + } + while (sr.pptr < sr.poolSize) { // extract some randomness from Math.random() + t = Math.floor(65536 * Math.random()); + sr.pool[sr.pptr++] = t >>> 8; + sr.pool[sr.pptr++] = t & 255; + } + sr.pptr = Math.floor(sr.poolSize * Math.random()); + sr.seedTime(); + // entropy + var entropyStr = ""; + // screen size and color depth: ~4.8 to ~5.4 bits + entropyStr += (window.screen.height * window.screen.width * window.screen.colorDepth); + entropyStr += (window.screen.availHeight * window.screen.availWidth * window.screen.pixelDepth); + // time zone offset: ~4 bits + var dateObj = new Date(); + var timeZoneOffset = dateObj.getTimezoneOffset(); + entropyStr += timeZoneOffset; + // user agent: ~8.3 to ~11.6 bits + entropyStr += navigator.userAgent; + // browser plugin details: ~16.2 to ~21.8 bits + var pluginsStr = ""; + for (var i = 0; i < navigator.plugins.length; i++) { + pluginsStr += navigator.plugins[i].name + " " + navigator.plugins[i].filename + " " + navigator.plugins[i].description + " " + navigator.plugins[i].version + ", "; + } + var mimeTypesStr = ""; + for (var i = 0; i < navigator.mimeTypes.length; i++) { + mimeTypesStr += navigator.mimeTypes[i].description + " " + navigator.mimeTypes[i].type + " " + navigator.mimeTypes[i].suffixes + ", "; + } + entropyStr += pluginsStr + mimeTypesStr; + // cookies and storage: 1 bit + entropyStr += navigator.cookieEnabled + typeof (sessionStorage) + typeof (localStorage); + // language: ~7 bit + entropyStr += navigator.language; + // history: ~2 bit + entropyStr += window.history.length; + // location + entropyStr += window.location; + + var entropyBytes = Crypto.SHA256(entropyStr, { asBytes: true }); + for (var i = 0 ; i < entropyBytes.length ; i++) { + sr.seedInt8(entropyBytes[i]); + } + } +})(); \ No newline at end of file